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; }