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: import java.util.ArrayList;
036: import java.util.HashMap;
037:
038: import com.vividsolutions.jts.util.Assert;
039: import com.vividsolutions.jump.I18N;
040: import com.vividsolutions.jump.coordsys.CoordinateSystem;
041:
042: /**
043: * Metadata for a FeatureCollection: attribute names and types.
044: * @see FeatureCollection
045: */
046: public class FeatureSchema implements Cloneable, Serializable {
047: private static final long serialVersionUID = -8627306219650589202L;
048: //<<TODO:QUESTION>> Is this an efficient implementation? Must cast the Integer to
049: //an int. [Jon Aquino]
050: private CoordinateSystem coordinateSystem = CoordinateSystem.UNSPECIFIED;
051: private HashMap attributeNameToIndexMap = new HashMap();
052: private int geometryIndex = -1;
053: private int attributeCount = 0;
054: private ArrayList attributeNames = new ArrayList();
055: private ArrayList attributeTypes = new ArrayList();
056:
057: //todo Deep-copy! [Jon Aquino]
058: //deep copy done 25. Juli 2005 [sstein]
059: public Object clone() {
060: try {
061: FeatureSchema fs = new FeatureSchema();
062: for (int i = 0; i < this .attributeCount; i++) {
063: AttributeType at = (AttributeType) this .attributeTypes
064: .get(i);
065: String aname = (String) this .attributeNames.get(i);
066: fs.addAttribute(aname, at);
067: fs.setCoordinateSystem(this .coordinateSystem);
068: }
069: return fs;
070: } catch (Exception ex) {
071: Assert.shouldNeverReachHere();
072: return null;
073: }
074: }
075:
076: /**
077: * Returns the zero-based index of the attribute with the given name
078: * (case-sensitive)
079: *@throws IllegalArgumentException if attributeName is unrecognized
080: */
081: public int getAttributeIndex(String attributeName) {
082: //<<TODO:RECONSIDER>> Attribute names are currently case sensitive.
083: //I wonder whether or not this is desirable. [Jon Aquino]
084: Integer index = (Integer) attributeNameToIndexMap
085: .get(attributeName);
086: if (index == null) {
087: throw new IllegalArgumentException(
088: I18N
089: .get("feature.FeatureSchema.unrecognized-attribute-name")
090: + " " + attributeName);
091: }
092: return index.intValue();
093: }
094:
095: /**
096: * Returns whether this FeatureSchema has an attribute with this name
097: * @param attributeName the name to look up
098: * @return whether this FeatureSchema has an attribute with this name
099: */
100: public boolean hasAttribute(String attributeName) {
101: return attributeNameToIndexMap.get(attributeName) != null;
102: }
103:
104: /**
105: * Returns the attribute index of the Geometry, or -1 if there is no
106: * Geometry attribute
107: */
108: public int getGeometryIndex() {
109: return geometryIndex;
110: }
111:
112: /**
113: * Returns the (case-sensitive) name of the attribute at the given zero-based index.
114: */
115: public String getAttributeName(int attributeIndex) {
116: return (String) attributeNames.get(attributeIndex);
117: }
118:
119: /**
120: * Returns whether the attribute at the given zero-based index is a string,
121: * integer, double, etc.
122: */
123: public AttributeType getAttributeType(int attributeIndex) {
124: return (AttributeType) attributeTypes.get(attributeIndex);
125: }
126:
127: /**
128: * Returns whether the attribute with the given name (case-sensitive) is a string,
129: * integer, double, etc.
130: */
131: public AttributeType getAttributeType(String attributeName) {
132: return getAttributeType(getAttributeIndex(attributeName));
133: }
134:
135: /**
136: * Returns the total number of spatial and non-spatial attributes in this
137: * FeatureSchema. There are 0 or 1 spatial attributes and 0 or more
138: * non-spatial attributes.
139: */
140: public int getAttributeCount() {
141: return attributeCount;
142: }
143:
144: /**
145: * Adds an attribute with the given case-sensitive name.
146: * @throws AssertionFailedException if a second Geometry is being added
147: */
148: public void addAttribute(String attributeName,
149: AttributeType attributeType) {
150: if (AttributeType.GEOMETRY == attributeType) {
151: Assert.isTrue(geometryIndex == -1);
152: geometryIndex = attributeCount;
153: }
154: attributeNames.add(attributeName);
155: attributeNameToIndexMap.put(attributeName, new Integer(
156: attributeCount));
157: attributeTypes.add(attributeType);
158: attributeCount++;
159: }
160:
161: /**
162: * Returns whether the two FeatureSchemas have the same attribute names
163: * with the same types and in the same order.
164: */
165: public boolean equals(Object other) {
166: return this .equals(other, false);
167: }
168:
169: /**
170: * Returns whether the two FeatureSchemas have the same attribute names
171: * with the same types and (optionally) in the same order.
172: */
173: public boolean equals(Object other, boolean orderMatters) {
174: if (!(other instanceof FeatureSchema)) {
175: return false;
176: }
177: FeatureSchema otherFeatureSchema = (FeatureSchema) other;
178: if (attributeNames.size() != otherFeatureSchema.attributeNames
179: .size()) {
180: return false;
181: }
182: for (int i = 0; i < attributeNames.size(); i++) {
183: String attributeName = (String) attributeNames.get(i);
184: if (!otherFeatureSchema.attributeNames
185: .contains(attributeName)) {
186: return false;
187: }
188: if (orderMatters
189: && !otherFeatureSchema.attributeNames.get(i)
190: .equals(attributeName)) {
191: return false;
192: }
193: if (getAttributeType(attributeName) != otherFeatureSchema
194: .getAttributeType(attributeName)) {
195: return false;
196: }
197: }
198: return true;
199: }
200:
201: /**
202: * Sets the CoordinateSystem associated with this FeatureSchema, but does
203: * not perform any reprojection.
204: * @return this FeatureSchema
205: */
206: public FeatureSchema setCoordinateSystem(
207: CoordinateSystem coordinateSystem) {
208: this .coordinateSystem = coordinateSystem;
209: return this ;
210: }
211:
212: /**
213: * @see #setCoordinateSystem(CoordinateSystem)
214: */
215: public CoordinateSystem getCoordinateSystem() {
216: return coordinateSystem;
217: }
218:
219: }
|