001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032: package com.vividsolutions.jump.feature;
033:
034: import java.io.Serializable;
035:
036: import com.vividsolutions.jts.geom.Geometry;
037: import com.vividsolutions.jts.util.Assert;
038:
039: /**
040: * Default implementation of the Feature interface. Subclasses need
041: * implement only the four remaining Feature methods: #getAttribute,
042: * #setAttribute, #getAttributes, #setAttributes
043: */
044: public abstract class AbstractBasicFeature implements Feature,
045: Serializable {
046: private static final long serialVersionUID = 4215477286292970800L;
047: private FeatureSchema schema;
048: private int id;
049:
050: /**
051: * A low-level accessor that is not normally used.
052: */
053: public void setSchema(FeatureSchema schema) {
054: this .schema = schema;
055: }
056:
057: /**
058: * Creates a new Feature based on the given metadata.
059: *
060: *@param featureSchema the metadata containing information on
061: * each column
062: */
063: public AbstractBasicFeature(FeatureSchema featureSchema) {
064: id = FeatureUtil.nextID();
065: this .schema = featureSchema;
066: }
067:
068: /**
069: * Returns a number that uniquely identifies this feature. This number is not
070: * persistent.
071: * @return n, where this feature is the nth Feature created by this application
072: */
073: public int getID() {
074: return id;
075: }
076:
077: /**
078: * Sets the specified attribute.
079: *
080: *@param attributeName the name of the attribute to set
081: *@param newAttribute the new attribute
082: */
083: public void setAttribute(String attributeName, Object newAttribute) {
084: setAttribute(schema.getAttributeIndex(attributeName),
085: newAttribute);
086: }
087:
088: /**
089: * Convenience method for setting the spatial attribute. JUMP Workbench
090: * PlugIns and CursorTools should not use this method directly, but should use an
091: * EditTransaction, so that the proper events are fired.
092: *
093: *@param geometry the new spatial attribute
094: */
095: public void setGeometry(Geometry geometry) {
096: setAttribute(schema.getGeometryIndex(), geometry);
097: }
098:
099: /**
100: * Returns the specified attribute.
101: *
102: *@param name the name of the attribute to get
103: *@return the attribute
104: */
105: public Object getAttribute(String name) {
106: try {
107: return getAttribute(schema.getAttributeIndex(name));
108: } catch (ArrayIndexOutOfBoundsException e) {
109: throw e;
110: }
111: }
112:
113: //<<TODO:DOC>>Update JavaDoc -- the attribute need not be a String [Jon Aquino]
114: /**
115: * Returns a String attribute. The attribute at the given index must be a
116: * String.
117: *
118: *@param attributeIndex the array index of the attribute
119: *@return the String attribute at the given index
120: */
121: public String getString(int attributeIndex) {
122: // return (String) attributes[attributeIndex];
123: //Dave B changed this so you can convert Integers->Strings
124: //Automatic conversion of integers to strings is a bit hack-like.
125: //Instead one should do #getAttribute followed by #toString.
126: //#getString should be strict: it should throw an Exception if it is used
127: //on a non-String attribute. [Jon Aquino]
128: Object result = getAttribute(attributeIndex);
129: //We used to eat ArrayOutOfBoundsExceptions here. I've removed this behaviour
130: //because ArrayOutOfBoundsExceptions are bugs and should be exposed. [Jon Aquino]
131: //Is it valid for an attribute to be null? If not, we should put an
132: //Assert here [Jon Aquino]
133: if (result != null) {
134: return result.toString();
135: } else {
136: return "";
137: }
138: }
139:
140: /**
141: * Returns a integer attribute.
142: *
143: *@param attributeIndex the index of the attribute to retrieve
144: *@return the integer attribute with the given name
145: */
146: public int getInteger(int attributeIndex) {
147: return ((Integer) getAttribute(attributeIndex)).intValue();
148: }
149:
150: /**
151: * Returns a double attribute.
152: *
153: *@param attributeIndex the index of the attribute to retrieve
154: *@return the double attribute with the given name
155: */
156: public double getDouble(int attributeIndex) {
157: return ((Double) getAttribute(attributeIndex)).doubleValue();
158: }
159:
160: //<<TODO:DOC>>Update JavaDoc -- the attribute need not be a String [Jon Aquino]
161: /**
162: * Returns a String attribute. The attribute with the given name must be a
163: * String.
164: *
165: *@param attributeName the name of the attribute to retrieve
166: *@return the String attribute with the given name
167: */
168: public String getString(String attributeName) {
169: return getString(schema.getAttributeIndex(attributeName));
170: }
171:
172: /**
173: * Convenience method for returning the spatial attribute.
174: *
175: *@return the feature's spatial attribute
176: */
177: public Geometry getGeometry() {
178: return (Geometry) getAttribute(schema.getGeometryIndex());
179: }
180:
181: /**
182: * Returns the feature's metadata
183: *
184: *@return the metadata describing the names and types of the attributes
185: */
186: public FeatureSchema getSchema() {
187: return schema;
188: }
189:
190: /**
191: * Clones this Feature. The geometry will also be cloned.
192: * @return a new Feature with the same attributes as this Feature
193: */
194: public Object clone() {
195: return clone(true);
196: }
197:
198: /**
199: * Clones this Feature.
200: * @param deep whether or not to clone the geometry
201: * @return a new Feature with the same attributes as this Feature
202: */
203: public Feature clone(boolean deep) {
204: return clone(this , deep);
205: }
206:
207: public static BasicFeature clone(Feature feature, boolean deep) {
208: BasicFeature clone = new BasicFeature(feature.getSchema());
209: for (int i = 0; i < feature.getSchema().getAttributeCount(); i++) {
210: if (feature.getSchema().getAttributeType(i) == AttributeType.GEOMETRY) {
211: clone.setAttribute(i, deep ? feature.getGeometry()
212: .clone() : feature.getGeometry());
213: } else {
214: clone.setAttribute(i, feature.getAttribute(i));
215: }
216: }
217: return clone;
218: }
219:
220: public int compareTo(Object o) {
221: return compare(this , (Feature) o);
222: }
223:
224: public static int compare(Feature a, Feature b) {
225: int geometryComparison = a.getGeometry().compareTo(
226: ((Feature) b).getGeometry());
227: if (geometryComparison != 0) {
228: return geometryComparison;
229: }
230: if (a == b) {
231: return 0;
232: }
233: //The features do not refer to the same object, so try to return something consistent. [Jon Aquino]
234: if (a.getID() != ((Feature) b).getID()) {
235: return a.getID() - ((Feature) b).getID();
236: }
237: //The ID is hosed. Last gasp: hope the hash codes are different. [Jon Aquino]
238: if (a.hashCode() != b.hashCode()) {
239: return a.hashCode() - b.hashCode();
240: }
241: Assert.shouldNeverReachHere();
242: return -1;
243: }
244: }
|