sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1709462 - in /sis/branches/JDK7: ./ core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/
Date Mon, 19 Oct 2015 18:17:37 GMT
Author: desruisseaux
Date: Mon Oct 19 18:17:37 2015
New Revision: 1709462

URL: http://svn.apache.org/viewvc?rev=1709462&view=rev
Log:
Merge projection work from JDK8 branch.

Modified:
    sis/branches/JDK7/   (props changed)
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/InitializerTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolarStereographicTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/TransverseMercatorTest.java

Propchange: sis/branches/JDK7/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Oct 19 18:17:37 2015
@@ -1,4 +1,4 @@
 /sis/branches/Android:1430670-1480699
 /sis/branches/JDK6:1394913-1508480
-/sis/branches/JDK8:1584960-1709036
+/sis/branches/JDK8:1584960-1709461
 /sis/trunk:1394364-1508466,1519089-1519674

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Initializer.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -305,10 +305,9 @@ final class Initializer {
     }
 
     /**
-     * Returns the radius of the conformal sphere at a given latitude.
-     * The radius of conformal sphere is computed from ρ, which is the radius of curvature in
-     * the meridian at latitude φ, and ν which is the radius of curvature in the prime vertical,
-     * as below:
+     * Returns the radius of the conformal sphere (assuming a semi-major axis length of 1) at a given latitude.
+     * The radius of conformal sphere is computed from ρ, which is the radius of curvature in the meridian at
+     * latitude φ, and ν which is the radius of curvature in the prime vertical, as below:
      *
      * <blockquote>Rc = √(ρ⋅ν) = √(1 – ℯ²) / (1 – ℯ²sin²φ)</blockquote>
      *
@@ -321,9 +320,9 @@ final class Initializer {
      */
     final double radiusOfConformalSphere(final double sinφ) {
         final DoubleDouble Rc = verbatim(1);
-        Rc.subtract(excentricitySquared);   //-- 1 - ℯ²
-        Rc.sqrt();                          //-- √(1 - ℯ²)
-        Rc.divide(rν2(sinφ));               //-- √(1 - ℯ²) / (1 - ℯ²sin²φ)
+        Rc.subtract(excentricitySquared);       //  1 - ℯ²
+        Rc.sqrt();                              //  √(1 - ℯ²)
+        Rc.divide(rν2(sinφ));                   //  √(1 - ℯ²) / (1 - ℯ²sin²φ)
         return Rc.value;
     }
 

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -353,7 +353,7 @@ public class LambertConicConformal exten
      * comparing two {@code LambertConicConformal} projections or formatting them in debug mode.
      */
     @Override
