sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rmarec...@apache.org
Subject svn commit: r1709049 - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
Date Fri, 16 Oct 2015 16:13:35 GMT
Author: rmarechal
Date: Fri Oct 16 16:13:34 2015
New Revision: 1709049

URL: http://svn.apache.org/viewvc?rev=1709049&view=rev
Log:
Projection : Add ObliqueStereographic spherical case and relative tests

Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java?rev=1709049&r1=1709048&r2=1709049&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
[UTF-8] Fri Oct 16 16:13:34 2015
@@ -59,10 +59,15 @@ public class ObliqueStereographic extend
     private static final long serialVersionUID = -1454098847621943639L;
 
     /**
+     * Maximum difference allowed when comparing real numbers.
+     */
+    static final double EPSILON = 1E-6;
+
+    /**
      * Conformal latitude of origin only use
      * into {@link #inverseTransform(double[], int, double[], int) }.
      */
-    private final double χ0;
+    protected final double χ0;
 
     /**
      * Value of sin(χ0) only use
@@ -70,7 +75,7 @@ public class ObliqueStereographic extend
      *
      * @see #χ0
      */
-    private final double sinχ0;
+    protected final double sinχ0;
 
     /**
      * Value of cos(χ0) only use
@@ -78,7 +83,7 @@ public class ObliqueStereographic extend
      *
      * @see #χ0
      */
-    private final double cosχ0;
+    protected final double cosχ0;
 
     /**
      * c, internaly parameter used to define conformal sphere, used
@@ -226,7 +231,7 @@ public class ObliqueStereographic extend
     public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException
{
         ObliqueStereographic kernel = this;
         if (excentricity == 0) {
-//            kernel = new Spherical(this);     // not implemented yet
+            kernel = new Spherical(this);     // not implemented yet
         }
         return context.completeTransform(factory, kernel);
     }
@@ -279,6 +284,10 @@ public class ObliqueStereographic extend
         final double cosχcosχ0 = cosχ * cosχ0;
         final double cosχsinλ  = cosχ * sinλ;
 
+        /*
+         * Moreover to convert conformal sphere coordinates into projection destination space,
+         * we retrieve same formula into spherical transformation case.
+         */
         final double B = 1 + sinχsinχ0 + cosχcosχ0 * cosλ;
 
         final double y = (sinχ * cosχ0 - cosχ * sinχ0 * cosλ) / B;
@@ -371,4 +380,95 @@ public class ObliqueStereographic extend
         }
         throw new ProjectionException(Errors.Keys.NoConvergence);
     }
