sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1712804 - in /sis/branches/JDK8/core: sis-feature/src/main/java/org/apache/sis/feature/ sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ sis-referencing/src/main/java/org/apache/sis/referencing/datum/ sis-referen...
Date Thu, 05 Nov 2015 16:07:21 GMT
Author: desruisseaux
Date: Thu Nov  5 16:07:09 2015
New Revision: 1712804

URL: http://svn.apache.org/viewvc?rev=1712804&view=rev
Log:
Initial support of Molodensky.inverse(), getParameterDescriptor(), getParameterValues() and
WKT.

Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.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/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform2D.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultEllipsoidTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java?rev=1712804&r1=1712803&r2=1712804&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
[UTF-8] Thu Nov  5 16:07:09 2015
@@ -336,11 +336,12 @@ public abstract class AbstractAttribute<
      * @see DefaultAttributeType#characteristics()
      */
     @Override
+    @SuppressWarnings("ReturnOfCollectionOrArrayField")
     public Map<String,Attribute<?>> characteristics() {
         if (characteristics == null) {
             characteristics = newCharacteristicsMap();
         }
-        return characteristics;
+        return characteristics;     // Intentionally modifiable
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java?rev=1712804&r1=1712803&r2=1712804&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
[UTF-8] Thu Nov  5 16:07:09 2015
@@ -123,8 +123,9 @@ final class MultiValuedAttribute<V> exte
      * @return The attribute values in a <cite>live</cite> collection.
      */
     @Override
+    @SuppressWarnings("ReturnOfCollectionOrArrayField")
     public Collection<V> getValues() {
-        return values;
+        return values;      // Intentionally modifiable
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java?rev=1712804&r1=1712803&r2=1712804&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeocentricAffineBetweenGeographic.java
[UTF-8] Thu Nov  5 16:07:09 2015
@@ -90,12 +90,12 @@ public abstract class GeocentricAffineBe
     public static final ParameterDescriptor<Double> TGT_SEMI_MINOR;
 
     static {
-        final ParameterBuilder builder = builder().setCodeSpace(Citations.OGC, Constants.OGC).setRequired(false);
-        DIMENSION      = builder.addName("dim")   .createBounded(Integer.class, 2, 3, null);
+        final ParameterBuilder builder = builder().setCodeSpace(Citations.OGC, Constants.OGC);
         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);
+        DIMENSION      = builder.addName("dim").setRequired(false).createBounded(Integer.class,
2, 3, null);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java?rev=1712804&r1=1712803&r2=1712804&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Molodensky.java
[UTF-8] Thu Nov  5 16:07:09 2015
@@ -37,8 +37,10 @@ import org.apache.sis.referencing.operat
 import org.apache.sis.internal.referencing.NilReferencingObject;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.Debug;
 
 
 /**
@@ -94,7 +96,10 @@ public final class Molodensky extends Ge
         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
+        builder.setRequired(false);
+        ParameterDescriptor<Double> a = builder.addName(TGT_SEMI_MAJOR.getName()).createStrictlyPositive(Double.NaN,
SI.METRE);
+        ParameterDescriptor<Double> b = builder.addName(TGT_SEMI_MINOR.getName()).createStrictlyPositive(Double.NaN,
SI.METRE);
+        PARAMETERS = builder.setRequired(true)
                 .addIdentifier("9604")
                 .addName("Molodensky")
                 .addName(Citations.OGC, "Molodenski")
@@ -105,7 +110,30 @@ public final class Molodensky extends Ge
                              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
+                             a, b);                             // OGC only
+    }
+
+    /**
+     * Creates a descriptor for the internal parameters of {@link MolodenskyTransform}.
+     * This is identical to the standard parameters except that the last 3 OGC parameters
+     * are replaced by the excentricity.
+     *
+     * @return Internal parameter descriptor.
+     */
+    @Debug
+    public static ParameterDescriptorGroup internal() {
+        final ParameterBuilder builder = builder().setCodeSpace(Citations.SIS, Constants.SIS);
+        ParameterDescriptor<Boolean> abridged = builder.addName("abridged").create(Boolean.class,
null);
+        return builder.addName("Molodensky")
+                .createGroup(DIMENSION,
+                             TX,
+                             TY,
+                             TZ,
+                             AXIS_LENGTH_DIFFERENCE,
+                             FLATTENING_DIFFERENCE,
+                             SRC_SEMI_MAJOR,
+                             MapProjection.EXCENTRICITY,
+                             abridged);
     }
 
     /**
@@ -271,8 +299,8 @@ public final class Molodensky extends Ge
         }
 
         /** Returns Δa as specified in the parameters if possible, or compute it otherwise.
*/
-        @Override public double semiMajorDifference(final org.opengis.referencing.datum.Ellipsoid
target) {
-            return (target == other && !Double.isNaN(Δa)) ? Δa : super.semiMajorDifference(target);
+        @Override public double semiMajorAxisDifference(final org.opengis.referencing.datum.Ellipsoid
target) {
+            return (target == other && !Double.isNaN(Δa)) ? Δa : super.semiMajorAxisDifference(target);
         }
 
         /** Returns Δf as specified in the parameters if possible, or compute it otherwise.
*/

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java?rev=1712804&r1=1712803&r2=1712804&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
[UTF-8] Thu Nov  5 16:07:09 2015
@@ -620,7 +620,7 @@ public class DefaultEllipsoid extends Ab
      * length of the other ellipsoid is converted into the units of this ellipsoid axis.
      *
      * <div class="note"><b>Example:</b>
-     * {@code WGS84.semiMajorDifference(ED50)} returns 251 metres. This information is a
parameter of
+     * {@code WGS84.semiMajorAxisDifference(ED50)} returns 251 metres. This information is
a parameter of
      * {@linkplain org.apache.sis.referencing.operation.transform.MolodenskyTransform Molodensky
transformations}.</div>
      *
      * @param  other The other ellipsoid from which to get semi-major axis length difference.
@@ -628,7 +628,7 @@ public class DefaultEllipsoid extends Ab
      *
      * @since 0.7
      */
-    public double semiMajorDifference(final Ellipsoid other) {
+    public double semiMajorAxisDifference(final Ellipsoid other) {
         double semiMajor = other.getSemiMajorAxis();
         semiMajor = other.getAxisUnit().getConverterTo(getAxisUnit()).convert(semiMajor);
  // Often a no-op.
         final DoubleDouble a = new DoubleDouble(semiMajor);     // Presumed accurate in base
10 if no unit conversion.

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=1712804&r1=1712803&r2=1712804&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] Thu Nov  5 16:07:09 2015
@@ -301,6 +301,9 @@ public class ContextualParameters extend
      */
     final synchronized ContextualParameters inverse(final ParameterDescriptorGroup desc)
{
         if (inverse == null) {
+            if (!isFrozen) {
+                freeze();
+            }
             inverse = new ContextualParameters(desc, this);
         }
         assert inverse.descriptor == desc;
@@ -534,7 +537,7 @@ public class ContextualParameters extend
      *
      * @see #ensureModifiable()
      */
-    final void freeze() {
+    private void freeze() {
         isFrozen = true;
         /*
          * Sort the parameter values in the same order than the parameter descriptor. This
is not essential,

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=1712804&r1=1712803&r2=1712804&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] Thu Nov  5 16:07:09 2015
@@ -269,12 +269,6 @@ public class EllipsoidalToCartesianTrans
             final MatrixSIS normalize = context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION);
             normalize.convertBefore(2, a, null);    // Divide ellipsoidal height by a.
         }
-        /*
-         * 'freeze()' should be invoked before to create the inverse transform in order to
allow ContextualParameters
-         * to cache the inverse matrices. This caching avoid to duplicate those matrices
if they are asked later (e.g.
-         * at WKT formatting time).
-         */
-        context.freeze();
         inverse = new Inverse();
     }
 
@@ -294,8 +288,8 @@ public class EllipsoidalToCartesianTrans
      *
      * <p>Input coordinates are expected to contain:</p>
      * <ol>
-     *   <li>longitudes in degrees relative to the prime meridian (usually Greenwich),</li>
-     *   <li>latitudes in degrees,</li>
+     *   <li>longitudes in <strong>degrees</strong> relative to the prime
meridian (usually Greenwich),</li>
+     *   <li>latitudes in <strong>degrees</strong>,</li>
      *   <li>optionally heights above the ellipsoid, in units of the ellipsoid axis
(usually metres).</li>
      * </ol>
      *

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java?rev=1712804&r1=1712803&r2=1712804&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java
[UTF-8] Thu Nov  5 16:07:09 2015
@@ -20,6 +20,7 @@ import java.util.Arrays;
 import java.io.Serializable;
 import javax.measure.unit.Unit;
 import javax.measure.quantity.Length;
+import javax.measure.converter.UnitConverter;
 import org.opengis.util.FactoryException;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.parameter.ParameterValueGroup;
@@ -33,8 +34,10 @@ import org.apache.sis.referencing.datum.
 import org.apache.sis.internal.referencing.provider.Molodensky;
 import org.apache.sis.internal.referencing.provider.AbridgedMolodensky;
 import org.apache.sis.internal.referencing.provider.MapProjection;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.Debug;
 
 import static java.lang.Math.*;
@@ -89,6 +92,15 @@ public class MolodenskyTransform extends
     private static final long serialVersionUID = 7206439437113286122L;
 
     /**
+     * Internal parameter descriptor, used only for debugging purpose.
+     * Created only when first needed.
+     *
+     * @see #getParameterDescriptors()
+     */
+    @Debug
+    private static ParameterDescriptorGroup DESCRIPTOR;
+
+    /**
      * The value of 1/sin(1″) multiplied by the conversion factor from arc-seconds to radians
(π/180)/(60⋅60).
      * This is the final multiplication factor for Δλ and Δφ.
      */
@@ -127,9 +139,28 @@ public class MolodenskyTransform extends
     private final byte type;
 
     /**
-     * X,Y,Z shifts in units of the semi-major axis of the source ellipsoid.
+     * Shift along the geocentric X axis (toward prime meridian)
+     * in units of the semi-major axis of the source ellipsoid.
+     *
+     * @see org.apache.sis.referencing.datum.BursaWolfParameters#tX
      */
-    private final double tX, tY, tZ;
+    protected final double tX;
+
+    /**
+     * Shift along the geocentric Y axis (toward 90°E)
+     * in units of the semi-major axis of the source ellipsoid.
+     *
+     * @see org.apache.sis.referencing.datum.BursaWolfParameters#tY
+     */
+    protected final double tY;
+
+    /**
+     * Shift along the geocentric Z axis (toward north pole)
+     * in units of the semi-major axis of the source ellipsoid.
+     *
+     * @see org.apache.sis.referencing.datum.BursaWolfParameters#tZ
+     */
+    protected final double tZ;
 
     /**
      * Semi-major axis length (<var>a</var>) of the source ellipsoid.
@@ -141,12 +172,15 @@ public class MolodenskyTransform extends
      * This can be computed by ℯ² = (a²-b²)/a² where
      * <var>a</var> is the <cite>semi-major</cite> axis length and
      * <var>b</var> is the <cite>semi-minor</cite> axis length.
+     *
+     * @see DefaultEllipsoid#getEccentricitySquared()
      */
     private final double excentricitySquared;
 
     /**
      * Difference in the semi-major axes of the target and source ellipsoids: {@code Δa
= target a - source a}.
-     * This field is needed explicitely only for the non-abridged form of Molodensky transformation.
+     *
+     * @see DefaultEllipsoid#semiMajorAxisDifference(Ellipsoid)
      */
     private final double Δa;
 
@@ -172,6 +206,13 @@ public class MolodenskyTransform extends
     private final ContextualParameters context;
 
     /**
+     * The inverse of this Molodensky transform.
+     *
+     * @see #inverse()
+     */
+    private MolodenskyTransform inverse;
+
+    /**
      * Creates a Molodensky transform from the specified parameters.
      * This {@code MolodenskyTransform} class expects ordinate values if the following order
and units:
      * <ol>
@@ -186,11 +227,9 @@ public class MolodenskyTransform extends
      * <ul>
      *   <li><cite>Normalization</cite> before {@code MolodenskyTransform}:<ul>
      *     <li>Conversion of (λ,φ) from degrees to radians.</li>
-     *     <li>Any implementation-dependent linear conversion of <var>h</var>.</li>
      *   </ul></li>
      *   <li><cite>Denormalization</cite> after {@code MolodenskyTransform}:<ul>
      *     <li>Conversion of (λ,φ) from radians to degrees.</li>
-     *     <li>Any implementation-dependent linear conversion of <var>h</var>.</li>
      *   </ul></li>
      * </ul>
      *
@@ -223,34 +262,30 @@ public class MolodenskyTransform extends
         if (isTarget3D) type |= TARGET_DIMENSION_MASK;
         this.type      = type;
         this.semiMajor = src.getSemiMajorAxis();
-        this.Δa        = src.semiMajorDifference(target);
+        this.Δa        = src.semiMajorAxisDifference(target);
         this.tX        = tX;
         this.tY        = tY;
         this.tZ        = tZ;
 
-        final double semiMinor   = src.getSemiMinorAxis();
-        final double ΔFlattening = src.flatteningDifference(target);
-        excentricitySquared      = src.getEccentricitySquared();
-        Δfmod = isAbridged ? (semiMajor * ΔFlattening) + (semiMajor - semiMinor) * (Δa
/ semiMajor)
-                           : (semiMinor * ΔFlattening);
+        final double semiMinor = src.getSemiMinorAxis();
+        final double Δf = src.flatteningDifference(target);
+        excentricitySquared = src.getEccentricitySquared();
+        Δfmod = isAbridged ? (semiMajor * Δf) + (semiMajor - semiMinor) * (Δa / semiMajor)
+                           : (semiMinor * Δf);
         /*
          * Copy parameters to the ContextualParameter. Those parameters are not used directly
          * by EllipsoidToCartesian, but we need to store them in case the user asks for them.
          * When both EPSG and OGC parameters exist for equivalent information, we use EPSG
ones.
          */
+        final Unit<Length> unit = src.getAxisUnit();
+        final UnitConverter c = target.getAxisUnit().getConverterTo(unit);
         context = new ContextualParameters(isAbridged ? AbridgedMolodensky.PARAMETERS : Molodensky.PARAMETERS,
                                            isSource3D ? 4 : 3, isTarget3D ? 4 : 3);
-        if (isSource3D == isTarget3D) {
-            context.getOrCreate(Molodensky.DIMENSION).setValue(isSource3D ? 3 : 2);
-        }
-        final Unit<Length> unit = src.getAxisUnit();
-        context.getOrCreate(Molodensky.TX)                    .setValue(tX, unit);
-        context.getOrCreate(Molodensky.TY)                    .setValue(tY, unit);
-        context.getOrCreate(Molodensky.TZ)                    .setValue(tZ, unit);
-        context.getOrCreate(Molodensky.AXIS_LENGTH_DIFFERENCE).setValue(Δa, unit);
-        context.getOrCreate(Molodensky.FLATTENING_DIFFERENCE) .setValue(ΔFlattening, Unit.ONE);
-        context.getOrCreate(Molodensky.SRC_SEMI_MAJOR)        .setValue(semiMajor,   unit);
-        context.getOrCreate(Molodensky.SRC_SEMI_MINOR)        .setValue(semiMinor,   unit);
+        setEPSG(context, unit, Δf);
+        context.getOrCreate(Molodensky.SRC_SEMI_MAJOR).setValue(semiMajor,   unit);
+        context.getOrCreate(Molodensky.SRC_SEMI_MINOR).setValue(semiMinor,   unit);
+        context.getOrCreate(Molodensky.TGT_SEMI_MAJOR).setValue(c.convert(target.getSemiMajorAxis()),
unit);
+        context.getOrCreate(Molodensky.TGT_SEMI_MINOR).setValue(c.convert(target.getSemiMinorAxis()),
unit);
         /*
          * Prepare two affine transforms to be executed before and after this MolodenskyTransform:
          *
@@ -259,13 +294,26 @@ public class MolodenskyTransform extends
          */
         context.normalizeGeographicInputs(0);
         context.denormalizeGeographicOutputs(0);
-        /*
-         * In the particular case of abridged Molondensky, there is some more terms than
we can
-         * delegate to the matrices. We can not do that for the non-abridged formulas however.
-         */
-        if (isTarget3D && isAbridged) {
-            context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION).convertAfter(2,
null, -Δa);
-        }
+    }
+
+    /**
+     * Sets the "dim" parameter and the EPSG parameters in the given group.
+     * The OGC parameters other than "dim" are not set by this method.
+     *
+     * @param pg   Where to set the parameters.
+     * @param unit The unit of measurement to declare.
+     * @param Δf   The flattening difference to set.
+     */
+    private void setEPSG(final Parameters pg, final Unit<?> unit, final double Δf)
{
+        final int dim = getSourceDimensions();
+        if (dim == getTargetDimensions()) {
+            pg.getOrCreate(Molodensky.DIMENSION).setValue(dim);
+        }
+        pg.getOrCreate(Molodensky.TX)                    .setValue(tX, unit);
+        pg.getOrCreate(Molodensky.TY)                    .setValue(tY, unit);
+        pg.getOrCreate(Molodensky.TZ)                    .setValue(tZ, unit);
+        pg.getOrCreate(Molodensky.AXIS_LENGTH_DIFFERENCE).setValue(Δa, unit);
+        pg.getOrCreate(Molodensky.FLATTENING_DIFFERENCE) .setValue(Δf, Unit.ONE);
     }
 
     /**
@@ -274,8 +322,8 @@ public class MolodenskyTransform extends
      * degrees to radians. The transform works with input and output coordinates in the following
units:
      *
      * <ol>
-     *   <li>longitudes in degrees relative to the prime meridian (usually Greenwich),</li>
-     *   <li>latitudes in degrees,</li>
+     *   <li>longitudes in <strong>degrees</strong> relative to the prime
meridian (usually Greenwich),</li>
+     *   <li>latitudes in <strong>degrees</strong>,</li>
      *   <li>optionally heights above the ellipsoid, in same units than the source
ellipsoids axes.</li>
      * </ol>
      *
@@ -300,13 +348,24 @@ public class MolodenskyTransform extends
         final MolodenskyTransform tr;
         if (!isSource3D && !isTarget3D) {
             tr = new MolodenskyTransform2D(source, target, tX, tY, tZ, isAbridged);
+            tr.inverse = new MolodenskyTransform2D(target, source, -tX, -tY, -tZ, isAbridged);
         } else {
             tr = new MolodenskyTransform(source, isSource3D, target, isTarget3D, tX, tY,
tZ, isAbridged);
+            tr.inverse = new MolodenskyTransform(target, isTarget3D, source, isSource3D,
-tX, -tY, -tZ, isAbridged);
         }
+        tr.inverse.inverse = tr;
         return tr.context.completeTransform(factory, tr);
     }
 
     /**
+     * Returns the unit of measurement of axis lengths. Current implementation arbitrarily
+     * returns the units of {@link #Δa} (this may change in any future SIS version).
+     */
+    private Unit<?> getLinearUnit() {
+        return context.getOrCreate(Molodensky.AXIS_LENGTH_DIFFERENCE).getUnit();
+    }
+
+    /**
      * Returns the parameters used for creating the complete transformation. Those parameters
describe a sequence
      * of <cite>normalize</cite> → {@code this} → <cite>denormalize</cite>
transforms, <strong>not</strong>
      * including {@linkplain org.apache.sis.referencing.cs.CoordinateSystems#swapAndScaleAxes
axis swapping}.
@@ -321,8 +380,8 @@ public class MolodenskyTransform extends
     }
 
     /**
-     * Returns a copy of internal parameter values of this {@code MolodenskyTransform} transform.
-     * The returned group contains parameter values for the number of dimensions and the
excentricity.
+     * Returns a copy of internal parameter values of this {@code MolodenskyTransform}.
+     * The returned group contains parameter values for the excentricity and the shift among
others.
      *
      * <div class="note"><b>Note:</b>
      * this method is mostly for {@linkplain org.apache.sis.io.wkt.Convention#INTERNAL debugging
purposes}
@@ -336,12 +395,11 @@ public class MolodenskyTransform extends
     @Override
     public ParameterValueGroup getParameterValues() {
         final Parameters pg = Parameters.castOrWrap(getParameterDescriptors().createValue());
-        final int dimension = getSourceDimensions();
-        if (dimension == getTargetDimensions()) {
-            pg.getOrCreate(Molodensky.DIMENSION).setValue(dimension);
-        }
+        final Unit<?> unit = getLinearUnit();
+        setEPSG(pg, unit, context.doubleValue(Molodensky.FLATTENING_DIFFERENCE));
+        pg.getOrCreate(Molodensky.SRC_SEMI_MAJOR).setValue(semiMajor, unit);
         pg.getOrCreate(MapProjection.EXCENTRICITY).setValue(sqrt(excentricitySquared));
-        // TODO: add other parameters
+        pg.parameter("abridged").setValue(isAbridged());
         return pg;
     }
 
@@ -354,7 +412,12 @@ public class MolodenskyTransform extends
     @Debug
     @Override
     public ParameterDescriptorGroup getParameterDescriptors() {
-        return null; // TODO
+        synchronized (MolodenskyTransform.class) {
+            if (DESCRIPTOR == null) {
+                DESCRIPTOR = Molodensky.internal();
+            }
+            return DESCRIPTOR;
+        }
     }
 
     /**
@@ -499,11 +562,12 @@ public class MolodenskyTransform extends
         dstPts[dstOff++] = φ + ANGULAR_SCALE * ((t*cosφ - tXY)*sinφ + tZ*cosφ) / ρ;
         if (isTarget3D) {
             t = Δfmod * sin2φ;                                              // A term in
the calculation of Δh
+            double d = Δa;
             if (!abridged) {
-                t = t/νden - Δa*νden;
-                // Note: in abridged Molodensky case, 'Δa' subtracted by the denormalization
matrix.
+                t /= νden;
+                d *= νden;
             }
-            dstPts[dstOff++] = h + tXY*cosφ + tZ*sinφ + t;
+            dstPts[dstOff++] = h + tXY*cosφ + tZ*sinφ + t - d;
         }
         if (!derivate) {
             return null;
@@ -585,10 +649,12 @@ public class MolodenskyTransform extends
             dstPts[dstOff++] = φ + ANGULAR_SCALE * ((t*cosφ - tXY)*sinφ + tZ*cosφ) /
ρ;
             if (isTarget3D) {
                 t = Δfmod * sin2φ;
+                double d = Δa;
                 if (!abridged) {
-                    t = t/νden - Δa*νden;
+                    t /= νden;
+                    d *= νden;
                 }
-                dstPts[dstOff++] = h + tXY*cosφ + tZ*sinφ + t;
+                dstPts[dstOff++] = h + tXY*cosφ + tZ*sinφ + t - d;
             }
             srcOff += srcInc;
             dstOff += dstInc;
@@ -610,4 +676,54 @@ public class MolodenskyTransform extends
      *       the method inherited from the subclass will work (even if slightly slower).
      */
 
+    /**
+     * Returns the inverse of this Molodensky transform. The source ellipsoid of the returned
transform will
+     * be the target ellipsoid of this transform, and conversely.
+     *
+     * @return A Molodensky transform from the target ellipsoid to the source ellipsoid of
this transform.
+     */
+    @Override
+    public MathTransform inverse() {
+        return inverse;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return {@inheritDoc}
+     */
+    @Override
+    protected int computeHashCode() {
+        return super.computeHashCode() + type + Numerics.hashCode(
+                        Double.doubleToLongBits(Δa)
+                +       Double.doubleToLongBits(Δfmod)
+                + 31 * (Double.doubleToLongBits(tX)
+                + 31 * (Double.doubleToLongBits(tY)
+                + 31 * (Double.doubleToLongBits(tZ)))));
+    }
+
+    /**
+     * Compares the specified object with this math transform for equality.
+     *
+     * @return {@inheritDoc}
+     */
+    @Override
+    public boolean equals(final Object object, final ComparisonMode mode) {
+        if (object == this) {
+            // Slight optimization
+            return true;
+        }
+        if (super.equals(object, mode)) {
+            final MolodenskyTransform that = (MolodenskyTransform) object;
+            return type == that.type
+                   && Numerics.equals(tX,                  that.tX)
+                   && Numerics.equals(tY,                  that.tY)
+                   && Numerics.equals(tZ,                  that.tZ)
+                   && Numerics.equals(Δa,                  that.Δa)
+                   && Numerics.equals(Δfmod,               that.Δfmod)
+                   && Numerics.equals(semiMajor,           that.semiMajor)
+                   && Numerics.equals(excentricitySquared, that.excentricitySquared);
+        }
+        return false;
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform2D.java?rev=1712804&r1=1712803&r2=1712804&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform2D.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform2D.java
[UTF-8] Thu Nov  5 16:07:09 2015
@@ -21,7 +21,6 @@ import java.awt.geom.Point2D;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform2D;
-import org.opengis.referencing.operation.NoninvertibleTransformException;
 import org.opengis.referencing.operation.TransformException;
 
 
@@ -78,7 +77,7 @@ final class MolodenskyTransform2D extend
      * Returns the inverse transform of this transform.
      */
     @Override
-    public MathTransform2D inverse() throws NoninvertibleTransformException {
+    public MathTransform2D inverse() {
         return (MathTransform2D) super.inverse();
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultEllipsoidTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultEllipsoidTest.java?rev=1712804&r1=1712803&r2=1712804&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultEllipsoidTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultEllipsoidTest.java
[UTF-8] Thu Nov  5 16:07:09 2015
@@ -84,16 +84,16 @@ public final strictfp class DefaultEllip
     }
 
     /**
-     * Tests {@link DefaultEllipsoid#semiMajorDifference(Ellipsoid)}. This test uses the
data provided
+     * Tests {@link DefaultEllipsoid#semiMajorAxisDifference(Ellipsoid)}. This test uses
the data provided
      * in §2.4.4.2 of IOGP Publication 373-7-2 – Geomatics Guidance Note number 7, part
2 – April 2015.
      *
      * @since 0.7
      */
     @Test
-    public void testSemiMajorDifference() {
+    public void testSemiMajorAxisDifference() {
         final DefaultEllipsoid e = new DefaultEllipsoid(GeodeticDatumMock.WGS84.getEllipsoid());
-        assertEquals("semiMajorDifference",   0, e.semiMajorDifference(GeodeticDatumMock.WGS84.getEllipsoid()),
STRICT);
-        assertEquals("semiMajorDifference", 251, e.semiMajorDifference(GeodeticDatumMock.ED50
.getEllipsoid()), STRICT);
+        assertEquals("semiMajorAxisDifference",   0, e.semiMajorAxisDifference(GeodeticDatumMock.WGS84.getEllipsoid()),
STRICT);
+        assertEquals("semiMajorAxisDifference", 251, e.semiMajorAxisDifference(GeodeticDatumMock.ED50
.getEllipsoid()), STRICT);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java?rev=1712804&r1=1712803&r2=1712804&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java
[UTF-8] Thu Nov  5 16:07:09 2015
@@ -21,7 +21,9 @@ import org.opengis.referencing.datum.Ell
 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.CommonCRS;
+import org.apache.sis.measure.Longitude;
 
 import static java.lang.StrictMath.toRadians;
 
@@ -29,6 +31,9 @@ import static java.lang.StrictMath.toRad
 import org.apache.sis.internal.referencing.provider.GeocentricTranslationTest;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.TestUtilities;
+import org.opengis.test.ToleranceModifier;
+import org.opengis.test.ToleranceModifiers;
 import org.junit.Test;
 
 import static org.apache.sis.test.Assert.*;
@@ -84,12 +89,20 @@ public final strictfp class MolodenskyTr
      */
     @Test
     public void testAbridgedMolodensky() throws FactoryException, TransformException {
-        isInverseTransformSupported = false;
         isDerivativeSupported = false;
         create(true);
         validate();
-        verifyTransform(GeocentricTranslationTest.samplePoint(1),
-                        GeocentricTranslationTest.samplePoint(5));
+        final double[] sample   = GeocentricTranslationTest.samplePoint(1);
+        final double[] expected = GeocentricTranslationTest.samplePoint(5);
+        isInverseTransformSupported = false;
+        verifyTransform(sample, expected);
+        /*
+         * When testing the inverse transformation, we need to relax slightly
+         * the tolerance for the 'h' value.
+         */
+        zTolerance = Formulas.LINEAR_TOLERANCE;
+        isInverseTransformSupported = true;
+        verifyTransform(sample, expected);
     }
 
     /**
@@ -107,12 +120,20 @@ public final strictfp class MolodenskyTr
     @Test
     @DependsOnMethod("testAbridgedMolodensky")
     public void testMolodensky() throws FactoryException, TransformException {
-        isInverseTransformSupported = false;
         isDerivativeSupported = false;
         create(false);
         validate();
-        verifyTransform(GeocentricTranslationTest.samplePoint(1),
-                        GeocentricTranslationTest.samplePoint(4));
+        final double[] sample   = GeocentricTranslationTest.samplePoint(1);
+        final double[] expected = GeocentricTranslationTest.samplePoint(4);
+        isInverseTransformSupported = false;
+        verifyTransform(sample, expected);
+        /*
+         * When testing the inverse transformation, we need to relax slightly
+         * the tolerance for the 'h' value.
+         */
+        zTolerance = Formulas.LINEAR_TOLERANCE;
+        isInverseTransformSupported = true;
+        verifyTransform(sample, expected);
     }
 
     /**
@@ -126,9 +147,84 @@ public final strictfp class MolodenskyTr
     @Test
     @DependsOnMethod("testMolodensky")
     public void testRandomPoints() throws FactoryException, TransformException {
-        isInverseTransformSupported = false;
         isDerivativeSupported = false;
         create(false);
-        verifyInDomain(CoordinateDomain.GEOGRAPHIC, 208129394);
+        tolerance  = Formulas.LINEAR_TOLERANCE * 3;     // To be converted in degrees by
ToleranceModifier.GEOGRAPHIC
+        zTolerance = Formulas.LINEAR_TOLERANCE * 2;
+        toleranceModifier = ToleranceModifiers.concatenate(ToleranceModifier.GEOGRAPHIC,
toleranceModifier);
+        verifyInDomain(new double[] {Longitude.MIN_VALUE, -85, -500},
+                       new double[] {Longitude.MIN_VALUE, +85, +500},
+                       new int[] {8, 8, 8},
+                       TestUtilities.createRandomNumberGenerator(208129394));
+    }
+
+    /**
+     * Tests the standard Well Known Text (version 1) formatting.
+     * The result is what we show to users, but may quite different than what SIS has in
memory.
+     *
+     * @throws FactoryException if an error occurred while creating a transform.
+     * @throws TransformException should never happen.
+     */
+    @Test
+    public void testWKT() throws FactoryException, TransformException {
+        create(true);
+        assertWktEquals("PARAM_MT[“Abridged_Molodenski”,\n" +
+                        "  PARAMETER[“dim”, 3],\n" +
+                        "  PARAMETER[“dx”, 84.87],\n" +
+                        "  PARAMETER[“dy”, 96.49],\n" +
+                        "  PARAMETER[“dz”, 116.95],\n" +
+                        "  PARAMETER[“Semi-major axis length difference”, 251.0],\n"
+
+                        "  PARAMETER[“Flattening difference”, 1.4192702255886284E-5],\n"
+
+                        "  PARAMETER[“src_semi_major”, 6378137.0],\n" +
+                        "  PARAMETER[“src_semi_minor”, 6356752.314245179],\n" +
+                        "  PARAMETER[“tgt_semi_major”, 6378388.0],\n" +
+                        "  PARAMETER[“tgt_semi_minor”, 6356911.9461279465]]");
+
+        transform = transform.inverse();
+        assertWktEquals("PARAM_MT[“Abridged_Molodenski”,\n" +
+                        "  PARAMETER[“dim”, 3],\n" +
+                        "  PARAMETER[“dx”, -84.87],\n" +
+                        "  PARAMETER[“dy”, -96.49],\n" +
+                        "  PARAMETER[“dz”, -116.95],\n" +
+                        "  PARAMETER[“Semi-major axis length difference”, -251.0],\n"
+
+                        "  PARAMETER[“Flattening difference”, -1.4192702255886284E-5],\n"
+
+                        "  PARAMETER[“src_semi_major”, 6378388.0],\n" +
+                        "  PARAMETER[“src_semi_minor”, 6356911.9461279465],\n" +
+                        "  PARAMETER[“tgt_semi_major”, 6378137.0],\n" +
+                        "  PARAMETER[“tgt_semi_minor”, 6356752.314245179]]");
+    }
+
+    /**
+     * Tests the internal Well Known Text formatting.
+     * This WKT shows what SIS has in memory for debugging purpose.
+     * This is normally not what we show to users.
+     *
+     * @throws FactoryException if an error occurred while creating a transform.
+     * @throws TransformException should never happen.
+     */
+    @Test
+    public void testInternalWKT() throws FactoryException, TransformException {
+        create(true);
+        assertInternalWktEquals(
+                "Concat_MT[Param_MT[“Affine”,\n" +
+                "    Parameter[“num_row”, 4],\n" +
+                "    Parameter[“num_col”, 4],\n" +
+                "    Parameter[“elt_0_0”, 0.017453292519943295],\n" +       // Degrees
to radians conversion
+                "    Parameter[“elt_1_1”, 0.017453292519943295]],\n" +
+                "  Param_MT[“Molodensky”,\n" +
+                "    Parameter[“X-axis translation”, 84.87, Unit[“metre”, 1, Id[“EPSG”,
9001]]],\n" +
+                "    Parameter[“Y-axis translation”, 96.49, Unit[“metre”, 1, Id[“EPSG”,
9001]]],\n" +
+                "    Parameter[“Z-axis translation”, 116.95, Unit[“metre”, 1, Id[“EPSG”,
9001]]],\n" +
+                "    Parameter[“Semi-major axis length difference”, 251.0, Unit[“metre”,
1, Id[“EPSG”, 9001]]],\n" +
+                "    Parameter[“Flattening difference”, 1.4192702255886284E-5, Unit[“unity”,
1, Id[“EPSG”, 9201]]],\n" +
+                "    Parameter[“src_semi_major”, 6378137.0, Unit[“metre”, 1, Id[“EPSG”,
9001]]],\n" +
+                "    Parameter[“excentricity”, 0.0818191908426215],\n" +
+                "    Parameter[“abridged”, TRUE],\n" +
+                "    Parameter[“dim”, 3]],\n" +
+                "  Param_MT[“Affine”,\n" +
+                "    Parameter[“num_row”, 4],\n" +
+                "    Parameter[“num_col”, 4],\n" +
+                "    Parameter[“elt_0_0”, 57.29577951308232],\n" +          // Radians
to degrees conversion
+                "    Parameter[“elt_1_1”, 57.29577951308232]]]");
     }
 }




Mime
View raw message