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 <[email protected]>
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);