sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1711928 - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/internal/referencing/provider/ main/java/org/apache/sis/referencing/operation/transform/ test/java/org/apache/sis/internal/referencing/provider/ test/java/o...
Date Mon, 02 Nov 2015 10:11:24 GMT
Author: desruisseaux
Date: Mon Nov  2 10:11:24 2015
New Revision: 1711928

URL: http://svn.apache.org/viewvc?rev=1711928&view=rev
Log:
Reorganize the providers for operations performing datum change (internal SIS classes only).
The operations that operate in the geographic domain and moved as subclasses of GeocentricAffineBetweenGeographic.
Molodensky operations are defined as subclasses of GeocentricAffineBetweenGeographic because they are approximation
of the "Geocentric translations (geographic domain)" operation.

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java
      - copied, changed from r1711325, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java
      - copied, changed from r1711325, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotationTest.java
      - copied, changed from r1711530, sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java
Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation2D.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation3D.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToGeographic.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation2D.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param2D.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param3D.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidalToCartesianTransform.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/GeocentricTranslationTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -17,17 +17,22 @@
 package org.apache.sis.internal.referencing.provider;
 
 import javax.xml.bind.annotation.XmlTransient;
-import javax.measure.unit.SI;
-import org.opengis.parameter.ParameterDescriptor;
-import org.apache.sis.internal.util.Constants;
+import org.opengis.util.FactoryException;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.OperationMethod;
 import org.apache.sis.metadata.iso.citation.Citations;
-import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.util.ArgumentChecks;
 
 
 /**
  * The provider for <cite>"Abridged Molodensky transformation"</cite> (EPSG:9605).
- * This provider constructs transforms between two geographic reference systems,
- * without passing though a geocentric one.
+ * This provider constructs transforms between two geographic reference systems without passing though a geocentric one.
+ * This class nevertheless extends {@link GeocentricAffineBetweenGeographic} because it is an approximation of
+ * {@link GeocentricTranslation3D}.
  *
  * <p>The translation terms (<var>dx</var>, <var>dy</var> and <var>dz</var>) are common to all authorities.
  * But remaining parameters are specified in different ways depending on the authority:</p>
@@ -46,68 +51,94 @@ import org.apache.sis.parameter.Paramete
  * @module
  */
 @XmlTransient