+
+    /**
+     * Provides the transform equations for the spherical case of the Oblique Stereographic
projection.
+     * In other words means {@link #excentricity} = 0.
+     *
+     * @author  Rémi Maréchal (Geomatys)
+     * @author  Martin Desruisseaux (Geomatys)
+     * @since   0.6
+     * @version 0.7
+     * @module
+     */
+    static final class Spherical extends ObliqueStereographic {
+        /**
+         * Constructs a new map projection from the supplied parameters.
+         *
+         * @param parameters The parameters of the projection to be created.
+         */
+        protected Spherical(ObliqueStereographic other) {
+            super(other);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Matrix transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff,
boolean derivate) throws ProjectionException {
+            final double φ = srcPts[srcOff + 1];
+            final double λ = srcPts[srcOff];
+
+            final double sinφ      = sin(φ);
+            final double cosφ      = cos(φ);
+            final double cosλ      = cos(λ);
+            final double sinλ      = sin(λ);
+            final double sinφsinχ0 = sinφ * sinχ0;
+            final double cosφcosχ0 = cosφ * cosχ0;
+            final double cosφsinλ  = cosφ * sinλ;
+
+            final double B = 1 + sinφsinχ0 + cosφcosχ0 * cosλ;
+
+            final double y = (sinφ * cosχ0 - cosφ * sinχ0 * cosλ) / B;
+            final double x =  cosφsinλ / B;
+
+            if (dstPts != null) {
+                dstPts[dstOff  ] = x;
+                dstPts[dstOff+1] = y;
+            }
+
+            if (!derivate) {
+                return null;
+            }
+
+            final double B2 = B * B;
+
+            //-- Jacobian coefficients
+            final double dx_dλ =   cosφ * (cosλ * (1 + sinφsinχ0) + cosφcosχ0) / B2;
+
+            final double dx_dφ = - sinλ * (sinφ + sinχ0) / B2;
+
+            final double dy_dλ =   cosφsinλ * (sinχ0 + sinφ) / B2;
+
+            final double dy_dφ =  (cosφcosχ0 + cosλ * (sinφsinχ0 + 1)) / B2;
+
+            return new Matrix2(dx_dλ, dx_dφ,
+                               dy_dλ, dy_dφ);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        protected void inverseTransform(double[] srcPts, int srcOff, double[] dstPts, int
dstOff) throws ProjectionException {
+            final double x = srcPts[srcOff  ];
+            final double y = srcPts[srcOff+1];
+            final double ρ = hypot(x, y);
+            double λ, φ;
+            if (abs(ρ) < EPSILON) {
+                φ = χ0;
+                λ = 0.0;
+            } else {
+                final double c    = 2 * atan(ρ);
+                final double cosc = cos(c);
+                final double sinc = sin(c);
+                final double ct   = ρ * cosχ0 * cosc - y * sinχ0 * sinc;
+                final double t    = x * sinc;
+                φ = asin(cosc * sinχ0 + y * sinc * cosχ0 / ρ);
+                λ = atan2(t, ct);
+            }
+            dstPts[dstOff]   = λ;
+            dstPts[dstOff+1] = φ;
+        }
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java?rev=1709049&r1=1709048&r2=1709049&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
[UTF-8] Fri Oct 16 16:13:34 2015
@@ -30,6 +30,10 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import static java.lang.Math.sqrt;
+import static java.lang.StrictMath.toRadians;
+import org.apache.sis.referencing.operation.matrix.Matrix2;
+import org.apache.sis.test.DependsOnMethod;
+import org.opengis.referencing.operation.Matrix;
 
 
 /**
@@ -43,6 +47,12 @@ import static java.lang.Math.sqrt;
  */
 public final strictfp class ObliqueStereographicTest extends MapProjectionTestCase {
     /**
+     * Tolerance used to compare spherical and oblique formula
+     * into same parameters context.
+     */
+    private final static double EPSG_SPHERICAL_TOLERANCE = 1E-15;
+
+    /**
      * Parameter values provided by the <a href = http://www.iogp.org/pubs/373-07-2.pdf>EPSG
guide</a>
      * for testing {@link ObliqueStereographic} transform conformity.
      *
@@ -65,30 +75,62 @@ public final strictfp class ObliqueStere
                                 R        = 6382644.571 / a;
 
     /**
-     * Tested {@link MathTransform} projection.
+     * Tested {@link ObliqueStereographic} projection.
+     */
+    private final ObliqueStereographic obliqueStereographic;
+
+    /**
+     * {@link ObliqueStereographic} projection define into spherical particularity case.
+     * Used to compute the expected transform, invert transform and derivative values
+     * when the projection is spherical.
      */
-    private final NormalizedProjection ObliqueStereographic;
+    private final ObliqueStereographic obliqueReference;
+
+    /**
+     * Tested {@link ObliqueStereographic} projection into spherical particularity case.
+     */
+    private final ObliqueStereographic.Spherical sphericalObliqueStereographic;
 
     /**
      * Buid tested {@link ObliqueStereographic} {@link MathTransform}.
      */
     public ObliqueStereographicTest() {
+
+        //-- oblique EPSG case
         final OperationMethod op = new org.apache.sis.internal.referencing.provider.ObliqueStereographic();
 
-        final ParameterValueGroup p = op.getParameters().createValue();
+        final ParameterValueGroup obliqueParameters = op.getParameters().createValue();
+
+        //-- implicit names from OGC.
+        obliqueParameters.parameter("semi_major").setValue(6377397.155);
+        obliqueParameters.parameter("inverse_flattening").setValue(299.15281);
+
+        //-- Name parameters from Epsg registry
+        obliqueParameters.parameter("Latitude of natural origin").setValue(52.156160556);
+        obliqueParameters.parameter("Longitude of natural origin").setValue(5.387638889);
+        obliqueParameters.parameter("Scale factor at natural origin").setValue(0.9999079);
+        obliqueParameters.parameter("False easting").setValue(155000.00);
+        obliqueParameters.parameter("False northing").setValue(463000.00);
+
+        obliqueStereographic = new ObliqueStereographic(op, (Parameters) obliqueParameters);
+
+
+        //-- spherical case
+        final ParameterValueGroup sphericalParameters = op.getParameters().createValue();
 
         //-- implicit names from OGC.
-        p.parameter("semi_major").setValue(6377397.155);
-        p.parameter("inverse_flattening").setValue(299.15281);
+        sphericalParameters.parameter("semi_major").setValue(6377397.155);
+        sphericalParameters.parameter("semi_minor").setValue(6377397.155);
 
         //-- Name parameters from Epsg registry
-        p.parameter("Latitude of natural origin").setValue(52.156160556);
-        p.parameter("Longitude of natural origin").setValue(5.387638889);
-        p.parameter("Scale factor at natural origin").setValue(0.9999079);
-        p.parameter("False easting").setValue(155000.00);
-        p.parameter("False northing").setValue(463000.00);
+        sphericalParameters.parameter("Latitude of natural origin").setValue(52.156160556);
+        sphericalParameters.parameter("Longitude of natural origin").setValue(5.387638889);
+        sphericalParameters.parameter("Scale factor at natural origin").setValue(0.9999079);
+        sphericalParameters.parameter("False easting").setValue(155000.00);
+        sphericalParameters.parameter("False northing").setValue(463000.00);
 
-        ObliqueStereographic = new ObliqueStereographic(op, (Parameters) p);
+        obliqueReference              = new ObliqueStereographic(op, (Parameters) sphericalParameters);
+        sphericalObliqueStereographic = new ObliqueStereographic.Spherical(obliqueReference);
     }
 
     /**
@@ -110,7 +152,7 @@ public final strictfp class ObliqueStere
 
         srcPts[0] = srcPts[0] * n;
 
-        ObliqueStereographic.transform(srcPts, 0, dstPts, 0, 1);
+        obliqueStereographic.transform(srcPts, 0, dstPts, 0, 1);
 
         final double destE = dstPts[0] * k0 * a * 2 * R + FE;
         final double destN = dstPts[1] * k0 * a * 2 * R + FN;
@@ -146,7 +188,7 @@ public final strictfp class ObliqueStere
         final double[] srcPts = new double[]{srcEast, srcNorth}; //-- meter
 
         final double[] dstPts = new double[2];
-        ObliqueStereographic.inverseTransform(srcPts, 0, dstPts, 0);
+        obliqueStereographic.inverseTransform(srcPts, 0, dstPts, 0);
 
         final double λO = 0.094032038;
 
@@ -170,7 +212,129 @@ public final strictfp class ObliqueStere
      * @see org.opengis.test.referencing.ParameterizedTransformTest#testObliqueStereographic()
      */
     @Test
-    public void testGeoapi() throws FactoryException, TransformException {
+    public void testObliqueStereographic() throws FactoryException, TransformException {
         createGeoApiTest(new org.apache.sis.internal.referencing.provider.ObliqueStereographic()).testObliqueStereographic();
     }
+
+    /**
+     * Verifies the consistency of elliptical formulas with the spherical formulas.
+     * This test compares the results between elliptical and spherical transform formulas
+     * from the particularity case stipulated into EPSG guide.
+     *
+     * @see ObliqueStereographic.Spherical#transform(double[], int, double[], int, boolean)
+     * with boolean setted to {@code false}
+     * @throws TransformException if an error occurred while projecting a coordinate.
+     */
+    @Test
+    @DependsOnMethod("testObliqueStereographic")
+    public void EPSGEllipticalWithSphericalTransform() throws TransformException {
+
+        final double[] srcPts = new double[]{6, 53}; //-- deg
+        srcPts[0] = Math.toRadians(srcPts[0] - 5.387638889) ;
+        srcPts[1] = Math.toRadians(srcPts[1]);
+
+        final double[] dstPts = new double[2];
+
+        srcPts[0] = srcPts[0] * n;
+
+        obliqueReference.transform(srcPts, 0, dstPts, 0, 1);
+
+        final double destE = dstPts[0] * k0 * a * 2 * R + FE;
+        final double destN = dstPts[1] * k0 * a * 2 * R + FN;
+
+        sphericalObliqueStereographic.transform(srcPts, 0, dstPts, 0, 1);
+
+        final double destSphereE = dstPts[0] * k0 * a * 2 * R + FE;
+        final double destSphereN = dstPts[1] * k0 * a * 2 * R + FN;
+
+        Assert.assertEquals("destination East coordinate",  destE, destSphereE, EPSG_SPHERICAL_TOLERANCE);
+        Assert.assertEquals("destination North coordinate", destN, destSphereN, EPSG_SPHERICAL_TOLERANCE);
+    }
+
+    /**
+     * Verifies the consistency of elliptical formulas with the spherical formulas.
+     * This test compares the results between elliptical and spherical invert transform formulas
+     * from the particularity case stipulated into EPSG guide.
+     *
+     * @see ObliqueStereographic.Spherical#inverseTransform(double[], int, double[], int)
+     * @throws ProjectionException if an error occurred while invert transformation computing.
+     */
+    @Test
+    @DependsOnMethod("testObliqueStereographic")
+    public void EPSGEllipticalWithSphericalInvertTransform() throws ProjectionException {
+        double srcEast  = 196105.28;
+        double srcNorth = 557057.74;
+
+        srcEast  -= FE;
+        srcNorth -= FN;
+        srcEast  /= k0;
+        srcNorth /= k0;
+        srcEast  /= a;
+        srcNorth /= a;
+        srcEast  /= (2 * R);
+        srcNorth /= (2 * R);
+
+        //-- tcheck transform
+        final double[] srcProjPts = new double[]{srcEast, srcNorth}; //-- meter
+
+        final double[] dstPts = new double[2];
+
+        obliqueReference.inverseTransform(srcProjPts, 0, dstPts, 0);
+
+        final double destλ = dstPts[0];
+        final double destφ = dstPts[1];
+
+        sphericalObliqueStereographic.inverseTransform(srcProjPts, 0, dstPts, 0);
+
+        final double destSphereλ = dstPts[0];
+        final double destSphereφ = dstPts[1];
+
+        Assert.assertEquals("destination East coordinate",  destλ, destSphereλ, EPSG_SPHERICAL_TOLERANCE);
+        Assert.assertEquals("destination North coordinate", destφ, destSphereφ, EPSG_SPHERICAL_TOLERANCE);
+    }
+
+    /**
+     * Verifies the consistency of elliptical formulas with the spherical formulas.
+     * This test compares the results between elliptical and spherical derivative formulas
+     * from the particularity case stipulated into EPSG guide.
+     *
+     * @see ObliqueStereographic.Spherical#transform(double[], int, double[], int, boolean)
+     * with boolean setted to {@code true}
+     * @throws ProjectionException if an error occurred while derivative computing.
+     */
+    @Test
+    @DependsOnMethod("testObliqueStereographic")
+    public void EPSGEllipticalWithSphericalDerivative() throws ProjectionException {
+
+        final Matrix2 derivativeTolerance = new Matrix2(EPSG_SPHERICAL_TOLERANCE, EPSG_SPHERICAL_TOLERANCE,
+                                                                                   EPSG_SPHERICAL_TOLERANCE,
EPSG_SPHERICAL_TOLERANCE);
+        final double[] srcPts = new double[]{6, 53}; //-- deg
+        srcPts[0] = Math.toRadians(srcPts[0] - 5.387638889) ;
+        srcPts[1] = Math.toRadians(srcPts[1]);
+
+        srcPts[0] = srcPts[0] * n;
+
+        //-- Derivative
+        final Matrix expectedDerivative = obliqueReference.transform(srcPts, 0, null, 0,
true);
+        final Matrix testedDerivative   = sphericalObliqueStereographic.transform(srcPts,
0, null, 0, true);
+
+        assertMatrixEquals("derivative spherical", expectedDerivative, testedDerivative,
derivativeTolerance);
+    }
+
+    /**
+     * Creates a projection and derivates a few points.
+     *
+     * @throws TransformException Should never happen.
+     */
+    @Test
+    public void testSphericalDerivative() throws TransformException {
+        transform = obliqueStereographic;
+        tolerance = 1E-9;
+
+        final double delta = toRadians(100.0 / 60) / 1852; // Approximatively 100 metres.
+        derivativeDeltas = new double[] {delta, delta};
+        verifyDerivative(toRadians( 0), toRadians( 0));
+        verifyDerivative(toRadians(-3), toRadians(30));
+        verifyDerivative(toRadians(+6), toRadians(60));
+    }
 }



Mime
View raw message