-    String[] getInternalParameterNames() {
+    final String[] getInternalParameterNames() {
         return new String[] {"n"};
     }
 
@@ -362,7 +362,7 @@ public class LambertConicConformal exten
      * comparing two {@code LambertConicConformal} projections or formatting them in debug mode.
      */
     @Override
-    double[] getInternalParameterValues() {
+    final double[] getInternalParameterValues() {
         return new double[] {n};
     }
 
@@ -405,7 +405,7 @@ public class LambertConicConformal exten
          * 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
+        final double θ    = srcPts[srcOff  ];     // θ = λ⋅n  (ignoring longitude of origin)
         final double φ    = srcPts[srcOff+1];     // Sign may be reversed
         final double absφ = abs(φ);
         final double sinθ = sin(θ);
@@ -430,9 +430,9 @@ public class LambertConicConformal exten
         if (!derivate) {
             return null;
         }
-        //
-        // End of map projection. Now compute the derivative.
-        //
+        /*
+         * End of map projection. Now compute the derivative.
+         */
         final double dρ;
         if (sinφ != 1) {
             dρ = n * dy_dφ(sinφ, cos(φ)) * ρ;
@@ -444,7 +444,7 @@ public class LambertConicConformal exten
     }
 
     /**
-     * Transforms the specified (<var>x</var>,<var>y</var>) coordinates and stores the (θ,φ) result in {@code dstPts}.
+     * Converts the specified (<var>x</var>,<var>y</var>) coordinates and stores the (θ,φ) result in {@code dstPts}.
      *
      * @throws ProjectionException if the point can not be converted.
      */

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -404,7 +404,7 @@ public class Mercator extends ConformalP
     }
 
     /**
-     * Transforms the specified (<var>x</var>,<var>y</var>) coordinates
+     * 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.

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -23,7 +23,6 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.util.FactoryException;
-
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.util.Workaround;
 import org.apache.sis.referencing.operation.matrix.Matrix2;
@@ -36,19 +35,27 @@ import static org.apache.sis.internal.re
 
 /**
  * <cite>Oblique Stereographic</cite> projection (EPSG code 9809).
- * The formulas used below are from the EPSG guide.
+ * See the <a href="http://mathworld.wolfram.com/StereographicProjection.html">Stereographic projection
+ * on MathWorld</a> for an overview.
+ *
+ * <div class="section">Description</div>
+ * The directions starting from the central point are true, but the areas and the lengths become
+ * increasingly deformed as one moves away from the center. This projection is frequently used
+ * for mapping polar areas, but can also be used for other limited areas centered on a point.
  *
- * <div class="section">References</div>
- * <ul>
- *   <li>{@code libproj4} is available at
- *       <a href = http://www.iogp.org/pubs/373-07-2.pdf>EPSG guide</a>.<br>
- *        Relevant files are: {@code PJ_sterea.c}, {@code pj_gauss.c},
- *        {@code pj_fwd.c}, {@code pj_inv.c} and {@code lib_proj.h}</li>
- * </ul>
+ * <p>This projection involves two steps: first a conversion of <em>geodetic</em> coordinates to <em>conformal</em>
+ * coordinates (i.e. latitudes and longitudes on a conformal sphere), then a spherical stereographic projection.
+ * For this reason this projection method is sometime known as <cite>"Double Stereographic"</cite>.</p>
+ *
+ * <div class="note"><b>Note:</b>
+ * there is another method known as <cite>"Oblique Stereographic Alternative"</cite> or sometime just
+ * <cite>"Stereographic"</cite>. That alternative uses a simplified conversion computing the conformal latitude
+ * of each point on the ellipsoid. Both methods are considered valid but produce slightly different results.
+ * For this reason EPSG considers them as different projection methods.</div>
  *
  * @author  Rémi Maréchal (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @since   0.6
+ * @since   0.7
  * @version 0.7
  * @module
  */
@@ -59,68 +66,32 @@ public class ObliqueStereographic extend
     private static final long serialVersionUID = -1454098847621943639L;
 
     /**
-     * Conformal latitude of origin only use
-     * into {@link #inverseTransform(double[], int, double[], int) }.
+     * Conformal latitude of origin (χ₀), together with its sine and cosine.
+     * In the spherical case, χ₀ = φ₀ (the geodetic latitude of origin).
      */
-    private final double χ0;
+    final double χ0, sinχ0, cosχ0;
 
     /**
-     * Value of sin(χ0) only use
-     * into {@link #transform(double[], int, double[], int, boolean)  }.
-     *
-     * @see #χ0
+     * Parameters used in the conformal sphere definition. Those parameters are used in both the
+     * {@linkplain #transform(double[], int, double[], int, boolean) forward} and
+     * {@linkplain #inverseTransform(double[], int, double[], int) inverse} projection.
+     * If the user-supplied ellipsoid is already a sphere, then those parameters are equal to 1.
      */
-    private final double sinχ0;
+    private final double c, n;
 
     /**
-     * Value of cos(χ0) only use
-     * into {@link #transform(double[], int, double[], int, boolean)  }.
-     *
-     * @see #χ0
+     * Parameters used in the {@linkplain #inverseTransform(double[], int, double[], int) inverse} projection.
+     * 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.
      */
-    private final double cosχ0;
+    private final double g, h;
 
     /**
-     * c, internaly parameter used to define conformal sphere, used
-     * into {@link #transform(double[], int, double[], int, boolean)  }
-     * and {@link #inverseTransform(double[], int, double[], int) }.
-     */
-    private final double c;
-
-    /**
-     * n, internaly parameter used to define conformal sphere, used
-     * into {@link #transform(double[], int, double[], int, boolean)  }
-     * and {@link #inverseTransform(double[], int, double[], int) }.
-     */
-    private final double n;
-
-    /**
-     * g, internaly parameter used to define conformal sphere coordinate conversion,
-     * during {@link #inverseTransform(double[], int, double[], int) }.
-     * More precisely g is used to compute i and j parameters and i and j,
-     * are used to compute only conformal longitude.
-     */
-    private final double g;
-
-    /**
-     * h, internaly parameter used to define conformal sphere coordinate conversion,
-     * during {@link #inverseTransform(double[], int, double[], int) }.
-     * More precisely h is used to compute i and j parameters and i and j,
-     * are used to compute only conformal longitude.
-     */
-    private final double h;
-
-    /**
-     * A convenient computing for 1 - {@link #excentricitySquared}.
-     */
-    private final double eS1;
-
-    /**
-     * Creates a Oblique Stereographic projection from the given parameters.
+     * Creates an Oblique Stereographic projection from the given parameters.
      * The {@code method} argument can be the description of one of the following:
      *
      * <ul>
-     *   <li><cite>"Oblique Stereographic"</cite>.</li>
+     *   <li><cite>"Oblique Stereographic"</cite>, also known as <cite>"Roussilhe"</cite>.</li>
      * </ul>
      *
      * @param method     Description of the projection parameters.
@@ -150,47 +121,52 @@ public class ObliqueStereographic extend
      */
     private ObliqueStereographic(final Initializer initializer) {
         super(initializer);
-
-        eS1 = 1 - excentricitySquared;
-
-        final double φ0 = toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
-
+        final double φ0      = toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
+        final double sinφ0   = sin(φ0);
         final double cosφ0   = cos(φ0);
         final double cos4_φ0 = pow(cosφ0, 4);
-        n = sqrt((1 + ((excentricitySquared * cos4_φ0) / eS1)));
-
-        final double sinφ0  = sin(φ0);
-        final double esinφ0 = excentricity * sinφ0;
-
-        final double s1 = (1 +  sinφ0) / (1 -  sinφ0);
-        final double s2 = (1 - esinφ0) / (1 + esinφ0);
-        final double w1 = pow(s1 * pow(s2, excentricity), n);
-
+        final double ℯsinφ0  = excentricity * sinφ0;
+        n = sqrt(1 + ((excentricitySquared * cos4_φ0) / (1 - excentricitySquared)));
         /*
-         * Original formula : sinχ0 = ...
-         * To avoid confusion with χ0 conformal latitude of origin,
-         * renamed sinχ0 into sinχc.
+         * Following variables use upper-case because they are written that way in the EPSG guide.
+         */
+        final double S1 = (1 +  sinφ0) / (1 -  sinφ0);
+        final double S2 = (1 - ℯsinφ0) / (1 + ℯsinφ0);
+        final double w1 = pow(S1 * pow(S2, excentricity), n);
+        /*
+         * The χ₁ variable below was named χ₀ in the EPSG guide. We use the χ₁ name in order to avoid confusion with
+         * the conformal latitude of origin, which is also named χ₀ in the EPSG guide. Mathematically, χ₀ and χ₁ are
+         * computed in the same way except that χ₁ is computed with w₁ and χ₀ is computed with w₀.
+         */
+        final double sinχ1 = (w1 - 1) / (w1 + 1);
+        c = ((n + sinφ0) * (1 - sinχ1)) /
+            ((n - sinφ0) * (1 + sinχ1));
+        /*
+         * Convert the geodetic latitude of origin φ₀ to the conformal latitude of origin χ₀.
          */
-        final double sinχc = (w1 - 1) / (w1 + 1);
-        c = (n + sinφ0) * (1 - sinχc) / ((n - sinφ0) * (1 + sinχc));
-
-        //-- for invert formula
         final double w2 = c * w1;
-        χ0 = asin((w2 - 1) / (w2 + 1));
-
-        sinχ0 = sin(χ0);
+        sinχ0 = (w2 - 1) / (w2 + 1);
+        χ0    = asin(sinχ0);
         cosχ0 = cos(χ0);
-
-        final double R = initializer.radiusOfConformalSphere(sinφ0);
-
-        g = tan(PI / 4 - χ0 / 2);
-        h = 2 * tan(χ0) + g;
-
+        /*
+         * Following variables are used only by the inverse projection.
+         */
+        g = tan(PI/4 - χ0/2);
+        h = 2*tan(χ0) + g;
+        /*
+         * One of the first steps performed by the stereographic projection is to multiply the longitude by n.
+         * Since this is a linear operation, we can combine it with other linear operations performed by the
+         * normalization matrix.
+         */
         final MatrixSIS normalize   = context.getMatrix(true);
         final MatrixSIS denormalize = context.getMatrix(false);
         normalize.convertAfter(0, n, null);
-
-        final double R2 = 2 * R;
+        /*
+         * One of the last steps performed by the stereographic projection is to multiply the easting and northing
+         * by 2 times the radius of the conformal sphere. Since this is a linear operation, we combine it with other
+         * linear operations performed by the denormalization matrix.
+         */
+        final double R2 = 2 * initializer.radiusOfConformalSphere(sinφ0);
         denormalize.convertBefore(0, R2, null);
         denormalize.convertBefore(1, R2, null);
     }
@@ -207,7 +183,28 @@ public class ObliqueStereographic extend
         n     = other.n;
         g     = other.g;
         h     = other.h;
-        eS1   = other.eS1;
+    }
+
+    /**
+     * Returns the names of additional internal parameters which need to be taken in account when
+     * comparing two {@code ObliqueStereographic} projections or formatting them in debug mode.
+     *
+     * <p>We could report any of the internal parameters. But since they are all derived from φ₀ and
+     * the {@linkplain #excentricity excentricity} and since the excentricity is already reported by
+     * the super-class, we report only χ₀ is a representative of the internal parameters.</p>
+     */
+    @Override
+    final String[] getInternalParameterNames() {
+        return new String[] {"χ₀"};
+    }
+
+    /**
+     * Returns the values of additional internal parameters which need to be taken in account when
+     * comparing two {@code ObliqueStereographic} projections or formatting them in debug mode.
+     */
+    @Override
+    final double[] getInternalParameterValues() {
+        return new double[] {χ0};
     }
 
     /**
@@ -226,7 +223,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);
         }
         return context.completeTransform(factory, kernel);
     }
@@ -240,135 +237,196 @@ public class ObliqueStereographic extend
      * @throws ProjectionException if the coordinate can not be converted.
      */
     @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 esinφ     = excentricity * sinφ;
-        final double v1_sinφ   = 1 - sinφ;
-        final double v1esinφ   = 1 + esinφ;
-        final double Sa        = (1 + sinφ)  / v1_sinφ;
-        final double Sb        = (1 - esinφ) / v1esinφ;
-        final double sbpowex   = pow(Sb, excentricity);
-        final double sasbpowex = Sa * sbpowex;
-        final double w         = c * pow(sasbpowex, n);
-        final double w1        = w + 1;
-        final double w1_w1     = (w - 1) / w1;
+    public Matrix transform(final double[] srcPts, final int srcOff,
+                            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];
+        final double sinφ  = sin(φ);
+        final double ℯsinφ = excentricity * sinφ;
+        final double Sa    = (1 +  sinφ) / (1 -  sinφ);
+        final double Sb    = (1 - ℯsinφ) / (1 + ℯsinφ);
+        final double w     = c * pow(Sa * pow(Sb, excentricity), n);
         /*
-         * Sometimes to compute projection coordinates values, computing pass by a
-         * "conformal sphere" to approximate as better, destination projection coordinates.
+         * Convert the geodetic coordinates (φ,λ) to conformal coordinates (χ,Λ) before to apply the
+         * actual stereographic projection.  The geodetic and conformal coordinates will be the same
+         * if the ellipsoid is already a sphere.
          */
