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

org.geotoolkit.referencing.operation.DefaultSingleOperation 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) 2004-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.
 *
 *    This package contains documentation from OpenGIS specifications.
 *    OpenGIS consortium's work is fully acknowledged here.
 */
package org.geotoolkit.referencing.operation;

import java.util.Map;
import net.jcip.annotations.Immutable;

import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.Projection;
import org.opengis.referencing.operation.Transformation;
import org.opengis.referencing.operation.OperationMethod;
import org.opengis.referencing.operation.ConicProjection;
import org.opengis.referencing.operation.PlanarProjection;
import org.opengis.referencing.operation.CylindricalProjection;
import org.opengis.referencing.operation.CoordinateOperation;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.SingleOperation;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import org.geotoolkit.referencing.operation.transform.Parameterized;
import org.geotoolkit.referencing.operation.transform.PassThroughTransform;
import org.geotoolkit.internal.referencing.ParameterizedAffine;
import org.geotoolkit.internal.referencing.Semaphores;
import org.geotoolkit.io.wkt.Formatter;
import org.geotoolkit.util.Utilities;
import org.geotoolkit.util.ComparisonMode;
import org.geotoolkit.util.converter.Classes;
import org.geotoolkit.util.UnsupportedImplementationException;

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


/**
 * A parameterized mathematical operation on coordinates that transforms or converts
 * coordinates to another {@linkplain CoordinateReferenceSystem coordinate reference
 * system}. This coordinate operation thus uses an {@linkplain OperationMethod operation
 * method}, usually with associated parameter values.
 * 

* In the Geotk implementation, the {@linkplain #getParameterValues parameter values} * are inferred from the {@linkplain #transform transform}. Other implementations may * have to override the {@link #getParameterValues} method. *

* This is a single (not {@linkplain DefaultConcatenatedOperation concatenated}) * coordinate operation. * * @author Martin Desruisseaux (IRD, Geomatys) * @version 3.18 * * @since 2.0 * @module */ @Immutable public class DefaultSingleOperation extends AbstractCoordinateOperation implements SingleOperation { /** * Serial number for inter-operability with different versions. */ private static final long serialVersionUID = -2635450075620911309L; /** * The operation method. */ protected final OperationMethod method; /** * Constructs a new operation with the same values than the specified defining * conversion, together with the specified source and target CRS. This constructor * is used by {@link DefaultConversion} only. */ DefaultSingleOperation(final Conversion definition, final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS, final MathTransform transform) { super(definition, sourceCRS, targetCRS, transform); method = definition.getMethod(); } /** * Constructs an operation from a set of properties. * The properties given in argument follow the same rules than for the * {@linkplain AbstractCoordinateOperation#AbstractCoordinateOperation(Map, * CoordinateReferenceSystem, CoordinateReferenceSystem, MathTransform) * super-class constructor}. * * @param properties Set of properties. Should contains at least {@code "name"}. * @param sourceCRS The source CRS. * @param targetCRS The target CRS. * @param transform Transform from positions in the {@linkplain #getSourceCRS source CRS} * to positions in the {@linkplain #getTargetCRS target CRS}. * @param method The operation method. */ public DefaultSingleOperation(final Map properties, final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS, final MathTransform transform, final OperationMethod method) { super(properties, sourceCRS, targetCRS, transform); ensureNonNull("method", method); DefaultOperationMethod.checkDimensions(method, transform); this.method = method; } /** * Returns a coordinate operation of the specified class. This method constructs an instance * of {@link Transformation}, {@link ConicProjection}, {@link CylindricalProjection}, * {@link PlanarProjection}, {@link Projection} or {@link Conversion}. * * @param properties Set of properties. Should contains at least {@code "name"}. * @param sourceCRS The source CRS. * @param targetCRS The target CRS. * @param transform Transform from positions in the {@linkplain #getSourceCRS source CRS} * to positions in the {@linkplain #getTargetCRS target CRS}. * @param method The operation method, or {@code null}. * @param type The minimal type as {@linkplain Conversion}.class, * {@linkplain Projection}.class, etc. * This method may create an instance of a subclass of {@code type}. * @return A new coordinate operation of the given type. * * @see DefaultConversion#create(Map, CoordinateReferenceSystem, CoordinateReferenceSystem, MathTransform, OperationMethod, Class) */ public static CoordinateOperation create(final Map properties, final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS, final MathTransform transform, final OperationMethod method, Class type) { if (method != null) { if (method instanceof MathTransformProvider) { final Class candidate = ((MathTransformProvider) method).getOperationType(); if (candidate != null) { if (type == null) { type = candidate; } else if (type.isAssignableFrom(candidate)) { type = candidate.asSubclass(type); } } } if (type != null) { if (Transformation.class.isAssignableFrom(type)) { return new DefaultTransformation( properties, sourceCRS, targetCRS, transform, method); } if (ConicProjection.class.isAssignableFrom(type)) { return new DefaultConicProjection( properties, sourceCRS, targetCRS, transform, method); } if (CylindricalProjection.class.isAssignableFrom(type)) { return new DefaultCylindricalProjection( properties, sourceCRS, targetCRS, transform, method); } if (PlanarProjection.class.isAssignableFrom(type)) { return new DefaultPlanarProjection( properties, sourceCRS, targetCRS, transform, method); } if (Projection.class.isAssignableFrom(type)) { return new DefaultProjection( properties, sourceCRS, targetCRS, transform, method); } if (Conversion.class.isAssignableFrom(type)) { return new DefaultConversion( properties, sourceCRS, targetCRS, transform, method); } } return new DefaultSingleOperation( properties, sourceCRS, targetCRS, transform, method); } return new AbstractCoordinateOperation(properties, sourceCRS, targetCRS, transform); } /** * Returns the operation method. */ @Override public OperationMethod getMethod() { return method; } /** * Returns the parameter values. The default implementation infers the parameter * values from the {@linkplain #transform transform}, if possible. * * @throws UnsupportedOperationException if the parameters values can't be determined * for the current math transform implementation. * * @see DefaultMathTransformFactory#createParameterizedTransform(ParameterValueGroup) * @see Parameterized#getParameterValues() */ @Override public ParameterValueGroup getParameterValues() throws UnsupportedOperationException { MathTransform mt = transform; while (mt != null) { if (mt instanceof Parameterized) { final ParameterValueGroup param; if (mt instanceof ParameterizedAffine) { param = ((ParameterizedAffine) mt).parameters.getParameterValues(); } else { if (Semaphores.queryAndSet(Semaphores.PROJCS)) { throw new AssertionError(); // Should never happen. } try { param = ((Parameterized) mt).getParameterValues(); } finally { Semaphores.clear(Semaphores.PROJCS); } } if (param != null) { return param; } } if (mt instanceof PassThroughTransform) { mt = ((PassThroughTransform) mt).getSubTransform(); } else { break; } } throw new UnsupportedImplementationException(Classes.getClass(mt)); } /** * Compares this operation method with the specified object for equality. * If the {@code mode} argument value is {@link ComparisonMode#STRICT STRICT} or * {@link ComparisonMode#BY_CONTRACT BY_CONTRACT}, then all available properties * are compared including the {@linkplain DefaultOperationMethod#getFormula() formula}. * * @param object The object to compare to {@code this}. * @param mode {@link ComparisonMode#STRICT STRICT} for performing a strict comparison, or * {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only properties * relevant to transformations. * @return {@code true} if both objects are equal. */ @Override public boolean equals(final Object object, final ComparisonMode mode) { if (super.equals(object, mode)) { switch (mode) { case STRICT: { final DefaultSingleOperation that = (DefaultSingleOperation) object; return Utilities.equals(this.method, that.method); } case BY_CONTRACT: { final SingleOperation that = (SingleOperation) object; return deepEquals(getMethod(), that.getMethod(), mode); } default: { /* * We consider the operation method as metadata. We could argue that OperationMethod's * 'sourceDimension' and 'targetDimension' are not metadata, but their values should * be identical to the 'sourceCRS' and 'targetCRS' dimensions, already checked by the * superclass. We could also argue that 'OperationMethod.parameters' are not metadata, * but their values should have been taken in account for the MathTransform creation, * which was compared by the superclass. * * Comparing the MathTransforms instead of parameters avoid the problem of implicit * parameters. For example in a ProjectedCRS, the "semiMajor" and "semiMinor" axis * lengths are sometime provided as explicit parameters, and sometime inferred from * the geodetic datum. The two cases would be different set of parameters from the * OperationMethod's point of view, but still result in the creation of identical * MathTransform. * * An other rational for treating OperationMethod as metadata is that Geotk * MathTransformProvider extends DefaultOperationMethod. Consequently there is * a wide range of subclasses, which make the comparisons more difficult. For * example Mercator1SP and Mercator2SP providers are two different ways to describe * the same projection. The SQL-backed EPSG factory uses yet an other implementation. * * NOTE: A previous Geotk implementation made this final check: * * return nameMatches(this.method, that.method); * * but it was not strictly necessary since it was redundant with the comparisons of * MathTransforms. Actually it was preventing to detect that two CRS were equivalent * despite different method names (e.g. "Mercator (1SP)" and "Mercator (2SP)" when * the parameters are properly chosen). */ return true; } } } return false; } // Do NOT override 'computeHashCode()', since we don't want to include the 'method' field in // hash code calculation. See the comment inside the above 'equals(Object, ComparisonMode)' // method for more information. Note that the parent class uses the 'transform' hash code, // which should be sufficient. /** * {@inheritDoc} */ @Override public String formatWKT(final Formatter formatter) { final String name = super.formatWKT(formatter); append(formatter, method, "METHOD"); return name; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy