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 8c761eb Apply the wrapparound longitude on other map projections that
may be affected by this problem. A bug fix in previous commit has also be
corrected: missing a factor 2 in θ_span calculation.
8c761eb is described below
commit 8c761eb6834a637d15a0e4ec840d0ee2a0476146
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Dec 21 17:02:06 2019 +0100
Apply the wrapparound longitude on other map projections that may be
affected by this problem.
A bug fix in previous commit has also be corrected: missing a factor 2 in
θ_span calculation.
This commit complete https://issues.apache.org/jira/browse/SIS-486
---
.../operation/projection/AlbersEqualArea.java | 31 +++++++++----------
.../operation/projection/Initializer.java | 25 +++++++++++++++
.../projection/LambertConicConformal.java | 28 +++++++++++------
.../operation/projection/ObliqueStereographic.java | 36 ++++++++++++++--------
.../operation/projection/SatelliteTracking.java | 13 +++++++-
.../projection/LambertConicConformalTest.java | 9 ++++--
.../org/apache/sis/internal/util/DoubleDouble.java | 8 ++---
.../java/org/apache/sis/measure/Longitude.java | 6 ++--
.../apache/sis/internal/util/DoubleDoubleTest.java | 2 +-
9 files changed, 109 insertions(+), 49 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 7b90adb..88476ee 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
@@ -58,7 +58,7 @@ public class AlbersEqualArea extends EqualAreaProjection {
/**
* For cross-version compatibility.
*/
- private static final long serialVersionUID = -3024658742514888646L;
+ private static final long serialVersionUID = -3466040922402982480L;
/**
* Internal coefficients for computation, depending only on eccentricity
and values of standards parallels.
@@ -82,12 +82,12 @@ 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.
+ * Size of the [−n⋅π … n⋅π] range, which is the valid range of θ = n⋅λ
values.
+ * 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>
+ * @see Initializer#spanOfScaledLongitude(DoubleDouble)
*/
- final double rangeOfθ;
+ final double θ_span;
/**
* Creates an Albers Equal Area projection from the given parameters.
@@ -172,8 +172,7 @@ public class AlbersEqualArea extends EqualAreaProjection {
denormalize.convertBefore(0, rn, null); rn.negate();
denormalize.convertBefore(1, rn, ρ0); rn.inverseDivide(-1);
normalize.convertAfter(0, rn, null); // On this line, `rn` became
`n`.
- rn.multiply(DoubleDouble.createPi());
- rangeOfθ = rn.doubleValue();
+ θ_span = Initializer.spanOfScaledLongitude(rn);
}
/**
@@ -181,9 +180,9 @@ public class AlbersEqualArea extends EqualAreaProjection {
*/
AlbersEqualArea(final AlbersEqualArea other) {
super(other);
- nm = other.nm;
- C = other.C;
- rangeOfθ = other.rangeOfθ;
+ nm = other.nm;
+ C = other.C;
+ θ_span = other.θ_span;
}
/**
@@ -239,8 +238,8 @@ public class AlbersEqualArea extends EqualAreaProjection {
final boolean derivate) throws ProjectionException
{
// θ = n⋅λ reduced to [−n⋅π … n⋅π] range.
- final double θ = IEEEremainder(srcPts[srcOff], rangeOfθ);
- final double φ = srcPts[srcOff+1];
+ final double θ = IEEEremainder(srcPts[srcOff], θ_span);
+ final double φ = srcPts[srcOff + 1];
final double cosθ = cos(θ);
final double sinθ = sin(θ);
final double sinφ = sin(φ);
@@ -300,7 +299,7 @@ public class AlbersEqualArea extends EqualAreaProjection {
*
* @author Martin Desruisseaux (Geomatys)
* @author Rémi Maréchal (Geomatys)
- * @version 0.8
+ * @version 1.1
* @since 0.8
* @module
*/
@@ -308,7 +307,7 @@ public class AlbersEqualArea extends EqualAreaProjection {
/**
* For cross-version compatibility.
*/
- private static final long serialVersionUID = 9090765015127854096L;
+ private static final long serialVersionUID = -7238296545347764989L;
/**
* Constructs a new map projection from the parameters of the given
projection.
@@ -328,8 +327,8 @@ public class AlbersEqualArea extends EqualAreaProjection {
final boolean derivate)
{
// θ = n⋅λ reduced to [−n⋅π … n⋅π] range.
- final double θ = IEEEremainder(srcPts[srcOff], rangeOfθ);
- final double φ = srcPts[srcOff+1];
+ final double θ = IEEEremainder(srcPts[srcOff], θ_span);
+ final double φ = srcPts[srcOff + 1];
final double cosθ = cos(θ);
final double sinθ = sin(θ);
final double sinφ = sin(φ);
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
index 804d082..9e88f90 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
@@ -379,4 +379,29 @@ final class Initializer {
s.inverseDivide(cosφ);
return s.doubleValue();
}
+
+ /**
+ * Returns the size of the [−n⋅π … n⋅π] range, which is the valid range of
θ = n⋅λ values.
+ * This method is invoked by map projections that multiply the longitude
values by some scale factor before
+ * to use them in trigonometric functions. Usually we do not explicitly
wraparound the longitude values,
+ * because trigonometric functions do that automatically for us. However
if the longitude is multiplied
+ * by some factor before to be used in trigonometric functions, them that
implicit wraparound is not the
+ * one we expect. The map projection code needs to perform explicit
wraparound in such cases.
+ * Example:
+ *
+ * {@preformat java
+ * double spanθ = spanOfScaledLongitude(n); // Should be computed
only once.
+ * double θ = Math.IEEEremainder(λn, spanθ); // λ without n is
typically unknown.
+ * }
+ *
+ * @param n the factor by which longitude values are multiplied before
use in trigonometry.
+ * @return size of the [−n⋅π … n⋅π] range, for use in {@link
Math#IEEEremainder(double, double)}.
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/SIS-486">SIS-486</a>
+ */
+ static double spanOfScaledLongitude(final DoubleDouble n) {
+ final DoubleDouble r = DoubleDouble.createTwicePi();
+ r.multiply(n);
+ return abs(r.doubleValue());
+ }
}
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
index 090f0da..961eea2 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
@@ -60,7 +60,7 @@ import static org.apache.sis.math.MathFunctions.isPositive;
* @author André Gosselin (MPO)
* @author Rueben Schulz (UBC)
* @author Rémi Maréchal (Geomatys)
- * @version 0.8
+ * @version 1.1
* @since 0.6
* @module
*/
@@ -68,7 +68,7 @@ public class LambertConicConformal extends
ConformalProjection {
/**
* For cross-version compatibility.
*/
- private static final long serialVersionUID = 2067358524298002016L;
+ private static final long serialVersionUID = -8971522854919443706L;
/**
* Codes for variants of Lambert Conical Conformal projection. Those
variants modify the way the projections are
@@ -141,6 +141,14 @@ public class LambertConicConformal extends
ConformalProjection {
final double n;
/**
+ * Size of the [−n⋅π … n⋅π] range, which is the valid range of θ = n⋅λ
values.
+ * We need to ensure that θ values are inside that range before to use it
in trigonometric functions.
+ *
+ * @see Initializer#spanOfScaledLongitude(DoubleDouble)
+ */
+ final double θ_span;
+
+ /**
* Creates a Lambert projection from the given parameters.
* The {@code method} argument can be the description of one of the
following:
*
@@ -339,6 +347,7 @@ public class LambertConicConformal extends
ConformalProjection {
normalize .convertAfter(1, sφ, null);
denormalize.convertBefore(0, F, null); F.negate();
denormalize.convertBefore(1, F, rF);
+ θ_span = Initializer.spanOfScaledLongitude(sλ);
}
/**
@@ -346,7 +355,8 @@ public class LambertConicConformal extends
ConformalProjection {
*/
LambertConicConformal(final LambertConicConformal other) {
super(other);
- n = other.n;
+ n = other.n;
+ θ_span = other.θ_span;
}
/**
@@ -406,8 +416,8 @@ public class LambertConicConformal extends
ConformalProjection {
* the first non-linear one moved to the "normalize" affine transform,
and the linear operations
* applied after the last non-linear one moved to the "denormalize"
affine transform.
*/
- final double θ = srcPts[srcOff ]; // θ = λ⋅n (ignoring
longitude of origin)
- final double φ = srcPts[srcOff+1]; // Sign may be reversed
+ final double θ = IEEEremainder(srcPts[srcOff], θ_span); // θ =
λ⋅n (ignoring longitude of origin)
+ final double φ = srcPts[srcOff + 1]; //
Sign may be reversed
final double absφ = abs(φ);
final double sinθ = sin(θ);
final double cosθ = cos(θ);
@@ -490,7 +500,7 @@ public class LambertConicConformal extends
ConformalProjection {
* @author Martin Desruisseaux (MPO, IRD, Geomatys)
* @author André Gosselin (MPO)
* @author Rueben Schulz (UBC)
- * @version 0.6
+ * @version 1.1
* @since 0.6
* @module
*/
@@ -498,7 +508,7 @@ public class LambertConicConformal extends
ConformalProjection {
/**
* For cross-version compatibility.
*/
- private static final long serialVersionUID = -7005092237343502956L;
+ private static final long serialVersionUID = -8077690516096472987L;
/**
* Constructs a new map projection from the parameters of the given
projection.
@@ -517,8 +527,8 @@ public class LambertConicConformal extends
ConformalProjection {
final double[] dstPts, final int dstOff,
final boolean derivate)
{
- final double θ = srcPts[srcOff ]; // θ = λ⋅n
- final double φ = srcPts[srcOff+1]; // Sign may be reversed
+ final double θ = IEEEremainder(srcPts[srcOff], θ_span); //
θ = λ⋅n (ignoring longitude of origin)
+ final double φ = srcPts[srcOff + 1]; //
Sign may be reversed
final double absφ = abs(φ);
final double sinθ = sin(θ);
final double cosθ = cos(θ);
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 e4828f8..be81ee1 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
@@ -61,7 +61,7 @@ import static
org.apache.sis.internal.referencing.provider.ObliqueStereographic.
*
* @author Rémi Maréchal (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.1
* @since 0.7
* @module
*/
@@ -69,7 +69,7 @@ public class ObliqueStereographic extends
NormalizedProjection {
/**
* For cross-version compatibility.
*/
- private static final long serialVersionUID = -1454098847621943639L;
+ private static final long serialVersionUID = -1725537881127730658L;
/**
* Conformal latitude of origin (χ₀), together with its sine and cosine.
@@ -90,7 +90,15 @@ public class ObliqueStereographic extends
NormalizedProjection {
* More precisely <var>g</var> and <var>h</var> are used to compute
intermediate parameters <var>i</var>
* and <var>j</var>, which are themselves used to compute conformal
latitude and longitude.
*/
- final double g, h;
+ private final double g, h;
+
+ /**
+ * Size of the [−n⋅π … n⋅π] range, which is the valid range of Λ = n⋅λ
values.
+ * We need to ensure that Λ values are inside that range before to use it
in trigonometric functions.
+ *
+ * @see Initializer#spanOfScaledLongitude(DoubleDouble)
+ */
+ private final double θ_span;
/**
* Creates an Oblique Stereographic projection from the given parameters.
@@ -173,6 +181,7 @@ public class ObliqueStereographic extends
NormalizedProjection {
final double R2 = 2 * initializer.radiusOfConformalSphere(sinφ0);
denormalize.convertBefore(0, R2, null);
denormalize.convertBefore(1, R2, null);
+ θ_span = n * (2*PI);
}
/**
@@ -180,13 +189,14 @@ public class ObliqueStereographic extends
NormalizedProjection {
*/
ObliqueStereographic(final ObliqueStereographic other) {
super(other);
- χ0 = other.χ0;
- sinχ0 = other.sinχ0;
- cosχ0 = other.cosχ0;
- c = other.c;
- n = other.n;
- g = other.g;
- h = other.h;
+ χ0 = other.χ0;
+ sinχ0 = other.sinχ0;
+ cosχ0 = other.cosχ0;
+ c = other.c;
+ n = other.n;
+ g = other.g;
+ h = other.h;
+ θ_span = other.θ_span;
}
/**
@@ -256,8 +266,9 @@ public class ObliqueStereographic extends
NormalizedProjection {
final double[] dstPts, final int dstOff,
final boolean derivate) throws ProjectionException
{
- final double Λ = srcPts[srcOff ]; // Λ = λ⋅n (see below),
ignoring longitude of origin.
- final double φ = srcPts[srcOff+1];
+ // Λ = λ⋅n (see below), ignoring longitude of origin.
+ final double Λ = IEEEremainder(srcPts[srcOff], θ_span);
+ final double φ = srcPts[srcOff + 1];
final double sinφ = sin(φ);
final double ℯsinφ = eccentricity * sinφ;
final double Sa = (1 + sinφ) / (1 - sinφ);
@@ -407,6 +418,7 @@ public class ObliqueStereographic extends
NormalizedProjection {
final double[] dstPts, final int dstOff,
final boolean derivate)
{
+ // No need to enforce [−n⋅π … n⋅π] range here because n=1.
final double λ = srcPts[srcOff ];
final double φ = srcPts[srcOff+1];
/*
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 a941896..1b9d68b 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
@@ -69,7 +69,7 @@ public class SatelliteTracking extends NormalizedProjection {
/**
* For cross-version compatibility.
*/
- private static final long serialVersionUID = 859940667477896653L;
+ private static final long serialVersionUID = -209787336760184649L;
/**
* Sines and cosines of inclination between the plane of the Earth's
Equator and the plane
@@ -99,6 +99,14 @@ public class SatelliteTracking extends NormalizedProjection {
private final boolean isConic;
/**
+ * Size of the [−n⋅π … n⋅π] range, which is the valid range of θ = n⋅λ
values.
+ * We need to ensure that θ values are inside that range before to use it
in trigonometric functions.
+ *
+ * @see Initializer#spanOfScaledLongitude(DoubleDouble)
+ */
+ private final double θ_span;
+
+ /**
* Work around for RFE #4093999 in Sun's bug database ("Relax constraint on
* placement of this()/super() call in constructors").
*/
@@ -194,6 +202,7 @@ public class SatelliteTracking extends NormalizedProjection
{
normalize .convertAfter (0, n, null);
denormalize.convertBefore(0, +ρf, null);
denormalize.convertBefore(1, -ρf, ρ0);
+ θ_span = n * (2*PI);
} else {
/*
* Cylindrical projection case. The equations are (ignoring R and
λ₀):
@@ -205,6 +214,7 @@ public class SatelliteTracking extends NormalizedProjection
{
* The cosφ₁ (for x at dimension 0) and cosφ₁/F₁′ (for y at
dimension 1) factors are computed
* in advance and stored below. The remaining factor to compute in
transform(…) method is L.
*/
+ θ_span = 2*PI;
n = s0 = Double.NaN;
final double cotF = sqrt(cos2_φ1 - cos2_i) / (p2_on_p1*cos2_φ1 -
cos_i); // Cotangente of F₁.
denormalize.convertBefore(0, cosφ1, null);
@@ -298,6 +308,7 @@ public class SatelliteTracking extends NormalizedProjection
{
double x = srcPts[srcOff];
double y = λt - p2_on_p1 * λpm;
if (isConic) {
+ x = IEEEremainder(x, θ_span);
λpm = n*y + s0; // Use this variable for a new
purpose. Needed for derivative.
if ((Double.doubleToRawLongBits(λpm) ^
Double.doubleToRawLongBits(n)) < 0) {
/*
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
index 7ccb2c3..0edb4c7 100644
---
a/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
+++
b/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
@@ -48,7 +48,7 @@ import static org.apache.sis.test.Assert.*;
*
* @author Martin Desruisseaux (Geomatys)
* @author Rémi Maréchal (Geomatys)
- * @version 0.8
+ * @version 1.1
* @since 0.6
* @module
*/
@@ -357,9 +357,12 @@ public final strictfp class LambertConicConformalTest
extends MapProjectionTestC
@DependsOnMethod("testLambertConicConformal1SP")
public void testSerialization() throws FactoryException,
TransformException {
createNormalizedProjection(true, 40);
- final double[] source =
CoordinateDomain.GEOGRAPHIC_RADIANS_NORTH.generateRandomInput(TestUtilities.createRandomNumberGenerator(),
2, 10);
+ final double[] source = new double[] {
+ 70*PI/180, 27*PI/180,
+ 30*PI/180, 56*PI/180
+ };
final double[] target = new double[source.length];
- transform.transform(source, 0, target, 0, 10);
+ transform.transform(source, 0, target, 0, source.length / 2);
transform = assertSerializedEquals(transform);
tolerance = Formulas.LINEAR_TOLERANCE;
verifyTransform(source, target);
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 0aa5324..b5a9b02 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
@@ -309,12 +309,12 @@ public final class DoubleDouble extends Number {
}
/**
- * Returns a new {@code DoubleDouble} instance initialized to the PI value.
+ * Returns a new {@code DoubleDouble} instance initialized to the 2π value.
*
- * @return an instance initialized to the
3.14159265358979323846264338327950 value.
+ * @return an instance initialized to the
6.28318530717958647692528676655901 value.
*/
- public static DoubleDouble createPi() {
- return new DoubleDouble(3.14159265358979323846264338327950,
1.2246467991473532E-16);
+ public static DoubleDouble createTwicePi() {
+ return new DoubleDouble(6.28318530717958647692528676655901,
2.4492935982947064E-16);
}
/**
diff --git
a/core/sis-utility/src/main/java/org/apache/sis/measure/Longitude.java
b/core/sis-utility/src/main/java/org/apache/sis/measure/Longitude.java
index ec19f87..fe049be 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/Longitude.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/Longitude.java
@@ -127,9 +127,9 @@ public final class Longitude extends Angle {
}
/**
- * Returns the given longitude value normalized to the [{@linkplain
#MIN_VALUE -180} … {@linkplain #MAX_VALUE 180})°
- * range (upper value is exclusive). If the given value is outside the
longitude range, then this method adds or
- * subtracts a multiple of 360° in order to bring back the value to that
range.
+ * Returns the given longitude value normalized to the [{@value
#MIN_VALUE} … {@value #MAX_VALUE})°
+ * range (upper value is exclusive). If the given value is outside the
longitude range, then this
+ * method adds or subtracts a multiple of 360° in order to bring back the
value to that range.
*
* <p>Special cases:</p>
* <ul>
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 c08fc24..ebdf365 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
@@ -444,7 +444,7 @@ public final strictfp class DoubleDoubleTest extends
TestCase {
for (int i=0; ; i++) {
final DoubleDouble dd;
switch (i) {
- case 0: dd = DoubleDouble.createPi(); break;
+ case 0: dd = DoubleDouble.createTwicePi(); break;
case 1: dd = DoubleDouble.createRadiansToDegrees(); break;
case 2: dd = DoubleDouble.createDegreesToRadians(); break;
case 3: dd = DoubleDouble.createSecondsToRadians(); break;