This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit c01dd455bba8e8c9cb4677bdd12acc296213ec6c
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Tue May 3 19:22:24 2022 +0200

    Implement ESRI "Mercator Auxiliary Sphere" type 3 (with conversion of 
geodetic latitudes to authalic latitudes).
    This feature requires an additional degree of flexibility in the 
package-private projection constructors.
---
 .../operation/projection/AlbersEqualArea.java      |   2 +-
 .../operation/projection/AuthalicConversion.java   |  21 ++--
 .../operation/projection/AuthalicMercator.java     | 115 +++++++++++++++++++++
 .../operation/projection/AzimuthalEquidistant.java |   4 +-
 .../operation/projection/ConformalProjection.java  |   4 +-
 .../operation/projection/CylindricalEqualArea.java |   2 +-
 .../projection/LambertAzimuthalEqualArea.java      |   2 +-
 .../referencing/operation/projection/Mercator.java |  20 ++--
 .../operation/projection/MeridianArcBased.java     |   4 +-
 .../operation/projection/Mollweide.java            |   2 +-
 .../operation/projection/NormalizedProjection.java |  47 +++++----
 .../operation/projection/ObliqueStereographic.java |   4 +-
 .../operation/projection/Orthographic.java         |   2 +-
 .../operation/projection/SatelliteTracking.java    |   2 +-
 .../operation/projection/TransverseMercator.java   |   4 +-
 .../operation/projection/MercatorTest.java         |  50 +++++++--
 .../projection/ProjectionResultComparator.java     |   2 +-
 17 files changed, 222 insertions(+), 65 deletions(-)

diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
index 4fbe7b7155..e9d8caead0 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AlbersEqualArea.java
@@ -120,7 +120,7 @@ public class AlbersEqualArea extends AuthalicConversion {
      */
     @Workaround(library="JDK", version="1.7")
     private AlbersEqualArea(final Initializer initializer) {
-        super(initializer);
+        super(initializer, null);
         double φ0 = initializer.getAndStore(LATITUDE_OF_FALSE_ORIGIN);
         double φ1 = initializer.getAndStore(STANDARD_PARALLEL_1, φ0);
         double φ2 = initializer.getAndStore(STANDARD_PARALLEL_2, φ1);
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicConversion.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicConversion.java
index e96a9d3c4a..640a764a7b 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicConversion.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicConversion.java
@@ -106,12 +106,15 @@ abstract class AuthalicConversion extends 
NormalizedProjection {
     private final boolean useIterations;
 
     /**
-     * Creates a new normalized projection from the parameters computed by the 
given initializer.
+     * Creates a new normalized projection from the parameters computed by the 
given initializer,
+     * or from the parameters already computed by another projection.
+     * Exactly one of {@code initializer} or {@code other} shall be non-null.
      *
-     * @param  initializer  the initializer for computing map projection 
internal parameters.
+     * @param initializer  the initializer for computing map projection 
internal parameters, or {@code null}.
+     * @param other        the other projection from which to compute 
parameters, or {@code null}.
      */
-    AuthalicConversion(final Initializer initializer) {
-        super(initializer);
+    AuthalicConversion(final Initializer initializer, final 
NormalizedProjection other) {
+        super(initializer, other);
         isSpherical = (eccentricitySquared == 0);
         final double e2 = eccentricitySquared;
         final double e4 = e2 * e2;
@@ -153,11 +156,11 @@ abstract class AuthalicConversion extends 
NormalizedProjection {
      * instance without recomputing them.
      */
     AuthalicConversion(final AuthalicConversion other) {
-        super(other);
-        c2β     = other.c2β;
-        c4β     = other.c4β;
-        c6β     = other.c6β;
-        qmPolar = other.qmPolar;
+        super(null, other);
+        c2β           = other.c2β;
+        c4β           = other.c4β;
+        c6β           = other.c6β;
+        qmPolar       = other.qmPolar;
         isSpherical   = other.isSpherical;
         useIterations = other.useIterations;
     }
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicMercator.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicMercator.java
new file mode 100644
index 0000000000..2f331d44e2
--- /dev/null
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AuthalicMercator.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.operation.projection;
+
+import org.opengis.referencing.operation.Matrix;
+import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.referencing.operation.matrix.Matrix2;
+
+import static java.lang.Math.*;
+import static org.apache.sis.math.MathFunctions.atanh;
+
+
+/**
+ * Spherical Mercator projection after conversion of geodetic latitudes to 
authalic latitudes.
+ * This is used for implementation of ESRI "Mercator Auxiliary Sphere type 3" 
projection.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.2
+ * @since   1.2
+ * @module
+ */
+final class AuthalicMercator extends AuthalicConversion {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = -3546152970105798436L;
+
+    /**
+     * The type value for this map projection in ESRI <cite>Auxiliary sphere 
type</cite> parameter.
+     */
+    static final int TYPE = 3;
+
+    /**
+     * Creates a new normalized projection from the parameters computed by the 
given initializer.
+     *
+     * @param other  the other projection from which to compute parameters.
+     */
+    AuthalicMercator(final Mercator other) {
+        super(null, other);
+    }
+
+    /**
+     * Converts the specified (λ,φ) coordinate (units in radians) and stores 
the result in {@code dstPts}
+     * (linear distance on a unit sphere). In addition, opportunistically 
computes the projection derivative
+     * if {@code derivate} is {@code true}.
+     *
+     * @return the matrix of the projection derivative at the given source 
position,
+     *         or {@code null} if the {@code derivate} argument is {@code 
false}.
+     */
+    @Override
+    public Matrix transform(final double[] srcPts, final int srcOff,
+                            final double[] dstPts, final int dstOff,
+                            final boolean derivate)
+    {
+        final double φ = srcPts[srcOff+1];
+        final double sinβ = sinβ(sin(φ));
+        if (dstPts != null) {
+            dstPts[dstOff  ] = srcPts[srcOff];
+            dstPts[dstOff+1] = atanh(sinβ);
+        }
+        return derivate ? new Matrix2(1, 0, 0, 1/sqrt(1 - sinβ*sinβ)) : null;
+    }
+
+    /**
+     * Converts a list of coordinate points. This method performs the same 
calculation than above
+     * {@link #transform(double[], int, double[], int, boolean)} method, but 
is overridden for efficiency.
+     *
+     * @throws TransformException if a point can not be converted.
+     */
+    @Override
+    public void transform(final double[] srcPts, int srcOff,
+                          final double[] dstPts, int dstOff, int numPts)
+            throws TransformException
+    {
+        if (srcPts != dstPts || srcOff != dstOff) {
+            super.transform(srcPts, srcOff, dstPts, dstOff, numPts);
+        } else {
+            dstOff--;
+            while (--numPts >= 0) {
+                final double φ = dstPts[dstOff += DIMENSION];       // Same as 
srcPts[srcOff + 1].
+                dstPts[dstOff] = atanh(sinβ(sin(φ)));
+            }
+        }
+    }
+
+    /**
+     * Converts the specified (<var>x</var>,<var>y</var>) coordinates
+     * and stores the result in {@code dstPts} (angles in radians).
+     *
+     * @throws ProjectionException if the point can not be converted.
+     */
+    @Override
+    protected void inverseTransform(final double[] srcPts, final int srcOff,
+                                    final double[] dstPts, final int dstOff)
+            throws ProjectionException
+    {
+        final double y = srcPts[srcOff+1];          // Must be before writing 
x.
+        dstPts[dstOff  ] = srcPts[srcOff];          // Must be before writing 
y.
+        dstPts[dstOff+1] = φ(tanh(y));
+    }
+}
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AzimuthalEquidistant.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AzimuthalEquidistant.java
index e698d8c489..ba8c3e8185 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AzimuthalEquidistant.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/AzimuthalEquidistant.java
@@ -119,7 +119,7 @@ public class AzimuthalEquidistant extends 
NormalizedProjection {
      * @param initializer  the initializer for computing map projection 
internal parameters.
      */
     AzimuthalEquidistant(final Initializer initializer) {
-        super(initializer);
+        super(initializer, null);
         final double φ0 = 
toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
         cosφ0 = cos(φ0);
         sinφ0 = sin(φ0);
@@ -129,7 +129,7 @@ public class AzimuthalEquidistant extends 
NormalizedProjection {
      * Creates a new projection initialized to the same parameters than the 
given one.
      */
     AzimuthalEquidistant(final AzimuthalEquidistant other) {
-        super(other);
+        super(null, other);
         cosφ0 = other.cosφ0;
         sinφ0 = other.sinφ0;
     }
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
index 997c5c5ea8..857a9a350b 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ConformalProjection.java
@@ -111,7 +111,7 @@ abstract class ConformalProjection extends 
NormalizedProjection {
      * @param  initializer  the initializer for computing map projection 
internal parameters.
      */
     ConformalProjection(final Initializer initializer) {
-        super(initializer);
+        super(initializer, null);
         useIterations = (eccentricity >= ECCENTRICITY_THRESHOLD);
         final double e2 = eccentricitySquared;
         final double e4 = e2 * e2;
@@ -154,7 +154,7 @@ abstract class ConformalProjection extends 
NormalizedProjection {
      * instance without recomputing them.
      */
     ConformalProjection(final ConformalProjection other) {
-        super(other);
+        super(null, other);
         useIterations = other.useIterations;
         c2χ = other.c2χ;
         c4χ = other.c4χ;
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
index 24c2877a3c..0b1eca0c72 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
@@ -158,7 +158,7 @@ public class CylindricalEqualArea extends 
AuthalicConversion {
      */
     @Workaround(library="JDK", version="1.7")
     private CylindricalEqualArea(final Initializer initializer) {
-        super(initializer);
+        super(initializer, null);
         variant = (Variant) initializer.variant;
         final MatrixSIS denormalize = 
context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
         /*
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
index 8374e24989..58cff5ecbc 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertAzimuthalEqualArea.java
@@ -103,7 +103,7 @@ public class LambertAzimuthalEqualArea extends 
AuthalicConversion {
      */
     @Workaround(library="JDK", version="1.7")
     private LambertAzimuthalEqualArea(final Initializer initializer) {
-        super(initializer);
+        super(initializer, null);
         final double φ0    = 
toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
         final double sinφ0 = sin(φ0);
         final double cosφ0 = cos(φ0);
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
index 1ff60359eb..c22a8bd162 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
@@ -315,14 +315,7 @@ public class Mercator extends ConformalProjection {
                     throw new 
IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2,
                             
MercatorAuxiliarySphere.AUXILIARY_SPHERE_TYPE.getName().getCode(), type));
                 }
-                case 3: {
-                    throw new IllegalArgumentException("Type 3 not yet 
supported.");
-                    /*
-                     * For supporting this case, we need to convert geodetic 
latitude (φ) to authalic latitude (β)
-                     * using for example the formulas for Lambert Azimuthal 
Equal Area. We could set a flag telling
-                     * that we need to instantiate a subclass. Then we 
fall-through case 2 below.
-                     */
-                }
+                case AuthalicMercator.TYPE:
                 case 2: ratio = new DoubleDouble(Formulas.getAuthalicRadius(1, 
initializer.axisLengthRatio().value)); break;
                 case 1: ratio = initializer.axisLengthRatio(); break;
                 case 0: break;      // Same as "Popular Visualisation Pseudo 
Mercator".
@@ -382,8 +375,15 @@ public class Mercator extends ConformalProjection {
      */
     @Override
     public MathTransform createMapProjection(final MathTransformFactory 
factory) throws FactoryException {
-        Mercator kernel = this;
-        if ((variant.spherical || eccentricity == 0) && getClass() == 
Mercator.class) {
+        NormalizedProjection kernel = this;
+subst:  if ((variant.spherical || eccentricity == 0) && getClass() == 
Mercator.class) {
+            if (variant == Variant.AUXILIARY && eccentricity != 0) {
+                final int type = 
context.getValue(MercatorAuxiliarySphere.AUXILIARY_SPHERE_TYPE);
+                if (type == AuthalicMercator.TYPE) {
+                    kernel = new AuthalicMercator(this);
+                    break subst;
+                }
+            }
             kernel = new Spherical(this);
         }
         return context.completeTransform(factory, kernel);
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
index 6e369d8774..ea36ec94ce 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/MeridianArcBased.java
@@ -64,7 +64,7 @@ abstract class MeridianArcBased extends NormalizedProjection {
      * Creates a new normalized projection from the parameters computed by the 
given initializer.
      */
     MeridianArcBased(final Initializer initializer) {
-        super(initializer);
+        super(initializer, null);
         final double e2  = eccentricitySquared;
         final double e4  = e2*e2;
         final double e6  = e2*e4;
@@ -152,7 +152,7 @@ abstract class MeridianArcBased extends 
NormalizedProjection {
      * Creates a new projection initialized to the same parameters than the 
given one.
      */
     MeridianArcBased(final MeridianArcBased other) {
-        super(other);
+        super(null, other);
         cf0 = other.cf0;
         cf1 = other.cf1;
         cf2 = other.cf2;
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java
index 9e8d7b2108..f9c4d7534d 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mollweide.java
@@ -110,7 +110,7 @@ public class Mollweide extends NormalizedProjection {
      * @param parameters  the parameter values of the projection to create.
      */
     public Mollweide(final OperationMethod method, final Parameters 
parameters) {
-        super(initializer(method, parameters));
+        super(initializer(method, parameters), null);
         final MatrixSIS normalize   = 
context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION);
         final MatrixSIS denormalize = 
context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
         normalize  .convertAfter (0, 2*SQRT_2, null);
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
index e56e70dbbd..2fc5829ec5 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
@@ -421,32 +421,37 @@ public abstract class NormalizedProjection extends 
AbstractMathTransform2D imple
     protected NormalizedProjection(final OperationMethod method, final 
Parameters parameters,
             final Map<ParameterRole, ? extends ParameterDescriptor<? extends 
Number>> roles)
     {
-        this(new Initializer(method, parameters, roles, null));
+        this(new Initializer(method, parameters, roles, null), null);
     }
 
     /**
-     * Creates a new normalized projection from the parameters computed by the 
given initializer.
+     * Creates a new normalized projection from the parameters computed by the 
given initializer,
+     * or from the parameters already computed by another projection.
+     * Exactly one of {@code initializer} or {@code other} shall be non-null.
      *
-     * @param initializer  the initializer for computing map projection 
internal parameters.
-     */
-    NormalizedProjection(final Initializer initializer) {
-        context             = initializer.context;
-        eccentricitySquared = initializer.eccentricitySquared.doubleValue();
-        eccentricity        = sqrt(eccentricitySquared);    // 
DoubleDouble.sqrt() does not make any difference here.
-        inverse             = new Inverse(this);
-    }
-
-    /**
-     * Creates a new projection initialized to the values of the given one. 
This constructor may be invoked after
-     * we determined that the default implementation can be replaced by an 
other one, for example using spherical
-     * formulas instead of the ellipsoidal ones. This constructor allows to 
transfer all parameters to the new
-     * instance without recomputing them.
+     * The {@code other} argument may be used after we determined that the 
default implementation can
+     * be replaced by another one, for example using spherical formulas 
instead of the ellipsoidal ones.
+     * This constructor allows to transfer all parameters to the new instance 
without recomputing them.
+     *
+     * <h4>Design note</h4>
+     * We do not define two separated constructors because doing so can force 
some subclasses
+     * to duplicate non-trivial calculations in the two constructors.
+     *
+     * @param initializer  the initializer for computing map projection 
internal parameters, or {@code null}.
+     * @param other        the other projection from which to compute 
parameters, or {@code null}.
      */
-    NormalizedProjection(final NormalizedProjection other) {
-        context             = other.context;
-        eccentricity        = other.eccentricity;
-        eccentricitySquared = other.eccentricitySquared;
-        inverse             = new Inverse(this);
+    NormalizedProjection(final Initializer initializer, final 
NormalizedProjection other) {
+        if (initializer != null) {
+            context             = initializer.context;
+            eccentricitySquared = 
initializer.eccentricitySquared.doubleValue();
+            eccentricity        = sqrt(eccentricitySquared);
+            // Use of DoubleDouble.sqrt() does not make any difference here.
+        } else {
+            context             = other.context;
+            eccentricity        = other.eccentricity;
+            eccentricitySquared = other.eccentricitySquared;
+        }
+        inverse = new Inverse(this);
     }
 
     /**
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
index 4796e00475..615bad75ba 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
@@ -137,7 +137,7 @@ public class ObliqueStereographic extends 
NormalizedProjection {
      * ("Relax constraint on placement of this()/super() call in 
constructors").
      */
     private ObliqueStereographic(final Initializer initializer) {
-        super(initializer);
+        super(initializer, null);
         final double φ0     = 
toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
         final double sinφ0  = sin(φ0);
         final double ℯsinφ0 = eccentricity * sinφ0;
@@ -191,7 +191,7 @@ public class ObliqueStereographic extends 
NormalizedProjection {
      * Creates a new projection initialized to the same parameters than the 
given one.
      */
     ObliqueStereographic(final ObliqueStereographic other) {
-        super(other);
+        super(null, other);
         χ0      = other.χ0;
         sinχ0   = other.sinχ0;
         cosχ0   = other.cosχ0;
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Orthographic.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Orthographic.java
index 4dbb366589..70979ec728 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Orthographic.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Orthographic.java
@@ -101,7 +101,7 @@ public class Orthographic extends NormalizedProjection {
      */
     @Workaround(library="JDK", version="1.8")
     private Orthographic(final Initializer initializer) {
-        super(initializer);
+        super(initializer, null);
         final double φ0 = 
toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
         sinφ0 = sin(φ0);
         cosφ0 = cos(φ0);
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/SatelliteTracking.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/SatelliteTracking.java
index 1a1b122053..7bab551abb 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/SatelliteTracking.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/SatelliteTracking.java
@@ -135,7 +135,7 @@ public class SatelliteTracking extends NormalizedProjection 
{
      * ("Relax constraint on placement of this()/super() call in 
constructors").
      */
     private SatelliteTracking(final Initializer initializer) {
-        super(initializer);
+        super(initializer, null);
         final double φ0 = 
toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
         final double φ1 = 
toRadians(initializer.getAndStore(STANDARD_PARALLEL_1));
         final double φ2 = 
toRadians(initializer.getAndStore(STANDARD_PARALLEL_2));
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
index dfb7fc647b..478cc86683 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
@@ -221,7 +221,7 @@ public class TransverseMercator extends 
NormalizedProjection {
      * This constructor is used also by {@link ZonedGridSystem}.
      */
     TransverseMercator(final Initializer initializer) {
-        super(initializer);
+        super(initializer, null);
         final double φ0 = 
toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
         /*
          * Opportunistically use double-double arithmetic for computation of B 
since we will store
@@ -337,7 +337,7 @@ public class TransverseMercator extends 
NormalizedProjection {
      * Creates a new projection initialized to the same parameters than the 
given one.
      */
     TransverseMercator(final TransverseMercator other) {
-        super(other);
+        super(null, other);
         cf2 = other.cf2;
         cf4 = other.cf4;
         cf6 = other.cf6;
diff --git 
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
 
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
index 4e0452a798..aa93ec41fd 100644
--- 
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
+++ 
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
@@ -267,9 +267,31 @@ public final strictfp class MercatorTest extends 
MapProjectionTestCase {
         createGeoApiTest(new MillerCylindrical()).testMiller();
     }
 
+    /**
+     * Tests the <cite>"Mercator Auxiliary Sphere"</cite> case with type 3.
+     * This type mandate conversion between geodetic latitude and authalic 
latitude.
+     * The values used in this test are close to <cite>"Mercator 
(Spherical)"</cite> (EPSG:1026) case.
+     *
+     * @throws FactoryException if an error occurred while creating the map 
projection.
+     * @throws TransformException if an error occurred while projecting a 
coordinate.
+     */
+    @Test
+    @DependsOnMethod("testMercatorSpherical")
+    public void testAuthalicLatitudeConversion() throws FactoryException, 
TransformException {
+        final double[] source = {-100.33333333333333, 24.381786944444446};
+        final double[] target = {
+            -11156569.90  -      0.31,      // Expected value from spherical 
test − empirical correction.
+              2796869.94  -  11759.14
+        };
+        createAuxiliarySphereProjection(AuthalicMercator.TYPE);
+        tolerance = Formulas.LINEAR_TOLERANCE;
+        verifyTransform(source, target);
+    }
+
     /**
      * Tests the <cite>"Mercator Auxiliary Sphere"</cite> case.
      * For the sphere type 0, which is the default, this is equivalent to 
pseudo-Mercator.
+     * This simple test measures the length of an arc of 1 radian at equator.
      *
      * @throws FactoryException if an error occurred while creating the map 
projection.
      * @throws TransformException if an error occurred while projecting a 
coordinate.
@@ -277,26 +299,38 @@ public final strictfp class MercatorTest extends 
MapProjectionTestCase {
     @Test
     @DependsOnMethod("testPseudoMercator")
     public void testMercatorAuxiliarySphere() throws FactoryException, 
TransformException {
-        final MercatorAuxiliarySphere provider = new MercatorAuxiliarySphere();
         tolerance = Formulas.LINEAR_TOLERANCE;
-        for (int type = 0; type <= 2; type++) {
-            final Parameters values = 
Parameters.castOrWrap(provider.getParameters().createValue());
-            values.parameter(Constants.SEMI_MAJOR).setValue(WGS84_A);
-            values.parameter(Constants.SEMI_MINOR).setValue(WGS84_B);
-            values.parameter("Auxiliary_Sphere_Type").setValue(type);
-            transform = new 
MathTransformFactoryMock(provider).createParameterizedTransform(values);
-            validate();
+        for (int type = 0; type <= AuthalicMercator.TYPE; type++) {
+            createAuxiliarySphereProjection(type);
             final double expected;
             switch (type) {
                 case 0: expected = WGS84_A;    break;   // 6378137
                 case 1: expected = WGS84_B;    break;   // 6356752.31
                 case 2: expected = 6371007.18; break;   // Authalic radius
+                case 3: expected = 6371007.18; break;
                 default: throw new AssertionError(type);
             }
             verifyTransform(new double[] {180/Math.PI, 0, 0, 0}, new double[] 
{expected, 0, 0, 0});
         }
     }
 
+    /**
+     * Creates an ESRI  <cite>"Mercator Auxiliary Sphere"</cite> projection.
+     * The axis lengths are those of WGS 84, which result in an authalic 
radius of about 6371007 meters.
+     *
+     * @param  type  the <cite>"Auxiliary sphere type"</cite> parameter value.
+     * @throws FactoryException if an error occurred while creating the map 
projection.
+     */
+    private void createAuxiliarySphereProjection(final int type) throws 
FactoryException {
+        final MercatorAuxiliarySphere provider = new MercatorAuxiliarySphere();
+        final Parameters values = 
Parameters.castOrWrap(provider.getParameters().createValue());
+        values.parameter(Constants.SEMI_MAJOR).setValue(WGS84_A);
+        values.parameter(Constants.SEMI_MINOR).setValue(WGS84_B);
+        values.parameter("Auxiliary_Sphere_Type").setValue(type);
+        transform = new 
MathTransformFactoryMock(provider).createParameterizedTransform(values);
+        validate();
+    }
+
     /**
      * Performs the same tests than {@link #testSpecialLatitudes()} and {@link 
#testDerivative()},
      * but using spherical formulas.
diff --git 
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ProjectionResultComparator.java
 
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ProjectionResultComparator.java
index cfd768497f..c971cfc1c5 100644
--- 
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ProjectionResultComparator.java
+++ 
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ProjectionResultComparator.java
@@ -82,7 +82,7 @@ final strictfp class ProjectionResultComparator extends 
NormalizedProjection {
      * Creates a projection which will compare the results of the two given 
projections.
      */
     ProjectionResultComparator(final NormalizedProjection reference, final 
NormalizedProjection tested) {
-        super(reference);
+        super(null, reference);
         this.reference = reference;
         this.tested    = tested;
     }

Reply via email to