-public abstract class AbridgedMolodensky extends AbstractProvider {
+public final class AbridgedMolodensky extends GeocentricAffineBetweenGeographic {
     /**
      * Serial number for inter-operability with different versions.
      */
     private static final long serialVersionUID = -3889456253400732280L;
 
     /**
-     * The default value for geographic source and target dimensions.
-     * We have to provide a default value because the {@link #DIMENSION} parameter is not an EPSG parameter.
-     * The default value is set to 3 because this family of operations is implicitly three-dimensional in the
-     * EPSG database.
-     *
-     * <div class="note"><b>Maintenance note:</b>
-     * if this default value is modified, then the handling of the two- and three-dimensional cases in
-     * {@link AbridgedMolodenskyTransform} must be adjusted accordingly.</div>
+     * The group of all parameters expected by this coordinate operation.
      */
-    private static final int DEFAULT_DIMENSION = 3;
-
-    /**
-     * The operation parameter descriptor for the number of source and target geographic dimensions (2 or 3).
-     * This is an OGC-specific parameter.
-     */
-    public static final ParameterDescriptor<Integer> DIMENSION;
+    private static final ParameterDescriptorGroup PARAMETERS;
+    static {
+        PARAMETERS = builder()
+                .addIdentifier("9605")
+                .addName("Abridged Molodensky")
+                .addName(Citations.OGC, "Abridged_Molodenski")
+                .createGroupWithSameParameters(Molodensky.PARAMETERS);
+    }
 
     /**
-     * The operation parameter descriptor for the {@code "src_semi_major"} optional parameter value.
-     * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}.
-     */
-    static final ParameterDescriptor<Double> SRC_SEMI_MAJOR;
+     * The providers for all combinations between 2D and 3D cases.
+     * Array length is 4. Index is build with following rule:
+     * <ul>
+     *   <li>Bit 1: dimension of source coordinates (0 for 2D, 1 for 3D).</li>
+     *   <li>Bit 0: dimension of target coordinates (0 for 2D, 1 for 3D).</li>
+     * </ul>
+     */
+    private final AbridgedMolodensky[] redimensioned;
+
+    /**
+     * Constructs a new provider.
+     */
+    @SuppressWarnings("ThisEscapedInObjectConstruction")
+    public AbridgedMolodensky() {
+        super(3, 3, PARAMETERS);
+        redimensioned = new AbridgedMolodensky[4];
+        redimensioned[0] = new AbridgedMolodensky(2, 2, redimensioned);
+        redimensioned[1] = new AbridgedMolodensky(2, 3, redimensioned);
+        redimensioned[2] = new AbridgedMolodensky(3, 2, redimensioned);
+        redimensioned[3] = this;
+    }
 
     /**
-     * The operation parameter descriptor for the {@code "src_semi_minor"} optional parameter value.
-     * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}.
-     */
-    static final ParameterDescriptor<Double> SRC_SEMI_MINOR;
+     * Constructs a provider for the given dimensions.
+     *
+     * @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 redimensioned   Providers for all combinations between 2D and 3D cases.
+     */
+    private AbridgedMolodensky(final int sourceDimension, final int targetDimension, final AbridgedMolodensky[] redimensioned) {
+        super(sourceDimension, targetDimension, PARAMETERS);
+        this.redimensioned = redimensioned;
+    }
 
     /**
-     * The operation parameter descriptor for the {@code "src_semi_major"} optional parameter value.
-     * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}.
-     */
-    static final ParameterDescriptor<Double> TGT_SEMI_MAJOR;
+     * Returns the same operation method, but for different number of dimensions.
+     *
+     * @param  sourceDimensions The desired number of input dimensions.
+     * @param  targetDimensions The desired number of output dimensions.
+     * @return The redimensioned operation method, or {@code this} if no change is needed.
+     */
+    @Override
+    public OperationMethod redimension(final int sourceDimensions, final int targetDimensions) {
+        ArgumentChecks.ensureBetween("sourceDimensions", 2, 3, sourceDimensions);
+        ArgumentChecks.ensureBetween("targetDimensions", 2, 3, targetDimensions);
+        return redimensioned[((sourceDimensions & 1) << 1) | (targetDimensions & 1)];
+    }
 
     /**
-     * The operation parameter descriptor for the {@code "src_semi_minor"} optional parameter value.
-     * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}.
+     * While Abridged Molodensky method is an approximation of geocentric translation, this is not exactly that.
      */
-    static final ParameterDescriptor<Double> TGT_SEMI_MINOR;
-
-    static {
-        final ParameterBuilder builder = builder();
-        /*
-         * OGC parameters not defined in EPSG database.
-         */
-        builder.setCodeSpace(Citations.OGC, Constants.OGC).setRequired(false);
-        DIMENSION = builder.addName("dim").createBounded(2, 3, DEFAULT_DIMENSION);
-        SRC_SEMI_MAJOR = builder.addName("src_semi_major").createStrictlyPositive(Double.NaN, SI.METRE);
-        SRC_SEMI_MINOR = builder.addName("src_semi_minor").createStrictlyPositive(Double.NaN, SI.METRE);
-        TGT_SEMI_MAJOR = builder.addName("tgt_semi_major").createStrictlyPositive(Double.NaN, SI.METRE);
-        TGT_SEMI_MINOR = builder.addName("tgt_semi_minor").createStrictlyPositive(Double.NaN, SI.METRE);
+    @Override
+    int getType() {
+        return OTHER;
     }
 
-    private AbridgedMolodensky() {
-        super(DEFAULT_DIMENSION, DEFAULT_DIMENSION, null);
+    /**
+     * Creates an Abridged Molodensky transform from the specified group of parameter values.
+     *
+     * @param  factory The factory to use for creating concatenated transforms.
+     * @param  values  The group of parameter values.
+     * @return The created Abridged Molodensky transform.
+     * @throws FactoryException if a transform can not be created.
+     */
+    @Override
+    public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup values)
+            throws FactoryException
+    {
+        return Molodensky.createMathTransform(factory, Parameters.castOrWrap(values),
+                getSourceDimensions(), getTargetDimensions(), true);
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -57,7 +57,7 @@ public final class CoordinateFrameRotati
      * Constructs the provider.
      */
     public CoordinateFrameRotation() {
-        super(3, PARAMETERS);
+        super(3, 3, PARAMETERS);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation2D.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation2D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation2D.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -31,7 +31,7 @@ import org.opengis.parameter.ParameterDe
  * @module
  */
 @XmlTransient
-public final class CoordinateFrameRotation2D extends GeocentricAffine {
+public final class CoordinateFrameRotation2D extends GeocentricAffineBetweenGeographic {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -57,7 +57,7 @@ public final class CoordinateFrameRotati
      * Constructs the provider.
      */
     public CoordinateFrameRotation2D() {
-        super(2, PARAMETERS);
+        super(2, 2, PARAMETERS);
     }
 
     /**
@@ -65,6 +65,6 @@ public final class CoordinateFrameRotati
      */
     @Override
     int getType() {
-        return GEOGRAPHIC | FRAME_ROTATION;
+        return FRAME_ROTATION;
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation3D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation3D.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation3D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotation3D.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -31,7 +31,7 @@ import org.opengis.parameter.ParameterDe
  * @module
  */
 @XmlTransient
-public final class CoordinateFrameRotation3D extends GeocentricAffine {
+public final class CoordinateFrameRotation3D extends GeocentricAffineBetweenGeographic {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -57,7 +57,7 @@ public final class CoordinateFrameRotati
      * Constructs the provider.
      */
     public CoordinateFrameRotation3D() {
-        super(3, PARAMETERS);
+        super(3, 3, PARAMETERS);
     }
 
     /**
@@ -65,6 +65,6 @@ public final class CoordinateFrameRotati
      */
     @Override
     int getType() {
-        return GEOGRAPHIC | FRAME_ROTATION;
+        return FRAME_ROTATION;
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffine.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -47,6 +47,12 @@ import org.apache.sis.util.logging.Loggi
 
 /**
  * The base class of operation methods performing a translation, rotation and/or scale in geocentric coordinates.
+ * Those methods may or may not include a Geographic/Geocentric conversion before the operation in geocentric domain,
+ * depending on whether or not implementations extend the {@link GeocentricAffineBetweenGeographic} subclass.
+ *
+ * <div class="note"><b>Note on class name:</b>
+ * the {@code GeocentricAffine} class name is chosen as a generalization of {@link GeocentricTranslation}.
+ * "Geocentric translations" is an operation name defined by EPSG.</div>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.7
@@ -130,26 +136,22 @@ public abstract class GeocentricAffine e
     /**
      * Return value for {@link #getType()}.
      */
-    static final int TRANSLATION=1, SEVEN_PARAM=2, FRAME_ROTATION=3;
-
-    /**
-     * Mask that can be combined with {@link #TRANSLATION}, {@link #SEVEN_PARAM} or {@link #FRAME_ROTATION}
-     * for meaning that the operation is performed in the geographic domain.
-     */
-    static final int GEOGRAPHIC = 4;
+    static final int TRANSLATION=1, SEVEN_PARAM=2, FRAME_ROTATION=3, OTHER=0;
 
     /**
      * Constructs a provider with the specified parameters.
-     * This constructor is for subclass constructors only.
+     *
+     * @param sourceDimensions Number of dimensions in the source CRS of this operation method.
+     * @param targetDimensions Number of dimensions in the target CRS of this operation method.
      */
-    GeocentricAffine(final int dimension, final ParameterDescriptorGroup parameters) {
-        super(dimension, dimension, parameters);
+    GeocentricAffine(int sourceDimensions, int targetDimensions, ParameterDescriptorGroup parameters) {
+        super(sourceDimensions, targetDimensions, parameters);
     }
 
     /**
-     * Returns the operation type.
+     * Returns the interface implemented by all coordinate operations that extends this class.
      *
-     * @return Interface implemented by all coordinate operations that use this method.
+     * @return Fixed to {@link Transformation}.
      */
     @Override
     public final Class<Transformation> getOperationType() {
@@ -157,30 +159,32 @@ public abstract class GeocentricAffine e
     }
 
     /**
-     * Returns the operation type as one of {@link #TRANSLATION}, {@link #SEVEN_PARAM} or
-     * {@link #FRAME_ROTATION} constants.
+     * Returns the operation sub-type as one of {@link #TRANSLATION}, {@link #SEVEN_PARAM},
+     * {@link #FRAME_ROTATION} or {@link #OTHER} constants.
      */
     abstract int getType();
 
     /**
      * Creates a math transform from the specified group of parameter values.
+     * The default implementation creates an affine transform, but some subclasses
+     * will wrap that affine operation into Geographic/Geocentric conversions.
      *
-     * @param  factory Ignored (can be null).
+     * @param  factory The factory to use for creating concatenated transforms.
      * @param  values The group of parameter values.
      * @return The created math transform.
      * @throws FactoryException if a transform can not be created.
      */
     @Override
     @SuppressWarnings("fallthrough")
-    public final MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup values)
+    public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup values)
             throws FactoryException
     {
         final BursaWolfParameters parameters = new BursaWolfParameters(null, null);
         final Parameters pv = Parameters.castOrWrap(values);
-        final int type = getType();
-        switch (type & ~GEOGRAPHIC) {
+        boolean reverseRotation = false;
+        switch (getType()) {
             default:             throw new AssertionError();
-            case FRAME_ROTATION: parameters.reverseRotation();         // Fall through
+            case FRAME_ROTATION: reverseRotation = true;               // Fall through
             case SEVEN_PARAM:    parameters.rX = pv.doubleValue(RX);
                                  parameters.rY = pv.doubleValue(RY);
                                  parameters.rZ = pv.doubleValue(RZ);
@@ -189,34 +193,10 @@ public abstract class GeocentricAffine e
                                  parameters.tY = pv.doubleValue(TY);
                                  parameters.tZ = pv.doubleValue(TZ);
         }
-        MathTransform transform = MathTransforms.linear(parameters.getPositionVectorTransformation(null));
-        if ((type & GEOGRAPHIC) != 0) {
-            /*
-             * Create a "Geographic to Geocentric" conversion with ellipsoid axis length units converted to metres
-             * (the unit implied by AbridgedMolodensky.SRC_SEMI_MAJOR) because it is the unit of Bursa-Wolf param.
-             * that we created above.
-             */
-            Parameters step = Parameters.castOrWrap(factory.getDefaultParameters(GeographicToGeocentric.NAME));
-            step.getOrCreate(MapProjection.SEMI_MAJOR).setValue(pv.doubleValue(AbridgedMolodensky.SRC_SEMI_MAJOR));
-            step.getOrCreate(MapProjection.SEMI_MINOR).setValue(pv.doubleValue(AbridgedMolodensky.SRC_SEMI_MINOR));
-            step.getOrCreate(AbridgedMolodensky.DIMENSION).setValue(getSourceDimensions());
-            final MathTransform toGeocentric = factory.createParameterizedTransform(step);
-            /*
-             * Create a "Geocentric to Geographic" conversion with ellipsoid axis length units converted to metres
-             * because this is the unit of the Geocentric CRS used above.
-             */
-            step = Parameters.castOrWrap(factory.getDefaultParameters(GeocentricToGeographic.NAME));
-            step.getOrCreate(MapProjection.SEMI_MAJOR).setValue(pv.doubleValue(AbridgedMolodensky.TGT_SEMI_MAJOR));
-            step.getOrCreate(MapProjection.SEMI_MINOR).setValue(pv.doubleValue(AbridgedMolodensky.TGT_SEMI_MINOR));
-            step.getOrCreate(AbridgedMolodensky.DIMENSION).setValue(getTargetDimensions());
-            final MathTransform toGeographic = factory.createParameterizedTransform(step);
-            /*
-             * The  Geocentric → Affine → Geographic  chain.
-             */
-            transform = factory.createConcatenatedTransform(toGeocentric,
-                        factory.createConcatenatedTransform(transform, toGeographic));
+        if (reverseRotation) {
+            parameters.reverseRotation();
         }
-        return transform;
+        return MathTransforms.linear(parameters.getPositionVectorTransformation(null));
     }
 
     /**

Copied: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java (from r1711325, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java?p2=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java&p1=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java&r1=1711325&r2=1711928&rev=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -18,55 +18,50 @@ package org.apache.sis.internal.referenc
 
 import javax.xml.bind.annotation.XmlTransient;
 import javax.measure.unit.SI;
+import org.opengis.util.FactoryException;
+import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptor;
-import org.apache.sis.internal.util.Constants;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.parameter.InvalidParameterValueException;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.internal.util.Constants;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.util.resources.Errors;
 
 
 /**
- * The provider for <cite>"Abridged Molodensky transformation"</cite> (EPSG:9605).
- * This provider constructs transforms between two geographic reference systems,
- * without passing though a geocentric one.
- *
- * <p>The translation terms (<var>dx</var>, <var>dy</var> and <var>dz</var>) are common to all authorities.
- * But remaining parameters are specified in different ways depending on the authority:</p>
- *
- * <ul>
- *   <li>EPSG defines <cite>"Semi-major axis length difference"</cite>
- *       and <cite>"Flattening difference"</cite> parameters.</li>
- *   <li>OGC rather defines "{@code src_semi_major}", "{@code src_semi_minor}",
- *       "{@code tgt_semi_major}", "{@code tgt_semi_minor}" and "{@code dim}" parameters.</li>
- * </ul>
+ * The base class of operation methods performing an affine operation in geocentric coordinates
+ * concatenated with conversion from/to geographic coordinates. This base class is also used for
+ * operation methods performing <em>approximation</em> of above, even if they do not really pass
+ * through geocentric coordinates.
  *
- * @author  Rueben Schulz (UBC)
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.7
  * @version 0.7
  * @module
  */
 @XmlTransient
-public abstract class AbridgedMolodensky extends AbstractProvider {
+public abstract class GeocentricAffineBetweenGeographic extends GeocentricAffine {
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -3889456253400732280L;
-
-    /**
-     * The default value for geographic source and target dimensions.
-     * We have to provide a default value because the {@link #DIMENSION} parameter is not an EPSG parameter.
-     * The default value is set to 3 because this family of operations is implicitly three-dimensional in the
-     * EPSG database.
-     *
-     * <div class="note"><b>Maintenance note:</b>
-     * if this default value is modified, then the handling of the two- and three-dimensional cases in
-     * {@link AbridgedMolodenskyTransform} must be adjusted accordingly.</div>
-     */
-    private static final int DEFAULT_DIMENSION = 3;
+    private static final long serialVersionUID = -6202315859507526222L;
 
     /**
      * The operation parameter descriptor for the number of source and target geographic dimensions (2 or 3).
-     * This is an OGC-specific parameter.
+     * This is an OGC-specific parameter for the {@link Molodensky} and {@link AbridgedMolodensky} operations,
+     * but Apache SIS uses it also for Geographic/Geocentric conversions.
+     *
+     * <p>We do not provide default value for this parameter (neither we do for other OGC-specific parameters
+     * in this class) because this parameter is used with both two- and three-dimensional operation methods.
+     * If we want to provide a default value, we could but it would complicate a little bit the code since we
+     * could no longer reuse the same {@code PARAMETERS} constant for operation methods of any number of dimensions.
+     * Furthermore it would not solve the case where the number of input dimensions is different than the number of
+     * output dimensions. We can not afford to have wrong default values since it would confuse our interpretation
+     * of user's parameters in {@link #createMathTransform(MathTransformFactory, ParameterValueGroup)}.</p>
      */
     public static final ParameterDescriptor<Integer> DIMENSION;
 
@@ -95,19 +90,83 @@ public abstract class AbridgedMolodensky
     static final ParameterDescriptor<Double> TGT_SEMI_MINOR;
 
     static {
-        final ParameterBuilder builder = builder();
-        /*
-         * OGC parameters not defined in EPSG database.
-         */
-        builder.setCodeSpace(Citations.OGC, Constants.OGC).setRequired(false);
-        DIMENSION = builder.addName("dim").createBounded(2, 3, DEFAULT_DIMENSION);
+        final ParameterBuilder builder = builder().setCodeSpace(Citations.OGC, Constants.OGC).setRequired(false);
+        DIMENSION      = builder.addName("dim")   .createBounded(Integer.class, 2, 3, null);
         SRC_SEMI_MAJOR = builder.addName("src_semi_major").createStrictlyPositive(Double.NaN, SI.METRE);
         SRC_SEMI_MINOR = builder.addName("src_semi_minor").createStrictlyPositive(Double.NaN, SI.METRE);
         TGT_SEMI_MAJOR = builder.addName("tgt_semi_major").createStrictlyPositive(Double.NaN, SI.METRE);
         TGT_SEMI_MINOR = builder.addName("tgt_semi_minor").createStrictlyPositive(Double.NaN, SI.METRE);
     }
 
-    private AbridgedMolodensky() {
-        super(DEFAULT_DIMENSION, DEFAULT_DIMENSION, null);
+    /**
+     * Constructs a provider with the specified parameters.
+     *
+     * @param sourceDimensions Number of dimensions in the source CRS of this operation method.
+     * @param targetDimensions Number of dimensions in the target CRS of this operation method.
+     */
+    GeocentricAffineBetweenGeographic(int sourceDimensions, int targetDimensions, ParameterDescriptorGroup parameters) {
+        super(sourceDimensions, targetDimensions, parameters);
+    }
+
+    /**
+     * Returns the number of dimensions declared in the given parameter group, or 0 if none.
+     * If this method returns a non-zero value, then it is guaranteed to be either 2 or 3.
+     *
+     * @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.
+     */
+    static int getDimension(final Parameters values) throws InvalidParameterValueException {
+        final Integer value = values.getValue(DIMENSION);
+        if (value == null) {
+            return 0;
+        }
+        final int dimension = value;  // Unboxing.
+        if (dimension != 2 && dimension != 3) {
+            throw new InvalidParameterValueException(Errors.format(
+                    Errors.Keys.IllegalArgumentValue_2, "dim", value), "dim", value);
+        }
+        return dimension;
+    }
+
+    /**
+     * Creates a math transform from the specified group of parameter values.
+     * This method wraps the affine operation into Geographic/Geocentric conversions.
+     *
+     * @param  factory The factory to use for creating concatenated transforms.
+     * @param  values The group of parameter values.
+     * @return The created math transform.
+     * @throws FactoryException if a transform can not be created.
+     */
+    @Override
+    public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup values)
+            throws FactoryException
+    {
+        final Parameters pv = Parameters.castOrWrap(values);
+        final MathTransform affine = super.createMathTransform(factory, pv);
+        final int dimension = getDimension(pv);
+        /*
+         * Create a "Geographic to Geocentric" conversion with ellipsoid axis length units converted to metres
+         * (the unit implied by SRC_SEMI_MAJOR) because it is the unit of Bursa-Wolf param. that we created above.
+         */
+        Parameters step = Parameters.castOrWrap(factory.getDefaultParameters(GeographicToGeocentric.NAME));
+        step.getOrCreate(MapProjection.SEMI_MAJOR).setValue(pv.doubleValue(SRC_SEMI_MAJOR));
+        step.getOrCreate(MapProjection.SEMI_MINOR).setValue(pv.doubleValue(SRC_SEMI_MINOR));
+        step.getOrCreate(DIMENSION).setValue(dimension != 0 ? dimension : getSourceDimensions());
+        final MathTransform toGeocentric = factory.createParameterizedTransform(step);
+        /*
+         * Create a "Geocentric to Geographic" conversion with ellipsoid axis length units converted to metres
+         * because this is the unit of the Geocentric CRS used above.
+         */
+        step = Parameters.castOrWrap(factory.getDefaultParameters(GeocentricToGeographic.NAME));
+        step.getOrCreate(MapProjection.SEMI_MAJOR).setValue(pv.doubleValue(TGT_SEMI_MAJOR));
+        step.getOrCreate(MapProjection.SEMI_MINOR).setValue(pv.doubleValue(TGT_SEMI_MINOR));
+        step.getOrCreate(DIMENSION).setValue(dimension != 0 ? dimension : getTargetDimensions());
+        final MathTransform toGeographic = factory.createParameterizedTransform(step);
+        /*
+         * The  Geocentric → Affine → Geographic  chain.
+         */
+        return factory.createConcatenatedTransform(toGeocentric,
+               factory.createConcatenatedTransform(affine, toGeographic));
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToGeographic.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToGeographic.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToGeographic.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricToGeographic.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -40,6 +40,8 @@ import org.apache.sis.metadata.iso.citat
  * @since   0.7
  * @version 0.7
  * @module
+ *
+ * @see GeographicToGeocentric
  */
 public final class GeocentricToGeographic extends AbstractProvider {
     /**
@@ -59,31 +61,31 @@ public final class GeocentricToGeographi
     static {
         PARAMETERS = builder()
             .addName(Citations.OGC, NAME)
-            .createGroupForMapProjection(AbridgedMolodensky.DIMENSION);
+            .createGroupForMapProjection(GeocentricAffineBetweenGeographic.DIMENSION);
             // Not really a map projection, but we leverage the same axis parameters.
     }
 
     /**
      * The provider for the other number of dimensions (2D or 3D).
      */
-    private final GeocentricToGeographic complement;
+    private final GeocentricToGeographic redimensioned;
 
     /**
      * Constructs a provider for the 3-dimensional case.
      */
     public GeocentricToGeographic() {
         super(3, 3, PARAMETERS);
-        complement = new GeocentricToGeographic(this);
+        redimensioned = new GeocentricToGeographic(this);
     }
 
     /**
      * Constructs a provider for the 2-dimensional case.
      *
-     * @param complement The three-dimensional case.
+     * @param redimensioned The three-dimensional case.
      */
-    private GeocentricToGeographic(final GeocentricToGeographic complement) {
+    private GeocentricToGeographic(final GeocentricToGeographic redimensioned) {
         super(3, 2, PARAMETERS);
-        this.complement = complement;
+        this.redimensioned = redimensioned;
     }
 
     /**
@@ -128,6 +130,6 @@ public final class GeocentricToGeographi
     public OperationMethod redimension(final int sourceDimensions, final int targetDimensions) {
         ArgumentChecks.ensureBetween("sourceDimensions", 3, 3, sourceDimensions);
         ArgumentChecks.ensureBetween("targetDimensions", 2, 3, targetDimensions);
-        return (targetDimensions == getTargetDimensions()) ? this : complement;
+        return (targetDimensions == getTargetDimensions()) ? this : redimensioned;
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -52,7 +52,7 @@ public final class GeocentricTranslation
      * Constructs the provider.
      */
     public GeocentricTranslation() {
-        super(3, PARAMETERS);
+        super(3, 3, PARAMETERS);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation2D.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation2D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation2D.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -31,7 +31,7 @@ import org.opengis.parameter.ParameterDe
  * @module
  */
 @XmlTransient
-public final class GeocentricTranslation2D extends GeocentricAffine {
+public final class GeocentricTranslation2D extends GeocentricAffineBetweenGeographic {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -45,10 +45,10 @@ public final class GeocentricTranslation
         PARAMETERS = builder()
             .addIdentifier("9603")
             .addName("Geocentric translations (geog2D domain)")
-            .createGroup(AbridgedMolodensky.SRC_SEMI_MAJOR,
-                         AbridgedMolodensky.SRC_SEMI_MINOR,
-                         AbridgedMolodensky.TGT_SEMI_MAJOR,
-                         AbridgedMolodensky.TGT_SEMI_MINOR,
+            .createGroup(SRC_SEMI_MAJOR,
+                         SRC_SEMI_MINOR,
+                         TGT_SEMI_MAJOR,
+                         TGT_SEMI_MINOR,
                          TX, TY, TZ);
     }
 
@@ -56,7 +56,7 @@ public final class GeocentricTranslation
      * Constructs the provider.
      */
     public GeocentricTranslation2D() {
-        super(2, PARAMETERS);
+        super(2, 2, PARAMETERS);
     }
 
     /**
@@ -64,6 +64,6 @@ public final class GeocentricTranslation
      */
     @Override
     int getType() {
-        return GEOGRAPHIC | TRANSLATION;
+        return TRANSLATION;
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricTranslation3D.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -31,7 +31,7 @@ import org.opengis.parameter.ParameterDe
  * @module
  */
 @XmlTransient
-public final class GeocentricTranslation3D extends GeocentricAffine {
+public final class GeocentricTranslation3D extends GeocentricAffineBetweenGeographic {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -52,7 +52,7 @@ public final class GeocentricTranslation
      * Constructs the provider.
      */
     public GeocentricTranslation3D() {
-        super(3, PARAMETERS);
+        super(3, 3, PARAMETERS);
     }
 
     /**
@@ -60,6 +60,6 @@ public final class GeocentricTranslation
      */
     @Override
     int getType() {
-        return GEOGRAPHIC | TRANSLATION;
+        return TRANSLATION;
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -21,7 +21,6 @@ import javax.measure.quantity.Length;
 import org.opengis.util.FactoryException;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptorGroup;
-import org.opengis.parameter.InvalidParameterValueException;
 import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.parameter.ParameterValue;
 import org.opengis.referencing.operation.Conversion;
@@ -32,9 +31,9 @@ import org.apache.sis.internal.system.Lo
 import org.apache.sis.referencing.operation.transform.EllipsoidalToCartesianTransform;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.internal.util.Constants;
+import org.apache.sis.parameter.Parameters;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.logging.Logging;
-import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -49,6 +48,8 @@ import org.apache.sis.util.resources.Err
  * @since   0.7
  * @version 0.7
  * @module
+ *
+ * @see GeocentricToGeographic
  */
 public final class GeographicToGeocentric extends AbstractProvider {
     /**
@@ -71,31 +72,31 @@ public final class GeographicToGeocentri
             .addIdentifier("9602")
             .addName("Geographic/geocentric conversions")
             .addName(Citations.OGC, NAME)
-            .createGroupForMapProjection(AbridgedMolodensky.DIMENSION);
+            .createGroupForMapProjection(GeocentricAffineBetweenGeographic.DIMENSION);
             // Not really a map projection, but we leverage the same axis parameters.
     }
 
     /**
      * The provider for the other number of dimensions (2D or 3D).
      */
-    private final GeographicToGeocentric complement;
+    private final GeographicToGeocentric redimensioned;
 
     /**
      * Constructs a provider for the 3-dimensional case.
      */
     public GeographicToGeocentric() {
         super(3, 3, PARAMETERS);
-        complement = new GeographicToGeocentric(this);
+        redimensioned = new GeographicToGeocentric(this);
     }
 
     /**
      * Constructs a provider for the 2-dimensional case.
      *
-     * @param complement The three-dimensional case.
+     * @param redimensioned The three-dimensional case.
      */
-    private GeographicToGeocentric(final GeographicToGeocentric complement) {
+    private GeographicToGeocentric(final GeographicToGeocentric redimensioned) {
         super(2, 3, PARAMETERS);
-        this.complement = complement;
+        this.redimensioned = redimensioned;
     }
 
     /**
@@ -130,26 +131,21 @@ public final class GeographicToGeocentri
     static MathTransform createMathTransform(final Class<?> caller, final MathTransformFactory factory,
             final ParameterValueGroup values) throws FactoryException
     {
-        boolean is3D = true;
+        boolean is3D;
         try {
             /*
              * Set 'is3D' to false if the given parameter group contains a "DIM" parameter having value 2.
              * If the parameter value is 3 or if there is no parameter value, then 'is3D' is set to true,
              * which is consistent with the default value.
              */
-            final int dimension = values.parameter("dim").intValue();
-            switch (dimension) {
-                case 2:  is3D = false;      break;
-                case 3:  /* already true */ break;
-                default: throw new InvalidParameterValueException(Errors.format(Errors.Keys.
-                            IllegalArgumentValue_2, "dim", dimension), "dim", dimension);
-            }
+            is3D = GeocentricAffineBetweenGeographic.getDimension(Parameters.castOrWrap(values)) != 2;
         } catch (ParameterNotFoundException e) {
             /*
              * Should never happen with the parameter descriptors provided by SIS, but could happen
              * if the user provided its own descriptor. Default to three-dimensional case.
              */
             Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION), caller, "createMathTransform", e);
+            is3D = true;
         }
         final ParameterValue<?> semiMajor = values.parameter(Constants.SEMI_MAJOR);
         final Unit<Length> unit = semiMajor.getUnit().asType(Length.class);
@@ -169,6 +165,6 @@ public final class GeographicToGeocentri
     public OperationMethod redimension(final int sourceDimensions, final int targetDimensions) {
         ArgumentChecks.ensureBetween("sourceDimensions", 2, 3, sourceDimensions);
         ArgumentChecks.ensureBetween("targetDimensions", 3, 3, targetDimensions);
-        return (sourceDimensions == getSourceDimensions()) ? this : complement;
+        return (sourceDimensions == getSourceDimensions()) ? this : redimensioned;
     }
 }

Copied: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java (from r1711325, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java?p2=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java&p1=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java&r1=1711325&r2=1711928&rev=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbridgedMolodensky.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -18,16 +18,25 @@ package org.apache.sis.internal.referenc
 
 import javax.xml.bind.annotation.XmlTransient;
 import javax.measure.unit.SI;
+import javax.measure.unit.Unit;
+import org.opengis.util.FactoryException;
+import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptor;
-import org.apache.sis.internal.util.Constants;
+import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.OperationMethod;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.parameter.Parameters;
+import org.apache.sis.util.ArgumentChecks;
 
 
 /**
- * The provider for <cite>"Abridged Molodensky transformation"</cite> (EPSG:9605).
- * This provider constructs transforms between two geographic reference systems,
- * without passing though a geocentric one.
+ * The provider for "<cite>Molodensky transformation</cite>" (EPSG:9604).
+ * This provider constructs transforms between two geographic reference systems without passing though a geocentric one.
+ * This class nevertheless extends {@link GeocentricAffineBetweenGeographic} because it is an approximation of
+ * {@link GeocentricTranslation3D}.
  *
  * <p>The translation terms (<var>dx</var>, <var>dy</var> and <var>dz</var>) are common to all authorities.
  * But remaining parameters are specified in different ways depending on the authority:</p>
@@ -46,68 +55,162 @@ import org.apache.sis.parameter.Paramete
  * @module
  */
 @XmlTransient
-public abstract class AbridgedMolodensky extends AbstractProvider {
+public final class Molodensky extends GeocentricAffineBetweenGeographic {
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -3889456253400732280L;
+    private static final long serialVersionUID = 8126525068450868912L;
 
     /**
-     * The default value for geographic source and target dimensions.
-     * We have to provide a default value because the {@link #DIMENSION} parameter is not an EPSG parameter.
-     * The default value is set to 3 because this family of operations is implicitly three-dimensional in the
-     * EPSG database.
-     *
-     * <div class="note"><b>Maintenance note:</b>
-     * if this default value is modified, then the handling of the two- and three-dimensional cases in
-     * {@link AbridgedMolodenskyTransform} must be adjusted accordingly.</div>
+     * The operation parameter descriptor for the <cite>Semi-major axis length difference</cite>
+     * 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}.
      */
-    private static final int DEFAULT_DIMENSION = 3;
+    private static final ParameterDescriptor<Double> AXIS_LENGTH_DIFFERENCE;
 
     /**
-     * The operation parameter descriptor for the number of source and target geographic dimensions (2 or 3).
-     * This is an OGC-specific parameter.
+     * The operation parameter descriptor for the <cite>Flattening difference</cite> 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}.
      */
-    public static final ParameterDescriptor<Integer> DIMENSION;
+    private static final ParameterDescriptor<Double> FLATTENING_DIFFERENCE;
 
     /**
-     * The operation parameter descriptor for the {@code "src_semi_major"} optional parameter value.
-     * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}.
+     * The group of all parameters expected by this coordinate operation.
      */
-    static final ParameterDescriptor<Double> SRC_SEMI_MAJOR;
+    static final ParameterDescriptorGroup PARAMETERS;
+    static {
+        final ParameterBuilder builder = builder();
+        AXIS_LENGTH_DIFFERENCE = builder.addName("Semi-major axis length difference").create(Double.NaN, SI.METRE);
+        FLATTENING_DIFFERENCE  = builder.addName("Flattening difference").createBounded(-1, +1, Double.NaN, Unit.ONE);
+        PARAMETERS = builder
+                .addIdentifier("9604")
+                .addName("Molodensky")
+                .addName(Citations.OGC, "Molodenski")
+                .createGroup(DIMENSION,                         // OGC only
+                             TX,                                // OGC and EPSG
+                             TY,                                // OGC and EPSG
+                             TZ,                                // OGC and EPSG
+                             AXIS_LENGTH_DIFFERENCE,            // EPSG only
+                             FLATTENING_DIFFERENCE,             // EPSG only
+                             SRC_SEMI_MAJOR, SRC_SEMI_MINOR,    // OGC only
+                             TGT_SEMI_MAJOR, TGT_SEMI_MINOR);   // OGC only
+    }
 
     /**
-     * The operation parameter descriptor for the {@code "src_semi_minor"} optional parameter value.
-     * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}.
-     */
-    static final ParameterDescriptor<Double> SRC_SEMI_MINOR;
+     * The providers for all combinations between 2D and 3D cases.
+     * Array length is 4. Index is build with following rule:
+     * <ul>
+     *   <li>Bit 1: dimension of source coordinates (0 for 2D, 1 for 3D).</li>
+     *   <li>Bit 0: dimension of target coordinates (0 for 2D, 1 for 3D).</li>
+     * </ul>
+     */
+    private final Molodensky[] redimensioned;
+
+    /**
+     * Constructs a new provider.
+     */
+    @SuppressWarnings("ThisEscapedInObjectConstruction")
+    public Molodensky() {
+        super(3, 3, PARAMETERS);
+        redimensioned = new Molodensky[4];
+        redimensioned[0] = new Molodensky(2, 2, redimensioned);
+        redimensioned[1] = new Molodensky(2, 3, redimensioned);
+        redimensioned[2] = new Molodensky(3, 2, redimensioned);
+        redimensioned[3] = this;
+    }
 
     /**
-     * The operation parameter descriptor for the {@code "src_semi_major"} optional parameter value.
-     * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}.
-     */
-    static final ParameterDescriptor<Double> TGT_SEMI_MAJOR;
+     * Constructs a provider for the given dimensions.
+     *
+     * @param sourceDimensions Number of dimensions in the source CRS of this operation method.
+     * @param targetDimensions Number of dimensions in the target CRS of this operation method.
+     * @param redimensioned    Providers for all combinations between 2D and 3D cases.
+     */
+    private Molodensky(final int sourceDimensions, final int targetDimensions, final Molodensky[] redimensioned) {
+        super(sourceDimensions, targetDimensions, PARAMETERS);
+        this.redimensioned = redimensioned;
+    }
+
+    /**
+     * Returns the same operation method, but for different number of dimensions.
+     *
+     * @param  sourceDimensions The desired number of input dimensions.
+     * @param  targetDimensions The desired number of output dimensions.
+     * @return The redimensioned operation method, or {@code this} if no change is needed.
+     */
+    @Override
+    public OperationMethod redimension(final int sourceDimensions, final int targetDimensions) {
+        ArgumentChecks.ensureBetween("sourceDimensions", 2, 3, sourceDimensions);
+        ArgumentChecks.ensureBetween("targetDimensions", 2, 3, targetDimensions);
+        return redimensioned[((sourceDimensions & 1) << 1) | (targetDimensions & 1)];
+    }
 
     /**
-     * The operation parameter descriptor for the {@code "src_semi_minor"} optional parameter value.
-     * Valid values range from 0 to infinity. Units are {@linkplain SI#METRE metres}.
+     * While Molodensky method is an approximation of geocentric translation, this is not exactly that.
      */
-    static final ParameterDescriptor<Double> TGT_SEMI_MINOR;
+    @Override
+    int getType() {
+        return OTHER;
+    }
 
-    static {
-        final ParameterBuilder builder = builder();
-        /*
-         * OGC parameters not defined in EPSG database.
-         */
-        builder.setCodeSpace(Citations.OGC, Constants.OGC).setRequired(false);
-        DIMENSION = builder.addName("dim").createBounded(2, 3, DEFAULT_DIMENSION);
-        SRC_SEMI_MAJOR = builder.addName("src_semi_major").createStrictlyPositive(Double.NaN, SI.METRE);
-        SRC_SEMI_MINOR = builder.addName("src_semi_minor").createStrictlyPositive(Double.NaN, SI.METRE);
-        TGT_SEMI_MAJOR = builder.addName("tgt_semi_major").createStrictlyPositive(Double.NaN, SI.METRE);
-        TGT_SEMI_MINOR = builder.addName("tgt_semi_minor").createStrictlyPositive(Double.NaN, SI.METRE);
+    /**
+     * Creates a Molodensky transform from the specified group of parameter values.
+     *
+     * @param  factory The factory to use for creating concatenated transforms.
+     * @param  values  The group of parameter values.
+     * @return The created Molodensky transform.
+     * @throws FactoryException if a transform can not be created.
+     */
+    @Override
+    public MathTransform createMathTransform(final MathTransformFactory factory, final ParameterValueGroup values)
+            throws FactoryException
+    {
+        return createMathTransform(factory, Parameters.castOrWrap(values),
+                getSourceDimensions(), getTargetDimensions(), false);
     }
 
-    private AbridgedMolodensky() {
-        super(DEFAULT_DIMENSION, DEFAULT_DIMENSION, null);
+    /**
+     * Creates a (potentially abridged) Molodensky transform from the specified group of parameter values.
+     * The specified number of dimensions are <em>default</em> values; they may be overridden by user parameters.
+     *
+     * @param  factory          The factory to use for creating concatenated transforms.
+     * @param  values           The group of parameter values specified by the users.
+     * @param  sourceDimensions Number of source dimensions (2 or 3) of the operation method.
+     * @param  targetDimensions Number of target dimensions (2 or 3) of the operation method.
+     * @param  isAbridged       {@code true} for the abridged form.
+     * @return The created (abridged) Molodensky transform.
+     * @throws FactoryException if a transform can not be created.
+     */
+    static MathTransform createMathTransform(final MathTransformFactory factory, final Parameters values,
+            int sourceDimensions, int targetDimensions, final boolean isAbridged) throws FactoryException
+    {
+        int dimension = getDimension(values);
+        if (dimension != 0) {
+            sourceDimensions = targetDimensions = dimension;
+        }
+        /*
+         * The code below implicitly converts all parameter values to metres.
+         * We do not try to preserve user-specified units since the unit used
+         * in the geocentric domain does not have any impact on the input/output
+         * geographic coordinates.
+         */
+        final double a = values.doubleValue(SRC_SEMI_MAJOR);
+        final double b = values.doubleValue(SRC_SEMI_MINOR);
+        final double ta, tb;
+        double d = values.doubleValue(AXIS_LENGTH_DIFFERENCE);
+        ta = Double.isNaN(d) ? values.doubleValue(TGT_SEMI_MAJOR) : a + d;
+        d = values.doubleValue(FLATTENING_DIFFERENCE);
+        if (Double.isNaN(d)) {
+            tb = values.doubleValue(TGT_SEMI_MINOR);
+        } else {
+            tb = ta*(b/a - d);
+        }
+        final double dx = values.doubleValue(TX);
+        final double dy = values.doubleValue(TY);
+        final double dz = values.doubleValue(TZ);
+        throw new UnsupportedOperationException("Not supported yet.");
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -56,7 +56,7 @@ public final class PositionVector7Param
      * Constructs the provider.
      */
     public PositionVector7Param() {
-        super(3, PARAMETERS);
+        super(3, 3, PARAMETERS);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param2D.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param2D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param2D.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -29,7 +29,7 @@ import org.opengis.parameter.ParameterDe
  * @module
  */
 @XmlTransient
-public final class PositionVector7Param2D extends GeocentricAffine {
+public final class PositionVector7Param2D extends GeocentricAffineBetweenGeographic {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -43,10 +43,10 @@ public final class PositionVector7Param2
         PARAMETERS = builder()
             .addIdentifier("9606")
             .addName("Position Vector transformation (geog2D domain)")
-            .createGroup(AbridgedMolodensky.SRC_SEMI_MAJOR,
-                         AbridgedMolodensky.SRC_SEMI_MINOR,
-                         AbridgedMolodensky.TGT_SEMI_MAJOR,
-                         AbridgedMolodensky.TGT_SEMI_MINOR,
+            .createGroup(SRC_SEMI_MAJOR,
+                         SRC_SEMI_MINOR,
+                         TGT_SEMI_MAJOR,
+                         TGT_SEMI_MINOR,
                          TX, TY, TZ, RX, RY, RZ, DS);
         /*
          * NOTE: we omit the "Bursa-Wolf" alias because it is ambiguous, since it can apply
@@ -59,7 +59,7 @@ public final class PositionVector7Param2
      * Constructs the provider.
      */
     public PositionVector7Param2D() {
-        super(2, PARAMETERS);
+        super(2, 2, PARAMETERS);
     }
 
     /**
@@ -67,6 +67,6 @@ public final class PositionVector7Param2
      */
     @Override
     int getType() {
-        return GEOGRAPHIC | SEVEN_PARAM;
+        return SEVEN_PARAM;
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param3D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param3D.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param3D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/PositionVector7Param3D.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -29,7 +29,7 @@ import org.opengis.parameter.ParameterDe
  * @module
  */
 @XmlTransient
-public final class PositionVector7Param3D extends GeocentricAffine {
+public final class PositionVector7Param3D extends GeocentricAffineBetweenGeographic {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -55,7 +55,7 @@ public final class PositionVector7Param3
      * Constructs the provider.
      */
     public PositionVector7Param3D() {
-        super(3, PARAMETERS);
+        super(3, 3, PARAMETERS);
     }
 
     /**
@@ -63,6 +63,6 @@ public final class PositionVector7Param3
      */
     @Override
     int getType() {
-        return GEOGRAPHIC | SEVEN_PARAM;
+        return SEVEN_PARAM;
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -304,9 +304,8 @@ public class ContextualParameters extend
      * <div class="note"><b>Note:</b>
      * The definition of "kernel" is left to implementors.
      * In the particular case of Apache SIS implementation of map projections,
-     * kernels are instances of {@link org.apache.sis.referencing.operation.projection.NormalizedProjection},
-     * {@link EllipsoidalToCartesianTransform} or {@link AbridgedMolodenskyTransform}.
-     * </div>
+     * kernels are instances of {@link org.apache.sis.referencing.operation.projection.NormalizedProjection}.
+     * Other "kernels" in SIS are {@link EllipsoidalToCartesianTransform} and {@link MolodenskyTransform}.</div>
      *
      * @return The description of the parameters.
      */

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidalToCartesianTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidalToCartesianTransform.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidalToCartesianTransform.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidalToCartesianTransform.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -50,13 +50,14 @@ import org.apache.sis.referencing.operat
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.parameter.ParameterBuilder;
+import org.apache.sis.parameter.Parameters;
 import org.apache.sis.util.resources.Errors;
 
 import static java.lang.Math.*;
 import static org.apache.sis.internal.referencing.provider.MapProjection.SEMI_MAJOR;
 import static org.apache.sis.internal.referencing.provider.MapProjection.SEMI_MINOR;
 import static org.apache.sis.internal.referencing.provider.MapProjection.EXCENTRICITY;
-import static org.apache.sis.internal.referencing.provider.AbridgedMolodensky.DIMENSION;
+import static org.apache.sis.internal.referencing.provider.GeocentricAffineBetweenGeographic.DIMENSION;
 
 
 /**
@@ -356,9 +357,9 @@ public class EllipsoidalToCartesianTrans
     @Debug
     @Override
     public ParameterValueGroup getParameterValues() {
-        final ParameterValueGroup pg = getParameterDescriptors().createValue();
-        pg.parameter("excentricity").setValue(sqrt(excentricitySquared));
-        pg.parameter("dim").setValue(getSourceDimensions());
+        final Parameters pg = Parameters.castOrWrap(getParameterDescriptors().createValue());
+        pg.getOrCreate(EXCENTRICITY).setValue(sqrt(excentricitySquared));
+        pg.getOrCreate(DIMENSION).setValue(getSourceDimensions());
         return pg;
     }
 

Copied: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotationTest.java (from r1711530, sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotationTest.java?p2=sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotationTest.java&p1=sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java&r1=1711530&r2=1711928&rev=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/CoordinateFrameRotationTest.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -17,20 +17,22 @@
 package org.apache.sis.internal.referencing.provider;
 
 import org.opengis.util.FactoryException;
-import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.TransformException;
-import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.referencing.operation.transform.LinearTransform;
 import org.apache.sis.referencing.operation.transform.MathTransformTestCase;
+import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
+import static java.lang.StrictMath.toRadians;
 import static org.junit.Assert.*;
 
 
 /**
- * Tests {@link PositionVector7Param} and {@link PositionVector7Param3D}.
+ * Tests {@link CoordinateFrameRotation} and {@link CoordinateFrameRotation3D}.
+ * This test uses the same sample point than {@link PositionVector7ParamTest},
+ * but with the rotation in the opposite direction.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.7
@@ -38,50 +40,19 @@ import static org.junit.Assert.*;
  * @module
  */
 @DependsOn({
-    GeocentricTranslationTest.class
+    PositionVector7ParamTest.class
 })
-public final strictfp class PositionVector7ParamTest extends MathTransformTestCase {
+public final strictfp class CoordinateFrameRotationTest extends MathTransformTestCase {
     /**
-     * Returns the sample point for a step in the example given by the EPSG guidance note.
-     *
-     * <blockquote><b>Source:</b>
-     * §2.4.3.3 <cite>Three-parameter geocentric translations</cite> in
-     * IOGP Publication 373-7-2 – Geomatics Guidance Note number 7, part 2 – April 2015
-     * </blockquote>
-     *
-     * @param  step The step as a value from 2 to 3 inclusive.
-     * @return The sample point at the given step.
-     */
-    static double[] samplePoint(final int step) {
-        switch (step) {
-            case 2: return new double[] {
-                        3657660.66,                 // X: Toward prime meridian
-                         255768.55,                 // Y: Toward 90° east
-                        5201382.11                  // Z: Toward north pole
-                    };
-            case 3: return new double[] {
-                        3657660.78,                 // X: Toward prime meridian
-                         255778.43,                 // Y: Toward 90° east
-                        5201387.75                  // Z: Toward north pole
-                    };
-            default: throw new AssertionError(step);
-        }
-    }
-
-    /**
-     * Creates the transform for EPSG:1238.
+     * Creates the transformation from WGS 72 to WGS 84.
      */
-    private void createTransform() throws FactoryException {
-        final PositionVector7Param method = new PositionVector7Param();
-        final ParameterValueGroup values = method.getParameters().createValue();
-        values.parameter("Z-axis translation").setValue(+4.5  );    // metres
-        values.parameter("Z-axis rotation")   .setValue(+0.554);    // arc-seconds
-        values.parameter("Scale difference")  .setValue(+0.219);    // parts per million
-        transform = method.createMathTransform(DefaultFactories.forBuildin(MathTransformFactory.class), values);
+    private void createTransform(final GeocentricAffine method) throws FactoryException {
+        transform = PositionVector7ParamTest.createTransform(method, -1);
+        validate();
     }
 
     /**
-     * Tests <cite>"Position Vector transformation (geocentric domain)"</cite> (EPSG:1033)
+     * Tests <cite>"Coordinate Frame Rotation (geocentric domain)"</cite> (EPSG:1032).
      * with a sample point from WGS 72 to WGS 84 (EPSG Dataset transformation code 1238).
      *
      * @throws FactoryException if an error occurred while creating the transform.
@@ -89,11 +60,31 @@ public final strictfp class PositionVect
      */
     @Test
     public void testGeocentricDomain() throws FactoryException, TransformException {
-        createTransform();
+        createTransform(new CoordinateFrameRotation());
         tolerance = 0.01;  // Precision for (X,Y,Z) values given by EPSG
         derivativeDeltas = new double[] {100, 100, 100};    // In metres
         assertTrue(transform instanceof LinearTransform);
-        verifyTransform(samplePoint(2), samplePoint(3));
-        validate();
+        verifyTransform(PositionVector7ParamTest.samplePoint(2),
+                        PositionVector7ParamTest.samplePoint(3));
+    }
+
+    /**
+     * Tests <cite>"Coordinate Frame Rotation (geog3D domain)"</cite> (EPSG:1038).
+     *
+     * @throws FactoryException if an error occurred while creating the transform.
+     * @throws TransformException if transformation of a point failed.
+     */
+    @Test
+    @DependsOnMethod("testGeocentricDomain")
+    public void testGeographicDomain() throws FactoryException, TransformException {
+        final double delta = toRadians(100.0 / 60) / 1852;      // Approximatively 100 metres
+        derivativeDeltas = new double[] {delta, delta, 100};    // (Δλ, Δφ, Δh)
+        tolerance  = Formulas.ANGULAR_TOLERANCE;
+        zTolerance = Formulas.LINEAR_TOLERANCE;
+        zDimension = new int[] {2};
+        createTransform(new CoordinateFrameRotation3D());
+        assertFalse(transform instanceof LinearTransform);
+        verifyTransform(PositionVector7ParamTest.samplePoint(1),
+                        PositionVector7ParamTest.samplePoint(4));
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/GeocentricTranslationTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/GeocentricTranslationTest.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/GeocentricTranslationTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/GeocentricTranslationTest.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -127,7 +127,7 @@ public final strictfp class GeocentricTr
         values.parameter("X-axis translation").setValue( 84.87);
         values.parameter("Y-axis translation").setValue( 96.49);
         values.parameter("Z-axis translation").setValue(116.95);
-        if ((method.getType() & GeocentricAffine.GEOGRAPHIC) != 0) {
+        if (method instanceof GeocentricAffineBetweenGeographic) {
             setEllipsoids(values, CommonCRS.WGS84.ellipsoid(), CommonCRS.ED50.ellipsoid());
         }
         tolerance = precision(targetStep);
@@ -138,7 +138,7 @@ public final strictfp class GeocentricTr
     /**
      * Sets the source and target ellipsoid axes in the given parameter value group.
      */
-    private static void setEllipsoids(final ParameterValueGroup values, final Ellipsoid source, final Ellipsoid target) {
+    static void setEllipsoids(final ParameterValueGroup values, final Ellipsoid source, final Ellipsoid target) {
         values.parameter("src_semi_major").setValue(source.getSemiMajorAxis());
         values.parameter("src_semi_minor").setValue(source.getSemiMinorAxis());
         values.parameter("tgt_semi_major").setValue(target.getSemiMajorAxis());

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/PositionVector7ParamTest.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -18,14 +18,19 @@ package org.apache.sis.internal.referenc
 
 import org.opengis.util.FactoryException;
 import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.referencing.operation.transform.LinearTransform;
 import org.apache.sis.referencing.operation.transform.MathTransformTestCase;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
+import static java.lang.StrictMath.toRadians;
 import static org.junit.Assert.*;
 
 
@@ -49,11 +54,16 @@ public final strictfp class PositionVect
      * IOGP Publication 373-7-2 – Geomatics Guidance Note number 7, part 2 – April 2015
      * </blockquote>
      *
-     * @param  step The step as a value from 2 to 3 inclusive.
+     * @param  step The step as a value from 1 to 4 inclusive.
      * @return The sample point at the given step.
      */
     static double[] samplePoint(final int step) {
         switch (step) {
+            case 1: return new double[] {
+                        0,
+                        0,
+                        0
+                    };
             case 2: return new double[] {
                         3657660.66,                 // X: Toward prime meridian
                          255768.55,                 // Y: Toward 90° east
@@ -64,20 +74,38 @@ public final strictfp class PositionVect
                          255778.43,                 // Y: Toward 90° east
                         5201387.75                  // Z: Toward north pole
                     };
+            case 4: return new double[] {           // Anti-regression values (NOT provided by EPSG)
+                         0.5540 / 60 / 60,          // λ: Longitude
+                         0.1465 / 60 / 60,          // φ: Latitude
+                        -0.60                       // h: Height
+                    };
             default: throw new AssertionError(step);
         }
     }
 
     /**
-     * Creates the transform for EPSG:1238.
+     * Creates the transformation from WGS 72 to WGS 84.
+     *
+     * @param method The operation method to use.
+     * @param rotationSign {@code +1} for Position Vector, or -1 for Frame Rotation.
      */
-    private void createTransform() throws FactoryException {
-        final PositionVector7Param method = new PositionVector7Param();
+    static MathTransform createTransform(final GeocentricAffine method, final int rotationSign) throws FactoryException {
         final ParameterValueGroup values = method.getParameters().createValue();
-        values.parameter("Z-axis translation").setValue(+4.5  );    // metres
-        values.parameter("Z-axis rotation")   .setValue(+0.554);    // arc-seconds
-        values.parameter("Scale difference")  .setValue(+0.219);    // parts per million
-        transform = method.createMathTransform(DefaultFactories.forBuildin(MathTransformFactory.class), values);
+        values.parameter("Z-axis translation").setValue(+4.5  );                    // metres
+        values.parameter("Z-axis rotation")   .setValue(+0.554 * rotationSign);     // arc-seconds
+        values.parameter("Scale difference")  .setValue(+0.219);                    // parts per million
+        if (method instanceof GeocentricAffineBetweenGeographic) {
+            GeocentricTranslationTest.setEllipsoids(values, CommonCRS.WGS72.ellipsoid(), CommonCRS.WGS84.ellipsoid());
+        }
+        return method.createMathTransform(DefaultFactories.forBuildin(MathTransformFactory.class), values);
+    }
+
+    /**
+     * Creates the transformation from WGS 72 to WGS 84.
+     */
+    private void createTransform(final GeocentricAffine method) throws FactoryException {
+        transform = createTransform(method, +1);
+        validate();
     }
 
     /**
@@ -89,11 +117,29 @@ public final strictfp class PositionVect
      */
     @Test
     public void testGeocentricDomain() throws FactoryException, TransformException {
-        createTransform();
+        createTransform(new PositionVector7Param());
         tolerance = 0.01;  // Precision for (X,Y,Z) values given by EPSG
         derivativeDeltas = new double[] {100, 100, 100};    // In metres
         assertTrue(transform instanceof LinearTransform);
         verifyTransform(samplePoint(2), samplePoint(3));
-        validate();
+    }
+
+    /**
+     * Tests <cite>"Position Vector transformation (geog3D domain)"</cite> (EPSG:1037).
+     *
+     * @throws FactoryException if an error occurred while creating the transform.
+     * @throws TransformException if transformation of a point failed.
+     */
+    @Test
+    @DependsOnMethod("testGeocentricDomain")
+    public void testGeographicDomain() throws FactoryException, TransformException {
+        final double delta = toRadians(100.0 / 60) / 1852;      // Approximatively 100 metres
+        derivativeDeltas = new double[] {delta, delta, 100};    // (Δλ, Δφ, Δh)
+        tolerance  = Formulas.ANGULAR_TOLERANCE;
+        zTolerance = Formulas.LINEAR_TOLERANCE;
+        zDimension = new int[] {2};
+        createTransform(new PositionVector7Param3D());
+        assertFalse(transform instanceof LinearTransform);
+        verifyTransform(samplePoint(1), samplePoint(4));
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1711928&r1=1711927&r2=1711928&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Mon Nov  2 10:11:24 2015
@@ -100,6 +100,7 @@ import org.junit.BeforeClass;
     org.apache.sis.internal.referencing.provider.LongitudeRotationTest.class,
     org.apache.sis.internal.referencing.provider.GeocentricTranslationTest.class,
     org.apache.sis.internal.referencing.provider.PositionVector7ParamTest.class,
+    org.apache.sis.internal.referencing.provider.CoordinateFrameRotationTest.class,
     org.apache.sis.internal.referencing.provider.MapProjectionTest.class,
     org.apache.sis.internal.referencing.provider.AllProvidersTest.class,
     org.apache.sis.referencing.operation.transform.DefaultMathTransformFactoryTest.class,



Mime
View raw message