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

org.geotoolkit.referencing.operation.provider.Molodensky Maven / Gradle / Ivy

/*
 *    Geotoolkit.org - An Open Source Java GIS Toolkit
 *    http://www.geotoolkit.org
 *
 *    (C) 2002-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.referencing.operation.provider;

import java.util.Collection;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import net.jcip.annotations.Immutable;

import org.opengis.util.GenericName;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.ParameterNotFoundException;
import org.opengis.parameter.InvalidParameterValueException;
import org.opengis.referencing.operation.Transformation;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.GeocentricCRS;
import org.opengis.referencing.ReferenceIdentifier;

import org.geotoolkit.metadata.iso.citation.Citations;
import org.geotoolkit.referencing.NamedIdentifier;
import org.geotoolkit.referencing.datum.BursaWolfParameters;
import org.geotoolkit.referencing.operation.MathTransformProvider;
import org.geotoolkit.referencing.operation.transform.MolodenskyTransform;
import org.geotoolkit.internal.referencing.MathTransformDecorator;
import org.geotoolkit.parameter.DefaultParameterDescriptor;
import org.geotoolkit.resources.Vocabulary;
import org.geotoolkit.resources.Errors;

import static java.util.Collections.singletonMap;
import static org.geotoolkit.parameter.Parameters.doubleValue;
import static org.geotoolkit.parameter.Parameters.integerValue;
import static org.geotoolkit.referencing.operation.provider.UniversalParameters.createDescriptor;
import static org.geotoolkit.referencing.operation.provider.UniversalParameters.createDescriptorGroup;


/**
 * The provider for "Molodensky transformation" (EPSG:9604). This provider constructs
 * transforms from {@linkplain GeographicCRS geographic} to geographic coordinate reference systems,
 * without passing though {@linkplain GeocentricCRS geocentric} one.
 * 

* The translation terms (dx, dy and dz) are common to all authorities. * But remaining parameters are specified in different ways depending on the authority: *

*

    *
  • EPSG defines "Semi-major axis length difference" and * "Flattening difference" parameters.
  • *
  • OGC rather defines "{@code src_semi_major}", "{@code src_semi_minor}", * "{@code tgt_semi_major}", "{@code tgt_semi_minor}" and "{@code dim}" parameters.
  • *
  • Geotk splits the OGC "{@code dim}" parameters in two separated * "{@code src_dim}" and "{@code tgt_dim}" parameters.
  • *
* * *

The following table summarizes the parameters recognized by this provider. * For a more detailed parameter list, see the {@link #PARAMETERS} constant.

*

Operation name: {@code Molodenski}

* * * * * * * * * * * * * * *
Parameter nameDefault value
{@code dim}2
{@code src_dim}2
{@code tgt_dim}2
{@code dx}0 metres
{@code dy}0 metres
{@code dz}0 metres
{@code src_semi_major}
{@code src_semi_minor}
{@code tgt_semi_major}
{@code tgt_semi_minor}
{@code Semi-major axis length difference}
{@code Flattening difference}
* * * @author Rueben Schulz (UBC) * @author Martin Desruisseaux (IRD, Geomatys) * @version 3.20 * * @see MolodenskyTransform * @see Geotk coordinate operations matrix * * @since 2.1 * @module */ @Immutable public class Molodensky extends MathTransformProvider { /** * Serial number for inter-operability with different versions. */ private static final long serialVersionUID = 8126525068450868912L; /** * The operation parameter descriptor for the number of geographic dimension (2 or 3). * This argument applies on both the source and the target dimension. The default value * is 2. *

* Note: the default value may change in future versions, because the * EPSG database implicitly uses the Molodensky transform in 3-dimensional operations. * Users are well advised to always specify explicitely the dimension. * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor DIM = DefaultParameterDescriptor.create( singletonMap(NAME_KEY, new NamedIdentifier(Citations.OGC, "dim")), PositionVector7Param.DEFAULT_DIMENSION, 2, 3, false); /** * The operation parameter descriptor for the number of source geographic dimension (2 or 3). * This is a Geotk-specific argument. The standard parameter is {@link #DIM}, which set both * the source and target dimension. * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor SRC_DIM = PositionVector7Param.SRC_DIM; /** * The operation parameter descriptor for the number of target geographic dimension (2 or 3). * This is a Geotk-specific argument. The standard parameter is {@link #DIM}, which set both * the source and target dimension. * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor TGT_DIM = PositionVector7Param.TGT_DIM; /** * The operation parameter descriptor for the X-axis translation * ({@linkplain BursaWolfParameters#dx dx}) parameter value. Valid values range * from negative to positive infinity. Units are {@linkplain SI#METRE metres}. * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor DX = PositionVector7Param.DX; /** * The operation parameter descriptor for the Y-axis translation * ({@linkplain BursaWolfParameters#dy dy}) parameter value. Valid values range * from negative to positive infinity. Units are {@linkplain SI#METRE metres}. * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor DY = PositionVector7Param.DY; /** * The operation parameter descriptor for the Z-axis translation * ({@linkplain BursaWolfParameters#dz dz}) parameter value. Valid values range * from negative to positive infinity. Units are {@linkplain SI#METRE metres}. * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor DZ = PositionVector7Param.DZ; /** * The operation parameter descriptor for the {@code "src_semi_major"} parameter value. * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}. * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor SRC_SEMI_MAJOR = createDescriptor( identifiers(PositionVector7Param.SRC_SEMI_MAJOR), Double.NaN, 0.0, Double.POSITIVE_INFINITY, SI.METRE, true); /** * The operation parameter descriptor for the {@code "src_semi_minor"} parameter value. * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}. * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor SRC_SEMI_MINOR = createDescriptor( identifiers(PositionVector7Param.SRC_SEMI_MINOR), Double.NaN, 0.0, Double.POSITIVE_INFINITY, SI.METRE, true); /** * The operation parameter descriptor for the {@code "tgt_semi_major"} parameter value. * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}. *

* This parameter is mandatory, unless the {@link #AXIS_LENGTH_DIFFERENCE} parameter * is defined in which case the later is used. * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor TGT_SEMI_MAJOR = createDescriptor( identifiers(PositionVector7Param.TGT_SEMI_MAJOR), Double.NaN, 0.0, Double.POSITIVE_INFINITY, SI.METRE, true); /** * The operation parameter descriptor for the {@code "tgt_semi_minor"} parameter value. * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}. *

* This parameter is mandatory, unless the {@link #FLATTENING_DIFFERENCE} parameter * is defined in which case the later is used. * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor TGT_SEMI_MINOR = createDescriptor( identifiers(PositionVector7Param.TGT_SEMI_MINOR), Double.NaN, 0.0, Double.POSITIVE_INFINITY, SI.METRE, true); /** * The operation parameter descriptor for the Semi-major axis length difference * optional parameter value. This parameter is defined by the EPSG database and can be used * in replacement of {@link #TGT_SEMI_MAJOR}. *

* Units are {@linkplain SI#METRE metres}. * * @since 3.19 * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor AXIS_LENGTH_DIFFERENCE = createDescriptor( new NamedIdentifier[] { new NamedIdentifier(Citations.EPSG, "Semi-major axis length difference"), }, Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, SI.METRE, false); /** * The operation parameter descriptor for the Flattening difference optional * parameter value. This parameter is defined by the EPSG database and can be used in * replacement of {@link #TGT_SEMI_MINOR}. *

* Valid values range from -1 to +1, {@linkplain Unit#ONE dimensionless}. * * @since 3.19 * * @deprecated Invoke {@linkplain #PARAMETERS}.{@linkplain ParameterDescriptorGroup#descriptor(String) * descriptor(String)} instead. */ @Deprecated public static final ParameterDescriptor FLATTENING_DIFFERENCE = createDescriptor( new NamedIdentifier[] { new NamedIdentifier(Citations.EPSG, "Flattening difference"), }, Double.NaN, -1.0, +1.0, Unit.ONE, false); /** * Helper method for parameter descriptor creation. */ private static NamedIdentifier[] identifiers(final ParameterDescriptor parameter) { final Collection id = parameter.getAlias(); return id.toArray(new NamedIdentifier[id.size()]); } /** * The group of all parameters expected by this coordinate operation. * The following table lists the operation names and the parameters recognized by Geotk. * Note that the "Semi-major axis length difference" and "Flattening * difference" parameters are exclusive with all {@code "src_*"} and {@code "tgt_*"} * parameters (see class javadoc). *

* *

* * * * * * * * * * * * * *
* * * * * *
Name:OGC:Molodenski
Alias:EPSG:Molodensky
Geotk:Molodensky transform
Identifier:EPSG:9604
*
* * *
Name:OGC:dim
*
* * * * * *
Type:{@code Integer}
Obligation:optional
Value range:[2…3]
Default value:2
*
* * *
Name:Geotk:src_dim
*
* * * * * *
Type:{@code Integer}
Obligation:optional
Value range:[2…3]
Default value:2
*
* * *
Name:Geotk:tgt_dim
*
* * * * * *
Type:{@code Integer}
Obligation:optional
Value range:[2…3]
Default value:2
*
* * * *
Name:OGC:dx
Alias:EPSG:X-axis translation
*
* * * * * *
Type:{@code Double}
Obligation:mandatory
Value range:(-∞ … ∞) metres
Default value:0 metres
*
* * * *
Name:OGC:dy
Alias:EPSG:Y-axis translation
*
* * * * * *
Type:{@code Double}
Obligation:mandatory
Value range:(-∞ … ∞) metres
Default value:0 metres
*
* * * *
Name:OGC:dz
Alias:EPSG:Z-axis translation
*
* * * * * *
Type:{@code Double}
Obligation:mandatory
Value range:(-∞ … ∞) metres
Default value:0 metres
*
* * *
Name:OGC:src_semi_major
*
* * * * *
Type:{@code Double}
Obligation:mandatory
Value range:[0…∞) metres
*
* * *
Name:OGC:src_semi_minor
*
* * * * *
Type:{@code Double}
Obligation:mandatory
Value range:[0…∞) metres
*
* * *
Name:OGC:tgt_semi_major
*
* * * * *
Type:{@code Double}
Obligation:mandatory
Value range:[0…∞) metres
*
* * *
Name:OGC:tgt_semi_minor
*
* * * * *
Type:{@code Double}
Obligation:mandatory
Value range:[0…∞) metres
*
* * *
Name:EPSG:Semi-major axis length difference
*
* * * * *
Type:{@code Double}
Obligation:optional
Value range:(-∞ … ∞) metres
*
* * *
Name:EPSG:Flattening difference
*
* * * * *
Type:{@code Double}
Obligation:optional
Value range:[-1 … 1]
*
*/ public static final ParameterDescriptorGroup PARAMETERS = createDescriptorGroup( new ReferenceIdentifier[] { new NamedIdentifier(Citations.OGC, "Molodenski"), new NamedIdentifier(Citations.EPSG, "Molodensky"), new IdentifierCode (Citations.EPSG, 9604), new NamedIdentifier(Citations.GEOTOOLKIT, Vocabulary.formatInternational( Vocabulary.Keys.MOLODENSKY_TRANSFORM)) }, null, new ParameterDescriptor[] { DIM, SRC_DIM, TGT_DIM, DX, DY, DZ, SRC_SEMI_MAJOR, SRC_SEMI_MINOR, TGT_SEMI_MAJOR, TGT_SEMI_MINOR, AXIS_LENGTH_DIFFERENCE, FLATTENING_DIFFERENCE }, 0); /** * The providers for all combinations between 2D and 3D cases. Array length is 4. * Index is build with following rule: *
    *
  • Bit 1: dimension of source coordinates (0 for 2D, 1 for 3D).
  • *
  • Bit 0: dimension of target coordinates (0 for 2D, 1 for 3D).
  • *
*/ final Molodensky[] complements; /** * Returns the index in the {@link #complements} array for the given source and target * dimensions, which must be either 2 or 3. This method assumes that the arguments have * already been checked for validity. */ private static int index(final int sourceDimension, final int targetDimension) { return ((sourceDimension & 1) << 1) | (targetDimension & 1); } /** * Constructs a provider. */ public Molodensky() { // Following constructors register themself in the "complements" array. this(2, 2, PARAMETERS, new Molodensky[4]); new Molodensky(2, 3, PARAMETERS, complements); new Molodensky(3, 2, PARAMETERS, complements); new Molodensky(3, 3, PARAMETERS, complements); } /** * Constructs a provider from a set of parameters. * * @param sourceDimension Number of dimensions in the source CRS of this operation method. * @param targetDimension Number of dimensions in the target CRS of this operation method. * @param parameters The set of parameters (never {@code null}). * @param complements Providers for all combinations between 2D and 3D cases. */ Molodensky(final int sourceDimension, final int targetDimension, final ParameterDescriptorGroup parameters, final Molodensky[] complements) { super(sourceDimension, targetDimension, parameters); this.complements = complements; final int index = index(sourceDimension, targetDimension); if (complements[index] != null) { throw new AssertionError(index); } complements[index] = this; } /** * Returns the operation type. */ @Override public Class getOperationType() { return Transformation.class; } /** * Returns the dimension declared in the given parameter value, or 0 if none. If * this method returns a non-zero value, then it is guaranteed to be either 2 or 3. * * @param descriptor The descriptor of the dimension to get. * @param values The values from which to get the dimension. * @return The dimension, or 0 if none. * @throws InvalidParameterValueException if the dimension parameter has an invalid value. */ private static int dimension(final ParameterDescriptor descriptor, final ParameterValueGroup values) throws InvalidParameterValueException { final Integer value = integerValue(descriptor, values); if (value == null) { return 0; } final int dimension = value; // Unboxing. if (dimension != 2 && dimension != 3) { final String name = descriptor.getName().getCode(); throw new InvalidParameterValueException(Errors.format( Errors.Keys.ILLEGAL_ARGUMENT_$2, name, dimension), name, dimension); } return dimension; } /** * Creates a math transform from the specified group of parameter values. * * @param values The group of parameter values. * @return The created math transform. * @throws ParameterNotFoundException if a required parameter was not found. */ @Override protected MathTransform createMathTransform(final ParameterValueGroup values) throws ParameterNotFoundException { int srcDim = sourceDimension; int tgtDim = targetDimension; int dimension = dimension(DIM, values); if (dimension != 0) { srcDim = tgtDim = dimension; } dimension = dimension(SRC_DIM, values); if (dimension != 0) { srcDim = dimension; } dimension = dimension(TGT_DIM, values); if (dimension != 0) { tgtDim = dimension; } final double a = doubleValue(SRC_SEMI_MAJOR, values); final double b = doubleValue(SRC_SEMI_MINOR, values); final double ta, tb; double d = doubleValue(AXIS_LENGTH_DIFFERENCE, values); ta = Double.isNaN(d) ? doubleValue(TGT_SEMI_MAJOR, values) : a + d; d = doubleValue(FLATTENING_DIFFERENCE, values); if (Double.isNaN(d)) { tb = doubleValue(TGT_SEMI_MINOR, values); } else { tb = ta*(b/a - d); } final double dx = doubleValue(DX, values); final double dy = doubleValue(DY, values); final double dz = doubleValue(DZ, values); MathTransform transform = MolodenskyTransform.create(isAbridged(), a, b, srcDim == 3, ta, tb, tgtDim == 3, dx, dy, dz); final Molodensky provider = complements[index(srcDim, tgtDim)]; if (provider != this) { transform = new MathTransformDecorator(transform, provider); } return transform; } /** * Returns {@code true} for the abridged formulas. * This method is overridden by {@link AbridgedMolodensky}. */ boolean isAbridged() { return false; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy