/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2001-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotools.geometry; import java.awt.geom.Point2D; import java.io.Serializable; import java.util.Arrays; import org.opengis.util.Cloneable; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.geometry.DirectPosition; import org.opengis.geometry.MismatchedDimensionException; import org.geotools.resources.i18n.Errors; import org.geotools.resources.i18n.ErrorKeys; /** * Holds the coordinates for a position within some coordinate reference system. Since * {@code DirectPosition}s, as data types, will often be included in larger objects * (such as {@linkplain org.geotools.geometry.Geometry geometries}) that have references * to {@link CoordinateReferenceSystem}, the {@link #getCoordinateReferenceSystem} method * may returns {@code null} if this particular {@code DirectPosition} is included * in a larger object with such a reference to a {@linkplain CoordinateReferenceSystem * coordinate reference system}. In this case, the cordinate reference system is implicitly * assumed to take on the value of the containing object's {@link CoordinateReferenceSystem}. * <p> * This particular implementation of {@code DirectPosition} is said "General" because it * uses an {@linkplain #ordinates array of ordinates} of an arbitrary length. If the direct * position is know to be always two-dimensional, then {@link DirectPosition2D} may provides * a more efficient implementation. * <p> * Most methods in this implementation are final for performance reason. * * @since 2.0 * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) * * @see DirectPosition1D * @see DirectPosition2D * @see java.awt.geom.Point2D */ public class GeneralDirectPosition extends AbstractDirectPosition implements Serializable, Cloneable { /** * Serial number for interoperability with different versions. */ private static final long serialVersionUID = 9071833698385715524L; /** * The ordinates of the direct position. */ public final double[] ordinates; /** * The coordinate reference system for this position, or {@code null}. */ private CoordinateReferenceSystem crs; /** * Constructs a position using the specified coordinate reference system. * The number of dimensions is inferred from the coordinate reference system. * * @param crs The coordinate reference system to be given to this position. * @since 2.2 */ public GeneralDirectPosition(final CoordinateReferenceSystem crs) { this(crs.getCoordinateSystem().getDimension()); this.crs = crs; } /** * Constructs a position with the specified number of dimensions. * * @param numDim Number of dimensions. * @throws NegativeArraySizeException if {@code numDim} is negative. */ public GeneralDirectPosition(final int numDim) throws NegativeArraySizeException { ordinates = new double[numDim]; } /** * Constructs a position with the specified ordinates. * The {@code ordinates} array will be copied. * * @param ordinates The ordinate values to copy. */ public GeneralDirectPosition(final double[] ordinates) { this.ordinates = ordinates.clone(); } /** * Constructs a 2D position from the specified ordinates. Despite their name, the * (<var>x</var>,<var>y</var>) coordinates don't need to be oriented toward * ({@linkplain org.opengis.referencing.cs.AxisDirection#EAST East}, * {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH North}). * See the {@link DirectPosition2D} javadoc for details. * * @param x The first ordinate value. * @param y The second ordinate value. */ public GeneralDirectPosition(final double x, final double y) { ordinates = new double[] {x,y}; } /** * Constructs a 3D position from the specified ordinates. Despite their name, the * (<var>x</var>,<var>y</var>,<var>z</var>) coordinates don't need to be oriented toward * ({@linkplain org.opengis.referencing.cs.AxisDirection#EAST East}, * {@linkplain org.opengis.referencing.cs.AxisDirection#NORTH North}, * {@linkplain org.opengis.referencing.cs.AxisDirection#UP Up}). * * @param x The first ordinate value. * @param y The second ordinate value. * @param z The third ordinate value. */ public GeneralDirectPosition(final double x, final double y, final double z) { ordinates = new double[] {x,y,z}; } /** * Constructs a position from the specified {@link Point2D}. * * @param point The position to copy. */ public GeneralDirectPosition(final Point2D point) { this(point.getX(), point.getY()); } /** * Constructs a position initialized to the same values than the specified point. * * @param point The position to copy. * * @since 2.2 */ public GeneralDirectPosition(final DirectPosition point) { ordinates = point.getCoordinate(); // Should already be cloned. crs = point.getCoordinateReferenceSystem(); } /** * Returns the coordinate reference system in which the coordinate is given. * May be {@code null} if this particular {@code DirectPosition} is included * in a larger object with such a reference to a {@linkplain CoordinateReferenceSystem * coordinate reference system}. * * @return The coordinate reference system, or {@code null}. */ public final CoordinateReferenceSystem getCoordinateReferenceSystem() { return crs; } /** * Set the coordinate reference system in which the coordinate is given. * * @param crs The new coordinate reference system, or {@code null}. * @throws MismatchedDimensionException if the specified CRS doesn't have the expected * number of dimensions. */ public void setCoordinateReferenceSystem(final CoordinateReferenceSystem crs) throws MismatchedDimensionException { checkCoordinateReferenceSystemDimension(crs, getDimension()); this.crs = crs; } /** * The length of coordinate sequence (the number of entries). * This may be less than or equal to the dimensionality of the * {@linkplain #getCoordinateReferenceSystem() coordinate reference system}. * * @return The dimensionality of this position. */ public final int getDimension() { return ordinates.length; } /** * Returns a sequence of numbers that hold the coordinate of this position in its * reference system. * * @return A copy of the {@linkplain #ordinates coordinates}. */ @Override public final double[] getCoordinate() { return ordinates.clone(); } /** * Returns the ordinate at the specified dimension. * * @param dimension The dimension in the range 0 to {@linkplain #getDimension dimension}-1. * @return The coordinate at the specified dimension. * @throws IndexOutOfBoundsException if the specified dimension is out of bounds. */ public final double getOrdinate(int dimension) throws IndexOutOfBoundsException { return ordinates[dimension]; } /** * Sets the ordinate value along the specified dimension. * * @param dimension the dimension for the ordinate of interest. * @param value the ordinate value of interest. * @throws IndexOutOfBoundsException if the specified dimension is out of bounds. */ public final void setOrdinate(int dimension, double value) throws IndexOutOfBoundsException { ordinates[dimension] = value; } /** * Set this coordinate to the specified direct position. If the specified position * contains a {@linkplain CoordinateReferenceSystem coordinate reference system}, * then the CRS for this position will be set to the CRS of the specified position. * * @param position The new position for this point. * @throws MismatchedDimensionException if this point doesn't have the expected dimension. * * @since 2.2 */ public final void setLocation(final DirectPosition position) throws MismatchedDimensionException { ensureDimensionMatch("position", position.getDimension(), ordinates.length); setCoordinateReferenceSystem(position.getCoordinateReferenceSystem()); for (int i=0; i<ordinates.length; i++) { ordinates[i] = position.getOrdinate(i); } } /** * Set this coordinate to the specified direct position. This method is identical to * {@link #setLocation(DirectPosition)}, but is slightly faster in the special case * of an {@code GeneralDirectPosition} implementation. * * @param position The new position for this point. * @throws MismatchedDimensionException if this point doesn't have the expected dimension. */ public final void setLocation(final GeneralDirectPosition position) throws MismatchedDimensionException { ensureDimensionMatch("position", position.ordinates.length, ordinates.length); setCoordinateReferenceSystem(position.crs); System.arraycopy(position.ordinates, 0, ordinates, 0, ordinates.length); } /** * Set this coordinate to the specified {@link Point2D}. * This coordinate must be two-dimensional. * * @param point The new coordinate for this point. * @throws MismatchedDimensionException if this coordinate point is not two-dimensional. */ public final void setLocation(final Point2D point) throws MismatchedDimensionException { if (ordinates.length != 2) { throw new MismatchedDimensionException(Errors.format( ErrorKeys.NOT_TWO_DIMENSIONAL_$1, ordinates.length)); } ordinates[0] = point.getX(); ordinates[1] = point.getY(); } /** * Returns a {@link Point2D} with the same coordinate as this direct position. * This is a convenience method for interoperability with Java2D. * * @return This position as a two-dimensional point. * @throws IllegalStateException if this coordinate point is not two-dimensional. */ public Point2D toPoint2D() throws IllegalStateException { if (ordinates.length != 2) { throw new IllegalStateException(Errors.format( ErrorKeys.NOT_TWO_DIMENSIONAL_$1, ordinates.length)); } return new Point2D.Double(ordinates[0], ordinates[1]); } /** * Returns a hash value for this coordinate. */ @Override public int hashCode() { int code = Arrays.hashCode(ordinates); if (crs != null) { code += crs.hashCode(); } assert code == super.hashCode(); return code; } /** * Returns a deep copy of this position. */ @Override public GeneralDirectPosition clone() { return new GeneralDirectPosition(ordinates); } }