Author: desruisseaux
Date: Wed Mar 25 17:13:15 2015
New Revision: 1669159

URL: http://svn.apache.org/r1669159
Log:
Referencing: partial port of Mercator initialization operations
(construction of normalization and denormalization affines).

Modified:
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/formulas.html
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/UnitaryProjectionTest.java

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java?rev=1669159&r1=1669158&r2=1669159&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
 [UTF-8] Wed Mar 25 17:13:15 2015
@@ -25,6 +25,7 @@ import org.apache.sis.internal.referenci
 import org.apache.sis.internal.referencing.provider.Mercator2SP;
 import org.apache.sis.internal.referencing.provider.PseudoMercator;
 import org.apache.sis.internal.referencing.provider.MillerCylindrical;
+import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.referencing.operation.matrix.Matrix2;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.parameter.Parameters;
@@ -87,6 +88,37 @@ public class Mercator extends UnitaryPro
      */
     protected Mercator(final OperationMethod method, final Parameters values) {
         super(method, values);
+        double φ1 = abs(values.doubleValue(Mercator2SP.STANDARD_PARALLEL));
+        double φ0 =     values.doubleValue(Mercator2SP.LATITUDE_OF_ORIGIN);
+        double λ0 =     values.doubleValue(Mercator2SP.CENTRAL_MERIDIAN);
+        double k0 =     values.doubleValue(Mercator2SP.SCALE_FACTOR);
+        double FE =     values.doubleValue(Mercator2SP.FALSE_EASTING);
+        double FN =     values.doubleValue(Mercator2SP.FALSE_NORTHING);
+
+        φ1 = toRadians(φ1);
+        k0 *= cos(φ1);
+        if (!isSpherical()) {
+            k0 /= rν(sin(φ1));
+        }
+        final MatrixSIS normalize   = parameters.normalizeGeographicInputs(λ0);
+        final MatrixSIS denormalize = parameters.denormalizeCartesianOutputs(
+                values.doubleValue(Mercator2SP.SEMI_MAJOR) * k0, FE, FN);
+        /*
+         * A correction that allows us to employ a latitude of origin that is 
not correspondent to the equator,
+         * as described in Snyder and al. at page 47. This is the same 
correction factor than the one applied
+         * for the Mercator (2SP) case, constant "ko" in EPSG:9805.
+         *
+         * The scale correction is multiplied with the global scale, which 
allows the Apache SIS referencing
+         * module to merge this correction with the scale factor in a single 
multiplication.
+         */
+        φ0 = toRadians(φ0);
+        double scale = cos(φ0) / rν(sin(φ0));
+        final boolean isMiller = 
IdentifiedObjects.isHeuristicMatchForName(values.getDescriptor(), 
MillerCylindrical.NAME);
+        if (isMiller) {
+            scale *= 1.25;
+        }
+        denormalize.concatenate(0, scale, null);
+        denormalize.concatenate(1, scale, null);
     }
 
     /**

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java?rev=1669159&r1=1669158&r2=1669159&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
 [UTF-8] Wed Mar 25 17:13:15 2015
@@ -31,6 +31,7 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.apache.sis.internal.referencing.ExtendedPrecisionMatrix;
 import org.apache.sis.internal.referencing.WKTUtilities;
+import org.apache.sis.internal.util.DoubleDouble;
 import org.apache.sis.parameter.Parameterized;
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
@@ -75,8 +76,8 @@ import static org.apache.sis.util.Argume
  *     {@link ParameterValueGroup}, initializes the projection, then saves the 
parameter values that
  *     it actually used in a new {@code ContextualParameters} instance.</li>
  *
- *   <li>The map projection constructor may keep only the non-linear 
parameters for itself, and gives the linear parameters
- *     to the {@link #normalizeGeographic(double)} and {@link 
#denormalizeCartesian(double, double, double, double)} methods.
+ *   <li>The map projection constructor may keep only the non-linear 
parameters for itself, and gives the linear parameters to the
+ *     {@link #normalizeGeographicInputs(double)} and {@link 
#denormalizeCartesianOutputs(double, double, double)} methods.
  *     The constructor is free to apply additional operations on the two 
affine transforms
  *     ({@linkplain #normalization(boolean) normalize / denormalize}) after 
the above-cited methods have been invoked.</li>
  * </ol>
@@ -115,17 +116,7 @@ public class ContextualParameters extend
      *
      * @see #normalization(boolean)
      */
