001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, 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: // J2SE dependencies
020: import java.awt.geom.Point2D;
021: import java.io.Serializable;
022:
023: // OpenGIS dependencies
024: import org.opengis.util.Cloneable;
025: import org.opengis.referencing.cs.AxisDirection; // For javadoc
026: import org.opengis.referencing.crs.CoordinateReferenceSystem;
027: import org.opengis.geometry.DirectPosition;
028: import org.opengis.geometry.MismatchedDimensionException;
029:
030: // Geotools dependencies
031: import org.geotools.resources.i18n.Errors;
032: import org.geotools.resources.i18n.ErrorKeys;
033:
034: /**
035: * Holds the coordinates for a position within some coordinate reference system. Since
036: * {@code DirectPosition}s, as data types, will often be included in larger objects
037: * (such as {@linkplain org.geotools.geometry.Geometry geometries}) that have references
038: * to {@link CoordinateReferenceSystem}, the {@link #getCoordinateReferenceSystem} method
039: * may returns {@code null} if this particular {@code DirectPosition} is included
040: * in a larger object with such a reference to a {@linkplain CoordinateReferenceSystem
041: * coordinate reference system}. In this case, the cordinate reference system is implicitly
042: * assumed to take on the value of the containing object's {@link CoordinateReferenceSystem}.
043: * <p>
044: * This particular implementation of {@code DirectPosition} is said "General" because it
045: * uses an {@linkplain #ordinates array of ordinates} of an arbitrary length. If the direct
046: * position is know to be always two-dimensional, then {@link DirectPosition2D} may provides
047: * a more efficient implementation.
048: * <p>
049: * Most methods in this implementation are final for performance reason.
050: *
051: * @since 2.0
052: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/geometry/GeneralDirectPosition.java $
053: * @version $Id: GeneralDirectPosition.java 26137 2007-07-03 17:59:44Z desruisseaux $
054: * @author Martin Desruisseaux
055: *
056: * @see DirectPosition1D
057: * @see DirectPosition2D
058: * @see java.awt.geom.Point2D
059: */
060: public class GeneralDirectPosition extends AbstractDirectPosition
061: implements Serializable, Cloneable {
062: /**
063: * Serial number for interoperability with different versions.
064: */
065: private static final long serialVersionUID = 9071833698385715524L;
066:
067: /**
068: * The ordinates of the direct position.
069: */
070: public final double[] ordinates;
071:
072: /**
073: * The coordinate reference system for this position, or {@code null}.
074: */
075: private CoordinateReferenceSystem crs;
076:
077: /**
078: * Constructs a position using the specified coordinate reference system.
079: * The number of dimensions is inferred from the coordinate reference system.
080: *
081: * @since 2.2
082: */
083: public GeneralDirectPosition(final CoordinateReferenceSystem crs) {
084: this (crs.getCoordinateSystem().getDimension());
085: this .crs = crs;
086: }
087:
088: /**
089: * Constructs a position with the specified number of dimensions.
090: *
091: * @param numDim Number of dimensions.
092: * @throws NegativeArraySizeException if {@code numDim} is negative.
093: */
094: public GeneralDirectPosition(final int numDim)
095: throws NegativeArraySizeException {
096: ordinates = new double[numDim];
097: }
098:
099: /**
100: * Constructs a position with the specified ordinates.
101: * The {@code ordinates} array will be copied.
102: */
103: public GeneralDirectPosition(final double[] ordinates) {
104: this .ordinates = (double[]) ordinates.clone();
105: }
106:
107: /**
108: * Constructs a 2D position from the specified ordinates. Despite their name, the
109: * (<var>x</var>,<var>y</var>) coordinates don't need to be oriented toward
110: * ({@linkplain AxisDirection#EAST East}, {@linkplain AxisDirection#NORTH North}).
111: * See the {@link DirectPosition2D} javadoc for details.
112: */
113: public GeneralDirectPosition(final double x, final double y) {
114: ordinates = new double[] { x, y };
115: }
116:
117: /**
118: * Constructs a 3D position from the specified ordinates. Despite their name, the
119: * (<var>x</var>,<var>y</var>,<var>z</var>) coordinates don't need to be oriented toward
120: * ({@linkplain AxisDirection#EAST East}, {@linkplain AxisDirection#NORTH North},
121: * {@linkplain AxisDirection#UP Up}).
122: */
123: public GeneralDirectPosition(final double x, final double y,
124: final double z) {
125: ordinates = new double[] { x, y, z };
126: }
127:
128: /**
129: * Constructs a position from the specified {@link Point2D}.
130: */
131: public GeneralDirectPosition(final Point2D point) {
132: this (point.getX(), point.getY());
133: }
134:
135: /**
136: * Constructs a position initialized to the same values than the specified point.
137: *
138: * @since 2.2
139: */
140: public GeneralDirectPosition(final DirectPosition point) {
141: ordinates = (double[]) point.getCoordinates(); // Should already be cloned.
142: crs = point.getCoordinateReferenceSystem();
143: }
144:
145: /**
146: * Returns the coordinate reference system in which the coordinate is given.
147: * May be {@code null} if this particular {@code DirectPosition} is included
148: * in a larger object with such a reference to a {@linkplain CoordinateReferenceSystem
149: * coordinate reference system}.
150: *
151: * @return The coordinate reference system, or {@code null}.
152: */
153: public final CoordinateReferenceSystem getCoordinateReferenceSystem() {
154: return crs;
155: }
156:
157: /**
158: * Set the coordinate reference system in which the coordinate is given.
159: *
160: * @param crs The new coordinate reference system, or {@code null}.
161: * @throws MismatchedDimensionException if the specified CRS doesn't have the expected
162: * number of dimensions.
163: */
164: public void setCoordinateReferenceSystem(
165: final CoordinateReferenceSystem crs)
166: throws MismatchedDimensionException {
167: checkCoordinateReferenceSystemDimension(crs, getDimension());
168: this .crs = crs;
169: }
170:
171: /**
172: * The length of coordinate sequence (the number of entries).
173: * This may be less than or equal to the dimensionality of the
174: * {@linkplain #getCoordinateReferenceSystem() coordinate reference system}.
175: *
176: * @return The dimensionality of this position.
177: */
178: public final int getDimension() {
179: return ordinates.length;
180: }
181:
182: /**
183: * Returns a sequence of numbers that hold the coordinate of this position in its
184: * reference system.
185: *
186: * @return A copy of the {@linkplain #ordinates coordinates}.
187: */
188: public final double[] getCoordinates() {
189: return (double[]) ordinates.clone();
190: }
191:
192: /**
193: * Returns the ordinate at the specified dimension.
194: *
195: * @param dimension The dimension in the range 0 to {@linkplain #getDimension dimension}-1.
196: * @return The coordinate at the specified dimension.
197: * @throws IndexOutOfBoundsException if the specified dimension is out of bounds.
198: */
199: public final double getOrdinate(int dimension)
200: throws IndexOutOfBoundsException {
201: return ordinates[dimension];
202: }
203:
204: /**
205: * Sets the ordinate value along the specified dimension.
206: *
207: * @param dimension the dimension for the ordinate of interest.
208: * @param value the ordinate value of interest.
209: * @throws IndexOutOfBoundsException if the specified dimension is out of bounds.
210: */
211: public final void setOrdinate(int dimension, double value)
212: throws IndexOutOfBoundsException {
213: ordinates[dimension] = value;
214: }
215:
216: /**
217: * Set this coordinate to the specified direct position. If the specified position
218: * contains a {@linkplain CoordinateReferenceSystem coordinate reference system},
219: * then the CRS for this position will be set to the CRS of the specified position.
220: *
221: * @param position The new position for this point.
222: * @throws MismatchedDimensionException if this point doesn't have the expected dimension.
223: *
224: * @since 2.2
225: */
226: public final void setLocation(final DirectPosition position)
227: throws MismatchedDimensionException {
228: ensureDimensionMatch("position", position.getDimension(),
229: ordinates.length);
230: setCoordinateReferenceSystem(position
231: .getCoordinateReferenceSystem());
232: for (int i = 0; i < ordinates.length; i++) {
233: ordinates[i] = position.getOrdinate(i);
234: }
235: }
236:
237: /**
238: * Set this coordinate to the specified direct position. This method is identical to
239: * {@link #setLocation(DirectPosition)}, but is slightly faster in the special case
240: * of an {@code GeneralDirectPosition} implementation.
241: *
242: * @param position The new position for this point.
243: * @throws MismatchedDimensionException if this point doesn't have the expected dimension.
244: */
245: public final void setLocation(final GeneralDirectPosition position)
246: throws MismatchedDimensionException {
247: ensureDimensionMatch("position", position.ordinates.length,
248: ordinates.length);
249: setCoordinateReferenceSystem(position.crs);
250: System.arraycopy(position.ordinates, 0, ordinates, 0,
251: ordinates.length);
252: }
253:
254: /**
255: * Set this coordinate to the specified {@link Point2D}.
256: * This coordinate must be two-dimensional.
257: *
258: * @param point The new coordinate for this point.
259: * @throws MismatchedDimensionException if this coordinate point is not two-dimensional.
260: */
261: public final void setLocation(final Point2D point)
262: throws MismatchedDimensionException {
263: if (ordinates.length != 2) {
264: throw new MismatchedDimensionException(Errors.format(
265: ErrorKeys.NOT_TWO_DIMENSIONAL_$1, new Integer(
266: ordinates.length)));
267: }
268: ordinates[0] = point.getX();
269: ordinates[1] = point.getY();
270: }
271:
272: /**
273: * Returns a {@link Point2D} with the same coordinate as this direct position.
274: * This is a convenience method for interoperability with Java2D.
275: *
276: * @throws IllegalStateException if this coordinate point is not two-dimensional.
277: */
278: public Point2D toPoint2D() throws IllegalStateException {
279: if (ordinates.length != 2) {
280: throw new IllegalStateException(Errors.format(
281: ErrorKeys.NOT_TWO_DIMENSIONAL_$1, new Integer(
282: ordinates.length)));
283: }
284: return new Point2D.Double(ordinates[0], ordinates[1]);
285: }
286:
287: /**
288: * Formats the specified position.
289: *
290: * @since 2.3
291: *
292: * @deprecated Use {@link org.geotools.measure.CoordinateFormat} instead.
293: */
294: public static String toString(final DirectPosition position) {
295: return AbstractDirectPosition.toString(position);
296: }
297:
298: /**
299: * Returns a hash value for this coordinate.
300: */
301: public int hashCode() {
302: int code = hashCode(ordinates);
303: if (crs != null) {
304: code += crs.hashCode();
305: }
306: assert code == super .hashCode();
307: return code;
308: }
309:
310: /**
311: * Returns a hash value for the specified ordinates.
312: *
313: * @todo Remove this method when we will alowed to use J2SE 1.5 runtime.
314: */
315: static int hashCode(final double[] ordinates) {
316: int code = 1;
317: if (ordinates != null) {
318: for (int i = 0; i < ordinates.length; i++) {
319: final long bits = Double.doubleToLongBits(ordinates[i]);
320: code = 31 * code + ((int) (bits) ^ (int) (bits >>> 32));
321: }
322: }
323: return code;
324: }
325:
326: /**
327: * Returns a deep copy of this position.
328: */
329: public Object clone() {
330: return new GeneralDirectPosition(ordinates);
331: }
332: }
|