/* * 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 org.opengis.geometry.DirectPosition; import org.opengis.geometry.MismatchedDimensionException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.geotools.util.Utilities; import org.geotools.resources.Classes; import org.geotools.resources.i18n.Errors; import org.geotools.resources.i18n.ErrorKeys; /** * Base class for {@linkplain DirectPosition direct position} implementations. This base class * provides default implementations for {@link #toString}, {@link #equals} and {@link #hashCode} * methods. * <p> * This class do not holds any state. The decision to implement {@link java.io.Serializable} * or {@link org.geotools.util.Cloneable} interfaces is left to implementors. * * @since 2.4 * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) */ public abstract class AbstractDirectPosition implements DirectPosition { /** * Constructs a direct position. */ protected AbstractDirectPosition() { } /** * Returns always {@code this}, the direct position for this * {@linkplain org.opengis.geometry.coordinate.Position position}. * * @since 2.5 */ public DirectPosition getDirectPosition() { return this; } /** * Sets this direct position to the given position. If the given position is * {@code null}, then all ordinate values are set to {@linkplain Double#NaN NaN}. * * @param position The new position. * * @since 2.5 */ public void setPosition(final DirectPosition position) { final int dimension = getDimension(); if (position != null) { ensureDimensionMatch("position", position.getDimension(), dimension); for (int i=0; i<dimension; i++) { setOrdinate(i, position.getOrdinate(i)); } } else { for (int i=0; i<dimension; i++) { setOrdinate(i, Double.NaN); } } } /** * Returns a sequence of numbers that hold the coordinate of this position in its * reference system. * * @return The coordinates. */ public double[] getCoordinate() { final double[] ordinates = new double[getDimension()]; for (int i=0; i<ordinates.length; i++) { ordinates[i] = getOrdinate(i); } return ordinates; } /** * Convenience method for checking coordinate reference system validity. * * @param crs The coordinate reference system to check. * @param expected the dimension expected. * @throws MismatchedDimensionException if the CRS dimension is not valid. */ static void checkCoordinateReferenceSystemDimension(final CoordinateReferenceSystem crs, final int expected) throws MismatchedDimensionException { if (crs != null) { final int dimension = crs.getCoordinateSystem().getDimension(); if (dimension != expected) { throw new MismatchedDimensionException(Errors.format(ErrorKeys.MISMATCHED_DIMENSION_$3, crs.getName().getCode(), dimension, expected)); } } } /** * Convenience method for checking object dimension validity. * This method is usually invoked for argument checking. * * @param name The name of the argument to check. * @param dimension The object dimension. * @param expectedDimension The Expected dimension for the object. * @throws MismatchedDimensionException if the object doesn't have the expected dimension. */ static void ensureDimensionMatch(final String name, final int dimension, final int expectedDimension) throws MismatchedDimensionException { if (dimension != expectedDimension) { throw new MismatchedDimensionException(Errors.format(ErrorKeys.MISMATCHED_DIMENSION_$3, name, dimension, expectedDimension)); } } /** * Returns a string representation of this coordinate. The default implementation is okay * for occasional formatting (for example for debugging purpose). But if there is a lot * of positions to format, users will get more control by using their own instance of * {@link org.geotools.measure.CoordinateFormat}. */ @Override public String toString() { return toString(this); } /** * Formats the specified position. */ static String toString(final DirectPosition position) { final StringBuilder buffer = new StringBuilder(Classes.getShortClassName(position)).append('['); final int dimension = position.getDimension(); for (int i=0; i<dimension; i++) { if (i != 0) { buffer.append(", "); } buffer.append(position.getOrdinate(i)); } return buffer.append(']').toString(); } /** * Returns a hash value for this coordinate. * * @return A hash code value for this position. */ @Override public int hashCode() { return hashCode(this); } /** * Returns a hash value for the given coordinate. */ static int hashCode(final DirectPosition position) { final int dimension = position.getDimension(); int code = 1; for (int i=0; i<dimension; i++) { final long bits = Double.doubleToLongBits(position.getOrdinate(i)); code = 31 * code + ((int)(bits) ^ (int)(bits >>> 32)); } final CoordinateReferenceSystem crs = position.getCoordinateReferenceSystem(); if (crs != null) { code += crs.hashCode(); } return code; } /** * Returns {@code true} if the specified object is also a {@linkplain DirectPosition * direct position} with equals {@linkplain #getCoordinate coordinate} and * {@linkplain #getCoordinateReferenceSystem CRS}. * * @param object The object to compare with this position. * @return {@code true} if the given object is equals to this position. */ @Override public boolean equals(final Object object) { if (object instanceof DirectPosition) { final DirectPosition that = (DirectPosition) object; final int dimension = getDimension(); if (dimension == that.getDimension()) { for (int i=0; i<dimension; i++) { if (!Utilities.equals(this.getOrdinate(i), that.getOrdinate(i))) { return false; } } if (Utilities.equals(this.getCoordinateReferenceSystem(), that.getCoordinateReferenceSystem())) { assert hashCode() == that.hashCode() : this; return true; } } } return false; } }