-        //-- latitude coordinate into conformal sphere space.
-        final double χ    = asin(w1_w1);
+        final double χ    = asin((w - 1) / (w + 1));
         final double cosχ = cos(χ);
         final double sinχ = sin(χ);
         /*
-         * Longitude coordinate into conformal sphere space is Λ = n(λ–ΛO)+ ΛO.
-         * But in our case, all of this linears computing are delegate into
-         * normalize matrix. See contructor for more precisions.
-         * We work directly with λ.
+         * The conformal longitude is  Λ = n⋅(λ - λ₀) + Λ₀  where λ is the geodetic longitude.
+         * But in Apache SIS implementation, the multiplication by  n  has been merged in the
+         * constructor with other linear operations performed by the "normalization" matrix.
+         * Consequently the value obtained at srcPts[srcOff] is already Λ - Λ₀, not λ - λ₀.
          */
-        final double cosλ = cos(λ);
-        final double sinλ = sin(λ);
+        final double cosΛ = cos(Λ);
+        final double sinΛ = sin(Λ);
         /*
-         * Now transform conformal sphere coordinates
-         * into projection destination space
+         * Now apply the stereographic projection on the conformal sphere using the (χ,Λ) coordinates.
+         * Note that the formulas below are the same than the formulas in the Spherical inner class.
+         * The only significant difference is that the spherical case does not contain all the above
+         * code which converted (φ,λ) into (χ,Λ).
          */
         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;
-
+        final double B = 1 + sinχsinχ0 + cosχcosχ0 * cosΛ;
         if (dstPts != null) {
-            dstPts[dstOff  ] = x;
-            dstPts[dstOff+1] = y;
+            dstPts[dstOff  ] = cosχ * sinΛ / B;                             // Easting (x)
+            dstPts[dstOff+1] = (sinχ * cosχ0 - cosχ * sinχ0 * cosΛ) / B;    // Northing (y)
         }
-
         if (!derivate) {
             return null;
         }
+        /*
+         * Now compute the derivative, if the user asked for it.
+         * Notes:
+         *
+         *     ∂Sa/∂λ = 0
+         *     ∂Sb/∂λ = 0
+         *      ∂w/∂λ = 0
+         *      ∂χ/∂λ = 0
+         *     ∂Sa/∂φ =  2⋅cosφ   / (1 -  sinφ)²
+         *     ∂Sb/∂φ = -2⋅ℯ⋅cosφ / (1 - ℯ⋅sinφ)²
+         *      ∂w/∂φ =  2⋅n⋅w⋅(1/cosφ - ℯ²⋅cosφ/(1 - ℯ²⋅sin²φ));
+         */
+        final double cosφ = cos(φ);
+        final double dχ_dφ = (1/cosφ - cosφ*excentricitySquared/(1 - ℯsinφ*ℯsinφ)) * 2*n*sqrt(w) / (w + 1);
 
-        final double cosφ   = cos(φ);
-        final double B2     = B * B;
-
-        //-- derivative code
-        //-- dSa_dλ = 0;
-        final double dSa_dφ = 2 * cosφ / (v1_sinφ * v1_sinφ);
-
-        //-- dSb_dλ = 0;
-        final double dSb_dφ = - 2 * excentricity * cosφ / (v1esinφ * v1esinφ);
-
-        //-- dsasbpowex_dλ = 0;
-        final double dsasbpowex_dφ = dSa_dφ * sbpowex + Sa * excentricity * dSb_dφ * pow(Sb, excentricity - 1);
-
-        //-- dw_dλ = 0;
-        final double dw_dφ = c * n * dsasbpowex_dφ * pow(sasbpowex, n - 1);
-
-        //-- dχ_dλ = 0;
-        final double dχ_dφ = dw_dφ / (w1 * sqrt(w));
-
-        final double addsinχsinχ0 = sinχ + sinχ0;
-
-        //-- Jacobian coefficients
-        final double dx_dλ = cosχ * (cosλ * (1 + sinχsinχ0) + cosχcosχ0) / B2;
-
-        final double dx_dφ = - dχ_dφ * sinλ * addsinχsinχ0 / B2;
-
-        final double dy_dλ = cosχsinλ * addsinχsinχ0 / B2;
-
-        final double dy_dφ = dχ_dφ * (cosχcosχ0 + cosλ * (sinχsinχ0 + 1)) / B2;
-
-        return new Matrix2(dx_dλ, dx_dφ,
-                           dy_dλ, dy_dφ);
+        final double B2 = B * B;
+        final double d = (cosχcosχ0 + cosΛ * (sinχsinχ0 + 1)) / B2;     // Matrix diagonal
+        final double t = sinΛ * (sinχ + sinχ0) / B2;                    // Matrix anti-diagonal
+        /*                   ┌              ┐
+         *                   │ ∂x/∂λ, ∂x/∂φ │
+         * Jacobian        = │              │
+         *    (Proj(λ,φ))    │ ∂y/∂λ, ∂y/∂φ │
+         *                   └              ┘
+         */
+        return new Matrix2(d*cosχ,  -t*dχ_dφ,
+                           t*cosχ,   d*dχ_dφ);
     }
 
     /**
-     * Transforms the specified (x, y) coordinates and stores the result in {@code dstPts} (angles in radians).
+     * 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(double[] srcPts, int srcOff, double[] dstPts, int dstOff) throws ProjectionException {
-        final double x = srcPts[srcOff];
-        final double y = srcPts[srcOff + 1];
-
+        final double x = srcPts[srcOff  ];
+        final double y = srcPts[srcOff+1];
         final double i = atan(x / (h + y));
         final double j = atan(x / (g - y)) - i;
         /*
-         * Longitude coordinate into conformal sphere space is Λ = j + 2 * i
-         * Where λ = Λ + Λ0, but Λ0 is added into normalize matrix which regroup all linears operations.
-         * Also in our particularity case Geodetic longitude λ is the same.
+         * The conformal longitude is  Λ = j + 2i + Λ₀.  In the particular case of stereographic projection,
+         * the geodetic longitude λ is equals to Λ. Furthermore in Apache SIS implementation, Λ₀ is added by
+         * the denormalization matrix and shall not be handled here. The only remaining part is λ = j + 2i.
          */
-        final double λ    = j + 2*i;
-
-        //-- latitude coordinate into conformal sphere space.
-        final double χ    = χ0 + 2*atan((y - x*tan(j/2)));
-        final double sinχ = sin(χ);
-
-        final double ψ = log((1 + sinχ) / (c * (1 - sinχ))) / (2 * n);
-
-        double φi_1 = 2*atan(exp(ψ)) - PI/2;
-
+        final double λ = j + 2*i;
+        /*
+         * Calculation of geodetic latitude φ involves first the calculation of conformal latitude χ,
+         * then calculation of isometric latitude ψ, and finally calculation of φ by an iterative method.
+         */
+        final double sinχ = sin(χ0 + 2*atan(y - x*tan(j/2)));
+        final double ψ = log((1 + sinχ) / ((1 - sinχ)*c)) / (2*n);
+        double φ = 2*atan(exp(ψ)) - PI/2;                               // First approximation
         for (int it = 0; it < MAXIMUM_ITERATIONS; it++) {
-            final double sinφi_1  = sin(φi_1);
-            final double esinφi_1 = excentricity*sinφi_1;
+            final double ℯsinφ = excentricity * sin(φ);
+            final double ψi = log(tan(φ/2 + PI/4) * pow((1 - ℯsinφ) / (1 + ℯsinφ), excentricity/2));
+            final double Δφ = (ψ - ψi) * cos(φ) * (1 - ℯsinφ*ℯsinφ) / (1 - excentricitySquared);
+            φ += Δφ;
+            if (abs(Δφ) <= ITERATION_TOLERANCE) {
+                dstPts[dstOff  ] = λ;
+                dstPts[dstOff+1] = φ;
+                return;
+            }
+        }
+        throw new ProjectionException(Errors.Keys.NoConvergence);
+    }
+
+    /**
+     * Provides the transform equations for the spherical case of the Oblique Stereographic projection.
+     * This implementation can be used when {@link #excentricity} = 0.
+     *
+     * @author  Rémi Maréchal (Geomatys)
+     * @author  Martin Desruisseaux (Geomatys)
+     * @since   0.7
+     * @version 0.7
+     * @module
+     */
+    static final class Spherical extends ObliqueStereographic {
+        /**
+         * For cross-version compatibility.
+         */
+        private static final long serialVersionUID = -1454098847621943639L;
 
-            double ψi_1 = log(tan(φi_1/2 + PI/4) * pow((1 - esinφi_1) / (1 + esinφi_1), excentricity / 2));
+        /**
+         * 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);
+        }
 
-            final double φi = φi_1 - (ψi_1 - ψ) * cos(φi_1) * (1 - esinφi_1 * esinφi_1) / eS1;
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public Matrix transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, boolean derivate) throws ProjectionException {
+            final double λ = srcPts[srcOff  ];
+            final double φ = srcPts[srcOff+1];
+            /*
+             * In the spherical case,  φ = χ  and  λ = Λ.
+             */
+            final double sinφ      = sin(φ);
+            final double cosφ      = cos(φ);
+            final double sinλ      = sin(λ);
+            final double cosλ      = cos(λ);
+            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λ;
+            if (dstPts != null) {
+                dstPts[dstOff  ] = cosφsinλ / B;
+                dstPts[dstOff+1] = (sinφ*cosχ0 - cosφ*sinχ0 *cosλ) / B;
+            }
+            if (!derivate) {
+                return null;
+            }
+            final double B2 = B * B;
+            final double d = (cosφcosφ0 + cosλ * (sinφsinφ0 + 1)) / B2;
+            final double t = sinλ * (sinφ + sinχ0) / B2;
+            return new Matrix2(d*cosφ, -t,
+                               t*cosφ,  d);
+        }
 
