sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1674095 - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/internal/referencing/provider/ main/java/org/apache/sis/referencing/operation/matrix/ main/java/org/apache/sis/referencing/operation/projection/ main/java/o...
Date Thu, 16 Apr 2015 15:40:27 GMT
Author: desruisseaux
Date: Thu Apr 16 15:40:27 2015
New Revision: 1674095

URL: http://svn.apache.org/r1674095
Log:
Referencing: renamed MatrixSIS.concatenate(...) as convertBefore(...) and added a convertAfter(...) method.
This allow us to bring a little bit more consistency in NormalizedProjection constructor, by doing all the
work for the common parameters (central meridian, scale factor, false easting, false northing) without the
need for subclasses to invoke 'scaleAndTranslate2D' themselves (the later method can actually be removed).

Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConformal.java
    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/projection/NormalizedProjection.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.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/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java?rev=1674095&r1=1674094&r2=1674095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java [UTF-8] Thu Apr 16 15:40:27 2015
@@ -27,9 +27,11 @@ import org.opengis.referencing.operation
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.parameter.ParameterBuilder;
 import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.referencing.operation.transform.ContextualParameters;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.internal.referencing.j2d.ParameterizedAffine;
+import org.apache.sis.internal.util.DoubleDouble;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.resources.Messages;
 
@@ -263,21 +265,24 @@ public final class Equirectangular exten
          *   4) Scale longitude by cos(φ1).
          */
         φ1 = toRadians(φ1);
-        context.getMatrix(true).concatenate(0, cos(φ1), null);
+        context.getMatrix(true).convertBefore(0, cos(φ1), null);
         context.normalizeGeographicInputs(λ0)
-               .concatenate(1, null, -φ0);
+               .convertBefore(1, null, -φ0);
         /*
-         * At this point, we usually invoke scaleAndTranslate2D(false, a, fe, fn) where 'a' (the semi-major
-         * axis length) is taken as the Earth radius (R). However quoting EPSG: "If the figure of the earth
-         * used is an ellipsoid rather than a sphere then R should be calculated as the radius of the conformal
-         * sphere at the projection origin at latitude φ1 using the formula for RC given in section 1.2, table 3".
+         * At this point, we usually invoke 'denormalize.convertAfter(…, a, …)' where 'a' (the semi-major axis length)
+         * is taken as the Earth radius (R). However quoting EPSG: "If the figure of the earth used is an ellipsoid
+         * rather than a sphere then R should be calculated as the radius of the conformal sphere at the projection
+         * origin at latitude φ1 using the formula for RC given in section 1.2, table 3".
          */
         if (a != b) {
             final double rs = b / a;
             final double sinφ1 = sin(φ1);
             a = b / (1 - (1 - rs*rs) * (sinφ1*sinφ1));
         }
-        context.scaleAndTranslate2D(false, a, fe, fn);
+        final DoubleDouble k = new DoubleDouble(a);
+        final MatrixSIS denormalize = context.getMatrix(false);
+        denormalize.convertAfter(0, k, new DoubleDouble(fe));
+        denormalize.convertAfter(1, k, new DoubleDouble(fn));
         /*
          * Creates the ConcatenatedTransform, letting the factory returns the cached instance
          * if the caller already invoked this method previously (which usually do not happen).

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java?rev=1674095&r1=1674094&r2=1674095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java [UTF-8] Thu Apr 16 15:40:27 2015
@@ -47,7 +47,8 @@ import org.apache.sis.util.resources.Err
  *     <ul>
  *       <li>{@link #isAffine()}</li>
  *       <li>{@link #normalizeColumns()}</li>
- *       <li>{@link #concatenate(int, Number, Number)}</li>
+ *       <li>{@link #convertBefore(int, Number, Number)}</li>
+ *       <li>{@link #convertAfter(int, Number, Number)}</li>
  *     </ul>
  *   </li>
  * </ul>
@@ -268,7 +269,7 @@ public abstract class MatrixSIS implemen
      * @return {@code true} if this matrix is an identity matrix.
      *
      * @see Matrices#isIdentity(Matrix, double)
-     * @see java.awt.geom.AffineTransform#isIdentity()
+     * @see AffineTransform#isIdentity()
      */
     @Override
     public abstract boolean isIdentity();
@@ -318,35 +319,26 @@ public abstract class MatrixSIS implemen
     }
 
     /**
-     * Assuming that this matrix represents an affine transform, applies a scale and a translation
-     * on the given dimension.
-     * If:
-     * <ul>
-     *   <li>{@code original} is this matrix before this method call</li>
-     *   <li>{@code modified} is this matrix after this method call</li>
-     * </ul>
-     *
-     * then transforming a coordinate by {@code modified} is equivalent to first replacing the ordinate
-     * value at dimension {@code srcDim} by ({@code scale} × <var>ordinate</var> + {@code offset}),
-     * then apply the {@code original} transform.
+     * Assuming that this matrix represents an affine transform, concatenates a scale and a translation on the
+     * given dimension. Converting a point with the resulting matrix is equivalent to first convert the point
+     * with {@code ordinates[srcDim] = ordinates[srcDim] * scale + offset}, then apply the original matrix.
      *
-     * <div class="section">Comparison with Java2D</div>
+     * <div class="section">Equivalence between this method and Java2D {@code AffineTransform} methods</div>
      * If this matrix was an instance of Java2D {@link AffineTransform}, then invoking this method would
      * be equivalent to invoke the following {@code AffineTransform} methods in the order shown below:
      *
-     * <table class="sis">
-     *   <caption>Equivalence between this method and {@code AffineTransform} ({@code at}) methods</caption>
+     * <table class="sis" summary="Equivalence between this method and AffineTransform methods">
      *   <tr>
-     *     <th>{@code concatenate(0, scale, offset)}</th>
-     *     <th class="sep">{@code concatenate(1, scale, offset)}</th>
-     *   </tr>
-     *   <tr>
-     *     <td><code>at.{@linkplain AffineTransform#translate(double, double) translate}(offset, 0)</code></td>
-     *     <td class="sep"><code>at.{@linkplain AffineTransform#translate(double, double) translate}(0, offset)</code></td>
-     *   </tr>
-     *   <tr>
-     *     <td><code>at.{@linkplain AffineTransform#scale(double, double) scale}(scale, 1)</code></td>
-     *     <td class="sep"><code>at.{@linkplain AffineTransform#scale(double, double) scale}(1, scale)</code></td>
+     *     <th>{@code MatrixSIS} method</th>
+     *     <th class="sep">{@code AffineTransform} methods</th>
+     *   </tr><tr>
+     *     <td>{@code concatenate(0, scale, offset)}</td>
+     *     <td class="sep"><code>at.{@linkplain AffineTransform#translate(double, double) translate}(offset, 0);
+     *     at.{@linkplain AffineTransform#scale(double, double) scale}(scale, 1);</code></td>
+     *   </tr><tr>
+     *     <td>{@code concatenate(1, scale, offset)}</td>
+     *     <td class="sep"><code>at.{@linkplain AffineTransform#translate(double, double) translate}(0, offset);
+     *     at.{@linkplain AffineTransform#scale(double, double) scale}(1, scale);</code></td>
      *   </tr>
      * </table>
      *
@@ -359,7 +351,7 @@ public abstract class MatrixSIS implemen
      *
      * @since 0.6
      */
-    public void concatenate(final int srcDim, final Number scale, final Number offset) {
+    public void convertBefore(final int srcDim, final Number scale, final Number offset) {
         final int lastCol = getNumCol() - 1;
         ArgumentChecks.ensureValidIndex(lastCol, srcDim);
         final DoubleDouble s = new DoubleDouble();
@@ -381,12 +373,45 @@ public abstract class MatrixSIS implemen
     }
 
     /**
+     * Assuming that this matrix represents an affine transform, pre-concatenates a scale and a translation on the
+     * given dimension. Converting a point with the resulting matrix is equivalent to first convert the point with
+     * the original matrix, then convert the result with {@code ordinates[tgtDim] = ordinates[tgtDim] * scale + offset}.
+     *
+     * @param tgtDim The dimension of the ordinate to rescale in the target coordinates.
+     * @param scale  The amount by which to multiply the target ordinate value after this transform, or {@code null} if none.
+     * @param offset The amount by which to translate the target ordinate value after this transform, or {@code null} if none.
+     * @throws UnsupportedOperationException if this matrix is unmodifiable.
+     *
+     * @see AffineTransform#preConcatenate(AffineTransform)
+     *
+     * @since 0.6
+     */
+    public void convertAfter(final int tgtDim, final Number scale, final Number offset) {
+        final int lastRow = getNumRow() - 1;
+        final int lastCol = getNumCol() - 1;
+        ArgumentChecks.ensureValidIndex(lastRow, tgtDim);
+        final DoubleDouble s = new DoubleDouble();
+        if (scale != null) {
+            for (int i=lastCol; i>=0; i--) {
+                get(tgtDim, i, s);
+                s.multiply(scale);
+                set(tgtDim, i, s);
+            }
+        }
+        if (offset != null) {
+            get(tgtDim, lastCol, s);
+            s.add(offset);
+            set(tgtDim, lastCol, s);
+        }
+    }
+
+    /**
      * Returns a new matrix which is the result of multiplying this matrix with the specified one.
      * In other words, returns {@code this} × {@code matrix}.
      *
      * <div class="section">Relationship with coordinate operations</div>
      * In the context of coordinate operations, {@code Matrix.multiply(other)} is equivalent to
-     * <code>{@linkplain java.awt.geom.AffineTransform#concatenate AffineTransform.concatenate}(other)</code>:
+     * <code>{@linkplain AffineTransform#concatenate AffineTransform.concatenate}(other)</code>:
      * first transforms by the supplied transform and then transform the result by the original transform.
      *
      * @param  matrix The matrix to multiply to this matrix.
@@ -423,7 +448,7 @@ public abstract class MatrixSIS implemen
      * @return The inverse of this matrix.
      * @throws NoninvertibleMatrixException if this matrix is not invertible.
      *
-     * @see java.awt.geom.AffineTransform#createInverse()
+     * @see AffineTransform#createInverse()
      */
     public MatrixSIS inverse() throws NoninvertibleMatrixException {
         return Solver.inverse(this, true);

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConformal.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConformal.java?rev=1674095&r1=1674094&r2=1674095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConformal.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConformal.java [UTF-8] Thu Apr 16 15:40:27 2015
@@ -106,8 +106,10 @@ public class LambertConformal extends No
     @Workaround(library="JDK", version="1.7")
     private LambertConformal(final OperationMethod method, final Parameters parameters, final byte type) {
         super(method, parameters, null,
-                (type == SP1) ? LambertConformal1SP.FALSE_EASTING  : LambertConformal2SP.EASTING_AT_FALSE_ORIGIN,
-                (type == SP1) ? LambertConformal1SP.FALSE_NORTHING : LambertConformal2SP.NORTHING_AT_FALSE_ORIGIN);
+                (type == SP1) ? LambertConformal1SP.CENTRAL_MERIDIAN : LambertConformal2SP.LONGITUDE_OF_FALSE_ORIGIN,
+                LambertConformal1SP.SCALE_FACTOR,
+                (type == SP1) ? LambertConformal1SP.FALSE_EASTING    : LambertConformal2SP.EASTING_AT_FALSE_ORIGIN,
+                (type == SP1) ? LambertConformal1SP.FALSE_NORTHING   : LambertConformal2SP.NORTHING_AT_FALSE_ORIGIN);
         double φ0 = getAndStore(parameters,
                 (type == SP1) ? LambertConformal1SP.LATITUDE_OF_ORIGIN : LambertConformal2SP.LATITUDE_OF_FALSE_ORIGIN);
         /*
@@ -160,8 +162,8 @@ public class LambertConformal extends No
          * the linear operations in the (de)normalize affine transforms:
          *
          * Normalization:
-         *   - Subtract central meridian to longitudes.
-         *   - Convert longitudes and latitudes from degrees to radians
+         *   - Subtract central meridian to longitudes (done by the super-class constructor).
+         *   - Convert longitudes and latitudes from degrees to radians (done by the super-class constructor)
          *   - Multiply longitude by 'n'.
          *   - In the Belgium case only, subtract BELGE_A to the scaled longitude.
          *
@@ -169,20 +171,16 @@ public class LambertConformal extends No
          *   - Revert the sign of y (by negating the factor F).
          *   - Scale x and y by F.
          *   - Translate y by ρ0.
-         *   - Multiply by the scale factor.
+         *   - Multiply by the scale factor (done by the super-class constructor).
          *   - Add false easting and fasle northing (done by the super-class constructor).
          */
-        context.getMatrix(true).concatenate(0, new DoubleDouble(-n, 0),      // Multiplication factor for longitudes.
+        context.getMatrix(true).convertAfter(0, new DoubleDouble(-n, 0),    // Multiplication factor for longitudes.
                 (type == BELGIUM) ? new DoubleDouble(-BELGE_A, 0) : null);  // Longitude translation for Belgium.
-        context.normalizeGeographicInputs(getAndStore(parameters,
-                (type == SP1) ? LambertConformal1SP.CENTRAL_MERIDIAN
-                              : LambertConformal2SP.LONGITUDE_OF_FALSE_ORIGIN));
 
-        final double k0 = getAndStore(parameters, LambertConformal1SP.SCALE_FACTOR);
-        final MatrixSIS denormalize = context.scaleAndTranslate2D(false, k0, 0, 0);
-        denormalize.concatenate(0, F, null);
+        final MatrixSIS denormalize = context.getMatrix(false);
+        denormalize.convertBefore(0, F, null);
         F.negate();
-        denormalize.concatenate(1, F, ρ0);
+        denormalize.convertBefore(1, F, ρ0);
     }
 
     /**

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=1674095&r1=1674094&r2=1674095&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] Thu Apr 16 15:40:27 2015
@@ -132,8 +132,8 @@ public class Mercator extends Normalized
      */
     @Workaround(library="JDK", version="1.7")
     private Mercator(final OperationMethod method, final Parameters parameters, final byte type) {
-        super(method, parameters,
-                (type == SPHERICAL) ? Mercator2SP     .STANDARD_PARALLEL        : null,     // See note below.
+        super(method, parameters, // Rational for the 2 next arguments are explained in comments later.
+                (type == SPHERICAL) ? Mercator2SP.STANDARD_PARALLEL : null, null, Mercator1SP.SCALE_FACTOR,
                 (type == REGIONAL ) ? RegionalMercator.EASTING_AT_FALSE_ORIGIN  : Mercator1SP.FALSE_EASTING,
                 (type == REGIONAL ) ? RegionalMercator.NORTHING_AT_FALSE_ORIGIN : Mercator1SP.FALSE_NORTHING);
         /*
@@ -175,13 +175,12 @@ public class Mercator extends Normalized
          * if they really want, since we sometime see such CRS definitions.
          */
         final double φ1 = toRadians(getAndStore(parameters, Mercator2SP.STANDARD_PARALLEL));
-        double k0 = getAndStore(parameters, Mercator1SP.SCALE_FACTOR);
-        k0 *= cos(φ1) / rν(sin(φ1));
+        final DoubleDouble k0 = new DoubleDouble(cos(φ1), 0);
+        k0.divide(rν(sin(φ1)), 0);
         /*
          * In principle we should rotate the central meridian (λ0) in the normalization transform, as below:
          *
-         *     context.normalizeGeographicInputs(λ0);
-         *     context.scaleAndTranslate2D(false, k0, 0, 0);
+         *     context.normalizeGeographicInputs(λ0);   // Actually done by the super-class constructor.
          *
          * However in the particular case of Mercator projection, we will apply the longitude rotation in the
          * denormalization matrix instead.   This is possible only for this particular projection because the
@@ -189,19 +188,20 @@ public class Mercator extends Normalized
          * simple as possible, we increase the chances of efficient concatenation of an inverse with a forward
          * projection.
          */
-        final MatrixSIS   normalize = context.normalizeGeographicInputs(0);
-        final MatrixSIS denormalize = context.scaleAndTranslate2D(false, k0, 0, 0);
+        final MatrixSIS denormalize = context.getMatrix(false);
+        denormalize.convertBefore(0, k0, null);
+        denormalize.convertBefore(1, k0, null);
         if (λ0 != 0) {
             final DoubleDouble offset = DoubleDouble.createDegreesToRadians();
             offset.multiply(-λ0);
-            denormalize.concatenate(0, null, offset);
+            denormalize.convertBefore(0, null, offset);
         }
         if (φ0 != 0) {
-            denormalize.concatenate(1, null, new DoubleDouble(-log(expOfNorthing(φ0, excentricity * sin(φ0)))));
+            denormalize.convertBefore(1, null, new DoubleDouble(-log(expOfNorthing(φ0, excentricity * sin(φ0)))));
         }
         if (type == MILLER) {
-            normalize  .concatenate(1, new DoubleDouble(0.8),  null);
-            denormalize.concatenate(1, new DoubleDouble(1.25), null);
+            context.getMatrix(true).convertBefore(1, new DoubleDouble(0.8), null);
+            denormalize.convertBefore(1, new DoubleDouble(1.25), null);
         }
     }
 

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java?rev=1674095&r1=1674094&r2=1674095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] Thu Apr 16 15:40:27 2015
@@ -25,6 +25,7 @@ import org.opengis.parameter.ParameterVa
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.GeneralParameterDescriptor;
+import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransform2D;
@@ -39,10 +40,12 @@ import org.apache.sis.parameter.Paramete
 import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.referencing.operation.transform.AbstractMathTransform2D;
 import org.apache.sis.referencing.operation.transform.ContextualParameters;
 import org.apache.sis.internal.referencing.provider.MapProjection;
 import org.apache.sis.internal.referencing.Formulas;
+import org.apache.sis.internal.util.DoubleDouble;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.Numerics;
 
@@ -69,8 +72,7 @@ import java.util.Objects;
  *   <li>On output, the {@link #transform(double[],int,double[],int,boolean) transform(…)} method returns
  *   (<var>x</var>, <var>y</var>) values on a sphere or ellipse having a semi-major axis length (<var>a</var>) of 1.
  *   The multiplication by the scale factor (<var>k</var>₀) and the translation by false easting (FE) and false
- *   northing (FN) are applied by the {@linkplain ContextualParameters#scaleAndTranslate2D denormalization}
- *   affine transform.</li>
+ *   northing (FN) are applied by the {@linkplain ContextualParameters#getMatrix denormalization} affine transform.</li>
  * </ul>
  *
  * The normalization and denormalization steps are represented below by the matrices immediately on the left and right
@@ -121,6 +123,7 @@ import java.util.Objects;
  * @version 0.6
  * @module
  *
+ * @see ContextualParameters
  * @see <a href="http://mathworld.wolfram.com/MapProjection.html">Map projections on MathWorld</a>
  */
 public abstract class NormalizedProjection extends AbstractMathTransform2D implements Serializable {
@@ -197,42 +200,58 @@ public abstract class NormalizedProjecti
      *   </li>
      *   <li>On the <b>denormalization</b> matrix (to be applied after {@code this} transform):
      *     <ul>
-     *       <li>{@linkplain ContextualParameters#scaleAndTranslate2D(boolean, double, double, double) Scale}
-     *           by the <cite>semi-major</cite> axis length.</li>
+     *       <li>{@linkplain MatrixSIS#convertAfter(int, Number, Number) Scale} by the <cite>semi-major</cite> axis length.</li>
+     *       <li>If a scale factor is present (not all map projections have a scale factor), apply that scale.</li>
      *       <li>Translate by the <cite>false easting</cite> and <cite>false northing</cite> (after the scale).</li>
      *     </ul>
      *   </li>
      *   <li>On the <b>contextual parameters</b> (not the parameters of {@code this} transform):
      *     <ul>
      *       <li>Store the values for <cite>semi-major</cite> axis length, <cite>semi-minor</cite> axis length,
-     *           <cite>central meridian</cite>, <cite>false easting</cite> and <cite>false northing</cite> values.</li>
+     *         <cite>scale factor</cite> (if present), <cite>central meridian</cite>,
+     *         <cite>false easting</cite> and <cite>false northing</cite> values.</li>
      *     </ul>
      *   </li>
      * </ul>
      *
+     * In matrix form, this constructor creates the following matrices (subclasses are free to modify):
+     * <table class="sis" style="td {vertical-align: middle}">
+     *   <caption>Initial matrix coefficients after construction</caption>
+     *   <tr>
+     *     <th>Normalization</th>
+     *     <th>Denormalization</th>
+     *   </tr>
+     *   <tr>
+     *     <td>{@include ../transform/formulas.html#NormalizeGeographic}</td>
+     *     <td>{@include ../transform/formulas.html#DenormalizeCartesian}</td>
+     *   </tr>
+     * </table>
+     *
      * <div class="section">Pre-requite</div>
-     * The parameters of the given {@code method} argument shall contains descriptor for the given parameters
+     * The parameters of the given {@code method} argument shall contains descriptors for the given parameters
      * (using OGC names):
      * <ul>
      *   <li>{@code "semi_major"}       (mandatory)</li>
      *   <li>{@code "semi_minor"}       (mandatory)</li>
-     *   <li>{@code "central_meridian"} (optional, default to 0°)</li>
-     *   <li>{@code "false_easting"}    (optional, default to 0 metre)</li>
-     *   <li>{@code "false_northing"}   (optional, default to 0 metre)</li>
+     *   <li>{@code "central_meridian"} default to 0°)</li>
+     *   <li>{@code "scale_factor"}     (optional, default to 1)</li>
+     *   <li>{@code "false_easting"}    (default to 0 metre)</li>
+     *   <li>{@code "false_northing"}   (default to 0 metre)</li>
      * </ul>
      *
      * <div class="note"><b>Note:</b>
      * Apache SIS uses EPSG names as much as possible, but this constructor is an exception to this rule.
      * In this particular case we use OGC names because they are identical for a wide range of projections.
-     * For example there is at least two different EPSG names for the <cite>false northing</cite> parameter,
+     * For example there is at least three different EPSG names for the <cite>scale factor</cite> parameter,
      * depending on the projection:
      *
      * <ul>
-     *   <li><cite>Northing at false origin</cite></li>
-     *   <li><cite>Northing at projection centre</cite></li>
+     *   <li><cite>Scale factor at natural origin</cite></li>
+     *   <li><cite>Scale factor on initial line</cite></li>
+     *   <li><cite>Scale factor on pseudo standard parallel</cite></li>
      * </ul>
      *
-     * OGC defines only {@code "false_northing"} for all, which makes a convenient name to look for in this
+     * OGC defines only {@code "scale_factor"} for all, which makes a convenient name to look for in this
      * constructor.</div>
      *
      * @param method     Description of the map projection parameters.
@@ -240,9 +259,10 @@ public abstract class NormalizedProjecti
      */
     protected NormalizedProjection(final OperationMethod method, final Parameters parameters) {
         this(method, parameters, null,
+                descriptor(method, Constants.CENTRAL_MERIDIAN),
+                descriptor(method, Constants.SCALE_FACTOR),     // Optional (handled in a special way).
                 descriptor(method, Constants.FALSE_EASTING),
                 descriptor(method, Constants.FALSE_NORTHING));
-        context.normalizeGeographicInputs(getAndStore(parameters, descriptor(method, Constants.CENTRAL_MERIDIAN)));
     }
 
     /**
@@ -251,18 +271,23 @@ public abstract class NormalizedProjecti
      */
     private static ParameterDescriptor<Double> descriptor(final OperationMethod method, final String name) {
         ensureNonNull("method", method);
-        return Parameters.cast((ParameterDescriptor<?>) method.getParameters().descriptor(name), Double.class);
+        final GeneralParameterDescriptor p;
+        try {
+            p = method.getParameters().descriptor(name);
+        } catch (ParameterNotFoundException e) {
+            if (name == Constants.SCALE_FACTOR) {   // Identity comparison is okay here.
+                return null;
+            }
+            throw e;
+        }
+        return Parameters.cast((ParameterDescriptor<?>) p, Double.class);
     }
 
     /**
      * Constructs a new map projection by fetching the values using the given parameter descriptors.
-     * At the difference of the {@link #NormalizedProjection(OperationMethod, Parameters)} constructor,
-     * this constructor does <strong>not</strong> apply the following operations:
-     *
-     * <ul>
-     *   <li>Normalization: no operation done. Callers shall invoke
-     *     {@link ContextualParameters#normalizeGeographicInputs(double)} themselves.</li>
-     * </ul>
+     * This constructor is equivalent to the {@link #NormalizedProjection(OperationMethod, Parameters)} constructor,
+     * except that the descriptors are explicitely specified. Note that the list of arguments may change in any future
+     * SIS version.
      *
      *
      * <div class="section">Radius of conformal sphere (Rc)</div>
@@ -271,7 +296,7 @@ public abstract class NormalizedProjecti
      * <cite>Geomatics Guidance Note Number 7, part 2, version 49</cite> from EPSG: table 3 in section
      * 1.2 and explanation in section 1.3.3.1).
      *
-     * <p><b>Important usage notes:</b><p>
+     * <p><b>Important usage notes:</b></p>
      * <ul>
      *   <li>The {@code conformalSphereAtφ} argument shall be non-null <strong>only</strong> when the user
      *       requested explicitely spherical formulas, for example the <cite>"Mercator (Spherical)"</cite>
@@ -286,13 +311,17 @@ public abstract class NormalizedProjecti
      */
     NormalizedProjection(final OperationMethod method, final Parameters parameters,
             final ParameterDescriptor<Double> conformalSphere_φ,
+            final ParameterDescriptor<Double> centralMeridian,
+            final ParameterDescriptor<Double> scaleFactor,
             final ParameterDescriptor<Double> falseEasting,
             final ParameterDescriptor<Double> falseNorthing)
     {
         ensureNonNull("parameters", parameters);
         context = new ContextualParameters(method);
+
               double a  = getAndStore(parameters, MapProjection.SEMI_MAJOR);
         final double b  = getAndStore(parameters, MapProjection.SEMI_MINOR);
+        final double λ0 = getAndStore(parameters, centralMeridian);
         final double fe = getAndStore(parameters, falseEasting);
         final double fn = getAndStore(parameters, falseNorthing);
         final double rs = b / a;
@@ -313,7 +342,14 @@ public abstract class NormalizedProjecti
             final double sinφ = sin(toRadians(parameters.doubleValue(conformalSphere_φ)));
             a = b / (1 - excentricitySquared * (sinφ*sinφ));
         }
-        context.scaleAndTranslate2D(false, a, fe, fn);
+        context.normalizeGeographicInputs(λ0);
+        final DoubleDouble k = new DoubleDouble(a);
+        if (scaleFactor != null) {
+            k.multiply(getAndStore(parameters, scaleFactor));
+        }
+        final MatrixSIS denormalize = context.getMatrix(false);
+        denormalize.convertAfter(0, k, new DoubleDouble(fe));
+        denormalize.convertAfter(1, k, new DoubleDouble(fn));
         inverse = new Inverse();
     }
 
@@ -372,6 +408,9 @@ public abstract class NormalizedProjecti
      * This method shall be invoked at construction time only.
      */
     final double getAndStore(final Parameters parameters, final ParameterDescriptor<Double> descriptor) {
+        if (descriptor == null) {
+            return 0;   // Default value for all parameters except scale factor.
+        }
         final double value = parameters.doubleValue(descriptor);    // Apply a unit conversion if needed.
         final Double defaultValue = descriptor.getDefaultValue();
         if (defaultValue == null || !defaultValue.equals(value)) {

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java?rev=1674095&r1=1674094&r2=1674095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java [UTF-8] Thu Apr 16 15:40:27 2015
@@ -122,7 +122,7 @@
  * <ul>
  *   <li>A {@linkplain org.apache.sis.referencing.operation.transform.ContextualParameters#normalizeGeographicInputs normalization} affine transform</li>
  *   <li>A {@link      org.apache.sis.referencing.operation.projection.NormalizedProjection} subclass</li>
- *   <li>A {@linkplain org.apache.sis.referencing.operation.transform.ContextualParameters#scaleAndTranslate2D denormalization} affine transform</li>
+ *   <li>A {@linkplain org.apache.sis.referencing.operation.transform.ContextualParameters#getMatrix denormalization} affine transform</li>
  * </ul>
  *
  * The first step (<cite>"normalization"</cite>) converts longitude and latitude values from degrees to radians

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=1674095&r1=1674094&r2=1674095&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] Thu Apr 16 15:40:27 2015
@@ -98,8 +98,8 @@ import static org.apache.sis.util.Argume
  *     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 #normalizeGeographicInputs normalizeGeographicInputs(…)}
- *     and {@link #scaleAndTranslate2D scaleAndTranslate2D(…)} methods, which will create the matrices show above.
+ *     and gives the linear parameters to the {@link #normalizeGeographicInputs normalizeGeographicInputs(…)} and
+ *     {@link MatrixSIS#convertAfter MatrixSIS.convertAfter(…)} methods, which will create the matrices show above.
  *     The projection constructor is free to apply additional operations on the two affine transforms
  *     ({@linkplain #getMatrix(boolean) normalize / denormalize}) before or after the above-cited
  *     methods have been invoked.</li>
@@ -240,21 +240,39 @@ public class ContextualParameters extend
 
     /**
      * Returns the affine transforms to be applied before or after the non-linear kernel operation.
-     *
-     * <p>Immediately after {@linkplain #ContextualParameters(OperationMethod) construction}, those matrices
+     * Immediately after {@linkplain #ContextualParameters(OperationMethod) construction}, those matrices
      * are modifiable identity matrices. Callers can modify the matrix element values, typically by calls to
-     * the {@link MatrixSIS#concatenate(int, Number, Number) MatrixSIS.concatenate(…)} method. Alternatively,
-     * the following methods can be invoked for applying some frequently used configurations:
+     * the {@link MatrixSIS#convertBefore(int, Number, Number) MatrixSIS.convertBefore(…)} method.
+     * Alternatively, the following methods can be invoked for applying some frequently used configurations:
      *
      * <ul>
      *   <li>{@link #normalizeGeographicInputs(double)}</li>
      *   <li>{@link #denormalizeGeographicOutputs(double)}</li>
-     *   <li>{@link #scaleAndTranslate2D(boolean, double, double, double)}</li>
      * </ul>
      *
      * After the {@link #completeTransform(MathTransformFactory, MathTransform) completeTransform(…)} method has been
      * invoked, the matrices returned by this method are {@linkplain Matrices#unmodifiable(Matrix) unmodifiable}.
      *
+     *
+     * <div class="section">Application to map projections</div>
+     * After {@link org.apache.sis.referencing.operation.projection.NormalizedProjection} construction,
+     * those matrices are initialized to the following values:
+     *
+     * <table class="sis" style="td {vertical-align: middle}">
+     *   <caption>Initial matrix coefficients after construction</caption>
+     *   <tr>
+     *     <th>{@code getMatrix(true)}</th>
+     *     <th>{@code getMatrix(false)}</th>
+     *   </tr><tr>
+     *     <td>{@include formulas.html#NormalizeGeographic}</td>
+     *     <td>{@include formulas.html#DenormalizeCartesian}</td>
+     *   </tr>
+     * </table>
+     *
+     * <div class="note"><b>Note:</b>
+     * Some {@code NormalizedProjection} subclasses apply further modifications on those matrices.
+     * </div>
+     *
      * @param  norm {@code true} for fetching the <cite>normalization</cite> transform to apply before the kernel,
      *         or {@code false} for the <cite>denormalization</cite> transform to apply after the kernel.
      * @return The matrix for the requested normalization ({@code true}) or denormalization ({@code false}) affine transform.
@@ -269,43 +287,6 @@ public class ContextualParameters extend
     }
 
     /**
-     * Concatenates a uniform two-dimensional scale and a translation to the (de)normalization matrix.
-     * The scale and translations are applied only on the two first dimensions.
-     *
-     * <div class="section">Application to map projections</div>
-     * In map projections, the scale is the <cite>semi-major</cite> axis length (<var>a</var>) – potentially multiplied
-     * by an other scale factor <var>k</var>₀ – and the translation terms are the <cite>false easting</cite> (FE) and
-     * <cite>false northing</cite> (FN). The following method invocation:
-     *
-     * {@preformat java
-     *   scaleAndTranslate2D(false, a*k0, FE, FN);
-     * }
-     *
-     * is then equivalent to {@linkplain java.awt.geom.AffineTransform#concatenate concatenating} the denormalization
-     * matrix with the following matrix. This will have the effect of applying the conversion described above after
-     * the non-linear kernel operation.
-     *
-     * <center>{@include formulas.html#DenormalizeCartesian}</center>
-     *
-     * @param  norm  {@code true} to apply the scale and translations on the <cite>normalize</cite> transform,
-     *               or {@code false} to apply them on the <cite>denormalize</cite> transform.
-     * @param  scale The scale to apply on the 2 first axes.
-     * @param  tx    The translation to apply on the <var>x</var> axis after the scale.
-     * @param  ty    The translation to apply on the <var>y</var> axis after the scale.
-     * @return The (de)normalization affine transform as a matrix.
-     *         Callers can change that matrix directly if they want to apply additional (de)normalization operations.
-     * @throws IllegalStateException if this {@code ContextualParameter} has been made unmodifiable.
-     */
-    public MatrixSIS scaleAndTranslate2D(final boolean norm, double scale, double tx, double ty) {
-        ensureModifiable();
-        final MatrixSIS m = (MatrixSIS) (norm ? normalize : denormalize);  // Must be the same instance, not a copy.
-        final DoubleDouble s = (scale != 1) ? new DoubleDouble(scale) : null;
-        m.concatenate(0, s, (tx != 0) ? tx : null);
-        m.concatenate(1, s, (ty != 0) ? ty : null);
-        return m;
-    }
-
-    /**
      * Prepends a normalization step converting input ordinates in the two first dimensions from degrees to radians.
      * The normalization can optionally subtract the given λ₀ value (in degrees) from the longitude.
      *
@@ -333,8 +314,8 @@ public class ContextualParameters extend
             offset.multiply(toRadians);
         }
         final MatrixSIS normalize = (MatrixSIS) this.normalize;  // Must be the same instance, not a copy.
-        normalize.concatenate(0, toRadians, offset);
-        normalize.concatenate(1, toRadians, null);
+        normalize.convertBefore(0, toRadians, offset);
+        normalize.convertBefore(1, toRadians, null);
         return normalize;
     }
 
@@ -358,8 +339,8 @@ public class ContextualParameters extend
         ensureModifiable();
         final DoubleDouble toDegrees = DoubleDouble.createRadiansToDegrees();
         final MatrixSIS denormalize = (MatrixSIS) this.denormalize;  // Must be the same instance, not a copy.
-        denormalize.concatenate(0, toDegrees, (λ0 != 0) ? λ0 : null);
-        denormalize.concatenate(1, toDegrees, null);
+        denormalize.convertAfter(0, toDegrees, (λ0 != 0) ? λ0 : null);
+        denormalize.convertAfter(1, toDegrees, null);
         return denormalize;
     }
 

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java?rev=1674095&r1=1674094&r2=1674095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java [UTF-8] Thu Apr 16 15:40:27 2015
@@ -95,14 +95,26 @@ public final strictfp class GeneralMatri
     }
 
     /**
-     * Tests {@link MatrixSIS#concatenate(int, Number, Number)} using {@link AffineTranform}
+     * Tests {@link MatrixSIS#convertBefore(int, Number, Number)} using {@link AffineTranform}
      * as a reference implementation.
      *
      * @since 0.6
      */
     @Test
-    public void testConcatenate() {
-        testConcatenate(new GeneralMatrix(3, 3, true, 1), true);    // Double precision
-        testConcatenate(new GeneralMatrix(3, 3, true, 2), true);    // Double-double precision
+    public void testConvertBefore() {
+        testConvertBefore(new GeneralMatrix(3, 3, true, 1), true);    // Double precision
+        testConvertBefore(new GeneralMatrix(3, 3, true, 2), true);    // Double-double precision
+    }
+
+    /**
+     * Tests {@link MatrixSIS#convertAfter(int, Number, Number)} using {@link AffineTranform}
+     * as a reference implementation.
+     *
+     * @since 0.6
+     */
+    @Test
+    public void testConvertAfter() {
+        testConvertAfter(new GeneralMatrix(3, 3, true, 1));    // Double precision
+        testConvertAfter(new GeneralMatrix(3, 3, true, 2));    // Double-double precision
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java?rev=1674095&r1=1674094&r2=1674095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java [UTF-8] Thu Apr 16 15:40:27 2015
@@ -102,13 +102,24 @@ public final strictfp class Matrix3Test
     }
 
     /**
-     * Tests {@link MatrixSIS#concatenate(int, Number, Number)} using {@link AffineTranform}
+     * Tests {@link MatrixSIS#convertBefore(int, Number, Number)} using {@link AffineTranform}
      * as a reference implementation.
      *
      * @since 0.6
      */
     @Test
-    public void testConcatenate() {
-        testConcatenate(new Matrix3(), true);
+    public void testConvertBefore() {
+        testConvertBefore(new Matrix3(), true);
+    }
+
+    /**
+     * Tests {@link MatrixSIS#convertAfter(int, Number, Number)} using {@link AffineTranform}
+     * as a reference implementation.
+     *
+     * @since 0.6
+     */
+    @Test
+    public void testConvertAfter() {
+        testConvertAfter(new Matrix3());
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java?rev=1674095&r1=1674094&r2=1674095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] Thu Apr 16 15:40:27 2015
@@ -397,9 +397,9 @@ public abstract strictfp class MatrixTes
     }
 
     /**
-     * Tests {@link MatrixSIS#concatenate(int, Number, Number)} using {@link AffineTranform}
+     * Tests {@link MatrixSIS#convertBefore(int, Number, Number)} using {@link AffineTranform}
      * as a reference implementation. This test can be run only with matrices of size 3×3.
-     * Consequently it is sub-classes responsibility to add a {@code testConcatenate()} method
+     * Consequently it is sub-classes responsibility to add a {@code testConvertBefore()} method
      * which invoke this method.
      *
      * @param matrix The matrix of size 3×3 to test.
@@ -408,7 +408,7 @@ public abstract strictfp class MatrixTes
      *
      * @since 0.6
      */
-    final void testConcatenate(final MatrixSIS matrix, final boolean withShear) {
+    final void testConvertBefore(final MatrixSIS matrix, final boolean withShear) {
         initialize(4599164481916500056L);
         final AffineTransform at = new AffineTransform();
         if (withShear) {
@@ -445,19 +445,60 @@ public abstract strictfp class MatrixTes
             /*
              * Apply the operation and compare with our reference implementation.
              */
-            matrix.concatenate(srcDim, scale, offset);
-            final String message = (offset == null) ? "After scale" :
-                                   (scale  == null) ? "After translate" : "After scale and translate";
-            assertEqualsRelative(message, 0,                  matrix, 2, 0);
-            assertEqualsRelative(message, 0,                  matrix, 2, 1);
-            assertEqualsRelative(message, 1,                  matrix, 2, 2);
-            assertEqualsRelative(message, at.getTranslateX(), matrix, 0, 2);
-            assertEqualsRelative(message, at.getTranslateY(), matrix, 1, 2);
-            assertEqualsRelative(message, at.getScaleX(),     matrix, 0, 0);
-            assertEqualsRelative(message, at.getScaleY(),     matrix, 1, 1);
-            assertEqualsRelative(message, at.getShearX(),     matrix, 0, 1);
-            assertEqualsRelative(message, at.getShearY(),     matrix, 1, 0);
-            assertTrue("isAffine", matrix.isAffine());
+            matrix.convertBefore(srcDim, scale, offset);
+            assertCoefficientsEqual(at, matrix);
+        }
+    }
+
+    /**
+     * Asserts that the given matrix has approximatively the same coefficients than the given affine transform.
+     */
+    private static void assertCoefficientsEqual(final AffineTransform at, final MatrixSIS matrix) {
+        assertEqualsRelative("m20",        0,                  matrix, 2, 0);
+        assertEqualsRelative("m21",        0,                  matrix, 2, 1);
+        assertEqualsRelative("m22",        1,                  matrix, 2, 2);
+        assertEqualsRelative("translateX", at.getTranslateX(), matrix, 0, 2);
+        assertEqualsRelative("translateY", at.getTranslateY(), matrix, 1, 2);
+        assertEqualsRelative("scaleX",     at.getScaleX(),     matrix, 0, 0);
+        assertEqualsRelative("scaleY",     at.getScaleY(),     matrix, 1, 1);
+        assertEqualsRelative("shearX",     at.getShearX(),     matrix, 0, 1);
+        assertEqualsRelative("shearY",     at.getShearY(),     matrix, 1, 0);
+        assertTrue("isAffine", matrix.isAffine());
+    }
+
+    /**
+     * Tests {@link MatrixSIS#convertAfter(int, Number, Number)} using {@link AffineTranform}
+     * as a reference implementation. This test can be run only with matrices of size 3×3.
+     * Consequently it is sub-classes responsibility to add a {@code testConvertAfter()} method
+     * which invoke this method.
+     *
+     * @param matrix The matrix of size 3×3 to test.
+     *
+     * @since 0.6
+     */
+    final void testConvertAfter(final MatrixSIS matrix) {
+        initialize(6501103578268988251L);
+        final AffineTransform pre = new AffineTransform();
+        final AffineTransform at = AffineTransform.getShearInstance(nextNonZeroRandom(), nextNonZeroRandom());
+        matrix.setElement(0, 1, at.getShearX());
+        matrix.setElement(1, 0, at.getShearY());
+        for (int i=0; i<30; i++) {
+            final Number scale  = nextNonZeroRandom();
+            final Number offset = nextNonZeroRandom();
+            final int tgtDim = (i & 1);
+            switch (tgtDim) {
+                default: pre.setToIdentity();
+                         break;
+                case 0:  pre.setToTranslation(offset.doubleValue(), 0);
+                         pre.scale(scale.doubleValue(), 1);
+                         break;
+                case 1:  pre.setToTranslation(0, offset.doubleValue());
+                         pre.scale(1, scale.doubleValue());
+                         break;
+            }
+            at.preConcatenate(pre);
+            matrix.convertAfter(tgtDim, scale, offset);
+            assertCoefficientsEqual(at, matrix);
         }
     }
 

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java?rev=1674095&r1=1674094&r2=1674095&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/NoOp.java [UTF-8] Thu Apr 16 15:40:27 2015
@@ -20,7 +20,6 @@ import java.util.Collections;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.operation.Matrix;
-import org.apache.sis.internal.referencing.provider.MapProjection;
 import org.apache.sis.referencing.operation.DefaultOperationMethod;
 import org.apache.sis.parameter.ParameterBuilder;
 import org.apache.sis.parameter.Parameters;
@@ -57,9 +56,7 @@ final strictfp class NoOp extends Normal
     private NoOp(final Parameters parameters) {
         super(new DefaultOperationMethod(
                 Collections.singletonMap(DefaultOperationMethod.NAME_KEY, parameters.getDescriptor().getName()),
-                2, 2, parameters.getDescriptor()), parameters, null,
-                MapProjection.SEMI_MAJOR,   // Should actually by FALSE_EASTING,  but we do not care for this test.
-                MapProjection.SEMI_MINOR);  // Should actually by FALSE_NORTHING, but we do not care for this test.
+                2, 2, parameters.getDescriptor()), parameters, null, null, null, null, null);
     }
 
     /**



Mime
View raw message