/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * Copyright (C) 2003 Vivid Solutions * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.vividsolutions.jump.feature; import java.io.Serializable; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.util.Assert; /** * Default implementation of the Feature interface. Subclasses need * implement only the four remaining Feature methods: #getAttribute, * #setAttribute, #getAttributes, #setAttributes */ public abstract class AbstractBasicFeature implements Feature, Serializable { private static final long serialVersionUID = 4215477286292970800L; private FeatureSchema schema; private int id; /** * A low-level accessor that is not normally used. */ public void setSchema(FeatureSchema schema) { this.schema = schema; } /** * Creates a new Feature based on the given metadata. * *@param featureSchema the metadata containing information on * each column */ public AbstractBasicFeature(FeatureSchema featureSchema) { id = FeatureUtil.nextID(); this.schema = featureSchema; } /** * Returns a number that uniquely identifies this feature. This number is not * persistent. * @return n, where this feature is the nth Feature created by this application */ public int getID() { return id; } /** * Sets the specified attribute. * *@param attributeName the name of the attribute to set *@param newAttribute the new attribute */ public void setAttribute(String attributeName, Object newAttribute) { setAttribute(schema.getAttributeIndex(attributeName), newAttribute); } /** * Convenience method for setting the spatial attribute. JUMP Workbench * PlugIns and CursorTools should not use this method directly, but should use an * EditTransaction, so that the proper events are fired. * *@param geometry the new spatial attribute */ public void setGeometry(Geometry geometry) { setAttribute(schema.getGeometryIndex(), geometry); } /** * Returns the specified attribute. * *@param name the name of the attribute to get *@return the attribute */ public Object getAttribute(String name) { try { return getAttribute(schema.getAttributeIndex(name)); } catch (ArrayIndexOutOfBoundsException e) { throw e; } } //<<TODO:DOC>>Update JavaDoc -- the attribute need not be a String [Jon Aquino] /** * Returns a String attribute. The attribute at the given index must be a * String. * *@param attributeIndex the array index of the attribute *@return the String attribute at the given index */ public String getString(int attributeIndex) { // return (String) attributes[attributeIndex]; //Dave B changed this so you can convert Integers->Strings //Automatic conversion of integers to strings is a bit hack-like. //Instead one should do #getAttribute followed by #toString. //#getString should be strict: it should throw an Exception if it is used //on a non-String attribute. [Jon Aquino] Object result = getAttribute(attributeIndex); //We used to eat ArrayOutOfBoundsExceptions here. I've removed this behaviour //because ArrayOutOfBoundsExceptions are bugs and should be exposed. [Jon Aquino] //Is it valid for an attribute to be null? If not, we should put an //Assert here [Jon Aquino] if (result != null) { return result.toString(); } else { return ""; } } /** * Returns a integer attribute. * *@param attributeIndex the index of the attribute to retrieve *@return the integer attribute with the given name */ public int getInteger(int attributeIndex) { return ((Integer) getAttribute(attributeIndex)).intValue(); } /** * Returns a double attribute. * *@param attributeIndex the index of the attribute to retrieve *@return the double attribute with the given name */ public double getDouble(int attributeIndex) { return ((Double) getAttribute(attributeIndex)).doubleValue(); } //<<TODO:DOC>>Update JavaDoc -- the attribute need not be a String [Jon Aquino] /** * Returns a String attribute. The attribute with the given name must be a * String. * *@param attributeName the name of the attribute to retrieve *@return the String attribute with the given name */ public String getString(String attributeName) { return getString(schema.getAttributeIndex(attributeName)); } /** * Convenience method for returning the spatial attribute. * *@return the feature's spatial attribute */ public Geometry getGeometry() { return (Geometry) getAttribute(schema.getGeometryIndex()); } /** * Returns the feature's metadata * *@return the metadata describing the names and types of the attributes */ public FeatureSchema getSchema() { return schema; } /** * Clones this Feature. The geometry will also be cloned. * @return a new Feature with the same attributes as this Feature */ public Object clone() { return clone(true); } /** * Clones this Feature. * @param deep whether or not to clone the geometry * @return a new Feature with the same attributes as this Feature */ public Feature clone(boolean deep) { return clone(this, deep); } public static BasicFeature clone(Feature feature, boolean deep) { BasicFeature clone = new BasicFeature(feature.getSchema()); for (int i = 0; i < feature.getSchema().getAttributeCount(); i++) { if (feature.getSchema().getAttributeType(i) == AttributeType.GEOMETRY) { clone.setAttribute(i, deep ? feature.getGeometry().clone() : feature.getGeometry()); } else { clone.setAttribute(i, feature.getAttribute(i)); } } return clone; } public int compareTo(Object o) { return compare(this, (Feature)o); } public static int compare(Feature a, Feature b) { int geometryComparison = a.getGeometry().compareTo(((Feature) b).getGeometry()); if (geometryComparison != 0) { return geometryComparison; } if (a == b) { return 0; } //The features do not refer to the same object, so try to return something consistent. [Jon Aquino] if (a.getID() != ((Feature) b).getID()) { return a.getID() - ((Feature) b).getID(); } //The ID is hosed. Last gasp: hope the hash codes are different. [Jon Aquino] if (a.hashCode() != b.hashCode()) { return a.hashCode() - b.hashCode(); } Assert.shouldNeverReachHere(); return -1; } }