-            if (abs(φi - φi_1) <= ITERATION_TOLERANCE) {
-                dstPts[dstOff]     = λ;
-                dstPts[dstOff + 1] = φi;
-                return;
+        /**
+         * {@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);
+            final double λ, φ;
+            if (abs(ρ) < ANGULAR_TOLERANCE) {
+                φ = χ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);
             }
-            φi_1 = φi;
+            dstPts[dstOff]   = λ;
+            dstPts[dstOff+1] = φ;
         }
-        throw new ProjectionException(Errors.Keys.NoConvergence);
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -41,6 +41,13 @@ import static org.apache.sis.internal.ut
 
 /**
  * <cite>Polar Stereographic</cite> projection (EPSG codes 9810, 9829, 9830).
+ * This is a special case of {@link ObliqueStereographic} when the projection origin is at a pole.
+ *
+ * <p>EPSG defines three variants for this projection, <cite>A</cite>, <cite>B</cite> and <cite>C</cite>,
+ * which differ by the way the parameters are specified. The <cite>"Polar Stereographic (variant B)"</cite>
+ * projection includes a <cite>"Latitude of standard parallel"</cite> parameter where is effective the scale factor
+ * (normally 1). The <cite>"Polar Stereographic (variant A)"</cite> forces its <cite>"Latitude of natural origin"</cite>
+ * parameter to ±90°, depending on the hemisphere.</p>
  *
  * @author  Gerald Evenden (USGS)
  * @author  André Gosselin (MPO)
@@ -51,7 +58,6 @@ import static org.apache.sis.internal.ut
  * @version 0.6
  * @module
  *
- * @see EquatorialStereographic
  * @see ObliqueStereographic
  */
 public class PolarStereographic extends ConformalProjection {
@@ -316,7 +322,7 @@ public class PolarStereographic extends
     }
 
     /**
-     * Transforms the specified (x,y) coordinates and stores the result in {@code dstPts} (angles in radians).
+     * Converts the specified (x,y) coordinates and stores the result in {@code dstPts} (angles in radians).
      *
      * @throws ProjectionException if the point can not be converted.
      */

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/TransverseMercator.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -34,6 +34,7 @@ import org.apache.sis.util.Workaround;
 import static java.lang.Math.*;
 import static org.apache.sis.math.MathFunctions.asinh;
 import static org.apache.sis.math.MathFunctions.atanh;
+import static org.apache.sis.internal.referencing.provider.TransverseMercator.*;
 
 
 /**
@@ -115,10 +116,10 @@ public class TransverseMercator extends
             xOffset = ParameterRole.FALSE_WESTING;
             yOffset = ParameterRole.FALSE_SOUTHING;
         }
-        roles.put(ParameterRole.CENTRAL_MERIDIAN, org.apache.sis.internal.referencing.provider.TransverseMercator.LONGITUDE_OF_ORIGIN);
-        roles.put(ParameterRole.SCALE_FACTOR,     org.apache.sis.internal.referencing.provider.TransverseMercator.SCALE_FACTOR);
-        roles.put(xOffset,                        org.apache.sis.internal.referencing.provider.TransverseMercator.FALSE_EASTING);
-        roles.put(yOffset,                        org.apache.sis.internal.referencing.provider.TransverseMercator.FALSE_NORTHING);
+        roles.put(ParameterRole.CENTRAL_MERIDIAN, LONGITUDE_OF_ORIGIN);
+        roles.put(ParameterRole.SCALE_FACTOR, SCALE_FACTOR);
+        roles.put(xOffset, FALSE_EASTING);
+        roles.put(yOffset, FALSE_NORTHING);
         return new Initializer(method, parameters, roles, isSouth ? (byte) 1 : (byte) 0);
     }
 
@@ -129,8 +130,7 @@ public class TransverseMercator extends
     @Workaround(library="JDK", version="1.7")
     private TransverseMercator(final Initializer initializer) {
         super(initializer);
-        final double φ0 = toRadians(initializer.getAndStore(
-                org.apache.sis.internal.referencing.provider.TransverseMercator.LATITUDE_OF_ORIGIN));
+        final double φ0 = toRadians(initializer.getAndStore(LATITUDE_OF_ORIGIN));
         /*
          * Opportunistically use double-double arithmetic for computation of B since we will store
          * it in the denormalization matrix, and there is no sine/cosine functions involved here.
@@ -383,33 +383,30 @@ public class TransverseMercator extends
             sinh_8η0 = sinh_4η0 * cosh_4η0;             assert identityEquals(sinh_8η0, sinh(8*η0) / 8) : η0;
         }
         /*
-         * Assuming that (λ, φ) ↦ Proj((λ, φ))
-         * where Proj is defined by: Proj((λ, φ)) : (η(λ, φ), ξ(λ, φ)).
-         *
-         * => (λ, φ) ↦ (η(λ, φ), ξ(λ, φ)).
+         * The projection of (λ,φ) is given by (η⋅B, ξ⋅B+M₀) — ignoring scale factors and false easting/northing.
+         * But the B and M₀ parameters have been merged by the constructor with other linear operations in the
+         * "denormalization" matrix. Consequently we only need to compute (η,ξ) below.
          */
-        //-- ξ(λ, φ)
-        final double ξ = cf8 * sin_8ξ0 * cosh_8η0
-                       + cf6 * sin_6ξ0 * cosh_6η0
-                       + cf4 * sin_4ξ0 * cosh_4η0
-                       + cf2 * sin_2ξ0 * cosh_2η0
-                       + ξ0;
-
-        //-- η(λ, φ)
-        final double η = cf8 * cos_8ξ0 * sinh_8η0
-                       + cf6 * cos_6ξ0 * sinh_6η0
-                       + cf4 * cos_4ξ0 * sinh_4η0
-                       + cf2 * cos_2ξ0 * sinh_2η0
-                       + η0;
-
         if (dstPts != null) {
-            dstPts[dstOff  ] = η;
-            dstPts[dstOff+1] = ξ;
+            // η(λ,φ)
+            dstPts[dstOff  ] = cf8 * cos_8ξ0 * sinh_8η0
+                             + cf6 * cos_6ξ0 * sinh_6η0
+                             + cf4 * cos_4ξ0 * sinh_4η0
+                             + cf2 * cos_2ξ0 * sinh_2η0
+                             + η0;
+            // ξ(λ,φ)
+            dstPts[dstOff+1] = cf8 * sin_8ξ0 * cosh_8η0
+                             + cf6 * sin_6ξ0 * cosh_6η0
+                             + cf4 * sin_4ξ0 * cosh_4η0
+                             + cf2 * sin_2ξ0 * cosh_2η0
+                             + ξ0;
         }
         if (!derivate) {
             return null;
         }
-
+        /*
+         * Now compute the derivative, if the user asked for it.
+         */
         final double cosλ          = cos(λ);                                        //-- λ
         final double cosφ          = cos(φ);                                        //-- φ
         final double cosh2Q        = coshQ * coshQ;                                 //-- Q
@@ -428,14 +425,14 @@ public class TransverseMercator extends
         final double dξ0_dλ = sinhQ * sinhη0 * cosλ / (cosh2Q_sin2λ * sqrt1_thQchη0);
         final double dξ0_dφ = (dQ_dφ * coshη0 / cosh2Q + dη0_dφ * sinhη0 * tanhQ) / sqrt1_thQchη0;
         /*
-         * Assuming that Jac(Proj((λ, φ))) is the Jacobian matrix of Proj((λ, φ)) function.
+         * Jac(Proj(λ,φ)) is the Jacobian matrix of Proj(λ,φ) function.
+         * So the derivative of Proj(λ,φ) is defined by:
          *
-         * So the derivative of Proj((λ, φ)) is defined by:
-         *                    ┌                              ┐
-         *                    │ dη(λ, φ) / dλ, dη(λ, φ) / dφ │
-         * Jac              = │                              │
-         *    (Proj(λ, φ))    │ dξ(λ, φ) / dλ, dξ(λ, φ) / dφ │
-         *                    └                              ┘
+         *                   ┌                        ┐
+         *                   │ ∂η(λ,φ)/∂λ, ∂η(λ,φ)/∂φ │
+         * Jac             = │                        │
+         *    (Proj(λ,φ))    │ ∂ξ(λ,φ)/∂λ, ∂ξ(λ,φ)/∂φ │
+         *                   └                        ┘
          */
         //-- dξ(λ, φ) / dλ
         final double dξ_dλ = dξ0_dλ

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/InitializerTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/InitializerTest.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/InitializerTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/InitializerTest.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -17,19 +17,17 @@
 package org.apache.sis.referencing.operation.projection;
 
 import java.util.EnumMap;
-
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.operation.OperationMethod;
-
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.referencing.provider.ObliqueStereographic;
 import org.apache.sis.parameter.Parameters;
+import org.opengis.test.TestCase;
 import org.junit.Test;
 
-import static org.apache.sis.internal.referencing.provider.ObliqueStereographic.*;
+import static java.lang.StrictMath.*;
 import static org.opengis.test.Assert.*;
-import org.opengis.test.TestCase;
 
 
 /**
@@ -41,40 +39,52 @@ import org.opengis.test.TestCase;
  * @version 0.7
  * @module
  */
-public strictfp class InitializerTest extends TestCase{
+public final strictfp class InitializerTest extends TestCase{
     /**
      * Tests the {@link Initializer#radiusOfConformalSphere(double)} method.
-     * This test compute the Radius of conformal Sphere using the values given by the
-     * <a href = http://www.iogp.org/pubs/373-07-2.pdf>EPSG guide</a> for the Stereographic projection.
-     *
-     * @see Initializer#radiusOfConformalSphere(double)
+     * This test computes the Radius of Conformal Sphere using the values given
+     * by the <a href="http://www.iogp.org/pubs/373-07-2.pdf">EPSG guide</a> for
+     * the <cite>Amersfoort / RD New</cite> projection (a Stereographic one).
      */
     @Test
     public void testRadiusOfConformalSphere() {
-        final EnumMap<NormalizedProjection.ParameterRole, ParameterDescriptor<Double>> roles =
-                new EnumMap<>(NormalizedProjection.ParameterRole.class);
-        roles.put(NormalizedProjection.ParameterRole.CENTRAL_MERIDIAN, LONGITUDE_OF_ORIGIN);
-        roles.put(NormalizedProjection.ParameterRole.SCALE_FACTOR,     SCALE_FACTOR);
-        roles.put(NormalizedProjection.ParameterRole.FALSE_EASTING,    FALSE_EASTING);
-        roles.put(NormalizedProjection.ParameterRole.FALSE_NORTHING,   FALSE_NORTHING);
-
         final OperationMethod op = new ObliqueStereographic();
         final ParameterValueGroup p = op.getParameters().createValue();
-
-        //-- Implicit parameters (OGC names).
+        /*
+         * Following parameters are not given explicitely by EPSG definitions since they are
+         * usually inferred from the datum.  However in the particular case of this test, we
+         * need to provide them. The names used below are either OGC names or SIS extensions.
+         */
         p.parameter("semi_major").setValue(6377397.155);
         p.parameter("inverse_flattening").setValue(299.15281);
-
-        //-- Explicit parameters from EPSG registry
+        /*
+         * Following parameters are reproduced verbatim from EPSG registry and EPSG guide.
+         */
         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);
-
+        /*
+         * The following lines are a typical way to create an Initializer instance.
+         * The EnumMap tells to the Initializer constructor which parameters to look for.
+         * We construct this map here for testing purpose, but users normally do not have
+         * to do that since this map is provided by the ObliqueStereographic class itself.
+         */
+        final EnumMap<NormalizedProjection.ParameterRole, ParameterDescriptor<Double>> roles =
+                new EnumMap<>(NormalizedProjection.ParameterRole.class);
+        roles.put(NormalizedProjection.ParameterRole.CENTRAL_MERIDIAN, ObliqueStereographic.LONGITUDE_OF_ORIGIN);
+        roles.put(NormalizedProjection.ParameterRole.SCALE_FACTOR,     ObliqueStereographic.SCALE_FACTOR);
+        roles.put(NormalizedProjection.ParameterRole.FALSE_EASTING,    ObliqueStereographic.FALSE_EASTING);
+        roles.put(NormalizedProjection.ParameterRole.FALSE_NORTHING,   ObliqueStereographic.FALSE_NORTHING);
         final Initializer initializer = new Initializer(op, (Parameters) p, roles, (byte) 0);
-
+        /*
+         * The following lines give an example of how Apache SIS projection constructors
+         * use the Initializer class.
+         */
+        final double φ0 = toRadians(initializer.getAndStore(ObliqueStereographic.LATITUDE_OF_ORIGIN));
+        assertTrue(φ0 > 0);
         assertEquals("Conformal Sphere Radius", 6382644.571, 6377397.155 *
-                initializer.radiusOfConformalSphere(Math.sin(Math.toRadians(52.156160556))), Formulas.LINEAR_TOLERANCE);
+                initializer.radiusOfConformalSphere(sin(φ0)), Formulas.LINEAR_TOLERANCE);
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -166,10 +166,10 @@ public final strictfp class LambertConic
     @Test
     @DependsOnMethod("testSpecialLatitudes")
     public void testDerivative() throws TransformException {
-        if (transform == null) {    // May have been initialized by 'testSphericalCase'.
-            createNormalizedProjection(true, 40);   // Elliptical case
+        if (transform == null) {                                // May have been initialized by 'testSphericalCase'.
+            createNormalizedProjection(true, 40);               // Elliptical case
         }
-        final double delta = toRadians(100.0 / 60) / 1852; // Approximatively 100 metres.
+        final double delta = toRadians(100.0 / 60) / 1852;      // Approximatively 100 metres.
         derivativeDeltas = new double[] {delta, delta};
         tolerance = 1E-9;
         verifyDerivative(toRadians( 0), toRadians( 0));

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MercatorTest.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -50,6 +50,7 @@ import static org.apache.sis.referencing
 public final strictfp class MercatorTest extends MapProjectionTestCase {
     /**
      * Creates a new instance of {@link Mercator} for a sphere or an ellipsoid.
+     * The new instance is stored in the inherited {@link #transform} field.
      *
      * @param ellipse {@code false} for a sphere, or {@code true} for WGS84 ellipsoid.
      */
@@ -116,12 +117,12 @@ public final strictfp class MercatorTest
     @Test
     @DependsOnMethod("testSpecialLatitudes")
     public void testDerivative() throws TransformException {
-        if (transform == null) {    // May have been initialized by 'testSphericalCase'.
-            createNormalizedProjection(true);       // Elliptical case
+        if (transform == null) {                                // May have been initialized by 'testSphericalCase'.
+            createNormalizedProjection(true);                   // Elliptical case
         }
-        final double delta = toRadians(100.0 / 60) / 1852;    // Approximatively 100 metres.
+        final double delta = toRadians(100.0 / 60) / 1852;      // Approximatively 100 metres.
         derivativeDeltas = new double[] {delta, delta};
-        tolerance = 1E-9;    // More severe than Formulas.LINEAR_TOLERANCE.
+        tolerance = 1E-9;                                       // More severe than Formulas.LINEAR_TOLERANCE.
         verifyDerivative(toRadians(15), toRadians( 30));
         verifyDerivative(toRadians(10), toRadians(-60));
     }

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NormalizedProjectionTest.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -39,7 +39,8 @@ import static org.apache.sis.internal.jd
 @DependsOn({
     // Following dependency is where the basic parameters (e.g. SEMI_MAJOR) are tested.
     // Those parameters are needed by NoOp pseudo-projection, which is used in this package.
-    org.apache.sis.internal.referencing.provider.MapProjectionTest.class
+    org.apache.sis.internal.referencing.provider.MapProjectionTest.class,
+    InitializerTest.class
 })
 public final strictfp class NormalizedProjectionTest extends TransformTestCase {
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/ObliqueStereographicTest.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -16,24 +16,26 @@
  */
 package org.apache.sis.referencing.operation.projection;
 
+import javax.measure.unit.SI;
 import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.util.FactoryException;
-
-import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.referencing.operation.transform.ContextualParameters;
-
-import org.junit.Assert;
+import org.apache.sis.referencing.operation.matrix.Matrix2;
+import org.apache.sis.internal.referencing.Formulas;
+import org.apache.sis.test.DependsOnMethod;
+import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
-import static java.lang.Math.sqrt;
+import static java.lang.StrictMath.*;
+import static org.junit.Assert.*;
 
 
 /**
- * Tests {@link ObliqueStereographic} projection.
+ * Tests the {@link ObliqueStereographic} class.
  *
  * @author  Rémi Marechal (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
@@ -41,123 +43,169 @@ import static java.lang.Math.sqrt;
  * @version 0.7
  * @module
  */
+@DependsOn({
+    InitializerTest.class,
+    NormalizedProjectionTest.class
+})
 public final strictfp class ObliqueStereographicTest extends MapProjectionTestCase {
     /**
-     * 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.
+     * 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. The test uses the parameters for
+     * the <cite>Amersfoort / RD New</cite> projection:
+     *
+     * <ul>
+     *   <li>Semi-major axis length:            <var>a</var>  = 6377397.155 metres</li>
+     *   <li>Inverse flattening:              1/<var>f</var>  = 299.15281</li>
+     *   <li>Latitude of natural origin:        <var>φ₀</var> = 52°09'22.178"N</li>
+     *   <li>Longitude of natural origin:       <var>λ₀</var> =  5°23'15.500"E</li>
+     *   <li>Scale factor at natural origin:    <var>k₀</var> = 0.9999079</li>
+     *   <li>False easting:                     <var>FE</var> = 155000.00 metres</li>
+     *   <li>False northing:                    <var>FN</var> = 463000.00 metres</li>
+     * </ul>
+     *
+     * Other parameters (<var>n</var>, <var>R</var>, <var>g</var>, <var>h</var>) are computed from the above.
+     * Those parameters fall in three groups:
+     *
+     * <ul>
+     *   <li>Parameters used in linear operations (additions or multiplications) performed <strong>before</strong> the
+     *       non-linear part (the "kernel") of the map projection. Those parameters are <var>λ₀</var> and <var>n</var>
+     *       and their values are stored in the normalization matrix given by
+     *       <code>{@linkplain ContextualParameters#getMatrix(boolean) ContextualParameters.getMatrix}(true)</code>.</li>
+     *
+     *   <li>Parameters used in linear operations (additions or multiplications) performed <strong>after</strong> the
+     *       non-linear part (the "kernel") of the map projection. Those parameters are <var>k₀</var>, <var>R</var>,
+     *       <var>FE</var> and <var>FN</var> and their values are stored in the denormalization matrix given by
+     *       <code>{@linkplain ContextualParameters#getMatrix(boolean) ContextualParameters.getMatrix}(false)</code>.</li>
      *
-     * @see ContextualParameters#getMatrix(boolean) where boolean is true for value n.
-     * @see ContextualParameters#getMatrix(boolean) where boolean is false for k0, a, FE, FN and R.
-     * @see Initializer#radiusOfConformalSphere(double) for value R
+     *   <li>Other parameters are either used in the non-linear "kernel" of the map projection or used for computing the
+     *       above-cited parameters.</li>
+     * </ul>
      *
+     * <p><b>Note 1:</b> value of <var>R</var> is computed by {@link Initializer#radiusOfConformalSphere(double)}.</p>
+     *
+     * <p><b>Note 2:</b> we do not follow the Java naming convention here (constants in upper cases) in order to use
+     * as much as possible the exact same symbols as in the EPSG guide.</p>
      */
-    private final static double eSQUARED = 0.08169683 * 0.08169683,     // Excentricity squared.
-                                φ0       = 0.910296727,                 // Latitude of natural origin (rad)
-
-                                //-- Some attributs are considered as linear and put into normalize matrix and apply before transform
-                                n        = sqrt(1 + (eSQUARED * Math.pow(Math.cos(φ0), 4)) / (1 - eSQUARED)),
-
-                                //-- Some attributs are considered as linear and put into denormalize matrix and apply just after
-                                k0       = 0.9999079,
-                                a        = 6377397.155,
-                                FE       = 155000.00,
-                                FN       = 463000.00,
-                                R        = 6382644.571 / a;
+    private static final double φ0  = 0.910296727,      // Latitude of natural origin (rad)
+        /* Before kernel */     λ0  = 0.094032038,      // Longitude of natural origin (rad)
+        /*  After kernel */     R   = 6382644.571,      // Radius of conformal sphere (m)
+                                a   = 6377397.155,      // Semi-major axis length (m)
+                                ivf = 299.15281,        // Inverse flattening factor
+                                e   = 0.08169683,       // Excentricity
+        /* Before kernel */     n   = 1.000475857,      // Coefficient computed from excentricity and φ₀.
+        /*  After kernel */     k0  = 0.9999079,        // Scale factor
+        /*  After kernel */     FE  = 155000.00,        // False Easting (m)
+        /*  After kernel */     FN  = 463000.00;        // False Northing (m)
 
     /**
-     * Tested {@link MathTransform} projection.
+     * Compares the <var>n</var> value given in the EPSG guide with the value computed from the formula.
      */
-    private final NormalizedProjection ObliqueStereographic;
+    @Test
+    public void testN() {
+        assertEquals(n, sqrt(1 + (e*e * pow(cos(φ0), 4)) / (1 - e*e)), 0.5E-9);
+    }
 
     /**
-     * Buid tested {@link ObliqueStereographic} {@link MathTransform}.
+     * Creates a new instance of {@link ObliqueStereographic} for a sphere or an ellipsoid.
+     * The new instance is stored in the inherited {@link #transform} field.
+     *
+     * @param ellipse {@code false} for the spherical case, or {@code true} for the ellipsoidal case.
      */
-    public ObliqueStereographicTest() {
+    private void createNormalizedProjection(final boolean ellipse) {
         final OperationMethod op = new org.apache.sis.internal.referencing.provider.ObliqueStereographic();
-
         final ParameterValueGroup p = op.getParameters().createValue();
+        /*
+         * Following parameters are not given explicitely by EPSG definitions since they are
+         * usually inferred from the datum.  However in the particular case of this test, we
+         * need to provide them. The names used below are either OGC names or SIS extensions.
+         */
+        if (!ellipse) {
+            p.parameter("semi_major").setValue(R);
+            p.parameter("semi_minor").setValue(R);
+        } else {
+            p.parameter("semi_major").setValue(a);
+            p.parameter("inverse_flattening").setValue(ivf);
+        }
+        /*
+         * Following parameters are reproduced verbatim from EPSG registry and EPSG guide.
+         */
+        p.parameter("Latitude of natural origin")    .setValue(φ0, SI.RADIAN);
+        p.parameter("Longitude of natural origin")   .setValue(λ0, SI.RADIAN);
+        p.parameter("Scale factor at natural origin").setValue(k0);
+        p.parameter("False easting")                 .setValue(FE, SI.METRE);
+        p.parameter("False northing")                .setValue(FN, SI.METRE);
 
-        //-- implicit names from OGC.
-        p.parameter("semi_major").setValue(6377397.155);
-        p.parameter("inverse_flattening").setValue(299.15281);
-
-        //-- 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);
-
-        ObliqueStereographic = new ObliqueStereographic(op, (Parameters) p);
+        transform = new ObliqueStereographic(op, (Parameters) p);
     }
 
     /**
-     * {@link MathTransform#transform(org.opengis.geometry.DirectPosition, org.opengis.geometry.DirectPosition) }
-     * test with expected values from
-     * <a href = http://www.iogp.org/pubs/373-07-2.pdf> EPSG guide</a>
+     * The point given in the EPSG guide for testing the map projection.
+     * (φ<sub>t</sub>, λ<sub>t</sub>) is the source geographic coordinate in degrees and
+     * (x<sub>t</sub>, y<sub>t</sub>) is the target projected coordinate in metres.
+     */
+    private static final double φt = 53,                // Latitude in degrees
+                                λt = 6,                 // Longitude in degrees
+                                Et = 196105.283,        // Easting in metres
+                                Nt = 557057.739;        // Northing in metres
+
+    /**
+     * Tests {@link ObliqueStereographic#transform(double[], int, double[], int, boolean)}
+     * with the values given by the EPSG guide.
      *
-     * @throws FactoryException if an error occurred while creating the map projection.
-     * @throws TransformException if an error occurred while projecting a coordinate.
+     * @throws TransformException if an error occurred while projecting the coordinate.
      */
     @Test
-    public void testEPSGTransform() throws FactoryException, TransformException {
-
-        final double[] srcPts = new double[]{6, 53}; //-- deg
-        srcPts[0] = Math.toRadians(srcPts[0] - 5.387638889) ;
-        srcPts[1] = Math.toRadians(srcPts[1]);
-
+    public void testTransform() throws TransformException {
+        final double[] srcPts = new double[] {λt, φt};   // in degrees
         final double[] dstPts = new double[2];
 
-        srcPts[0] = srcPts[0] * n;
+        // Linear operations (normalization) applied before NormalizedTransform.
+        srcPts[0] = toRadians(srcPts[0]) - λ0;
+        srcPts[1] = toRadians(srcPts[1]);
+        srcPts[0] *= n;
+
+        // The non-linear part of map projection (the "kernel").
+        createNormalizedProjection(true);
+        transform.transform(srcPts, 0, dstPts, 0, 1);
+
+        // Linear operations (denormalization) applied after NormalizedTransform.
+        dstPts[0] *= (k0 * 2*R);
+        dstPts[1] *= (k0 * 2*R);
+        dstPts[0] += FE;
+        dstPts[1] += FN;
 
-        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;
-
-        Assert.assertEquals("destination East coordinate",  196105.283, destE, Formulas.LINEAR_TOLERANCE);
-        Assert.assertEquals("destination North coordinate", 557057.739, destN, Formulas.LINEAR_TOLERANCE);
+        assertEquals("Easting",  Et, dstPts[0], Formulas.LINEAR_TOLERANCE);
+        assertEquals("Northing", Nt, dstPts[1], Formulas.LINEAR_TOLERANCE);
     }
 
-
-   /**
-     * Test method {@link ObliqueStereographic#inverseTransform(double[], int, double[], int)}
-     * test with expected values from
-     * <a href = http://www.iogp.org/pubs/373-07-2.pdf> EPSG guide</a>
+    /**
+     * Tests {@link ObliqueStereographic#inverseTransform(double[], int, double[], int)}
+     * with the values given by the EPSG guide.
      *
-     * @throws org.apache.sis.referencing.operation.projection.ProjectionException
+     * @throws TransformException if an error occurred while projecting the coordinate.
      */
     @Test
-    public void testEPSGinvertTransform() 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[] srcPts = new double[]{srcEast, srcNorth}; //-- meter
-
+    public void testInverseTransform() throws TransformException {
+        final double[] srcPts = new double[] {Et, Nt};  // in metres
         final double[] dstPts = new double[2];
-        ObliqueStereographic.inverseTransform(srcPts, 0, dstPts, 0);
 
-        final double λO = 0.094032038;
+        // Linear operations (normalization) applied before NormalizedTransform.
+        srcPts[0] -= FE;
+        srcPts[1] -= FN;
+        srcPts[0] /= (k0 * 2*R);
+        srcPts[1] /= (k0 * 2*R);
+
+        // The non-linear part of map projection (the "kernel").
+        createNormalizedProjection(true);
+        ((NormalizedProjection) transform).inverseTransform(srcPts, 0, dstPts, 0);
+
+        // Linear operations (denormalization) applied after NormalizedTransform.
+        dstPts[0] /= n;
+        dstPts[0] = toDegrees(dstPts[0] + λ0);
+        dstPts[1] = toDegrees(dstPts[1]);
 
-        double destλ = dstPts[0] / n + λO;
-        double destφ = dstPts[1];
-
-        destλ = Math.toDegrees(destλ);
-        destφ = Math.toDegrees(destφ);
-
-        Assert.assertEquals("destination East coordinate",  6, destλ, Formulas.ANGULAR_TOLERANCE);
-        Assert.assertEquals("destination North coordinate", 53, destφ, Formulas.ANGULAR_TOLERANCE);
+        assertEquals("Longitude", λt, dstPts[0], Formulas.ANGULAR_TOLERANCE);
+        assertEquals("Latitude",  φt, dstPts[1], Formulas.ANGULAR_TOLERANCE);
     }
 
     /**
@@ -170,7 +218,142 @@ public final strictfp class ObliqueStere
      * @see org.opengis.test.referencing.ParameterizedTransformTest#testObliqueStereographic()
      */
     @Test
-    public void testGeoapi() throws FactoryException, TransformException {
+    @DependsOnMethod({"testTransform", "testInverseTransform"})
+    public void testObliqueStereographic() throws FactoryException, TransformException {
         createGeoApiTest(new org.apache.sis.internal.referencing.provider.ObliqueStereographic()).testObliqueStereographic();
     }
+
+    /**
+     * Verifies the consistency of spherical formulas with the elliptical formulas.
+     * This test transforms the point given in the EPSG guide and takes the result
+     * of the elliptical implementation as a reference.
+     *
+     * @throws TransformException if an error occurred while projecting the coordinate.
+     */
+    @Test
+    @DependsOnMethod("testTransform")
+    public void testSphericalTransform() throws TransformException {
+        final double[] srcPts = new double[] {λt, φt};  // in degrees
+        final double[] dstPts = new double[2];
+        final double[] refPts = new double[2];
+
+        // Linear operations (normalization) applied before NormalizedTransform.
+        srcPts[0] = toRadians(srcPts[0]) - λ0;
+        srcPts[1] = toRadians(srcPts[1]);
+        srcPts[0] *= n;
+
+        // The non-linear part of map projection (the "kernel").
+        createNormalizedProjection(false);
+        transform.transform(srcPts, 0, refPts, 0, 1);
+
+        // Linear operations (denormalization) applied after NormalizedTransform.
+        refPts[0] *= (k0 * 2*R);
+        refPts[1] *= (k0 * 2*R);
+        refPts[0] += FE;
+        refPts[1] += FN;
+
+        // Transform the same point, now using the spherical implementation.
+        ObliqueStereographic spherical = (ObliqueStereographic) transform;
+        spherical = new ObliqueStereographic.Spherical(spherical);
+        spherical.transform(srcPts, 0, dstPts, 0, 1);
+
+        // Linear operations (denormalization) applied after NormalizedTransform.
+        dstPts[0] *= (k0 * 2*R);
+        dstPts[1] *= (k0 * 2*R);
+        dstPts[0] += FE;
+        dstPts[1] += FN;
+
+        // Use a smaller tolerance because spherical and elliptical formulas should be equivalent in this case.
+        assertArrayEquals("Spherical projection", refPts, dstPts, Formulas.ANGULAR_TOLERANCE / 1E6);
+    }
+
+    /**
+     * Verifies the consistency of spherical formulas with the elliptical formulas.
+     * This test computes the inverse transform of the point given in the EPSG guide
+     * and takes the result of the elliptical implementation as a reference.
+     *
+     * @throws TransformException if an error occurred while projecting the coordinate.
+     */
+    @Test
+    @DependsOnMethod("testInverseTransform")
+    public void testSphericalInverseTransform() throws TransformException {
+        final double[] srcPts = new double[] {Et, Nt};  // in metres
+        final double[] dstPts = new double[2];
+        final double[] refPts = new double[2];
+
+        // Linear operations (normalization) applied before NormalizedTransform.
+        srcPts[0] -= FE;
+        srcPts[1] -= FN;
+        srcPts[0] /= (k0 * 2*R);
+        srcPts[1] /= (k0 * 2*R);
+
+        // The non-linear part of map projection (the "kernel").
+        createNormalizedProjection(false);
+        ((NormalizedProjection) transform).inverseTransform(srcPts, 0, refPts, 0);
+
+        // Linear operations (denormalization) applied after NormalizedTransform.
+        refPts[0] /= n;
+        refPts[0] = toDegrees(refPts[0] + λ0);
+        refPts[1] = toDegrees(refPts[1]);
+
+        // Transform the same point, now using the spherical implementation.
+        ObliqueStereographic spherical = (ObliqueStereographic) transform;
+        spherical = new ObliqueStereographic.Spherical(spherical);
+        spherical.inverseTransform(srcPts, 0, dstPts, 0);
+
+        // Linear operations (denormalization) applied after NormalizedTransform.
+        dstPts[0] /= n;
+        dstPts[0] = toDegrees(dstPts[0] + λ0);
+        dstPts[1] = toDegrees(dstPts[1]);
+
+        // Use a smaller tolerance because spherical and elliptical formulas should be equivalent in this case.
+        assertArrayEquals("Spherical inverse projection", refPts, dstPts, Formulas.ANGULAR_TOLERANCE / 1E6);
+    }
+
+    /**
+     * Verifies the consistency of spherical formulas with the elliptical formulas.
+     * This test computes the derivative at a point and takes the result of the elliptical
+     * implementation as a reference.
+     *
+     * @throws TransformException if an error occurred while computing the derivative.
+     */
+    @Test
+    @DependsOnMethod("testDerivative")
+    public void testSphericalDerivative() throws TransformException {
+        final double[] srcPts = new double[] {λt, φt};  // in degrees
+        srcPts[0] = toRadians(srcPts[0]) - λ0;
+        srcPts[1] = toRadians(srcPts[1]);
+        srcPts[0] *= n;
+
+        // Using elliptical implementation.
+        createNormalizedProjection(false);
+        final Matrix reference = ((NormalizedProjection) transform).transform(srcPts, 0, null, 0, true);
+
+        // Using spherical implementation.
+        ObliqueStereographic spherical = (ObliqueStereographic) transform;
+        spherical = new ObliqueStereographic.Spherical(spherical);
+        final Matrix derivative = spherical.transform(srcPts, 0, null, 0, true);
+
+        tolerance = 1E-12;
+        assertMatrixEquals("Spherical derivative", reference, derivative,
+                new Matrix2(tolerance, tolerance,
+                            tolerance, tolerance));
+    }
+
+    /**
+     * Creates a projection and derivates a few points.
+     *
+     * @throws TransformException Should never happen.
+     */
+    @Test
+    public void testDerivative() throws TransformException {
+        createNormalizedProjection(true);
+        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));
+    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolarStereographicTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolarStereographicTest.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolarStereographicTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/PolarStereographicTest.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -70,7 +70,7 @@ public final strictfp class PolarStereog
     @Test
     public void testSphericalCaseSouth() throws FactoryException, TransformException {
         createNormalizedProjection(new PolarStereographicSouth());
-        final double delta = toRadians(100.0 / 60) / 1852; // Approximatively 100 metres.
+        final double delta = toRadians(100.0 / 60) / 1852;          // Approximatively 100 metres.
         derivativeDeltas = new double[] {delta, delta};
         verifyInDomain(CoordinateDomain.GEOGRAPHIC_RADIANS_SOUTH, 56763886);
     }

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/TransverseMercatorTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/TransverseMercatorTest.java?rev=1709462&r1=1709461&r2=1709462&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/TransverseMercatorTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/TransverseMercatorTest.java [UTF-8] Mon Oct 19 18:17:37 2015
@@ -117,7 +117,7 @@ public final strictfp class TransverseMe
         createNormalizedProjection(false, 0);
         tolerance = 1E-9;
 
-        final double delta = toRadians(100.0 / 60) / 1852; // Approximatively 100 metres.
+        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));
@@ -134,7 +134,7 @@ public final strictfp class TransverseMe
         createNormalizedProjection(true, 0);
         tolerance = 1E-9;
 
-        final double delta = toRadians(100.0 / 60) / 1852; // Approximatively 100 metres.
+        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));



Mime
View raw message