All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotoolkit.geometry.DirectPosition2D Maven / Gradle / Ivy

/*
 *    Geotoolkit.org - An Open Source Java GIS Toolkit
 *    http://www.geotoolkit.org
 *
 *    (C) 2004-2012, Open Source Geospatial Foundation (OSGeo)
 *    (C) 2009-2012, Geomatys
 *
 *    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.geotoolkit.geometry;

import java.awt.geom.Point2D;
import java.io.IOException;
import java.io.Serializable;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.AxisDirection;

import org.geotoolkit.util.Cloneable;
import org.geotoolkit.util.Utilities;
import org.geotoolkit.resources.Errors;


/**
 * Holds the coordinates for a two-dimensional position within some coordinate reference system.
 * This class inherits {@linkplain #x x} and {@linkplain #y y} fields. But despite their names,
 * they don't need to be oriented toward {@linkplain AxisDirection#EAST East} and {@linkplain
 * AxisDirection#NORTH North}. The (x,y) axis can have any orientation and
 * should be understood as "ordinate 0" and "ordinate 1" values instead.
 * This is not specific to this implementation; in Java2D too, the visual axis orientation depend
 * on the {@linkplain java.awt.Graphics2D#getTransform affine transform in the graphics context}.
 * 

* The rational for avoiding axis orientation restriction is that other {@link DirectPosition} * implementation do not have such restriction, and it would be hard to generalize. For example * there is no clear "x" or "y" classification for {@linkplain AxisDirection#NORTH_EAST North-East} * direction. *

* {@section Caution when used in collections} * Do not mix instances of this class with ordinary {@link Point2D} instances in a * {@link java.util.HashSet} or as {@link java.util.HashMap} keys. It is not possible to * meet both {@link Point2D#hashCode} and {@link DirectPosition#hashCode} contract, and this class * chooses to implements the later. Consequently, {@link #hashCode} is inconsistent with * {@link Point2D#equals} but is consistent with {@link DirectPosition#equals}. *

* In other words, it is safe to add instances of {@code DirectPosition2D} in a * {@code HashSet}, but it is unsafe to add them in a {@code HashSet}. * Collections that do not rely on {@link Object#hashCode}, like {@link java.util.ArrayList}, * are safe in all cases. * * @author Martin Desruisseaux (IRD, Geomatys) * @version 3.09 * * @see DirectPosition1D * @see GeneralDirectPosition * @see java.awt.geom.Point2D * * @since 2.0 * @module */ public class DirectPosition2D extends Point2D.Double implements DirectPosition, Serializable, Cloneable { /** * Serial number for inter-operability with different versions. */ private static final long serialVersionUID = 835130287438466996L; /** * The coordinate reference system for this position; */ private CoordinateReferenceSystem crs; /** * Constructs a position initialized to (0,0) with a {@code null} coordinate reference system. */ public DirectPosition2D() { } /** * Constructs a position with the specified coordinate reference system. * * @param crs The coordinate reference system, or {@code null}. */ public DirectPosition2D(final CoordinateReferenceSystem crs) { setCoordinateReferenceSystem(crs); } /** * Constructs a 2D position from the specified ordinates. Despite their name, * the (x,y) coordinates don't need to be oriented toward * ({@linkplain AxisDirection#EAST East}, {@linkplain AxisDirection#NORTH North}). * Those parameter names simply match the {@linkplain #x x} and {@linkplain #y y} * fields. See the class javadoc for details. * * @param x The x value. * @param y The y value. */ public DirectPosition2D(final double x, final double y) { super(x,y); } /** * Constructs a 2D position from the specified ordinates in the specified CRS. Despite * their name, the (x,y) coordinates don't need to be oriented toward * ({@linkplain AxisDirection#EAST East}, {@linkplain AxisDirection#NORTH North}). * Those parameter names simply match the {@linkplain #x x} and {@linkplain #y y} * fields. The actual axis orientations are determined by the specified CRS. * See the class javadoc for details. * * @param crs The coordinate reference system, or {@code null}. * @param x The x value. * @param y The y value. */ public DirectPosition2D(final CoordinateReferenceSystem crs, final double x, final double y) { super(x, y); setCoordinateReferenceSystem(crs); } /** * Constructs a position from the specified {@link Point2D}. * * @param point The point to copy. */ public DirectPosition2D(final Point2D point) { super(point.getX(), point.getY()); if (point instanceof DirectPosition) { setCoordinateReferenceSystem(((DirectPosition) point).getCoordinateReferenceSystem()); } } /** * Constructs a position initialized to the same values than the specified point. * * @param point The point to copy. * @throws MismatchedDimensionException if this point doesn't have the expected dimension. */ public DirectPosition2D(final DirectPosition point) throws MismatchedDimensionException { setLocation(point); } /** * Constructs a position initialized to the values parsed from the given string in * Well Known Text (WKT) format. The given string is typically a {@code POINT} * element like below: * * {@preformat wkt * POINT(6 10) * } * * @param wkt The {@code POINT} or other kind of element to parse. * @throws NumberFormatException If a number can not be parsed. * @throws IllegalArgumentException If the parenthesis are not balanced. * @throws MismatchedDimensionException If the given point is not two-dimensional. * * @see AbstractDirectPosition#toString(DirectPosition) * @see org.geotoolkit.measure.CoordinateFormat * * @since 3.09 */ public DirectPosition2D(final String wkt) throws NumberFormatException, IllegalArgumentException { final double[] ordinates = AbstractDirectPosition.parse(wkt); final int dimension = (ordinates != null) ? ordinates.length : 0; if (dimension != 2) { throw new MismatchedDimensionException(Errors.format( Errors.Keys.MISMATCHED_DIMENSION_$3, wkt, dimension, 2)); } x = ordinates[0]; y = ordinates[1]; } /** * Returns always {@code this}, the direct position for this * {@linkplain org.opengis.geometry.coordinate.Position position}. * * @since 2.5 */ @Override public DirectPosition getDirectPosition() { return this; } /** * 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 CRS. * * @return The coordinate reference system, or {@code null}. */ @Override public final CoordinateReferenceSystem getCoordinateReferenceSystem() { return crs; } /** * Sets the coordinate reference system in which the coordinate is given. * * @param crs The new coordinate reference system, or {@code null}. */ public void setCoordinateReferenceSystem(final CoordinateReferenceSystem crs) { AbstractDirectPosition.checkCoordinateReferenceSystemDimension(crs, 2); this.crs = crs; } /** * The length of coordinate sequence (the number of entries). * This is always 2 for {@code DirectPosition2D} objects. * * @return The dimensionality of this position. */ @Override public final int getDimension() { return 2; } /** * Returns a sequence of numbers that hold the coordinate of this position in its * reference system. * * @return The coordinate. */ @Override public double[] getCoordinate() { return new double[] {x,y}; } /** * Returns the ordinate at the specified dimension. * * @param dimension The dimension in the range 0 to 1 inclusive. * @return The coordinate at the specified dimension. * @throws IndexOutOfBoundsException if the specified dimension is out of bounds. * * @todo Provides a more detailed error message. */ @Override public final double getOrdinate(final int dimension) throws IndexOutOfBoundsException { switch (dimension) { case 0: return x; case 1: return y; default: throw new IndexOutOfBoundsException(Errors.format( Errors.Keys.INDEX_OUT_OF_BOUNDS_$1, 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. */ @Override public final void setOrdinate(int dimension, double value) throws IndexOutOfBoundsException { switch (dimension) { case 0: x = value; break; case 1: y = value; break; default: throw new IndexOutOfBoundsException(Errors.format( Errors.Keys.INDEX_OUT_OF_BOUNDS_$1, dimension)); } } /** * Sets 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. */ public void setLocation(final DirectPosition position) throws MismatchedDimensionException { AbstractDirectPosition.ensureDimensionMatch("position", position.getDimension(), 2); setCoordinateReferenceSystem(position.getCoordinateReferenceSystem()); x = position.getOrdinate(0); y = position.getOrdinate(1); } /** * Returns a {@link Point2D} with the same coordinate as this direct position. * * @return This position as a point. */ public Point2D toPoint2D() { return new Point2D.Double(x,y); } /** * Formats this position in the Well Known Text (WKT) format. * The output is like below: * *

{@code POINT(}{@linkplain #getCoordinate() ordinates}{@code )}
* * The output of this method can be * {@linkplain GeneralDirectPosition#GeneralDirectPosition(String) parsed} by the * {@link GeneralDirectPosition} constructor. */ @Override public String toString() { return AbstractDirectPosition.toString(this); } /** * Returns a hash value for this coordinate. This method implements the * {@link DirectPosition#hashCode} contract, not the {@link Point2D#hashCode} contract. * * @return A hash code value for this position. */ @Override public int hashCode() { return AbstractDirectPosition.hashCode(this); } /** * Compares this point with the specified object for equality. If the given object implements * the {@link DirectPosition} interface, then the comparison is performed as specified in its * {@link DirectPosition#equals} contract. Otherwise the comparison is performed as specified * in {@link Point2D#equals}. * * @param object The object to compare with this position. * @return {@code true} if the given object is equal to this position. */ @Override public boolean equals(final Object object) { /* * If the other object implements the DirectPosition interface, performs * the comparison as specified in DirectPosition.equals(Object) contract. */ if (object instanceof DirectPosition) { final DirectPosition other = (DirectPosition) object; if (other.getDimension() == 2 && Utilities.equals(other.getOrdinate(0), x) && Utilities.equals(other.getOrdinate(1), y) && Utilities.equals(other.getCoordinateReferenceSystem(), crs)) { assert hashCode() == other.hashCode() : this; return true; } return false; } /* * Otherwise performs the comparison as in Point2D.equals(Object). * Do NOT check the CRS if the given object is an ordinary Point2D. * This is necessary in order to respect the contract defined in Point2D. */ return super.equals(object); } /** * Returns a clone of this point. * * @return A clone of this position. */ @Override public DirectPosition2D clone() { return (DirectPosition2D) super.clone(); } /** * Write this object to the specified stream. This method is necessary * because the super-class is not serializable. */ private void writeObject(final ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeDouble(x); out.writeDouble(y); } /** * Read this object from the specified stream. This method is necessary * because the super-class is not serializable. */ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); x = in.readDouble(); y = in.readDouble(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy