sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1817597 [8/19] - in /sis/branches/ISO-19115-3: ./ application/ application/sis-console/ application/sis-console/src/main/artifact/ application/sis-console/src/main/artifact/lib/ application/sis-console/src/main/artifact/lib/darwin/ applica...
Date Sat, 09 Dec 2017 10:57:47 GMT
Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/CylindricalEqualArea.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -228,27 +228,27 @@ public class CylindricalEqualArea extend
     }
 
     /**
-     * Converts a list of coordinate point ordinal values.
-     *
-     * <div class="note"><b>Note:</b>
-     * We override the super-class method only as an optimization in the special case where the target coordinates
-     * are written at the same locations than the source coordinates. In such case, we can take advantage of the
-     * fact that the λ values are not modified by the normalized Cylindrical Equal Area projection.</div>
+     * Converts a list of coordinate points. This method performs the same calculation than above
+     * {@link #transform(double[], int, double[], int, boolean)} method, but is overridden for efficiency.
      *
      * @throws TransformException if a point can not be converted.
      */
     @Override
     public void transform(final double[] srcPts, int srcOff,
-                          final double[] dstPts, int dstOff, int numPts)
-            throws TransformException
+                          final double[] dstPts, int dstOff, int numPts) throws TransformException
     {
-        if (srcPts != dstPts || srcOff != dstOff) {
+        if (srcPts != dstPts || srcOff != dstOff || getClass() != CylindricalEqualArea.class) {
             super.transform(srcPts, srcOff, dstPts, dstOff, numPts);
         } else {
+            /*
+             * Override the super-class method only as an optimization in the special case where the target coordinates
+             * are written at the same locations than the source coordinates. In such case, we can take advantage of
+             * the fact that the λ values are not modified by the normalized Cylindrical Equal Area projection.
+             */
             dstOff--;
             while (--numPts >= 0) {
-                final double φ = dstPts[dstOff += 2];                   // Same as srcPts[srcOff + 1].
-                dstPts[dstOff] = qm_ellipsoid(sin(φ));                  // Part of Synder equation (10-15)
+                final double φ = dstPts[dstOff += DIMENSION];           // Same as srcPts[srcOff + 1].
+                dstPts[dstOff] = qm_ellipsoid(sin(φ));                  // Part of Snyder equation (10-15)
             }
         }
     }
@@ -268,7 +268,7 @@ public class CylindricalEqualArea extend
         dstPts[dstOff  ] = srcPts[srcOff  ];            // Must be before writing y.
         dstPts[dstOff+1] = φ(y);
         /*
-         * Equation 10-26 of Synder gives β = asin(2y⋅k₀/(a⋅qPolar)).
+         * Equation 10-26 of Snyder gives β = asin(2y⋅k₀/(a⋅qPolar)).
          * In our case it simplifies to sinβ = (y/qmPolar) because:
          *
          *   - y is already multiplied by 2k₀/a because of the denormalization matrix
@@ -299,7 +299,7 @@ public class CylindricalEqualArea extend
          */
         Spherical(final CylindricalEqualArea other) {
             super(other);
-            context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION).convertAfter(1, 2, null);
+            context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION).convertAfter(1, DIMENSION, null);
         }
 
         /**
@@ -322,8 +322,8 @@ public class CylindricalEqualArea extend
          * {@inheritDoc}
          *
          * <div class="note"><b>Note:</b>
-         * This method must be overridden because the {@link Mercator} class overrides the {@link NormalizedProjection}
-         * default implementation.</div>
+         * This method must be overridden because the {@link CylindricalEqualArea} class
+         * overrides the {@link NormalizedProjection} default implementation.</div>
          */
         @Override
         public void transform(final double[] srcPts, int srcOff,
@@ -335,7 +335,7 @@ public class CylindricalEqualArea extend
             } else {
                 dstOff--;
                 while (--numPts >= 0) {
-                    final double φ = dstPts[dstOff += 2];           // Same as srcPts[srcOff + 1].
+                    final double φ = dstPts[dstOff += DIMENSION];       // Same as srcPts[srcOff + 1].
                     dstPts[dstOff] = sin(φ);
                 }
             }

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/EqualAreaProjection.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/EqualAreaProjection.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/EqualAreaProjection.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/EqualAreaProjection.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -39,7 +39,7 @@ abstract class EqualAreaProjection exten
     private static final long serialVersionUID = -6175270149094989517L;
 
     /**
-     * {@code false} for using the original formulas as published by Synder, or {@code true} for using formulas
+     * {@code false} for using the original formulas as published by Snyder, or {@code true} for using formulas
      * modified using trigonometric identities. The use of trigonometric identities is for reducing the amount
      * of calls to the {@link Math#sin(double)} and similar methods. Some identities used are:
      *
@@ -54,13 +54,15 @@ abstract class EqualAreaProjection exten
      *
      *
      * <p><b>BENCHMARK AND ANALYSIS:</b>
-     * as of July 2016, benchmarking shows no benefit in using trigonometric identities for {@code EqualAreaProjection}
-     * (contrarily to {@link ConformalProjection} where we did measured a benefit). This may be because in this class,
+     * as of July 2016, benchmarking shows small benefit in using trigonometric identities for {@code EqualAreaProjection}
+     * (contrarily to {@link ConformalProjection} where we measured a greater benefit). This may be because in this class,
      * the series expansion is unconditionally followed by iterative method in order to reach the centimetric precision.
      * We observe that the original series expansion allows convergence in only one iteration, while the formulas using
-     * trigonometric identifies often requires two iterations. Consequently we disallow those modifications for now.</p>
+     * trigonometric identifies often requires two iterations.</p>
+     *
+     * @todo Redo the benchmark with JDK9, since {@code sin} seems much faster.
      */
-    private static final boolean ALLOW_TRIGONOMETRIC_IDENTITIES = false;
+    private static final boolean ALLOW_TRIGONOMETRIC_IDENTITIES = true;
 
     /**
      * Coefficients in the series expansion of the inverse projection,
@@ -191,7 +193,7 @@ abstract class EqualAreaProjection exten
     }
 
     /**
-     * Computes the latitude using equation 3-18 from Synder, followed by iterative resolution of Synder 3-16.
+     * Computes the latitude using equation 3-18 from Snyder, followed by iterative resolution of Snyder 3-16.
      * In theory, the series expansion given by equation 3-18 (φ ≈ c₂⋅sin(2β) + c₄⋅sin(4β) + c₈⋅sin(8β)) should
      * be used in replacement of the iterative method. However in practice the series expansion seems to not
      * have a sufficient amount of terms for achieving the centimetric precision, so we "finish" it by the
@@ -208,7 +210,7 @@ abstract class EqualAreaProjection exten
             φ = ci8 * sin(8*β)
               + ci4 * sin(4*β)
               + ci2 * sin(2*β)
-              + β;                                                                  // Synder 3-18
+              + β;                                                                  // Snyder 3-18
         } else {
             /*
              * Same formula than above, but rewriten using trigonometric identities in order to avoid
@@ -231,11 +233,11 @@ abstract class EqualAreaProjection exten
          * Use the iterative method for reaching the last part of missing accuracy. Usually this loop
          * will perform exactly one iteration, no more, because φ is already quite close to the result.
          *
-         * Mathematical note: Synder 3-16 gives q/(1-ℯ²) instead of y in the calculation of Δφ below.
-         * For Cylindrical Equal Area projection, Synder 10-17 gives  q = (qPolar⋅sinβ), which simplifies
+         * Mathematical note: Snyder 3-16 gives q/(1-ℯ²) instead of y in the calculation of Δφ below.
+         * For Cylindrical Equal Area projection, Snyder 10-17 gives  q = (qPolar⋅sinβ), which simplifies
          * as y.
          *
-         * For Albers Equal Area projection, Synder 14-19 gives  q = (C - ρ²n²/a²)/n,  which we rewrite
+         * For Albers Equal Area projection, Snyder 14-19 gives  q = (C - ρ²n²/a²)/n,  which we rewrite
          * as  q = (C - ρ²)/n  (see comment in AlbersEqualArea.inverseTransform(…) for the mathematic).
          * The y value given to this method is y = (C - ρ²) / (n⋅(1-ℯ²)) = q/(1-ℯ²), the desired value.
          */
