001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2007, GeoTools Project Managment Committee (PMC)
005: * (C) 2001, Institut de Recherche pour le D�veloppement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library 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 GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.geometry;
018:
019: // OpenGIS dependencies
020: import org.opengis.geometry.DirectPosition;
021: import org.opengis.geometry.MismatchedDimensionException;
022: import org.opengis.referencing.crs.CoordinateReferenceSystem;
023:
024: // Geotools dependencies
025: import org.geotools.resources.Utilities;
026: import org.geotools.resources.i18n.Errors;
027: import org.geotools.resources.i18n.ErrorKeys;
028:
029: /**
030: * Base class for {@linkplain DirectPosition direct position} implementations. This base class
031: * provides default implementations for {@link #toString}, {@link #equals} and {@link #hashCode}
032: * methods.
033: * <p>
034: * This class do not holds any state. The decision to implement {@link java.io.Serializable}
035: * or {@link org.geotools.util.Cloneable} interfaces is left to implementors.
036: *
037: * @since 2.4
038: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/geometry/AbstractDirectPosition.java $
039: * @version $Id: AbstractDirectPosition.java 28776 2008-01-15 20:26:28Z desruisseaux $
040: * @author Martin Desruisseaux
041: */
042: public abstract class AbstractDirectPosition implements DirectPosition {
043: /**
044: * Constructs a direct position.
045: */
046: protected AbstractDirectPosition() {
047: }
048:
049: /**
050: * Returns always {@code this}, the direct position for this
051: * {@linkplain org.opengis.geometry.coordinate.Position position}.
052: */
053: public DirectPosition getPosition() {
054: return this ;
055: }
056:
057: /**
058: * Returns a sequence of numbers that hold the coordinate of this position in its
059: * reference system.
060: *
061: * @return The coordinates.
062: */
063: public double[] getCoordinates() {
064: final double[] ordinates = new double[getDimension()];
065: for (int i = 0; i < ordinates.length; i++) {
066: ordinates[i] = getOrdinate(i);
067: }
068: return ordinates;
069: }
070:
071: /**
072: * Convenience method for checking coordinate reference system validity.
073: *
074: * @param crs The coordinate reference system to check.
075: * @param expected the dimension expected.
076: * @throws MismatchedDimensionException if the CRS dimension is not valid.
077: */
078: static void checkCoordinateReferenceSystemDimension(
079: final CoordinateReferenceSystem crs, final int expected)
080: throws MismatchedDimensionException {
081: if (crs != null) {
082: final int dimension = crs.getCoordinateSystem()
083: .getDimension();
084: if (dimension != expected) {
085: throw new MismatchedDimensionException(Errors.format(
086: ErrorKeys.MISMATCHED_DIMENSION_$3, crs
087: .getName().getCode(), new Integer(
088: dimension), new Integer(expected)));
089: }
090: }
091: }
092:
093: /**
094: * Convenience method for checking object dimension validity.
095: * This method is usually invoked for argument checking.
096: *
097: * @param name The name of the argument to check.
098: * @param dimension The object dimension.
099: * @param expectedDimension The Expected dimension for the object.
100: * @throws MismatchedDimensionException if the object doesn't have the expected dimension.
101: */
102: static void ensureDimensionMatch(final String name,
103: final int dimension, final int expectedDimension)
104: throws MismatchedDimensionException {
105: if (dimension != expectedDimension) {
106: throw new MismatchedDimensionException(Errors.format(
107: ErrorKeys.MISMATCHED_DIMENSION_$3, name,
108: new Integer(dimension), new Integer(
109: expectedDimension)));
110: }
111: }
112:
113: /**
114: * Returns a string representation of this coordinate. The default implementation is okay
115: * for occasional formatting (for example for debugging purpose). But if there is a lot
116: * of positions to format, users will get more control by using their own instance of
117: * {@link org.geotools.measure.CoordinateFormat}.
118: */
119: public String toString() {
120: return toString(this );
121: }
122:
123: /**
124: * Formats the specified position.
125: */
126: static String toString(final DirectPosition position) {
127: final StringBuffer buffer = new StringBuffer(Utilities
128: .getShortClassName(position)).append('[');
129: final int dimension = position.getDimension();
130: for (int i = 0; i < dimension; i++) {
131: if (i != 0) {
132: buffer.append(", ");
133: }
134: buffer.append(position.getOrdinate(i));
135: }
136: return buffer.append(']').toString();
137: }
138:
139: /**
140: * Returns a hash value for this coordinate.
141: */
142: public int hashCode() {
143: return hashCode(this );
144: }
145:
146: /**
147: * Returns a hash value for the given coordinate.
148: */
149: static int hashCode(final DirectPosition position) {
150: final int dimension = position.getDimension();
151: int code = 1;
152: for (int i = 0; i < dimension; i++) {
153: final long bits = Double.doubleToLongBits(position
154: .getOrdinate(i));
155: code = 31 * code + ((int) (bits) ^ (int) (bits >>> 32));
156: }
157: final CoordinateReferenceSystem crs = position
158: .getCoordinateReferenceSystem();
159: if (crs != null) {
160: code += crs.hashCode();
161: }
162: return code;
163: }
164:
165: /**
166: * Returns {@code true} if the specified object is also a {@linkplain DirectPosition
167: * direct position} with equals {@linkplain #getCoordinates coordinates} and
168: * {@linkplain #getCoordinateReferenceSystem CRS}.
169: */
170: public boolean equals(final Object object) {
171: if (object instanceof DirectPosition) {
172: final DirectPosition that = (DirectPosition) object;
173: final int dimension = getDimension();
174: if (dimension == that.getDimension()) {
175: for (int i = 0; i < dimension; i++) {
176: if (Double.doubleToLongBits(this .getOrdinate(i)) != Double
177: .doubleToLongBits(that.getOrdinate(i))) {
178: return false;
179: }
180: }
181: if (Utilities.equals(this
182: .getCoordinateReferenceSystem(), that
183: .getCoordinateReferenceSystem())) {
184: assert hashCode() == that.hashCode() : this ;
185: return true;
186: }
187: }
188: }
189: return false;
190: }
191:
192: /**
193: * Returns a deep copy of this position.
194: *
195: * @deprecated Will be removed after GeoAPI update.
196: */
197: public Object clone() {
198: try {
199: return super .clone();
200: } catch (CloneNotSupportedException exception) {
201: // Should not happen, since we are cloneable.
202: throw new AssertionError(exception);
203: }
204: }
205: }
|