-    private Matrix normalize,
-
-    /**
-     * The affine transform to be applied before (<cite>normalize</cite>) and 
after (<cite>denormalize</cite>)
-     * the kernel operation.On {@code ContextualParameters} construction, 
those affines are initially identity
-     * transforms, to be modified in-place by callers of {@link 
#normalization(boolean)}.
-     * After {@link #createConcatenatedTransform(MathTransformFactory, 
MathTransform)} has been invoked,
-     * they are typically (but not necessarily) replaced by the {@link 
LinearTransform} instance itself.
-     * @see #normalization(boolean)
-     */
-    denormalize;
+    private Matrix normalize, denormalize;
 
     /**
      * Creates a new group of parameters for the given non-linear coordinate 
operation method.
@@ -156,41 +147,6 @@ public class ContextualParameters extend
     }
 
     /**
-     * The affine transforms to be applied before or after the kernel 
operation. Those affines are initially
-     * identity transforms. Callers should invoke this method at the 
non-linear transform construction time
-     * (or at some time close to construction) in order to set the affine 
coefficients.
-     *
-     * @param  norm {@code true} for fetching the <cite>normalize</cite> 
transform to apply before the kernel,
-     *         or {@code false} for the <cite>denormalize</cite> transform to 
apply after the kernel.
-     * @return The requested normalize ({@code true}) or denormalize ({@code 
false}) affine transform.
-     */
-    public final MatrixSIS normalization(final boolean norm) {
-        return MatrixSIS.castOrCopy(norm ? normalize : denormalize);
-    }
-
-    /**
-     * Creates a chain of {@linkplain ConcatenatedTransform concatenated 
transforms} from the
-     * <cite>normalize</cite> transform, the given kernel and the 
<cite>denormalize</cite> transform.
-     *
-     * @param  kernel The (usually non-linear) kernel.
-     * @return The concatenation of <cite>normalize</cite> → <cite>the given 
kernel</cite> → <cite>denormalize</cite>
-     *         transforms.
-     */
-    final MathTransform createConcatenatedTransform(final MathTransformFactory 
factory, MathTransform kernel)
-            throws FactoryException
-    {
-        final MathTransform n = factory.createAffineTransform(normalize);
-        final MathTransform d = factory.createAffineTransform(denormalize);
-        Matrix m;
-        if ((m = MathTransforms.getMatrix(n)) != null)   normalize = m;
-        if ((m = MathTransforms.getMatrix(d)) != null) denormalize = m;
-        if (factory instanceof DefaultMathTransformFactory) {
-            kernel = ((DefaultMathTransformFactory) factory).unique(kernel);
-        }
-        return 
factory.createConcatenatedTransform(factory.createConcatenatedTransform(n, 
kernel), d);
-    }
-
-    /**
      * Returns the parameters for the whole <cite>normalize</cite> → 
<cite>non-linear kernel</cite> →
      * <cite>denormalize</cite> sequence. The parameter values may take effect 
in either the
      * {@linkplain #normalization(boolean) normalize/denormalize} transforms 
or in the kernel.
@@ -230,6 +186,97 @@ public class ContextualParameters extend
     }
 
     /**
+     * Prepends a normalization step before the non-linear kernel, which will 
convert ordinate values
+     * in the two first dimensions from degrees to radians. Before this 
conversion, the normalization
+     * can optionally subtract the given λ0 value (in degrees) from the 
longitude.
+     *
+     * <p>In other words, invoking this method is equivalent to convert 
coordinates using the following
+     * affine transform before any other operation:</p>
+     *
+     * <center><p>{@include formulas.html#Normalize}</p></center>
+     *
+     * @param  λ0 Longitude of the central meridian, in degrees.
+     * @return The normalization affine transform as a matrix.
+     *         Callers can change that matrix directly if they want to apply 
additional normalization operations.
+     */
+    public MatrixSIS normalizeGeographicInputs(final double λ0) {
+        /*
+         * In theory the check for (λ0 != 0) is useless. However Java has a 
notion of negative zero, and we want
+         * to avoid negative zeros because we do not want them to appear in 
WKT formatting of matrix elements.
+         */
+        final DoubleDouble toRadians = DoubleDouble.createDegreesToRadians();
+        DoubleDouble offset = null;
+        if (λ0 != 0) {
+            offset = new DoubleDouble(-λ0);
+            offset.multiply(toRadians);
+        }
+        final MatrixSIS normalize = normalization(true);
+        normalize.concatenate(0, toRadians, offset);
+        normalize.concatenate(1, toRadians, null);
+        return normalize;
+    }
+
+    /**
+     * Appends a normalization step after the non-linear kernel, which will 
scale the projected ordinates
+     * and add the false easting and northing.
+     *
+     * <p>In other words, invoking this method is equivalent to convert 
coordinates using the following
+     * affine transform after the non-linear kernel:</p>
+     *
+     * <center><p>{@include formulas.html#Deormalize}</p></center>
+     *
+     * @param scale The <cite>semi-major axis length</cite> (<var>a</var>), 
optionally multiplied by other scale factor (<var>k</var>₀).
+     * @param tx    The false easting (FE).
+     * @param ty    The false northing (FN).
+     * @return The denormalization affine transform as a matrix.
+     *         Callers can change that matrix directly if they want to apply 
additional denormalization operations.
+     */
+    public MatrixSIS denormalizeCartesianOutputs(double scale, double tx, 
double ty) {
+        final DoubleDouble s = new DoubleDouble(scale);
+        final MatrixSIS denormalize = normalization(false);
+        denormalize.concatenate(0, s, tx);
+        denormalize.concatenate(1, s, ty);
+        return denormalize;
+    }
+
+    /**
+     * The affine transforms to be applied before or after the kernel 
operation. Those affines are initially
+     * identity transforms. Callers should invoke this method at the 
non-linear transform construction time
+     * (or at some time close to construction) in order to set the affine 
coefficients.
+     *
+     * @param  norm {@code true} for fetching the <cite>normalize</cite> 
transform to apply before the kernel,
+     *         or {@code false} for the <cite>denormalize</cite> transform to 
apply after the kernel.
+     * @return The requested normalize ({@code true}) or denormalize ({@code 
false}) affine transform.
+     */
+    public final MatrixSIS normalization(final boolean norm) {
+        return MatrixSIS.castOrCopy(norm ? normalize : denormalize);
+    }
+
+    /**
+     * Creates a chain of {@linkplain ConcatenatedTransform concatenated 
transforms} from the
+     * <cite>normalize</cite> transform, the given kernel and the 
<cite>denormalize</cite> transform.
+     *
+     * @param  factory The factory to use for creating math transform 
instances.
+     * @param  kernel The (usually non-linear) kernel.
+     * @return The concatenation of <cite>normalize</cite> → <cite>the given 
kernel</cite> → <cite>denormalize</cite>
+     *         transforms.
+     * @throws FactoryException if an error occurred while creating a math 
transform instance.
+     */
+    public MathTransform createConcatenatedTransform(final 
MathTransformFactory factory, MathTransform kernel)
+            throws FactoryException
+    {
+        final MathTransform n = factory.createAffineTransform(normalize);
+        final MathTransform d = factory.createAffineTransform(denormalize);
+        Matrix m;
+        if ((m = MathTransforms.getMatrix(n)) != null)   normalize = m;
+        if ((m = MathTransforms.getMatrix(d)) != null) denormalize = m;
+        if (factory instanceof DefaultMathTransformFactory) {
+            kernel = ((DefaultMathTransformFactory) factory).unique(kernel);
+        }
+        return 
factory.createConcatenatedTransform(factory.createConcatenatedTransform(n, 
kernel), d);
+    }
+
+    /**
      * Unsupported operation, since {@code ContextualParameters} groups do not 
contain sub-groups.
      * This limitation may be revisited in future SIS version.
      *

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/formulas.html
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/formulas.html?rev=1669159&r1=1669158&r2=1669159&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/formulas.html
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/formulas.html
 [UTF-8] Wed Mar 25 17:13:15 2015
@@ -113,5 +113,57 @@
         </math>
       </td></tr>
     </table>
+
+
+
+
+    <h2>Normalize</h2>
+    <math display="block" alttext="MathML capable browser required">
+      <mfenced open="[" close="]">
+        <mtable>
+          <mtr>
+            <mtd><mi>π</mi><mo>/</mo><mn>180</mn></mtd>
+            <mtd><mn>0</mn></mtd>
+            
<mtd><mo>-</mo><mo>(</mo><mi>π</mi><mo>/</mo><mn>180</mn><mo>)</mo> <mo>∙</mo> 
<msub><mi>λ</mi><mn>0</mn></msub></mtd>
+          </mtr>
+          <mtr>
+            <mtd><mn>0</mn></mtd>
+            <mtd><mi>π</mi><mo>/</mo><mn>180</mn></mtd>
+            <mtd><mn>0</mn></mtd>
+          </mtr>
+          <mtr>
+            <mtd><mn>0</mn></mtd>
+            <mtd><mn>0</mn></mtd>
+            <mtd><mn>1</mn></mtd>
+          </mtr>
+        </mtable>
+      </mfenced>
+    </math>
+
+
+
+
+    <h2>Denormalize</h2>
+    <math display="block" alttext="MathML capable browser required">
+      <mfenced open="[" close="]">
+        <mtable>
+          <mtr>
+            <mtd><mi>a</mi> <mo>∙</mo> <msub><mi>k</mi><mn>0</mn></msub></mtd>
+            <mtd><mn>0</mn></mtd>
+            <mtd><mi>FE</mi></mtd>
+          </mtr>
+          <mtr>
+            <mtd><mn>0</mn></mtd>
+            <mtd><mi>a</mi> <mo>∙</mo> <msub><mi>k</mi><mn>0</mn></msub></mtd>
+            <mtd><mi>FN</mi></mtd>
+          </mtr>
+          <mtr>
+            <mtd><mn>0</mn></mtd>
+            <mtd><mn>0</mn></mtd>
+            <mtd><mn>1</mn></mtd>
+          </mtr>
+        </mtable>
+      </mfenced>
+    </math>
   </body>
 </html>

Modified: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/UnitaryProjectionTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/UnitaryProjectionTest.java?rev=1669159&r1=1669158&r2=1669159&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/UnitaryProjectionTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/UnitaryProjectionTest.java
 [UTF-8] Wed Mar 25 17:13:15 2015
@@ -225,17 +225,17 @@ public final strictfp class UnitaryProje
      */
     @Test
     @DependsOnMethod("testExpOfNorthing")
-    public void test_dN_dφ() throws TransformException {
+    public void test_dy_dφ() throws TransformException {
         tolerance = 1E-7;
-        doTest_dN_dφ(new NoOp(false));      // Spherical case
-        doTest_dN_dφ(new NoOp(true));       // Ellipsoidal case
+        doTest_dy_dφ(new NoOp(false));      // Spherical case
+        doTest_dy_dφ(new NoOp(true));       // Ellipsoidal case
     }
 
     /**
-     * Implementation of {@link #test_dN_dφ()}.
+     * Implementation of {@link #test_dy_dφ()}.
      * The {@link #projection} field must have been set before this method is 
called.
      */
-    private void doTest_dN_dφ(final NoOp projection) throws TransformException 
{
+    private void doTest_dy_dφ(final NoOp projection) throws TransformException 
{
         transform = new AbstractMathTransform1D() {
             @Override public double transform(final double φ) {
                 return expOfNorthing(projection, φ);


Reply via email to