org.geotoolkit.geometry.AbstractDirectPosition Maven / Gradle / Ivy
/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2001-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.util.Arrays;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.geotoolkit.util.XArrays;
import org.geotoolkit.util.Utilities;
import org.geotoolkit.referencing.CRS;
import org.geotoolkit.resources.Errors;
import static org.geotoolkit.util.Strings.trimFractionalPart;
/**
* Base class for {@linkplain DirectPosition direct position} implementations. This base class
* provides default implementations for {@link #toString}, {@link #equals} and {@link #hashCode}
* methods.
*
* This class do not holds any state. The decision to implement {@link java.io.Serializable}
* or {@link org.geotoolkit.util.Cloneable} interfaces is left to implementors.
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @version 3.16
*
* @since 2.4
* @module
*/
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
*/
@Override
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}.
*
* If this position and the given position have a non-null CRS, then the default implementation
* requires the CRS to be {@linkplain CRS#equalsIgnoreMetadata equals (ignoring metadata)}
* otherwise a {@link MismatchedReferenceSystemException} is thrown. However subclass may
* choose to assign the CRS of this position to the CRS of the given position.
*
* @param position The new position, or {@code null}.
* @throws MismatchedDimensionException If the given position doesn't have the expected dimension.
* @throws MismatchedReferenceSystemException If the given position doesn't use the expected CRS.
*
* @since 3.16 (derived from 2.5)
*/
public void setLocation(final DirectPosition position) throws MismatchedDimensionException
{
final int dimension = getDimension();
if (position != null) {
ensureDimensionMatch("position", position.getDimension(), dimension);
final CoordinateReferenceSystem crs = getCoordinateReferenceSystem();
if (crs != null) {
final CoordinateReferenceSystem other = position.getCoordinateReferenceSystem();
if (other != null && !CRS.equalsIgnoreMetadata(crs, other)) {
throw new IllegalArgumentException(Errors.format(
Errors.Keys.MISMATCHED_COORDINATE_REFERENCE_SYSTEM));
}
}
for (int i=0; iWell 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 toString(this);
}
/**
* Formats a {@code POINT} element from a direct position. This method formats the given
* position in the Well Known Text (WKT) format. The output is like below:
*
* {@code POINT(}{@linkplain DirectPosition#getCoordinate() ordinates}{@code )}
*
* The output of this method can be
* {@linkplain GeneralDirectPosition#GeneralDirectPosition(String) parsed} by the
* {@link GeneralDirectPosition} constructor.
*
* @param position The position to format.
* @return The position as a {@code POINT} in WKT format.
*
* @see GeneralDirectPosition#GeneralDirectPosition(String)
* @see org.geotoolkit.measure.CoordinateFormat
* @see org.geotoolkit.io.wkt
*
* @since 3.09
*/
public static String toString(final DirectPosition position) {
final StringBuilder buffer = new StringBuilder("POINT(");
final int dimension = position.getDimension();
for (int i=0; i= length) return null;
if (Character.isJavaIdentifierStart(c = wkt.charAt(i))) {
do if (++i >= length) return null;
while (Character.isJavaIdentifierPart(c = wkt.charAt(i)));
}
} while (Character.isWhitespace(c));
/*
* Skip the opening parenthesis, and the following whitespaces if any.
* We remember the matching parenthesis since we will look for it later.
* Note: we use character ' ' for "end of string".
*/
char close = ' ';
if (c == '(' || c == '[') {
close = (c == '(') ? ')' : ']';
do if (++i >= length) {
c = ' ';
break;
} while (Character.isWhitespace(c = wkt.charAt(i)));
}
/*
* Index i is either at the beginning of a number, at the closing parenthesis or at the end
* of string (in any cases we are not at a whitespace). Now process every space-separated
* ordinates until we reach the closing parenthesis or the end of string.
*/
double[] ordinates = new double[2];
int dimension = 0;
scan: while (true) {
if (c == close) {
/*
* We have reached the closing parenthesis. Having any non-whitespace
* character after this one is an error. Otherwise we are done.
*/
while (++i < length) {
if (!Character.isWhitespace(c = wkt.charAt(i))) {
throw new IllegalArgumentException(Errors.format(
Errors.Keys.UNPARSABLE_STRING_$2, wkt, wkt.substring(i)));
}
}
break scan;
}
/*
* We are at the beginning of a number. Find where the number ends (at
* the first whitespace or closing parenthesis), parse it and store it.
*/
final int start = i;
do if (++i >= length) {
i = length;
c = ' ';
break;
} while (!Character.isWhitespace(c = wkt.charAt(i)) && c != close);
if (dimension == ordinates.length) {
ordinates = Arrays.copyOf(ordinates, dimension*2);
}
ordinates[dimension++] = Double.parseDouble(wkt.substring(start, i));
/*
* Skip whitespaces. If we reach the end of string without finding
* the closing parenthesis, check if we were suppose to have any.
*/
while (Character.isWhitespace(c)) {
if (++i >= length) {
if (close != ' ') {
throw new IllegalArgumentException(Errors.format(
Errors.Keys.NON_EQUILIBRATED_PARENTHESIS_$2, wkt, close));
}
break scan;
}
c = wkt.charAt(i);
}
}
return XArrays.resize(ordinates, dimension);
}
/**
* 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>> 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 equal 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