@@ -251,7 +253,7 @@ abstract class EqualAreaProjection exten
             }
         }
         /*
-         * In the Albers Equal Area discussion, Synder said that above algorithm does not converge if
+         * In the Albers Equal Area discussion, Snyder said that above algorithm does not converge if
          *
          *   q = ±(1 - (1-ℯ²)/(2ℯ) ⋅ ln((1-ℯ)/(1+ℯ)))
          *
@@ -263,9 +265,9 @@ abstract class EqualAreaProjection exten
          *
          *   y  =  ±(1/(1-ℯ²) + atanh(ℯ)/ℯ)  =  ±qmPolar
          *
-         * which implies  sinβ = ±1. This is consistent with Synder discussion of Cylndrical Equal Area
+         * which implies  sinβ = ±1. This is consistent with Snyder discussion of Cylndrical Equal Area
          * projection, where he said exactly that about the same formula (that it does not converge for
-         * β = ±90°). In both case, Synder said that the result is φ = β, with the same sign.
+         * β = ±90°). In both case, Snyder said that the result is φ = β, with the same sign.
          */
         final double as = abs(sinβ);
         if (abs(as - 1) < ANGULAR_TOLERANCE) {

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/LambertConicConformal.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -58,7 +58,7 @@ import static org.apache.sis.internal.ut
  * @author  André Gosselin (MPO)
  * @author  Rueben Schulz (UBC)
  * @author  Rémi Maréchal (Geomatys)
- * @version 0.6
+ * @version 0.8
  * @since   0.6
  * @module
  */

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -32,6 +32,7 @@ import org.apache.sis.internal.referenci
 import org.apache.sis.internal.util.DoubleDouble;
 import org.apache.sis.referencing.operation.matrix.Matrix2;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.operation.transform.ContextualParameters;
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.util.Workaround;
@@ -69,7 +70,7 @@ import static org.apache.sis.internal.ut
  * @author  Rueben Schulz (UBC)
  * @author  Simon Reynard (Geomatys)
  * @author  Rémi Maréchal (Geomatys)
- * @version 0.6
+ * @version 0.8
  *
  * @see TransverseMercator
  *
@@ -372,12 +373,8 @@ public class Mercator extends ConformalP
     }
 
     /**
-     * Converts a list of coordinate point ordinal values.
-     *
-     * <div class="note"><b>Note:</b>
-     * We override the super-class method only as an optimization in the special case where the target coordinates
-     * are written at the same locations than the source coordinates. In such case, we can take advantage of the
-     * fact that the λ values are not modified by the normalized Mercator projection.</div>
+     * Converts a list of coordinate points. This method performs the same calculation than above
+     * {@link #transform(double[], int, double[], int, boolean)} method, but is overridden for efficiency.
      *
      * @throws TransformException if a point can not be converted.
      */
@@ -386,12 +383,17 @@ public class Mercator extends ConformalP
                           final double[] dstPts, int dstOff, int numPts)
             throws TransformException
     {
-        if (srcPts != dstPts || srcOff != dstOff) {
+        if (srcPts != dstPts || srcOff != dstOff || getClass() != Mercator.class) {
             super.transform(srcPts, srcOff, dstPts, dstOff, numPts);
         } else {
+            /*
+             * Override the super-class method only as an optimization in the special case where the target coordinates
+             * are written at the same locations than the source coordinates. In such case, we can take advantage of
+             * the fact that the λ values are not modified by the normalized Mercator projection.
+             */
             dstOff--;
             while (--numPts >= 0) {
-                final double φ = dstPts[dstOff += 2];                           // Same as srcPts[srcOff + 1].
+                final double φ = dstPts[dstOff += DIMENSION];                   // Same as srcPts[srcOff + 1].
                 if (φ != 0) {
                     /*
                      * See the javadoc of the Spherical inner class for a note
@@ -521,7 +523,7 @@ public class Mercator extends ConformalP
             } else {
                 dstOff--;
                 while (--numPts >= 0) {
-                    final double φ = dstPts[dstOff += 2];                       // Same as srcPts[srcOff + 1].
+                    final double φ = dstPts[dstOff += DIMENSION];               // Same as srcPts[srcOff + 1].
                     if (φ != 0) {
                         // See class javadoc for a note about explicit check for poles.
                         final double a = abs(φ);
@@ -552,4 +554,27 @@ public class Mercator extends ConformalP
             dstPts[dstOff+1] = PI/2 - 2*atan(exp(-y));              // Part of Snyder (7-4);
         }
     }
+
+    /**
+     * Invoked when {@link #tryConcatenate(boolean, MathTransform, MathTransformFactory)} detected a
+     * (inverse) → (affine) → (this) transforms sequence.
+     */
+    @Override
+    final MathTransform tryConcatenate(boolean projectedSpace, Matrix affine, MathTransformFactory factory)
+            throws FactoryException
+    {
+        /*
+         * Verify that the latitude row is an identity conversion except for the sign which is allowed to change
+         * (but no scale and no translation are allowed).  Ignore the longitude row because it just pass through
+         * this Mercator projection with no impact on any calculation.
+         */
+        if (affine.getElement(1,0) == 0 && affine.getElement(1, DIMENSION) == 0 && Math.abs(affine.getElement(1,1)) == 1) {
+            if (factory != null) {
+                return factory.createAffineTransform(affine);
+            } else {
+                return MathTransforms.linear(affine);
+            }
+        }
+        return super.tryConcatenate(projectedSpace, affine, factory);
+    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.referencing.operation.projection;
 
+import java.util.List;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Objects;
@@ -32,6 +33,7 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
 import org.opengis.util.FactoryException;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.CharSequences;
@@ -41,6 +43,8 @@ import org.apache.sis.parameter.Paramete
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.referencing.operation.transform.AbstractMathTransform;
 import org.apache.sis.referencing.operation.transform.AbstractMathTransform2D;
 import org.apache.sis.referencing.operation.transform.ContextualParameters;
 import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
@@ -49,9 +53,11 @@ import org.apache.sis.internal.referenci
 import org.apache.sis.internal.metadata.ReferencingServices;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.system.Modules;
+import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.logging.Logging;
 
 import static java.lang.Math.*;
 
@@ -117,7 +123,7 @@ import static java.lang.Math.*;
  * @author  André Gosselin (MPO)
  * @author  Rueben Schulz (UBC)
  * @author  Rémi Maréchal (Geomatys)
- * @version 0.7
+ * @version 0.8
  *
  * @see ContextualParameters
  * @see <a href="http://mathworld.wolfram.com/MapProjection.html">Map projections on MathWorld</a>
@@ -132,6 +138,15 @@ public abstract class NormalizedProjecti
     private static final long serialVersionUID = -4010883312927645853L;
 
     /**
+     * Number of input and output dimensions of all {@code NormalizedProjection}.
+     * We define this constant for clarity only; its value shall not be modified.
+     *
+     * @see #getSourceDimensions()
+     * @see #getTargetDimensions()
+     */
+    static final int DIMENSION = 2;
+
+    /**
      * Maximum difference allowed when comparing longitudes or latitudes in radians.
      * The current value takes the system-wide angular tolerance value (equivalent to
      * about 1 cm on Earth) converted to radians.
@@ -710,7 +725,7 @@ public abstract class NormalizedProjecti
      * Inverse of a normalized map projection.
      *
      * @author  Martin Desruisseaux (Geomatys)
-     * @version 0.6
+     * @version 0.8
      * @since   0.6
      * @module
      */
@@ -741,13 +756,131 @@ public abstract class NormalizedProjecti
                 return null;
             } else {
                 if (dstPts == null) {
-                    dstPts = new double[2];
+                    dstPts = new double[DIMENSION];
                     dstOff = 0;
                 }
                 inverseTransform(srcPts, srcOff, dstPts, dstOff);
                 return Matrices.inverse(NormalizedProjection.this.transform(dstPts, dstOff, null, 0, true));
             }
         }
+
+        /**
+         * Inverse transforms an arbitrary amount of coordinates. This method optimizes the
+         * case where conversions can be applied by a loop with indices in increasing order.
+         */
+        @Override
+        public void transform(final double[] srcPts, int srcOff,
+                              final double[] dstPts, int dstOff, int numPts) throws TransformException
+        {
+            if (srcPts == dstPts && srcOff < dstOff) {
+                super.transform(srcPts, srcOff, dstPts, dstOff, numPts);
+            } else while (--numPts >= 0) {
+                inverseTransform(srcPts, srcOff, dstPts, dstOff);
+                srcOff += DIMENSION;
+                dstOff += DIMENSION;
+            }
+        }
+
+        /**
+         * Concatenates or pre-concatenates in an optimized way this projection with the given transform, if possible.
+         * If no optimization is available, returns {@code null}.
+         */
+        @Override
+        protected MathTransform tryConcatenate(final boolean applyOtherFirst, final MathTransform other,
+                final MathTransformFactory factory) throws FactoryException
+        {
+            final Matrix m = getMiddleMatrix(this, other, applyOtherFirst);
+            if (m != null) {
+                /*
+                 * 'projectedSpace' values:
+                 *   - false if applyOtherFirst == false since we have (inverse projection) → (affine) → (projection).
+                 *   - true  if applyOtherFirst == true  since we have (projection) → (affine) → (inverse projection).
+                 */
+                return NormalizedProjection.this.tryConcatenate(applyOtherFirst, m, factory);
+            }
+            return super.tryConcatenate(applyOtherFirst, other, factory);
+        }
+    }
+
+    /**
+     * Concatenates or pre-concatenates in an optimized way this projection with the given transform, if possible.
+     * If transforms are concatenated in an (inverse projection) → (affine) → (projection) sequence where the
+     * (projection) and (inverse projection) steps are the {@linkplain #inverse() inverse} of each other,
+     * then in some particular case the sequence can be replaced by a single affine transform.
+     * If no such simplification is possible, this method returns {@code null}.
+     *
+     * @return the simplified (usually affine) transform, or {@code null} if no such optimization is available.
+     * @throws FactoryException if an error occurred while combining the transforms.
+     *
+     * @since 0.8
+     */
+    @Override
+    protected MathTransform tryConcatenate(final boolean applyOtherFirst, final MathTransform other,
+            final MathTransformFactory factory) throws FactoryException
+    {
+        final Matrix m = getMiddleMatrix(this, other, applyOtherFirst);
+        if (m != null) {
+            /*
+             * 'projectedSpace' values:
+             *   - false if applyOtherFirst == true  since we have (inverse projection) → (affine) → (projection).
+             *   - true  if applyOtherFirst == false since we have (projection) → (affine) → (inverse projection).
+             */
+            return tryConcatenate(!applyOtherFirst, m, factory);
+        }
+        return super.tryConcatenate(applyOtherFirst, other, factory);
+    }
+
+    /**
+     * Returns the concatenation of (inverse) → (affine) → (this) transforms, or {@code null} if none.
+     * The affine transform is applied in the geographic space with angular values in radians.
+     *
+     * <p>Above description is for the usual case where {@code projectedSpace} is {@code false}.
+     * If {@code true} (should be unusual), then the affine transform is rather applied in the
+     * projected space and the sequence to concatenate is (this) → (affine) → (inverse).</p>
+     *
+     * <p>Default implementation returns {@code null}. Subclasses should override if applicable.</p>
+     *
+     * @param  projectedSpace  {@code true} if affine transform is applied in projected instead than geographic space.
+     * @param  affine          the affine transform in the middle of (inverse) → (affine) → (this) transform sequence.
+     * @param  factory         the factory to use for creating new transform, or {@code null}.
+     * @return the optimized concatenation, or {@code null} if none.
+     */
+    MathTransform tryConcatenate(boolean projectedSpace, Matrix affine, MathTransformFactory factory)
+            throws FactoryException
+    {
+        return null;
+    }
+
+    /**
+     * If a sequence of 3 transforms are (inverse projection) → (affine) → (projection) where
+     * the (projection) and (inverse projection) steps are the inverse of each other, returns
+     * the matrix of the affine transform step. Otherwise returns {@code null}. This method
+     * accepts also (projection) → (affine) → (inverse projection) sequence, but such sequences
+     * should be much more unusual.
+     *
+     * @param  projection       either {@link NormalizedProjection} or {@link Inverse}.
+     * @param  other            the arbitrary transforms to be concatenated with the given projection.
+     * @param  applyOtherFirst  whether {@code other} is concatenated before {@code projection} or the converse.
+     * @return the 3×3 matrix of the affine transform step, or {@code null} if none.
+     */
+    static Matrix getMiddleMatrix(final AbstractMathTransform projection, final MathTransform other,
+            final boolean applyOtherFirst)
+    {
+        final List<MathTransform> steps = MathTransforms.getSteps(other);
+        if (steps.size() == 2) try {
+            final int oi = applyOtherFirst ? 0 : 1;
+            if (projection.equals(steps.get(oi).inverse(), ComparisonMode.IGNORE_METADATA)) {
+                final Matrix m = MathTransforms.getMatrix(steps.get(oi ^ 1));
+                if (Matrices.isAffine(m) && m.getNumRow() == DIMENSION+1 && m.getNumCol() == DIMENSION+1) {
+                    return m;
+                }
+            }
+        } catch (NoninvertibleTransformException e) {
+            Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION),
+                    (projection instanceof NormalizedProjection) ? NormalizedProjection.class : projection.getClass(),
+                    "tryConcatenate", e);
+        }
+        return null;
     }
 
     /**

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ObliqueStereographic.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -263,11 +263,14 @@ public class ObliqueStereographic extend
         /*
          * 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.
+         * if the ellipsoid is already a sphere.  The original formulas were:
+         *
+         *    χ = asin((w - 1) / (w + 1))
+         *
+         * But since the projection needs only sin(χ) and cos(χ), we avoid the costly asin(…) function.
          */
-        final double χ    = asin((w - 1) / (w + 1));
-        final double cosχ = cos(χ);
-        final double sinχ = sin(χ);
+        final double sinχ = (w - 1) / (w + 1);
+        final double cosχ = sqrt(1 - sinχ*sinχ);
         /*
          * The conformal longitude is  Λ = n⋅(λ - λ₀) + Λ₀  where λ is the geodetic longitude.
          * But in Apache SIS implementation, the multiplication by  n  has been merged in the
@@ -407,7 +410,7 @@ public class ObliqueStereographic extend
              * Formulas below are the same than the elliptical formulas after the geodetic coordinates
              * have been converted to conformal coordinates.  In this spherical case we do not need to
              * perform such conversion. Instead we have directly   χ = φ  and  Λ = λ.   The simplified
-             * EPSG formulas then become the same than Synder formulas for the spherical case.
+             * EPSG formulas then become the same than Snyder formulas for the spherical case.
              */
             final double sinφ      = sin(φ);
             final double cosφ      = cos(φ);
@@ -416,10 +419,10 @@ public class ObliqueStereographic extend
             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λ;                    // Synder 21-4
+            final double B = 1 + sinφsinφ0 + cosφcosφ0*cosλ;                    // Snyder 21-4
             if (dstPts != null) {
-                dstPts[dstOff  ] = cosφsinλ / B;                                // Synder 21-2
-                dstPts[dstOff+1] = (sinφ*cosχ0 - cosφ*sinχ0*cosλ) / B;          // Synder 21-3
+                dstPts[dstOff  ] = cosφsinλ / B;                                // Snyder 21-2
+                dstPts[dstOff+1] = (sinφ*cosχ0 - cosφ*sinχ0*cosλ) / B;          // Snyder 21-3
             }
             if (!derivate) {
                 return null;

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/PolarStereographic.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -197,7 +197,7 @@ public class PolarStereographic extends
         if (abs(φ1 + PI/2) < ANGULAR_TOLERANCE) {
             /*
              * Polar Stereographic (variant A)
-             * True scale at pole (part of Synder 21-33). From EPSG guide (April 2015) §1.3.7.2:
+             * True scale at pole (part of Snyder 21-33). From EPSG guide (April 2015) §1.3.7.2:
              *
              *    ρ = 2⋅a⋅k₀⋅t / √[(1+ℯ)^(1+ℯ) ⋅ (1–ℯ)^(1–ℯ)]
              *
@@ -212,7 +212,7 @@ public class PolarStereographic extends
         } else {
             /*
              * Polar Stereographic (variant B or C)
-             * Derived from Synder 21-32 and 21-33. From EPSG guide (April 2015) §1.3.7.2:
+             * Derived from Snyder 21-32 and 21-33. From EPSG guide (April 2015) §1.3.7.2:
              *
              *   tF = tan(π/4 + φ1/2) / {[(1 + ℯ⋅sinφ1) / (1 – ℯ⋅sinφ1)]^(ℯ/2)}
              *   mF = cosφ1 / √[1 – ℯ²⋅sin²φ1]
@@ -225,7 +225,7 @@ public class PolarStereographic extends
              *   ρ  = mF / tF
              *   k₀ = ρ⋅√[…]/2  but we do not need that value.
              *
-             * In the spherical case, should give ρ = 1 + sinφ1   (Synder 21-7 and 21-11).
+             * In the spherical case, should give ρ = 1 + sinφ1   (Snyder 21-7 and 21-11).
              */
             final double sinφ1 = sin(φ1);
             final double mF = initializer.scaleAtφ(sinφ1, cos(φ1));
@@ -378,8 +378,8 @@ public class PolarStereographic extends
             final double sinθ = sin(θ);
             final double cosθ = cos(θ);
             final double t    = tan(PI/4 + 0.5*φ);
-            final double x    = t * sinθ;               // Synder 21-5
-            final double y    = t * cosθ;               // Synder 21-6
+            final double x    = t * sinθ;               // Snyder 21-5
+            final double y    = t * cosθ;               // Snyder 21-6
             if (dstPts != null) {
                 dstPts[dstOff  ] = x;
                 dstPts[dstOff+1] = y;

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ProjectionException.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ProjectionException.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ProjectionException.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ProjectionException.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -32,7 +32,7 @@ import org.opengis.referencing.operation
  *   <li>If the expected mathematical value is infinite (for example the Mercator projection at ±90° of latitude),
  *       then the map projection should return a {@link Double#POSITIVE_INFINITY} or {@link Double#NEGATIVE_INFINITY},
  *       depending on the sign of the correct mathematical answer.</li>
- *   <li>If no real number is expected to exist for the input coordinate (for example the root of a negative value),
+ *   <li>If no real number is expected to exist for the input coordinate (for example at a latitude greater than 90°),
  *       then the map projection should return {@link Double#NaN}.</li>
  *   <li>If a real number is expected to exist but the map projection fails to compute it (for example because an
  *       iterative algorithm does not converge), then the projection should throw {@code ProjectionException}.</li>

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -317,7 +317,7 @@ public abstract class AbstractMathTransf
      *         double[] ordinates = Arrays.copyOfRange(srcPts, srcOff, srcOff + getSourceDimensions());
      *         derivative = this.derivative(new GeneralDirectPosition(ordinates));
      *     }
-     *     this.transform(srcPts, srcOff, dstPts, dstOff, 1);  // May overwrite srcPts.
+     *     this.transform(srcPts, srcOff, dstPts, dstOff, 1);                   // May overwrite srcPts.
      *     return derivative;
      * }
      *
@@ -357,8 +357,8 @@ public abstract class AbstractMathTransf
             throws TransformException;
 
     /**
-     * Transforms a list of coordinate point ordinal values. This method is provided for efficiently
-     * transforming many points. The supplied array of ordinal values will contain packed ordinal values.
+     * Transforms a list of coordinate points. This method is provided for efficiently transforming many points.
+     * The supplied array of coordinate values will contain packed coordinate values.
      *
      * <div class="note"><b>Example:</b> if the source dimension is 3, then the ordinates will be packed in this order:
      * (<var>x₀</var>,<var>y₀</var>,<var>z₀</var>,
@@ -443,8 +443,8 @@ public abstract class AbstractMathTransf
                     throw failure;
                 }
                 /*
-                 * Otherwise fills the ordinate values to NaN and count the number of exceptions,
-                 * so we known when to give up if there is too much of them. The first exception
+                 * Otherwise set the ordinate values to NaN and count the number of exceptions,
+                 * so we know when to give up if there is too much of them. The first exception
                  * will be propagated at the end of this method.
                  */
                 Arrays.fill(dstPts, dstOff, dstOff + Math.abs(dstInc), Double.NaN);
@@ -477,7 +477,7 @@ public abstract class AbstractMathTransf
     }
 
     /**
-     * Transforms a list of coordinate point ordinal values. The default implementation delegates
+     * Transforms a list of coordinate points. The default implementation delegates
      * to {@link #transform(double[], int, double[], int, int)} using a temporary array of doubles.
      *
      * <div class="note"><b>Implementation note:</b> see {@link IterationStrategy} javadoc for a method skeleton.</div>
@@ -607,7 +607,7 @@ public abstract class AbstractMathTransf
     }
 
     /**
-     * Transforms a list of coordinate point ordinal values. The default implementation delegates
+     * Transforms a list of coordinate points. The default implementation delegates
      * to {@link #transform(double[], int, double[], int, int)} using a temporary array of doubles.
      *
      * @param  srcPts  the array containing the source point coordinates.
@@ -670,7 +670,7 @@ public abstract class AbstractMathTransf
     }
 
     /**
-     * Transforms a list of coordinate point ordinal values. The default implementation delegates
+     * Transforms a list of coordinate points. The default implementation delegates
      * to {@link #transform(double[], int, double[], int, int)} using a temporary array of doubles
      * if necessary.
      *
@@ -792,7 +792,7 @@ public abstract class AbstractMathTransf
     }
 
     /**
-     * Concatenates or pre-concatenates in an optimized way this math transform with the given one.
+     * Concatenates or pre-concatenates in an optimized way this math transform with the given one, if possible.
      * A new math transform is created to perform the combined transformation.
      * The {@code applyOtherFirst} value determines the transformation order as bellow:
      *
@@ -807,7 +807,7 @@ public abstract class AbstractMathTransf
      *
      * If no special optimization is available for the combined transform, then this method returns {@code null}.
      * In the later case, the concatenation will be prepared by {@link DefaultMathTransformFactory} using a generic
-     * {@link ConcatenatedTransform}.
+     * implementation.
      *
      * <p>The default implementation always returns {@code null}. This method is ought to be overridden
      * by subclasses capable of concatenating some combination of transforms in a special way.</p>
@@ -816,7 +816,7 @@ public abstract class AbstractMathTransf
      *                          {@code false} if the transformation order is {@code this} followed by {@code other}.
      * @param  other            the other math transform to (pre-)concatenate with this transform.
      * @param  factory          the factory which is (indirectly) invoking this method, or {@code null} if none.
-     * @return the combined math transform, or {@code null} if no optimized combined transform is available.
+     * @return the math transforms combined in an optimized way, or {@code null} if no such optimization is available.
      * @throws FactoryException if an error occurred while combining the transforms.
      *
      * @see DefaultMathTransformFactory#createConcatenatedTransform(MathTransform, MathTransform)

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/CoordinateSystemTransform.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -157,9 +157,9 @@ abstract class CoordinateSystemTransform
     }
 
     /**
-     * Implementation of {@link DefaultMathTransformFactory#createCoordinateSystemChange(CoordinateSystem, CoordinateSystem)},
-     * defined here for reducing the {@code DefaultMathTransformFactory} weight in the common case where the conversions
-     * handled by this class are not needed.
+     * Implementation of {@link DefaultMathTransformFactory#createCoordinateSystemChange(CoordinateSystem,
+     * CoordinateSystem, Ellipsoid)}, defined here for reducing the {@code DefaultMathTransformFactory}
+     * weight in the common case where the conversions handled by this class are not needed.
      */
     static MathTransform create(final MathTransformFactory factory, final CoordinateSystem source,
             final CoordinateSystem target) throws FactoryException

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -53,7 +53,7 @@ import org.opengis.util.FactoryException
 import org.opengis.util.NoSuchIdentifierException;
 
 import org.apache.sis.io.wkt.Parser;
-import org.apache.sis.internal.util.LazySet;
+import org.apache.sis.internal.referencing.LazySet;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.internal.metadata.ReferencingServices;
@@ -128,7 +128,7 @@ import org.apache.sis.util.resources.Err
  * </ul>
  *
  * <p>The main purpose of those dynamic parameters is to support some less commonly used conventions
- * without duplicating the most commonly used conventions. The alternative ways are used in NetCDF
+ * without duplicating the most commonly used conventions. The alternative ways are used in netCDF
  * files for example, which often use spherical models instead than ellipsoidal ones.</p>
  *
  *
@@ -1203,25 +1203,6 @@ public class DefaultMathTransformFactory
     }
 
     /**
-     * Creates a math transform that represent a change of coordinate system.
-     *
-     * @param  source  the source coordinate system.
-     * @param  target  the target coordinate system.
-     * @return a conversion from the given source to the given target coordinate system.
-     * @throws FactoryException if the conversion can not be created.
-     *
-     * @deprecated Replaced by {@link #createCoordinateSystemChange(CoordinateSystem, CoordinateSystem, Ellipsoid)}
-     *
-     * @since 0.7
-     */
-    @Deprecated
-    public MathTransform createCoordinateSystemChange(final CoordinateSystem source, final CoordinateSystem target)
-            throws FactoryException
-    {
-        return createCoordinateSystemChange(source, target, null);
-    }
-
-    /**
      * Creates a math transform that represent a change of coordinate system. If exactly one argument is
      * an {@linkplain org.apache.sis.referencing.cs.DefaultEllipsoidalCS ellipsoidal coordinate systems},
      * then the {@code ellipsoid} argument is mandatory. In all other cases (including the case where both

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -153,7 +153,11 @@ public class MolodenskyTransform extends
         super(source, isSource3D, target, isTarget3D, tX, tY, tZ, null, isAbridged,
                 isAbridged ? AbridgedMolodensky.PARAMETERS : Molodensky.PARAMETERS);
         if (!isSource3D && !isTarget3D) {
-            inverse = new MolodenskyTransform2D(this, source, target);
+            if (isAbridged && tX == 0 && tY == 0 && tZ == 0) {
+                inverse = new AbridgedMolodenskyTransform2D(this, source, target);
+            } else {
+                inverse = new MolodenskyTransform2D(this, source, target);
+            }
         } else {
             inverse = new MolodenskyTransform(this, source, target);
         }
@@ -226,7 +230,11 @@ public class MolodenskyTransform extends
     {
         final MolodenskyTransform tr;
         if (!isSource3D && !isTarget3D) {
-            tr = new MolodenskyTransform2D(source, target, tX, tY, tZ, isAbridged);
+            if (isAbridged && tX == 0 && tY == 0 && tZ == 0) {
+                tr = new AbridgedMolodenskyTransform2D(source, target);
+            } else {
+                tr = new MolodenskyTransform2D(source, target, tX, tY, tZ, isAbridged);
+            }
         } else {
             tr = new MolodenskyTransform(source, isSource3D, target, isTarget3D, tX, tY, tZ, isAbridged);
         }

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform2D.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform2D.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform2D.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MolodenskyTransform2D.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -33,7 +33,7 @@ import org.opengis.referencing.operation
  * @since   0.7
  * @module
  */
-final class MolodenskyTransform2D extends MolodenskyTransform implements MathTransform2D {
+class MolodenskyTransform2D extends MolodenskyTransform implements MathTransform2D {
     /**
      * Serial number for compatibility with different versions.
      */
@@ -52,9 +52,9 @@ final class MolodenskyTransform2D extend
     /**
      * Constructs the inverse of a 2D transform.
      *
-     * @param inverse The transform for which to create the inverse.
-     * @param source  The source ellipsoid of the given {@code inverse} transform.
-     * @param target  The target ellipsoid of the given {@code inverse} transform.
+     * @param inverse  the transform for which to create the inverse.
+     * @param source   the source ellipsoid of the given {@code inverse} transform.
+     * @param target   the target ellipsoid of the given {@code inverse} transform.
      */
     MolodenskyTransform2D(final MolodenskyTransform inverse, final Ellipsoid source, final Ellipsoid target) {
         super(inverse, source, target);

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.crs.CRSAuthorityFactory
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.crs.CRSAuthorityFactory?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.crs.CRSAuthorityFactory [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.crs.CRSAuthorityFactory [UTF-8] Sat Dec  9 10:57:44 2017
@@ -1,2 +1,3 @@
 # Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.
+org.apache.sis.internal.referencing.EPSGFactoryProxy
 org.apache.sis.referencing.factory.CommonAuthorityFactory

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractEnvelopeTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -19,8 +19,8 @@ package org.apache.sis.geometry;
 import java.awt.geom.Rectangle2D;
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
-import org.opengis.referencing.crs.GeographicCRS;
-import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.crs.DefaultGeographicCRS;
+import org.apache.sis.referencing.crs.HardCodedCRS;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -36,7 +36,7 @@ import static org.apache.sis.test.Refere
  * Various implementations are used for each test.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.4
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -51,7 +51,7 @@ public final strictfp class AbstractEnve
     /**
      * The coordinate reference system used for the tests.
      */
-    static final GeographicCRS WGS84 = CommonCRS.WGS84.normalizedGeographic();
+    static final DefaultGeographicCRS WGS84 = HardCodedCRS.WGS84;
 
     /**
      * Creates an envelope of the given type. The type shall be one of the

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -21,6 +21,7 @@ import java.util.Locale;
 import java.util.TimeZone;
 import java.text.ParsePosition;
 import java.text.ParseException;
+import java.io.IOException;
 import org.opengis.geometry.DirectPosition;
 import org.apache.sis.measure.Angle;
 import org.apache.sis.referencing.crs.HardCodedCRS;
@@ -36,6 +37,8 @@ import static org.junit.Assert.*;
  * Tests the {@link CoordinateFormat} class.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @author  Michael Hausegger
+ *
  * @version 0.8
  *
  * @see org.apache.sis.measure.AngleFormatTest
@@ -63,6 +66,7 @@ public final strictfp class CoordinateFo
          * Try again with a different separator.
          */
         format.setSeparator("; ");
+        assertEquals("; ", format.getSeparator());
         assertEquals("4.64; 10.25; -3.12", format.format(position));
     }
 
@@ -75,30 +79,31 @@ public final strictfp class CoordinateFo
     @Test
     public void testParseUnknownCRS() throws ParseException {
         final CoordinateFormat format = new CoordinateFormat(null, null);
-        final ParsePosition index = new ParsePosition(0);
-        DirectPosition position = format.parse("23.78 -12.74 127.9 3.25", index);
+        final ParsePosition charPos = new ParsePosition(0);
+        DirectPosition position = format.parse("23.78 -12.74 127.9 3.25", charPos);
         assertArrayEquals(new double[] {23.78, -12.74, 127.9, 3.25}, position.getCoordinate(), STRICT);
-        assertEquals("ParsePosition.getErrorIndex()", -1, index.getErrorIndex());
-        assertEquals("ParsePosition.getIndex()",      23, index.getIndex());
+        assertEquals("ParsePosition.getErrorIndex()", -1, charPos.getErrorIndex());
+        assertEquals("ParsePosition.getIndex()",      23, charPos.getIndex());
         /*
          * Try another point having a different number of position
          * for verifying that no cached values are causing problem.
          */
-        index.setIndex(0);
-        position = format.parse("4.64 10.25 -3.12", index);
+        charPos.setIndex(0);
+        position = format.parse("4.64 10.25 -3.12", charPos);
         assertArrayEquals(new double[] {4.64, 10.25, -3.12}, position.getCoordinate(), STRICT);
-        assertEquals("ParsePosition.getErrorIndex()", -1, index.getErrorIndex());
-        assertEquals("ParsePosition.getIndex()",      16, index.getIndex());
+        assertEquals("ParsePosition.getErrorIndex()", -1, charPos.getErrorIndex());
+        assertEquals("ParsePosition.getIndex()",      16, charPos.getIndex());
         /*
          * Try again with a different separator. Also put or remove some spaces
          * around the separator for testing UnitFormat capabilities to ignore them.
          */
         format.setSeparator("; ");
-        index.setIndex(0);
-        position = format.parse("4.64;10.25 ;  -3.12", index);
+        assertEquals("; ", format.getSeparator());
+        charPos.setIndex(0);
+        position = format.parse("4.64;10.25 ;  -3.12", charPos);
         assertArrayEquals(new double[] {4.64, 10.25, -3.12}, position.getCoordinate(), STRICT);
-        assertEquals("ParsePosition.getErrorIndex()", -1, index.getErrorIndex());
-        assertEquals("ParsePosition.getIndex()",      19, index.getIndex());
+        assertEquals("ParsePosition.getErrorIndex()", -1, charPos.getErrorIndex());
+        assertEquals("ParsePosition.getIndex()",      19, charPos.getIndex());
     }
 
     /**
@@ -150,6 +155,7 @@ public final strictfp class CoordinateFo
          * Try again with the original CRS, but different separator.
          */
         format.setSeparator("; ");
+        assertEquals("; ", format.getSeparator());
         position.setCoordinateReferenceSystem(HardCodedCRS.GEOID_4D);
         assertEquals("getPattern(Angle)", anglePattern, format.getPattern(Angle.class));
         assertEquals("getPattern(Date)",   datePattern, format.getPattern(Date .class));
@@ -168,24 +174,97 @@ public final strictfp class CoordinateFo
         final CoordinateFormat format = new CoordinateFormat(Locale.FRANCE, TimeZone.getTimeZone("GMT+01:00"));
         format.applyPattern(Date.class, "dd-MM-yyyy HH:mm");
         format.setDefaultCRS(HardCodedCRS.GEOID_4D);
-        final ParsePosition index = new ParsePosition(11);
-        final DirectPosition pos = format.parse("(to skip); 23°46,8′E 12°44,4′S 127,9 m 22-09-2006 07:00 (ignore)", index);
+        final ParsePosition charPos = new ParsePosition(11);
+        final DirectPosition pos = format.parse("(to skip); 23°46,8′E 12°44,4′S 127,9 m 22-09-2006 07:00 (ignore)", charPos);
         assertArrayEquals(new double[] {23.78, -12.74, 127.90, 54000.25}, pos.getCoordinate(), STRICT);
-        assertEquals("ParsePosition.getErrorIndex()", -1, index.getErrorIndex());
-        assertEquals("ParsePosition.getIndex()",      55, index.getIndex());
+        assertEquals("ParsePosition.getErrorIndex()", -1, charPos.getErrorIndex());
+        assertEquals("ParsePosition.getIndex()",      55, charPos.getIndex());
         /*
          * Tests error message when parsing the same string but with unknown units of measurement.
          */
-        index.setIndex(11);
+        charPos.setIndex(11);
         try {
-            format.parse("(to skip); 23°46,8′E 12°44,4′S 127,9 Foo 22-09-2006 07:00", index);
+            format.parse("(to skip); 23°46,8′E 12°44,4′S 127,9 Foo 22-09-2006 07:00", charPos);
             fail("Should not have parsed a coordinate with unknown units.");
         } catch (ParseException e) {
-            assertEquals("ParsePosition.getIndex()",        11, index.getIndex());
-            assertEquals("ParsePosition.getErrorIndex()",   37, index.getErrorIndex());
+            assertEquals("ParsePosition.getIndex()",        11, charPos.getIndex());
+            assertEquals("ParsePosition.getErrorIndex()",   37, charPos.getErrorIndex());
             assertEquals("ParseException.getErrorOffset()", 37, e.getErrorOffset());
             assertEquals("Les caractères « Foo » après « 23°46,8′E 12°44,4′S 127,9 » sont inattendus.",
                          e.getLocalizedMessage());  // In the language specified at CoordinateFormat construction time.
         }
     }
+
+    /**
+     * Tests formatting a coordinate in default locale, then parsing the result. This test verifies that the
+     * parsing is consistent with formatting in whatever locale used by the platform. This test does not verify
+     * if the formatted string is equal to any expected value since it is locale-dependent.
+     *
+     * @throws IOException    should never happen since we format into a {@link StringBuffer}.
+     * @throws ParseException if {@code CoordinateFormat} fails to parse the value that it formatted.
+     */
+    @Test
+    public void testParseInDefaultLocale() throws IOException, ParseException {
+        CoordinateFormat format = new CoordinateFormat();
+        StringBuffer     buffer = new StringBuffer();
+        format.format(new DirectPosition2D(-3, 4), buffer);
+
+        ParsePosition  charPos  = new ParsePosition(0);
+        DirectPosition position = format.parse(buffer, charPos);
+        assertEquals("Should have parsed the whole text.", buffer.length(), charPos.getIndex());
+        assertEquals("DirectPosition.getDimension()", 2, position.getDimension());
+        assertArrayEquals(new double[] {-3, 4}, position.getCoordinate(), STRICT);
+    }
+
+    /**
+     * Tests parsing from a position different then the beginning of the string.
+     *
+     * @throws ParseException if the parsing failed.
+     */
+    @Test
+    public void testParseFromOffset() throws ParseException {
+        CoordinateFormat coordinateFormat = new CoordinateFormat(Locale.CANADA, null);
+        coordinateFormat.setDefaultCRS(VerticalCRSMock.BAROMETRIC_HEIGHT);
+        ParsePosition  charPos  = new ParsePosition(7);
+        DirectPosition position = coordinateFormat.parse("[skip] 12", charPos);
+        assertEquals("Should have parsed the whole text.", 9, charPos.getIndex());
+        assertEquals("DirectPosition.getDimension()", 1, position.getDimension());
+        assertArrayEquals(new double[] {12}, position.getCoordinate(), STRICT);
+    }
+
+    /**
+     * Verifies the pattern returned by {@link CoordinateFormat#getPattern(Class)}. This includes verifying that
+     * the method returns {@code null} when invoked for an unknown type, or a type that does not support pattern.
+     */
+    @Test
+    public void testGetPattern() {
+        CoordinateFormat coordinateFormat = new CoordinateFormat(Locale.UK, null);
+        assertEquals("#,##0.###", coordinateFormat.getPattern(Byte.class));
+        assertNull(coordinateFormat.getPattern(Object.class));
+        assertNull(coordinateFormat.getPattern(Class.class));
+    }
+
+    /**
+     * Verifies that {@link CoordinateFormat#applyPattern(Class, String)} when
+     * invoked for an unknown type, or for a type that does not support patterns.
+     */
+    @Test
+    public void testApplyPattern() {
+        CoordinateFormat format = new CoordinateFormat();
+        assertFalse(format.applyPattern(Object.class, "A dummy pattern"));
+        assertFalse(format.applyPattern(Class.class,  "A dummy pattern"));
+    }
+
+    /**
+     * Tests {@link CoordinateFormat#clone()}, then verifies that the clone has the same configuration
+     * than the original object.
+     */
+    @Test
+    public void testClone() {
+        CoordinateFormat format = new CoordinateFormat(Locale.CANADA, null);
+        CoordinateFormat clone  = format.clone();
+        assertNotSame("clone()", clone, format);
+        assertEquals("getSeparator()",  format.getSeparator(),  clone.getSeparator());
+        assertEquals("getDefaultCRS()", format.getDefaultCRS(), clone.getDefaultCRS());
+    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/EnvelopesTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -19,14 +19,18 @@ package org.apache.sis.geometry;
 import java.util.Collections;
 import org.opengis.geometry.Envelope;
 import org.opengis.util.FactoryException;
+import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.MathTransform2D;
 import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.referencing.operation.transform.MathTransformWrapper;
 import org.apache.sis.referencing.crs.DefaultCompoundCRS;
 import org.apache.sis.referencing.crs.HardCodedCRS;
-import org.apache.sis.referencing.operation.transform.MathTransformWrapper;
+import org.apache.sis.referencing.cs.AxesConvention;
+import org.apache.sis.referencing.CRS;
 import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.DependsOnMethod;
 import org.junit.Test;
 
 import static org.apache.sis.test.ReferencingAssert.*;
@@ -171,4 +175,56 @@ public final strictfp class EnvelopesTes
         assertEquals( -80, env2D.getMinimum(1), 0);
         assertEquals(  80, env2D.getMaximum(1), 0);
     }
+
+    /**
+     * Tests a transformation from a three-dimensional CRS where the range of longitude axis is changed.
+     * This is the same test than {@link #testAxisRangeChange()} but using a compound CRS as the source.
+     * Internally, this results in the concatenation of transforms. We want to ensure that information
+     * about axis range changes are not lost in this process.
+     *
+     * @throws FactoryException if an error occurred while creating the operation.
+     * @throws TransformException if an error occurred while transforming the envelope.
+     *
+     * @since 0.8
+     */
+    @Test
+    @DependsOnMethod("testAxisRangeChange")
+    public void testAxisRangeChange3D() throws FactoryException, TransformException {
+        testAxisRangeChange3D(HardCodedCRS.WGS84);
+    }
+
+    /**
+     * Tests a change of longitude axis range together with change of ellipsoid. This is the same test
+     * than {@link #testAxisRangeChange3D()} with an additional complexity: a change of ellipsoid.
+     * This causes the execution of different code branches in {@code ConcatenatedOperation} creation.
+     *
+     * @throws FactoryException if an error occurred while creating the operation.
+     * @throws TransformException if an error occurred while transforming the envelope.
+     *
+     * @since 0.8
+     */
+    @Test
+    @DependsOnMethod("testAxisRangeChange3D")
+    public void testAxisRangeChangeWithDatumShift() throws FactoryException, TransformException {
+        testAxisRangeChange3D(HardCodedCRS.SPHERE);
+    }
+
+    /**
+     * Implementation of {@link #testAxisRangeChange3D()} and {@link #testAxisRangeChangeWithDatumShift()}.
+     */
+    private void testAxisRangeChange3D(final GeographicCRS targetCRS) throws FactoryException, TransformException {
+        final GeneralEnvelope envelope  = new GeneralEnvelope(new double[] { -0.5, -90, 1000},
+                                                              new double[] {354.5, +90, 1002});
+        envelope.setCoordinateReferenceSystem(CRS.compound(
+                HardCodedCRS.WGS84.forConvention(AxesConvention.POSITIVE_RANGE), HardCodedCRS.TIME));
+        final GeneralEnvelope expected = createFromExtremums(targetCRS, -0.5, -90, -5.5, 90);
+        assertEnvelopeEquals(expected, Envelopes.transform(envelope, targetCRS), STRICT, STRICT);
+        /*
+         * When the envelope to transform span the full longitude range,
+         * target envelope should unconditionally be [-180 … +180]°.
+         */
+        envelope.setRange(0, -0.5, 359.5);
+        expected.setRange(0, -180, 180);
+        assertEnvelopeEquals(expected, Envelopes.transform(envelope, targetCRS), STRICT, STRICT);
+    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralEnvelopeTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -39,11 +39,11 @@ import static org.apache.sis.geometry.Ab
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 0.5
+ * @version 0.8
  * @since   0.3
  * @module
  */
-@DependsOn(AbstractEnvelopeTest.class)
+@DependsOn(ArrayEnvelopeTest.class)
 public strictfp class GeneralEnvelopeTest extends TestCase {
     /**
      * Tolerance threshold for floating point comparisons.
@@ -97,7 +97,7 @@ public strictfp class GeneralEnvelopeTes
             final double xLower, final double ymin, final double xUpper, final double ymax)
     {
         final double xmin, xmax;
-        if (MathFunctions.isNegative(xUpper - xLower)) { // Check for anti-meridian spanning.
+        if (MathFunctions.isNegative(xUpper - xLower)) {                // Check for anti-meridian spanning.
             xmin = -180;
             xmax = +180;
         } else {
@@ -131,25 +131,24 @@ public strictfp class GeneralEnvelopeTes
     private static void assertIntersectEquals(final GeneralEnvelope e1, final GeneralEnvelope e2,
             final double xmin, final double ymin, final double xmax, final double ymax)
     {
-        final boolean isEmpty = !(((xmax - xmin) * (ymax - ymin)) != 0);        // Use ! for catching NaN.
         final Envelope2D r1 = new Envelope2D(e1);
         final Envelope2D r2 = new Envelope2D(e2);
         final Envelope2D ri = r1.createIntersection(r2);
-        assertEquals("isEmpty", isEmpty, r1.isEmpty());
+        assertFalse("isEmpty", r1.isEmpty());
         assertEnvelopeEquals(ri, xmin, ymin, xmax, ymax);
         assertEquals("Interchanged arguments.", ri, r2.createIntersection(r1));
 
         // Compares with GeneralEnvelope.
         final GeneralEnvelope ei = new GeneralEnvelope(e1);
         ei.intersect(e2);
-        assertEquals("isEmpty", isEmpty, e1.isEmpty());
+        assertFalse("isEmpty", e1.isEmpty());
         assertEnvelopeEquals(ei, xmin, ymin, xmax, ymax);
         assertTrue("Using GeneralEnvelope.", ei.equals(ri, STRICT, false));
 
         // Interchanges arguments.
         ei.setEnvelope(e2);
         ei.intersect(e1);
-        assertEquals("isEmpty", isEmpty, e1.isEmpty());
+        assertFalse("isEmpty", e1.isEmpty());
         assertEnvelopeEquals(ei, xmin, ymin, xmax, ymax);
         assertTrue("Using GeneralEnvelope.", ei.equals(ri, STRICT, false));
     }
@@ -233,7 +232,7 @@ public strictfp class GeneralEnvelopeTes
         //  └──────────┘
         e1.setEnvelope(20, -20,  80, 12);
         e2.setEnvelope(40, -10, 100, 30);
-        final double ymin=-10, ymax=12; // Will not change anymore
+        final double ymin=-10, ymax=12;                         // Will not change anymore
         assertIntersectEquals(e1, e2, 40, ymin, 80, ymax);
         //  ────┐  ┌────
         //  ──┐ │  │ ┌──
@@ -272,6 +271,20 @@ public strictfp class GeneralEnvelopeTes
         //  ─────┘     └─────
         e2.setRange(0, 10, 90);
         assertIntersectEquals(e1, e2, NaN, ymin, NaN, ymax);
+        //  ────────┬────────
+        //        ┌─┼────┐
+        //        └─┼────┘
+        //  ────────┴────────
+        e1.setRange(0, 0.0, -0.0);
+        e2.setRange(0, -10,   30);
+        assertIntersectEquals(e1, e2, -10, ymin, 30, ymax);
+        //  ┌───────────────┐
+        //  │               │
+        //  │               │
+        //  └───────────────┘
+        e1.setRange(0, 0.0, -0.0);
+        e2.setRange(0, 0.0, -0.0);
+        assertIntersectEquals(e1, e2, 0.0, ymin, -0.0, ymax);
 
         // Post-test verification, mostly for SubEnvelope.
         verifyInvariants(e1);

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/ImmutableEnvelopeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/ImmutableEnvelopeTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/ImmutableEnvelopeTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/ImmutableEnvelopeTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -35,7 +35,7 @@ import static org.apache.sis.geometry.Ab
  * @since   0.3
  * @module
  */
-@DependsOn(AbstractEnvelopeTest.class)
+@DependsOn(ArrayEnvelopeTest.class)
 public final strictfp class ImmutableEnvelopeTest extends TestCase {
     /**
      * Tests {@code ImmutableEnvelope} serialization.

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/Shapes2DTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -17,6 +17,7 @@
 package org.apache.sis.geometry;
 
 import java.awt.geom.Rectangle2D;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.MathTransform2D;
@@ -42,6 +43,12 @@ public final strictfp class Shapes2DTest
      */
     @Override
     Rectangle2D createFromExtremums(CoordinateReferenceSystem crs, double xmin, double ymin, double xmax, double ymax) {
+        if (xmin > xmax) {
+            // This implementation does not support spanning anti-meridian.
+            final CoordinateSystemAxis axis = crs.getCoordinateSystem().getAxis(0);
+            xmin = axis.getMinimumValue();
+            xmax = axis.getMaximumValue();
+        }
         return new Rectangle2D.Double(xmin, ymin, xmax - xmin, ymax - ymin);
     }
 

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -28,7 +28,10 @@ import org.opengis.util.FactoryException
 import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.referencing.cs.AxesConvention;
 import org.apache.sis.referencing.operation.DefaultConversion;
+import org.apache.sis.referencing.operation.HardCodedConversions;
+import org.apache.sis.referencing.crs.HardCodedCRS;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -82,6 +85,12 @@ public abstract strictfp class Transform
     abstract void assertGeometryEquals(G expected, G actual, double tolx, double toly);
 
     /**
+     * Allows sub-classing in same package only.
+     */
+    TransformTestCase() {
+    }
+
+    /**
      * Tests the transformation of an envelope or rectangle. This is a relatively simple test case
      * working in the two-dimensional space only, with a coordinate operation of type "conversion"
      * (not a "transformation") and with no need to adjust for poles.
@@ -212,6 +221,29 @@ public abstract strictfp class Transform
     }
 
     /**
+     * Tests transform of an envelope over the ±180° limit. The Mercator projection used in this test
+     * is not expected to wrap the longitude around Earth when using only the {@code MathTransform}.
+     * However when the target CRS is known, then "wrap around" should be applied.
+     *
+     * @throws TransformException if an error occurred while transforming the envelope.
+     *
+     * @since 0.8
+     */
+    @Test
+    @DependsOnMethod("testTransform")
+    public final void testTransformOverAntiMeridian() throws TransformException {
+        final ProjectedCRS  sourceCRS  = HardCodedConversions.mercator();
+        final GeographicCRS targetCRS  = sourceCRS.getBaseCRS();
+        final Conversion    conversion = inverse(sourceCRS.getConversionFromBase());
+        final G expected  = createFromExtremums(targetCRS, 179, 40, 181, 50);
+        final G rectangle = createFromExtremums(sourceCRS,
+                19926188.852, 4838471.398,                      // Computed by SIS (not validated by external authority).
+                20148827.834, 6413524.594);
+        final G actual = transform(conversion, rectangle);
+        assertGeometryEquals(expected, actual, ANGULAR_TOLERANCE, ANGULAR_TOLERANCE);
+    }
+
+    /**
      * Returns the inverse of the given conversion. This method is not strictly correct
      * since we reuse the properties (name, aliases, etc.) from the given conversion.
      * However those properties are not significant for the purpose of this test.
@@ -220,4 +252,22 @@ public abstract strictfp class Transform
         return new DefaultConversion(IdentifiedObjects.getProperties(conversion), conversion.getTargetCRS(),
                 conversion.getSourceCRS(), null, conversion.getMethod(), conversion.getMathTransform().inverse());
     }
+
+    /**
+     * Tests a transformation where only the range of longitude axis is changed.
+     *
+     * @throws FactoryException if an error occurred while creating the operation.
+     * @throws TransformException if an error occurred while transforming the envelope.
+     *
+     * @since 0.8
+     */
+    @Test
+    public final void testAxisRangeChange() throws FactoryException, TransformException {
+        final GeographicCRS sourceCRS = HardCodedCRS.WGS84;
+        final GeographicCRS targetCRS = HardCodedCRS.WGS84.forConvention(AxesConvention.POSITIVE_RANGE);
+        final G rectangle = createFromExtremums(sourceCRS, -178, -70, 165, 80);
+        final G expected  = createFromExtremums(targetCRS,  182, -70, 165, 80);
+        final G actual    = transform(CRS.findOperation(sourceCRS, targetCRS, null), rectangle);
+        assertGeometryEquals(expected, actual, STRICT, STRICT);
+    }
 }

Modified: sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java?rev=1817597&r1=1817596&r2=1817597&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java [UTF-8] Sat Dec  9 10:57:44 2017
@@ -21,6 +21,7 @@ import org.opengis.referencing.cs.*;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.datum.PrimeMeridian;
+import org.opengis.referencing.datum.VerticalDatum;
 import org.opengis.referencing.IdentifiedObject;
 import org.apache.sis.referencing.datum.HardCodedDatum;
 import org.apache.sis.referencing.crs.HardCodedCRS;
@@ -56,6 +57,14 @@ public final strictfp class ReferencingU
     }
 
     /**
+     * Tests {@link ReferencingUtilities#isEllipsoidalHeight(VerticalDatum)}.
+     */
+    @Test
+    public void testEllipsoidalHeight() {
+        assertTrue(isEllipsoidalHeight(HardCodedDatum.ELLIPSOID));
+    }
+
+    /**
      * Asserts that normalization of the given CRS produces {@link HardCodedCRS#WGS84} (ignoring metadata).
      *
      * @param  message         the message to show in case of failure.
@@ -84,7 +93,7 @@ public final strictfp class ReferencingU
     }
 
     /**
-     * Tests {@link ReferencingUtilities#getPropertiesForModifiedCRS(IdentifiedObject, String...)}.
+     * Tests {@link ReferencingUtilities#getPropertiesForModifiedCRS(IdentifiedObject)}.
      *
      * @since 0.7
      */
@@ -110,7 +119,7 @@ public final strictfp class ReferencingU
         assertEquals("cylindricalCS",    toPropertyName(CoordinateSystem.class, CylindricalCS   .class).toString());
         assertEquals("ellipsoidalCS",    toPropertyName(CoordinateSystem.class, EllipsoidalCS   .class).toString());
         assertEquals("linearCS",         toPropertyName(CoordinateSystem.class, LinearCS        .class).toString());
-//      assertEquals("parametricCS",     toPropertyName(CoordinateSystem.class, ParametricCS    .class).toString());
+        assertEquals("parametricCS",     toPropertyName(CoordinateSystem.class, ParametricCS    .class).toString());
         assertEquals("polarCS",          toPropertyName(CoordinateSystem.class, PolarCS         .class).toString());
         assertEquals("sphericalCS",      toPropertyName(CoordinateSystem.class, SphericalCS     .class).toString());
         assertEquals("timeCS",           toPropertyName(CoordinateSystem.class, TimeCS          .class).toString());



Mime
View raw message