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

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

Go to download

Implementations of Coordinate Reference Systems (CRS), conversion and transformation services derived from ISO 19111.

There is a newer version: 3.20-geoapi-3.0
Show newest version
/*
 *    Geotoolkit.org - An Open Source Java GIS Toolkit
 *    http://www.geotoolkit.org
 *
 *    (C) 2005-2011, Open Source Geospatial Foundation (OSGeo)
 *    (C) 2009-2011, 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 org.opengis.util.FactoryException;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.CoordinateOperation;
import org.opengis.referencing.operation.CoordinateOperationFactory;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;

import org.geotoolkit.factory.Hints;
import org.geotoolkit.factory.FactoryFinder;
import org.geotoolkit.factory.FactoryRegistryException;
import org.geotoolkit.referencing.CRS;
import org.geotoolkit.referencing.crs.DefaultGeographicCRS;

import static org.geotoolkit.util.ArgumentChecks.ensureNonNull;


/**
 * A direct position capable to {@linkplain #transform transform} a point between an arbitrary CRS
 * and {@linkplain #getCoordinateReferenceSystem its own CRS}. This class caches the last transform
 * used in order to improve the performances when the {@linkplain CoordinateOperation#getSourceCRS
 * source} and {@linkplain CoordinateOperation#getTargetCRS target} CRS don't change often. Using
 * this class is faster than invoking {@linkplain CoordinateOperationFactory#createOperation
 * CoordinateOperationFactory.createOperation}(sourceCRS, targetCRS) for every points.
 *
 * 
    *
  • Note 1: * This class is advantageous on a performance point of view only if the same instance of * {@code TransformedDirectPosition} is used for transforming many points between arbitrary * CRS and this {@linkplain #getCoordinateReferenceSystem position CRS}.

  • * *
  • Note 2: * This convenience class is useful when the source and target CRS are not likely to * change often. If you are sure that the source and target CRS will not change at all * for a given set of positions, then using {@link CoordinateOperation} directly gives better * performances. This is because {@code TransformedDirectPosition} checks if the CRS changed * before every transformations, which may be costly.

  • * *
  • Note 3: * This class is called Transformed Direct Position because it is more commonly * used for transforming many points from arbitrary CRS to a common CRS (using the * {@link #transform(DirectPosition)} method) than the other way around.

  • *
* * This class usually don't appears in a public API. It is more typicaly used as a helper private * field in some more complex class. For example suppose that {@code MyClass} needs to perform its * internal working in some particular CRS, but we want robust API that adjusts itself to whatever * CRS the client happen to use. {@code MyClass} could be written as below: * * {@preformat java * public class MyClass { * private static final CoordinateReferenceSystem PUBLIC_CRS = ... * private static final CoordinateReferenceSystem INTERNAL_CRS = ... * * private final TransformedDirectPosition myPosition = * new TransformedDirectPosition(PUBLIC_CRS, INTERNAL_CRS, null); * * public void setPosition(DirectPosition position) throws TransformException { * // The position CRS is usually PUBLIC_CRS, but code below will work even if it is not. * myPosition.transform(position); * } * * public DirectPosition getPosition() throws TransformException { * return myPosition.inverseTransform(PUBLIC_CRS); * } * } * } * * @author Martin Desruisseaux (IRD) * @version 3.00 * * @since 2.2 * @level advanced * @module */ public class TransformedDirectPosition extends GeneralDirectPosition { /** * Serial number for inter-operability with different versions. */ private static final long serialVersionUID = -3988283183934950437L; /** * The factory to use for creating new coordinate operation. */ private final CoordinateOperationFactory factory; /** * The default source CRS. To be used only when the user invoked {@link #transform} with * a position without associated {@link CoordinateReferenceSystem}. May be {@code null} * if the default CRS is assumed equal to {@linkplain #getCoordinateReferenceSystem this * position CRS}. */ private final CoordinateReferenceSystem defaultCRS; /** * The last source CRS used, or {@code null}. The {@code targetCRS} is the * {@linkplain #getCoordinateReferenceSystem CRS associated with this position}. */ private transient CoordinateReferenceSystem sourceCRS; /** * The forward and inverse transforms. Will be created only when first needed. */ private transient MathTransform forward, inverse; /** * Creates a new direct position initialized with the * {@linkplain DefaultGeographicCRS#WGS84 WGS84} CRS. * * @since 2.3 */ public TransformedDirectPosition() { this(null, DefaultGeographicCRS.WGS84, null); } /** * Creates a new position which will contains the result of coordinate transformations from * {@code sourceCRS} to {@code targetCRS}. The {@linkplain #getCoordinateReferenceSystem CRS * associated with this position} will be initially set to {@code targetCRS}. * * @param sourceCRS The default CRS to be used by the * {@link #transform transform}(position) method only * when the user-supplied {@code position} has a null * {@linkplain DirectPosition#getCoordinateReferenceSystem associated CRS}. * This {@code sourceCRS} argument may be {@code null}, in which case it is assumed * the same than {@code targetCRS}. * * @param targetCRS The {@linkplain #getCoordinateReferenceSystem CRS associated with this * position}. Used for every {@linkplain #transform coordinate transformations} until * the next call to {@link #setCoordinateReferenceSystem setCoordinateReferenceSystem} * or {@link #setLocation(DirectPosition) setLocation}. This argument can not be null. * * @param hints The set of hints to use for fetching a {@link CoordinateOperationFactory}, * or {@code null} if none. * * @throws FactoryRegistryException if no {@linkplain CoordinateOperationFactory coordinate * operation factory} can be found for the specified hints. * * @since 2.3 */ public TransformedDirectPosition(final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS, final Hints hints) throws FactoryRegistryException { super(targetCRS); ensureNonNull("targetCRS", targetCRS); defaultCRS = CRS.equalsIgnoreMetadata(sourceCRS, targetCRS) ? null : sourceCRS; factory = FactoryFinder.getCoordinateOperationFactory(hints); } /** * Sets the coordinate reference system in which the coordinate is given. * The given CRS will be used as: *

*

    *
  • the {@linkplain CoordinateOperation#getTargetCRS target CRS} for every call to * {@link #transform(DirectPosition)}
  • *
  • the {@linkplain CoordinateOperation#getSourceCRS source CRS} for every call to * {@link #inverseTransform(CoordinateReferenceSystem)}
  • *
* * @param crs The new CRS for this direct position. * @throws MismatchedDimensionException if the specified CRS doesn't have the expected * number of dimensions. */ @Override public void setCoordinateReferenceSystem(final CoordinateReferenceSystem crs) throws MismatchedDimensionException { ensureNonNull("crs", crs); super.setCoordinateReferenceSystem(crs); forward = null; inverse = null; } /** * Sets the {@link #sourceCRS} field and create the associated {@link #forward} transform. * This method do not create yet the {@link #inverse} transform, since it may not be needed. */ private void setSourceCRS(final CoordinateReferenceSystem crs) throws TransformException { final CoordinateReferenceSystem targetCRS = getCoordinateReferenceSystem(); final CoordinateOperation operation; try { operation = factory.createOperation(crs, targetCRS); } catch (FactoryException exception) { throw new TransformException(exception.getLocalizedMessage(), exception); } /* * Note: 'sourceCRS' must be set last, when we are sure that all other fields * are set to their correct value. This is in order to keep this instance in * a consistent state in case an exception is thrown. */ forward = operation.getMathTransform(); inverse = null; sourceCRS = crs; } /** * Transforms a given position and stores the result in this object. * *
    *
  • The {@linkplain CoordinateOperation#getSourceCRS source CRS} is the * {@linkplain DirectPosition#getCoordinateReferenceSystem CRS associated with the given * position}, or the {@code sourceCRS} argument given at * {@linkplain #TransformedDirectPosition(CoordinateReferenceSystem, * CoordinateReferenceSystem, Hints) construction time} if and only if * the CRS associated with {@code position} is null.

  • * *
  • The {@linkplain CoordinateOperation#getTargetCRS target CRS} is the {@linkplain * #getCoordinateReferenceSystem CRS associated with this position}. This is always the * {@code targetCRS} argument given at {@linkplain * #TransformedDirectPosition(CoordinateReferenceSystem, CoordinateReferenceSystem, * Hints) construction time} or by the last call to {@link #setCoordinateReferenceSystem * setCoordinateReferenceSystem}.

  • *
* * @param position A position using an arbitrary CRS. This object will not be modified. * @throws TransformException if a coordinate transformation was required and failed. */ public void transform(final DirectPosition position) throws TransformException { CoordinateReferenceSystem userCRS = position.getCoordinateReferenceSystem(); if (userCRS == null) { userCRS = defaultCRS; if (userCRS == null) { setLocation(position); return; } } /* * A projection may be required. Checks if it is the same one than the one used * last time this method has been invoked. If the specified position uses a new * CRS, then gets the transformation and saves it in case the next call to this * method would uses again the same transformation. */ if (forward == null || !CRS.equalsIgnoreMetadata(sourceCRS, userCRS)) { setSourceCRS(userCRS); } if (forward.transform(position, this) != this) { throw new AssertionError(forward); // Should never occurs. } } /** * Returns a new point with the same coordinates than this one, but transformed in the given * CRS. This method never returns {@code this}, so the returned point usually doesn't need to * be cloned. * * @param crs The CRS for the position to be returned. * @return The same position than {@code this}, but transformed in the specified CRS. * @throws TransformException if a coordinate transformation was required and failed. * * @since 2.3 */ public DirectPosition inverseTransform(final CoordinateReferenceSystem crs) throws TransformException { if (inverse == null || !CRS.equalsIgnoreMetadata(sourceCRS, crs)) { ensureNonNull("crs", crs); setSourceCRS(crs); inverse = forward.inverse(); } return inverse.transform(this, null); } /** * Returns a new point with the same coordinates than this one, but transformed in the * {@code sourceCRS} given at {@linkplain #TransformedDirectPosition(CoordinateReferenceSystem, * CoordinateReferenceSystem, Hints) construction time}. This method never returns {@code this}, * so the returned point usually doesn't need to be cloned. * * @return The same position than {@code this}, but transformed in the source CRS. * @throws TransformException if a coordinate transformation was required and failed. * * @since 2.3 */ public DirectPosition inverseTransform() throws TransformException { if (defaultCRS != null) { return inverseTransform(defaultCRS); } else { return new GeneralDirectPosition(this); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy