sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Some map projections need explicit wraparound when the difference between given longitude and central meridian is greater than 180°. This commit applies the fix on Albers Equal Area.
Date Sat, 21 Dec 2019 13:54:21 GMT
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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 6fc05b4  Some map projections need explicit wraparound when the difference between
given longitude and central meridian is greater than 180°. This commit applies the fix on
Albers Equal Area.
6fc05b4 is described below

commit 6fc05b4b03985a74e776403608974b6564027be8
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sat Dec 21 14:51:17 2019 +0100

    Some map projections need explicit wraparound when the difference between given longitude
and central meridian is greater than 180°.
    This commit applies the fix on Albers Equal Area.
    
    https://issues.apache.org/jira/browse/SIS-486
---
 .../operation/projection/AlbersEqualArea.java      | 25 ++++++++---
 .../operation/projection/AlbersEqualAreaTest.java  | 51 +++++++++++++++++++++-
 .../org/apache/sis/internal/util/DoubleDouble.java | 11 ++++-
 .../apache/sis/internal/util/DoubleDoubleTest.java |  9 ++--
 4 files changed, 84 insertions(+), 12 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 fe17827..7b90adb 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
@@ -50,7 +50,7 @@ import static org.apache.sis.internal.referencing.provider.AlbersEqualArea.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Rémi Maréchal (Geomatys)
- * @version 0.8
+ * @version 1.1
  * @since   0.8
  * @module
  */
@@ -82,6 +82,14 @@ public class AlbersEqualArea extends EqualAreaProjection {
     final double C;
 
     /**
+     * The valid range of θ = n⋅λ values, which is [−n⋅π … n⋅π]. We need to
ensure that θ values
+     * are inside that range before to use it in trigonometric functions.
+     *
+     * <a href="https://issues.apache.org/jira/browse/SIS-486">SIS-486</a>
+     */
+    final double rangeOfθ;
+
+    /**
      * Creates an Albers Equal Area projection from the given parameters.
      *
      * @param method      description of the projection parameters.
@@ -163,7 +171,9 @@ public class AlbersEqualArea extends EqualAreaProjection {
         final MatrixSIS denormalize = context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION);
         denormalize.convertBefore(0, rn, null); rn.negate();
         denormalize.convertBefore(1, rn, ρ0);   rn.inverseDivide(-1);
-        normalize.convertAfter(0, rn, null);
+        normalize.convertAfter(0, rn, null);    // On this line, `rn` became `n`.
+        rn.multiply(DoubleDouble.createPi());
+        rangeOfθ = rn.doubleValue();
     }
 
     /**
@@ -171,8 +181,9 @@ public class AlbersEqualArea extends EqualAreaProjection {
      */
     AlbersEqualArea(final AlbersEqualArea other) {
         super(other);
-        nm = other.nm;
-        C  = other.C;
+        nm       = other.nm;
+        C        = other.C;
+        rangeOfθ = other.rangeOfθ;
     }
 
     /**
@@ -227,7 +238,8 @@ public class AlbersEqualArea extends EqualAreaProjection {
                             final double[] dstPts, final int dstOff,
                             final boolean derivate) throws ProjectionException
     {
-        final double θ = srcPts[srcOff  ];      // θ = n⋅λ
+        // θ = n⋅λ  reduced to  [−n⋅π … n⋅π]  range.
+        final double θ = IEEEremainder(srcPts[srcOff], rangeOfθ);
         final double φ = srcPts[srcOff+1];
         final double cosθ = cos(θ);
         final double sinθ = sin(θ);
@@ -315,7 +327,8 @@ public class AlbersEqualArea extends EqualAreaProjection {
                                 final double[] dstPts, final int dstOff,
                                 final boolean derivate)
         {
-            final double θ = srcPts[srcOff];                // θ = n⋅λ
+            // θ = n⋅λ  reduced to  [−n⋅π … n⋅π]  range.
+            final double θ = IEEEremainder(srcPts[srcOff], rangeOfθ);
             final double φ = srcPts[srcOff+1];
             final double cosθ = cos(θ);
             final double sinθ = sin(θ);
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java
index f29d1fa..a60e290 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/AlbersEqualAreaTest.java
@@ -24,6 +24,7 @@ import static java.lang.StrictMath.*;
 import static java.lang.Double.NaN;
 
 // Test dependencies
+
 import org.opengis.test.ToleranceModifier;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
@@ -40,7 +41,7 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Rémi Maréchal (Geomatys)
- * @version 0.8
+ * @version 1.1
  * @since   0.8
  * @module
  */
@@ -254,4 +255,52 @@ public final strictfp class AlbersEqualAreaTest extends MapProjectionTestCase
{
                        new int[]    {  5,  5},                  // Number of points to test
                        TestUtilities.createRandomNumberGenerator());
     }
+
+    /**
+     * Tests the projection of point where the difference between the given longitude value
and central meridian
+     * is close to 360°. In most map other map projection implementations, we rely on range
reductions performed
+     * automatically by trigonometric functions. However we can not rely on that effect in
the particular case of
+     * {@link AlbersEqualArea} because the longitude is pre-multiplied by a <var>n</var>
factor before to be used
+     * in trigonometric functions. The range reduction must be performed explicitly in map
projection code.
+     *
+     * <p>The math transform tested here is:</p>
+     * {@preformat wkt
+     *   Param_MT["Albers Equal Area",
+     *     Parameter["semi_major", 6378206.4, Unit["metre"]],
+     *     Parameter["semi_minor", 6356583.8, Unit["metre"]],
+     *     Parameter["Latitude of false origin", 50, Unit["degree"]],
+     *     Parameter["Longitude of false origin", -154, Unit["degree"]],
+     *     Parameter["Latitude of 1st standard parallel", 55, Unit["degree"]],
+     *     Parameter["Latitude of 2nd standard parallel", 65, Unit["degree"]]]
+     * }
+     *
+     * @throws FactoryException if an error occurred while creating the map projection.
+     * @throws TransformException if an error occurred while projecting a point.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-486">SIS-486</a>
+     */
+    @Test
+    public void testLongitudeWraparound() throws FactoryException, TransformException {
+        createCompleteProjection(new org.apache.sis.internal.referencing.provider.AlbersEqualArea(),
+                6378206.4,  // Semi-major axis length
+                6356583.8,  // Semi-minor axis length
+                -154,       // Central meridian
+                50,         // Latitude of origin
+                55,         // Standard parallel 1
+                65,         // Standard parallel 2
+                NaN,        // Scale factor (none)
+                NaN,        // False easting (none)
+                NaN);       // False northing (none)
+
+        tolerance = Formulas.LINEAR_TOLERANCE;
+        toleranceModifier = ToleranceModifier.PROJECTION;
+        /*
+         * Skip inverse transform because the 176.003° become -183.997°. It is not the
purpose
+         * of this test to verify longitude wraparound in inverse projection (we do not expect
+         * such wraparound to be applied).
+         */
+        isInverseTransformSupported = false;
+        verifyTransform(new double[] {176.00296518775082, 52.00158201757688},
+                        new double[] {-2000419.117, 680784.426});
+    }
 }
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
b/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
index 65498a5..0aa5324 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
@@ -56,7 +56,7 @@ import org.apache.sis.math.DecimalFunctions;
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
  *
  * @see <a href="http://en.wikipedia.org/wiki/Double-double_%28arithmetic%29#Double-double_arithmetic">Wikipedia:
Double-double arithmetic</a>
  *
@@ -309,6 +309,15 @@ public final class DoubleDouble extends Number {
     }
 
     /**
+     * Returns a new {@code DoubleDouble} instance initialized to the PI value.
+     *
+     * @return an instance initialized to the 3.14159265358979323846264338327950 value.
+     */
+    public static DoubleDouble createPi() {
+        return new DoubleDouble(3.14159265358979323846264338327950, 1.2246467991473532E-16);
+    }
+
+    /**
      * Returns a new {@code DoubleDouble} instance initialized to the conversion factor
      * from radians to angular degrees.
      *
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/util/DoubleDoubleTest.java
b/core/sis-utility/src/test/java/org/apache/sis/internal/util/DoubleDoubleTest.java
index 0401fc8..c08fc24 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/util/DoubleDoubleTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/internal/util/DoubleDoubleTest.java
@@ -37,7 +37,7 @@ import static java.lang.StrictMath.*;
  * Those tests need {@link DoubleDouble#DISABLED} to be set to {@code false}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
  * @since   0.4
  * @module
  */
@@ -444,9 +444,10 @@ public final strictfp class DoubleDoubleTest extends TestCase {
         for (int i=0; ; i++) {
             final DoubleDouble dd;
             switch (i) {
-                case 0:  dd = DoubleDouble.createRadiansToDegrees(); break;
-                case 1:  dd = DoubleDouble.createDegreesToRadians(); break;
-                case 2:  dd = DoubleDouble.createSecondsToRadians(); break;
+                case 0:  dd = DoubleDouble.createPi();               break;
+                case 1:  dd = DoubleDouble.createRadiansToDegrees(); break;
+                case 2:  dd = DoubleDouble.createDegreesToRadians(); break;
+                case 3:  dd = DoubleDouble.createSecondsToRadians(); break;
                 default: return;                                             // Test done.
             }
             assertEquals(DoubleDouble.errorForWellKnownValue(dd.value), dd.error, STRICT);


Mime
View raw message