sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1826248 [2/3] - in /sis/trunk: ./ application/sis-console/src/main/java/org/apache/sis/console/ core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ core/sis-metadata/src/main/java/org/apache/sis/io/wkt/ core/sis-referencing/s...
Date Thu, 08 Mar 2018 15:44:56 GMT
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -437,7 +437,7 @@ public abstract class NormalizedProjecti
         context             = initializer.context;
         eccentricitySquared = initializer.eccentricitySquared.value;
         eccentricity        = sqrt(eccentricitySquared);    // DoubleDouble.sqrt() does not make any difference here.
-        inverse             = new Inverse();
+        inverse             = new Inverse(this);
     }
 
     /**
@@ -450,7 +450,7 @@ public abstract class NormalizedProjecti
         context             = other.context;
         eccentricity        = other.eccentricity;
         eccentricitySquared = other.eccentricitySquared;
-        inverse             = new Inverse();
+        inverse             = new Inverse(this);
     }
 
     /**
@@ -725,20 +725,34 @@ public abstract class NormalizedProjecti
      * Inverse of a normalized map projection.
      *
      * @author  Martin Desruisseaux (Geomatys)
-     * @version 0.8
+     * @version 1.0
      * @since   0.6
      * @module
      */
-    private final class Inverse extends AbstractMathTransform2D.Inverse {
+    private static final class Inverse extends AbstractMathTransform2D.Inverse implements Serializable {
         /**
          * For cross-version compatibility.
          */
-        private static final long serialVersionUID = -9138242780765956870L;
+        private static final long serialVersionUID = 6014176098150309651L;
+
+        /**
+         * The enclosing transform.
+         */
+        private final NormalizedProjection forward;
 
         /**
          * Default constructor.
          */
-        Inverse() {
+        Inverse(final NormalizedProjection forward) {
+            this.forward = forward;
+        }
+
+        /**
+         * Returns the inverse of this math transform.
+         */
+        @Override
+        public MathTransform2D inverse() {
+            return forward;
         }
 
         /**
@@ -752,15 +766,15 @@ public abstract class NormalizedProjecti
                                 final boolean derivate) throws TransformException
         {
             if (!derivate) {
-                inverseTransform(srcPts, srcOff, dstPts, dstOff);
+                forward.inverseTransform(srcPts, srcOff, dstPts, dstOff);
                 return null;
             } else {
                 if (dstPts == null) {
                     dstPts = new double[DIMENSION];
                     dstOff = 0;
                 }
-                inverseTransform(srcPts, srcOff, dstPts, dstOff);
-                return Matrices.inverse(NormalizedProjection.this.transform(dstPts, dstOff, null, 0, true));
+                forward.inverseTransform(srcPts, srcOff, dstPts, dstOff);
+                return Matrices.inverse(forward.transform(dstPts, dstOff, null, 0, true));
             }
         }
 
@@ -775,7 +789,7 @@ public abstract class NormalizedProjecti
             if (srcPts == dstPts && srcOff < dstOff) {
                 super.transform(srcPts, srcOff, dstPts, dstOff, numPts);
             } else while (--numPts >= 0) {
-                inverseTransform(srcPts, srcOff, dstPts, dstOff);
+                forward.inverseTransform(srcPts, srcOff, dstPts, dstOff);
                 srcOff += DIMENSION;
                 dstOff += DIMENSION;
             }
@@ -796,7 +810,7 @@ public abstract class NormalizedProjecti
                  *   - 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 forward.tryConcatenate(applyOtherFirst, m, factory);
             }
             return super.tryConcatenate(applyOtherFirst, other, factory);
         }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ZonedGridSystem.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ZonedGridSystem.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ZonedGridSystem.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ZonedGridSystem.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -131,7 +131,7 @@ public class ZonedGridSystem extends Abs
         final MatrixSIS normalize = initializer.context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION);
         normalize.convertBefore(0, null, zoneWidth / -2);
         projection = (AbstractMathTransform) new TransverseMercator(initializer).createMapProjection(factory);
-        inverse    = new Inverse();
+        inverse    = new Inverse(this);
     }
 
 
@@ -185,15 +185,20 @@ public class ZonedGridSystem extends Abs
      * Inverse of a zoned grid system.
      *
      * @author  Martin Desruisseaux (Geomatys)
-     * @version 0.8
+     * @version 1.0
      * @since   0.8
      * @module
      */
-    private final class Inverse extends AbstractMathTransform2D.Inverse {
+    private static final class Inverse extends AbstractMathTransform2D.Inverse implements Serializable {
         /**
          * For cross-version compatibility.
          */
-        private static final long serialVersionUID = 1900563285661407519L;
+        private static final long serialVersionUID = -4417726238412154175L;
+
+        /**
+         * The enclosing transform.
+         */
+        private final ZonedGridSystem forward;
 
         /**
          * The projection that performs the actual work after we removed the zone number.
@@ -203,15 +208,24 @@ public class ZonedGridSystem extends Abs
         /**
          * Default constructor.
          */
-        Inverse() throws FactoryException {
+        Inverse(final ZonedGridSystem forward) throws FactoryException {
+            this.forward = forward;
             try {
-                inverseProjection = (AbstractMathTransform) projection.inverse();
+                inverseProjection = (AbstractMathTransform) forward.projection.inverse();
             } catch (NoninvertibleTransformException e) {
                 throw new FactoryException(e);                  // Should not happen.
             }
         }
 
         /**
+         * Returns the inverse of this math transform.
+         */
+        @Override
+        public MathTransform2D inverse() {
+            return forward;
+        }
+
+        /**
          * Inverse transforms the specified {@code srcPts} and stores the result in {@code dstPts}.
          * If the derivative has been requested, then this method will delegate the derivative
          * calculation to the enclosing class and inverts the resulting matrix.
@@ -228,7 +242,7 @@ public class ZonedGridSystem extends Abs
             dstPts[dstOff  ] = x;
             dstPts[dstOff+1] = y;
             final Matrix derivative = inverseProjection.transform(dstPts, dstOff, dstPts, dstOff, derivate);
-            dstPts[dstOff] += zone * zoneWidth + initialLongitude;
+            dstPts[dstOff] += zone * forward.zoneWidth + forward.initialLongitude;
             return derivative;
         }
     }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -159,7 +159,7 @@
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Rémi Maréchal (Geomatys)
  * @author  Adrian Custer (Geomatys)
- * @version 0.8
+ * @version 1.0
  *
  * @see <a href="http://www.remotesensing.org/geotiff/proj_list">Projections list on RemoteSensing.org</a>
  * @see <a href="http://mathworld.wolfram.com/MapProjection.html">Map projections on MathWorld</a>

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -18,7 +18,6 @@ package org.apache.sis.referencing.opera
 
 import java.util.List;
 import java.util.Arrays;
-import java.io.Serializable;
 import org.opengis.util.FactoryException;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
@@ -988,31 +987,20 @@ public abstract class AbstractMathTransf
 
     /**
      * Base class for implementations of inverse math transforms.
-     * This inner class is the inverse of the enclosing {@link AbstractMathTransform}.
+     * Subclasses need to implement the {@link #inverse()} method.
      *
      * <div class="section">Serialization</div>
-     * Instances of this class are serializable only if the enclosing math transform is also serializable.
-     * Serialized math transforms are not guaranteed to be compatible with future SIS versions.
-     * Serialization, if allowed, should be used only for short term storage or RMI between applications
+     * This object may or may not be serializable, at implementation choices.
+     * Most Apache SIS implementations are serializable, but the serialized objects are not guaranteed to be compatible
+     * with future SIS versions. Serialization should be used only for short term storage or RMI between applications
      * running the same SIS version.
      *
      * @author  Martin Desruisseaux (IRD, Geomatys)
-     * @version 0.6
+     * @version 1.0
      * @since   0.5
      * @module
      */
-    protected abstract class Inverse extends AbstractMathTransform implements Serializable {
-        /**
-         * Serial number for inter-operability with different versions. This serial number is
-         * especially important for inner classes, since the default {@code serialVersionUID}
-         * computation will not produce consistent results across implementations of different
-         * Java compiler. This is because different compilers may generate different names for
-         * synthetic members used in the implementation of inner classes. See:
-         *
-         * http://developer.java.sun.com/developer/bugParade/bugs/4211550.html
-         */
-        private static final long serialVersionUID = 3528274816628012283L;
-
+    protected abstract static class Inverse extends AbstractMathTransform {
         /**
          * Constructs an inverse math transform.
          */
@@ -1021,29 +1009,32 @@ public abstract class AbstractMathTransf
 
         /**
          * Gets the dimension of input points.
-         * The implementation returns the dimension of output points of the enclosing math transform.
+         * The default implementation returns the dimension of output points
+         * of the {@linkplain #inverse() inverse} math transform.
          *
          * @return {@inheritDoc}
          */
         @Override
-        public final int getSourceDimensions() {
-            return AbstractMathTransform.this.getTargetDimensions();
+        public int getSourceDimensions() {
+            return inverse().getTargetDimensions();
         }
 
         /**
          * Gets the dimension of output points.
-         * The implementation returns the dimension of input points of the enclosing math transform.
+         * The default implementation returns the dimension of input points
+         * of the {@linkplain #inverse() inverse} math transform.
          *
          * @return {@inheritDoc}
          */
         @Override
-        public final int getTargetDimensions() {
-            return AbstractMathTransform.this.getSourceDimensions();
+        public int getTargetDimensions() {
+            return inverse().getSourceDimensions();
         }
 
         /**
          * Gets the derivative of this transform at a point.
-         * The default implementation computes the inverse of the matrix returned by the enclosing math transform.
+         * The default implementation computes the inverse of the matrix
+         * returned by the {@linkplain #inverse() inverse} math transform.
          *
          * @return {@inheritDoc}
          * @throws NullPointerException if the derivative depends on coordinate and {@code point} is {@code null}.
@@ -1055,28 +1046,27 @@ public abstract class AbstractMathTransf
             if (point != null) {
                 point = this.transform(point, null);
             }
-            return Matrices.inverse(AbstractMathTransform.this.derivative(point));
+            return Matrices.inverse(inverse().derivative(point));
         }
 
         /**
-         * Returns the inverse of this math transform, which is the enclosing math transform.
+         * Returns the inverse of this math transform.
+         * The returned transform should be the enclosing math transform.
          *
-         * @return the enclosing math transform.
+         * @return the inverse of this transform.
          */
         @Override
-        public MathTransform inverse() {
-            return AbstractMathTransform.this;
-        }
+        public abstract MathTransform inverse();
 
         /**
          * Tests whether this transform does not move any points.
-         * The default implementation delegates this tests to the enclosing math transform.
+         * The default implementation delegates this tests to the {@linkplain #inverse() inverse} math transform.
          *
          * @return {@inheritDoc}
          */
         @Override
         public boolean isIdentity() {
-            return AbstractMathTransform.this.isIdentity();
+            return inverse().isIdentity();
         }
 
         /**
@@ -1086,13 +1076,13 @@ public abstract class AbstractMathTransf
          */
         @Override
         protected int computeHashCode() {
-            return super.computeHashCode() + 31*AbstractMathTransform.this.hashCode();
+            return super.computeHashCode() + 31 * inverse().hashCode();
         }
 
         /**
          * Compares the specified object with this inverse math transform for equality.
-         * The default implementation tests if {@code object} in an instance of the same class
-         * than {@code this}, and if so compares their enclosing {@code AbstractMathTransform}.
+         * The default implementation tests if {@code object} in an instance of the same class than {@code this},
+         * and if so compares their {@linkplain #inverse() inverse} {@code MathTransform}.
          *
          * @return {@inheritDoc}
          */
@@ -1102,7 +1092,13 @@ public abstract class AbstractMathTransf
                 return true;                                            // Slight optimization
             }
             if (object != null && object.getClass() == getClass()) {
-                return AbstractMathTransform.this.equals(((Inverse) object).inverse(), mode);
+                final MathTransform other = ((Inverse) object).inverse();
+                final MathTransform inverse = inverse();
+                if (inverse instanceof LenientComparable) {
+                    return ((LenientComparable) inverse).equals(other, mode);
+                } else {
+                    return inverse.equals(other);
+                }
             } else {
                 return false;
             }
@@ -1118,7 +1114,12 @@ public abstract class AbstractMathTransf
             if (parameters != null) {
                 return parameters.beforeFormat(transforms, index, inverse);
             } else {
-                return AbstractMathTransform.this.beforeFormat(transforms, index, !inverse);
+                final MathTransform inv = inverse();
+                if (inv instanceof AbstractMathTransform) {
+                    return ((AbstractMathTransform) inv).beforeFormat(transforms, index, !inverse);
+                } else {
+                    return index;
+                }
             }
         }
 
@@ -1143,7 +1144,7 @@ public abstract class AbstractMathTransf
                 return WKTKeywords.Param_MT;
             } else {
                 formatter.newLine();
-                formatter.append((FormattableObject) AbstractMathTransform.this);
+                formatter.append((FormattableObject) inverse());
                 return WKTKeywords.Inverse_MT;
             }
         }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -156,22 +156,17 @@ public abstract class AbstractMathTransf
      * This inner class is the inverse of the enclosing {@link AbstractMathTransform1D}.
      *
      * <div class="section">Serialization</div>
-     * Instances of this class are serializable only if the enclosing math transform is also serializable.
-     * Serialized math transforms are not guaranteed to be compatible with future SIS versions.
-     * Serialization, if allowed, should be used only for short term storage or RMI between applications
+     * This object may or may not be serializable, at implementation choices.
+     * Most Apache SIS implementations are serializable, but the serialized objects are not guaranteed to be compatible
+     * with future SIS versions. Serialization should be used only for short term storage or RMI between applications
      * running the same SIS version.
      *
      * @author  Martin Desruisseaux (Geomatys)
-     * @version 0.7
+     * @version 1.0
      * @since   0.7
      * @module
      */
-    protected abstract class Inverse extends AbstractMathTransform.Inverse implements MathTransform1D {
-        /**
-         * Serial number for inter-operability with different versions.
-         */
-        private static final long serialVersionUID = 2018412413506158560L;
-
+    protected abstract static class Inverse extends AbstractMathTransform.Inverse implements MathTransform1D {
         /**
          * Constructs an inverse math transform.
          */
@@ -179,12 +174,11 @@ public abstract class AbstractMathTransf
         }
 
         /**
-         * Returns the enclosing math transform.
+         * Returns the inverse of this math transform.
+         * The returned transform should be the enclosing math transform.
          */
         @Override
-        public MathTransform1D inverse() {
-            return (MathTransform1D) super.inverse();
-        }
+        public abstract MathTransform1D inverse();
 
         /**
          * Transforms a single point in the given array and opportunistically computes its derivative if requested.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -319,22 +319,17 @@ public abstract class AbstractMathTransf
      * This inner class is the inverse of the enclosing {@link AbstractMathTransform2D}.
      *
      * <div class="section">Serialization</div>
-     * Instances of this class are serializable only if the enclosing math transform is also serializable.
-     * Serialized math transforms are not guaranteed to be compatible with future SIS versions.
-     * Serialization, if allowed, should be used only for short term storage or RMI between applications
+     * This object may or may not be serializable, at implementation choices.
+     * Most Apache SIS implementations are serializable, but the serialized objects are not guaranteed to be compatible
+     * with future SIS versions. Serialization should be used only for short term storage or RMI between applications
      * running the same SIS version.
      *
      * @author  Martin Desruisseaux (Geomatys)
-     * @version 0.5
+     * @version 1.0
      * @since   0.5
      * @module
      */
-    protected abstract class Inverse extends AbstractMathTransform.Inverse implements MathTransform2D {
-        /**
-         * Serial number for inter-operability with different versions.
-         */
-        private static final long serialVersionUID = 5751908928042026412L;
-
+    protected abstract static class Inverse extends AbstractMathTransform.Inverse implements MathTransform2D {
         /**
          * Constructs an inverse math transform.
          */
@@ -342,12 +337,11 @@ public abstract class AbstractMathTransf
         }
 
         /**
-         * Returns the enclosing math transform.
+         * Returns the inverse of this math transform.
+         * The returned transform should be the enclosing math transform.
          */
         @Override
-        public MathTransform2D inverse() {
-            return (MathTransform2D) super.inverse();
-        }
+        public abstract MathTransform2D inverse();
 
         /**
          * Transforms the specified {@code ptSrc} and stores the result in {@code ptDst}.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -299,7 +299,7 @@ public class EllipsoidToCentricTransform
             final MatrixSIS normalize = context.getMatrix(ContextualParameters.MatrixRole.NORMALIZATION);
             normalize.convertBefore(2, a, null);    // Divide ellipsoidal height by a.
         }
-        inverse = new Inverse();
+        inverse = new Inverse(this);
     }
 
     /**
@@ -779,20 +779,34 @@ next:   while (--numPts >= 0) {
      * to ellipsoidal coordinates (λ,φ) or (λ,φ,<var>h</var>).
      *
      * @author  Martin Desruisseaux (IRD, Geomatys)
-     * @version 0.7
+     * @version 1.0
      * @since   0.7
      * @module
      */
-    private final class Inverse extends AbstractMathTransform.Inverse implements Serializable {
+    private static final class Inverse extends AbstractMathTransform.Inverse implements Serializable {
         /**
          * Serial number for inter-operability with different versions.
          */
-        private static final long serialVersionUID = 6942084702259211803L;
+        private static final long serialVersionUID = 33004303758761821L;
+
+        /**
+         * The enclosing transform.
+         */
+        private final EllipsoidToCentricTransform forward;
 
         /**
          * Creates the inverse of the enclosing transform.
          */
-        Inverse() {
+        Inverse(final EllipsoidToCentricTransform forward) {
+            this.forward = forward;
+        }
+
+        /**
+         * Returns the inverse of this math transform.
+         */
+        @Override
+        public MathTransform inverse() {
+            return forward;
         }
 
         /**
@@ -801,7 +815,7 @@ next:   while (--numPts >= 0) {
          */
         @Override
         protected ContextualParameters getContextualParameters() {
-            return context.inverse(GeocentricToGeographic.PARAMETERS);
+            return forward.context.inverse(GeocentricToGeographic.PARAMETERS);
         }
 
         /**
@@ -812,7 +826,7 @@ next:   while (--numPts >= 0) {
         @Override
         public ParameterValueGroup getParameterValues() {
             final ParameterValueGroup pg = getParameterDescriptors().createValue();
-            pg.values().addAll(EllipsoidToCentricTransform.this.getParameterValues().values());
+            pg.values().addAll(forward.getParameterValues().values());
             return pg;
         }
 
@@ -830,7 +844,7 @@ next:   while (--numPts >= 0) {
         public ParameterDescriptorGroup getParameterDescriptors() {
             return new DefaultParameterDescriptorGroup(Collections.singletonMap(ParameterDescriptorGroup.NAME_KEY,
                             new ImmutableIdentifier(Citations.SIS, Constants.SIS, "Centric to ellipsoid (radians domain)")),
-                    EllipsoidToCentricTransform.this.getParameterDescriptors());
+                    forward.getParameterDescriptors());
         }
 
         /**
@@ -860,14 +874,14 @@ next:   while (--numPts >= 0) {
         {
             final double[] point;
             final int offset;
-            if (derivate && (dstPts == null || !withHeight)) {
+            if (derivate && (dstPts == null || !forward.withHeight)) {
                 point  = new double[3];
                 offset = 0;
             } else {
                 point  = dstPts;
                 offset = dstOff;
             }
-            inverseTransform(srcPts, srcOff, point, offset, 1);
+            forward.inverseTransform(srcPts, srcOff, point, offset, 1);
             if (!derivate) {
                 return null;
             }
@@ -876,9 +890,9 @@ next:   while (--numPts >= 0) {
                 dstPts[dstOff+1] = point[1];
             }
             // We need to keep h during matrix inversion because (λ,φ,h) values are not independent.
-            Matrix matrix = EllipsoidToCentricTransform.this.derivative(new DirectPositionView(point, offset, 3));
+            Matrix matrix = forward.derivative(new DirectPositionView.Double(point, offset, 3));
             matrix = Matrices.inverse(matrix);
-            if (!withHeight) {
+            if (!forward.withHeight) {
                 matrix = MatrixSIS.castOrCopy(matrix).removeRows(2, 3);     // Drop height only after matrix inversion is done.
             }
             return matrix;
@@ -892,7 +906,7 @@ next:   while (--numPts >= 0) {
         public void transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)
                 throws TransformException
         {
-            inverseTransform(srcPts, srcOff, dstPts, dstOff, numPts);
+            forward.inverseTransform(srcPts, srcOff, dstPts, dstOff, numPts);
         }
 
         /**
@@ -918,7 +932,7 @@ next:   while (--numPts >= 0) {
         protected MathTransform tryConcatenate(final boolean applyOtherFirst, final MathTransform other,
                 final MathTransformFactory factory) throws FactoryException
         {
-            if (!applyOtherFirst && withHeight && other instanceof LinearTransform && other.getTargetDimensions() == 2) {
+            if (!applyOtherFirst && forward.withHeight && other instanceof LinearTransform && other.getTargetDimensions() == 2) {
                 /*
                  * Found a 3×4 matrix after this transform. We can reduce to a 3×3 matrix only if no dimension
                  * use the column that we are about to drop (i.e. all coefficients in that column are zero).
@@ -929,7 +943,7 @@ next:   while (--numPts >= 0) {
                     matrix.getElement(2,2) == 0)
                 {
                     matrix = MatrixSIS.castOrCopy(matrix).removeColumns(2, 3);
-                    final MathTransform tr2D = create2D().inverse();
+                    final MathTransform tr2D = forward.create2D().inverse();
                     if (factory != null) {
                         return factory.createConcatenatedTransform(tr2D, factory.createAffineTransform(matrix));
                     } else {
@@ -951,7 +965,7 @@ next:   while (--numPts >= 0) {
         @Override
         final int beforeFormat(final List<Object> transforms, int index, final boolean inverse) {
             index = super.beforeFormat(transforms, index, inverse);
-            if (!withHeight) {
+            if (!forward.withHeight) {
                 transforms.add(++index, new Geographic3Dto2D.WKT(false));
             }
             return index;

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -18,6 +18,7 @@ package org.apache.sis.referencing.opera
 
 import java.util.Arrays;
 import java.util.Objects;
+import java.io.Serializable;
 import javax.measure.Unit;
 import javax.measure.Quantity;
 import org.opengis.util.FactoryException;
@@ -382,7 +383,7 @@ public class InterpolatedTransform exten
      * To overridden by the two-dimensional transform case.
      */
     InterpolatedTransform.Inverse createInverse() {
-        return new Inverse();
+        return new Inverse(this);
     }
 
     /**
@@ -416,15 +417,20 @@ public class InterpolatedTransform exten
      *
      * @author  Rueben Schulz (UBC)
      * @author  Martin Desruisseaux (IRD, Geomatys)
-     * @version 0.7
+     * @version 1.0
      * @since   0.7
      * @module
      */
-    class Inverse extends AbstractMathTransform.Inverse {
+    static class Inverse extends AbstractMathTransform.Inverse implements Serializable {
         /**
          * Serial number for inter-operability with different versions.
          */
-        private static final long serialVersionUID = -6779719408779847014L;
+        private static final long serialVersionUID = 4335801994727826360L;
+
+        /**
+         * The enclosing transform.
+         */
+        private final InterpolatedTransform forward;
 
         /**
          * Difference allowed in iterative computations, in units of grid cell size.
@@ -434,15 +440,24 @@ public class InterpolatedTransform exten
         /**
          * Creates an inverse transform.
          */
-        Inverse() {
-            tolerance = grid.getCellPrecision();
-            if (!(tolerance > 0)) {         // Use ! for catching NaN.
+        Inverse(final InterpolatedTransform forward) {
+            this.forward = forward;
+            tolerance = forward.grid.getCellPrecision();
+            if (!(tolerance > 0)) {                                     // Use ! for catching NaN.
                 throw new IllegalArgumentException(Errors.format(
                         Errors.Keys.ValueNotGreaterThanZero_2, "grid.cellPrecision", tolerance));
             }
         }
 
         /**
+         * Returns the inverse of this math transform.
+         */
+        @Override
+        public MathTransform inverse() {
+            return forward;
+        }
+
+        /**
          * Transforms a single coordinate in a list of ordinal values,
          * and optionally returns the derivative at that location.
          *
@@ -452,6 +467,7 @@ public class InterpolatedTransform exten
         public final Matrix transform(final double[] srcPts, final int srcOff, double[] dstPts, int dstOff,
                                       final boolean derivate) throws TransformException
         {
+            final int dimension = forward.dimension;
             if (dstPts == null) {
                 dstPts = new double[dimension];
                 dstOff = 0;
@@ -462,7 +478,7 @@ public class InterpolatedTransform exten
             final double[] vector = new double[dimension];
             int it = Formulas.MAXIMUM_ITERATIONS;
             do {
-                grid.interpolateInCell(xi, yi, vector);
+                forward.grid.interpolateInCell(xi, yi, vector);
                 final double ox = xi;
                 final double oy = yi;
                 xi = x - vector[0];
@@ -487,8 +503,8 @@ public class InterpolatedTransform exten
                     dstPts[dstOff  ] = xi;      // Shall not be done before above loop.
                     dstPts[dstOff+1] = yi;
                     if (derivate) {
-                        return Matrices.inverse(InterpolatedTransform.this.derivative(
-                                new DirectPositionView(dstPts, dstOff, dimension)));
+                        return Matrices.inverse(forward.derivative(
+                                new DirectPositionView.Double(dstPts, dstOff, dimension)));
                     }
                     return null;
                 }
@@ -505,6 +521,7 @@ public class InterpolatedTransform exten
         public final void transform(double[] srcPts, int srcOff, final double[] dstPts, int dstOff, int numPts)
                 throws TransformException
         {
+            final int dimension = forward.dimension;
             int inc = dimension;
             if (srcPts == dstPts) {
                 switch (IterationStrategy.suggest(srcOff, inc, dstOff, inc, numPts)) {
@@ -531,7 +548,7 @@ nextPoint:  while (--numPts >= 0) {
                 final double y = yi = srcPts[srcOff+1];
                 int it = Formulas.MAXIMUM_ITERATIONS;
                 do {
-                    grid.interpolateInCell(xi, yi, vector);
+                    forward.grid.interpolateInCell(xi, yi, vector);
                     final double ox = xi;
                     final double oy = yi;
                     xi = x - vector[0];

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform2D.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform2D.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform2D.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform2D.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -84,14 +84,14 @@ final class InterpolatedTransform2D exte
      */
     @Override
     InterpolatedTransform.Inverse createInverse() {
-        return new Inverse();
+        return new Inverse(this);
     }
 
     /**
      * The inverse of the enclosing {@link InterpolatedTransform2D}.
      *
      * @author  Martin Desruisseaux (Geomatys)
-     * @version 0.7
+     * @version 1.0
      * @since   0.7
      * @module
      */
@@ -99,12 +99,13 @@ final class InterpolatedTransform2D exte
         /**
          * Serial number for inter-operability with different versions.
          */
-        private static final long serialVersionUID = 5739665311481484972L;
+        private static final long serialVersionUID = 4802773675799229357L;
 
         /**
          * Constructs the inverse of an interpolated transform.
          */
-        Inverse() {
+        Inverse(final InterpolatedTransform2D forward) {
+            super(forward);
         }
 
         /**

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/IterationStrategy.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/IterationStrategy.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/IterationStrategy.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/IterationStrategy.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -95,7 +95,7 @@ public enum IterationStrategy {
     DESCENDING(false),
 
     /**
-     * Copies the points to transform in a temporary array before to apply the transform.
+     * Copy the points to transform in a temporary array before to apply the transform.
      * The temporary array will be used for fetching the source ordinates.
      *
      * <p>This algorithm can be used as a fallback for any unknown enumeration.</p>
@@ -103,7 +103,7 @@ public enum IterationStrategy {
     BUFFER_SOURCE(true),
 
     /**
-     * Writes the transformed points in a temporary array and copies them to the
+     * Write the transformed points in a temporary array and copies them to the
      * destination subarray when the transformation is finished.
      *
      * <p>Developers are allowed to ignore this value and fallback on the same algorithm

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1D.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1D.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1D.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1D.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -97,7 +97,7 @@ final class LinearInterpolator1D extends
                 return;
             }
         }
-        inverse = new Inverse();
+        inverse = new Inverse(this);
     }
 
     /**
@@ -303,16 +303,30 @@ final class LinearInterpolator1D extends
      * a bilinear search for locating the lower and upper <var>x</var> values as integers, then interpolates the
      * <var>x</var> real value.
      */
-    private final class Inverse extends AbstractMathTransform1D.Inverse implements MathTransform1D {
+    private static final class Inverse extends AbstractMathTransform1D.Inverse implements MathTransform1D, Serializable {
         /**
          * For cross-version compatibility.
          */
-        private static final long serialVersionUID = 3179638888992528901L;
+        private static final long serialVersionUID = -5112948223332095009L;
+
+        /**
+         * The enclosing transform.
+         */
+        private final LinearInterpolator1D forward;
 
         /**
          * Creates a new inverse transform.
          */
-        Inverse() {
+        Inverse(final LinearInterpolator1D forward) {
+            this.forward = forward;
+        }
+
+        /**
+         * Returns the inverse of this math transform.
+         */
+        @Override
+        public MathTransform1D inverse() {
+            return forward;
         }
 
         /**
@@ -326,7 +340,7 @@ final class LinearInterpolator1D extends
                                 final boolean derivate) throws TransformException
         {
             final double d, x, y = srcPts[srcOff];
-            final double[] values = LinearInterpolator1D.this.values;
+            final double[] values = forward.values;
             int i = Arrays.binarySearch(values, y);
             if (i >= 0) {
                 x = i;
@@ -361,7 +375,7 @@ final class LinearInterpolator1D extends
          */
         @Override
         public double transform(final double y) {
-            final double[] values = LinearInterpolator1D.this.values;
+            final double[] values = forward.values;
             int i = Arrays.binarySearch(values, y);
             if (i >= 0) {
                 return i;
@@ -390,7 +404,7 @@ final class LinearInterpolator1D extends
          */
         @Override
         public double derivative(final double y) {
-            final double[] values = LinearInterpolator1D.this.values;
+            final double[] values = forward.values;
             int i = Arrays.binarySearch(values, y);
             if (i < 0) {
                 i = ~i;

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -16,10 +16,12 @@
  */
 package org.apache.sis.referencing.operation.transform;
 
+import java.util.Map;
 import java.util.List;
 import java.util.Collections;
 import java.awt.geom.AffineTransform;
 import org.opengis.util.FactoryException;
+import org.opengis.geometry.Envelope;
 import org.opengis.geometry.MismatchedDimensionException;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
@@ -51,7 +53,7 @@ import org.apache.sis.util.Static;
  * GeoAPI factory interfaces instead.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
  *
  * @see MathTransformFactory
  *
@@ -177,6 +179,45 @@ public final class MathTransforms extend
     }
 
     /**
+     * Creates a transform defined as one transform applied globally except in sub-areas where more accurate
+     * transforms are available. Such constructs appear in some datum shift files. The result of transforming
+     * a point by the returned {@code MathTransform} is as if iterating over all given {@link Envelope}s in
+     * no particular order, find the smallest one containing the point to transform (envelope border considered
+     * inclusive), then use the associated {@link MathTransform} for transforming the point.
+     * If the point is not found in any envelope, then the global transform is applied.
+     *
+     * <p>The following constraints apply:</p>
+     * <ul>
+     *   <li>The global transform must be a reasonable approximation of the specialized transforms
+     *       (this is required for calculating the inverse transform).</li>
+     *   <li>All transforms in the {@code specializations} map must have the same number of source and target
+     *       dimensions than the {@code global} transform.</li>
+     *   <li>All envelopes in the {@code specializations} map must have the same number of dimensions
+     *       than the global transform <em>source</em> dimensions.</li>
+     *   <li>In current implementation, each envelope must either be fully included in another envelope,
+     *       or not overlap any other envelope.</li>
+     * </ul>
+     *
+     * @param  global  the transform to use globally where there is no suitable specialization.
+     * @param  specializations  more accurate transforms available in some sub-areas.
+     * @return a transform applying the given global transform except in sub-areas where specializations are available.
+     * @throws IllegalArgumentException if a constraint is not meet.
+     *
+     * @since 1.0
+     */
+    public static MathTransform specialize(final MathTransform global, final Map<Envelope,MathTransform> specializations) {
+        ArgumentChecks.ensureNonNull("generic", global);
+        ArgumentChecks.ensureNonNull("specializations", specializations);
+        if (specializations.isEmpty()) {
+            return global;
+        } else if (global.getSourceDimensions() == 2 && global.getTargetDimensions() == 2) {
+            return new SpecializableTransform2D(global, specializations);
+        } else {
+            return new SpecializableTransform(global, specializations);
+        }
+    }
+
+    /**
      * Puts together a list of independent math transforms, each of them operating on a subset of ordinate values.
      * This method is often used for defining 4-dimensional (<var>x</var>,<var>y</var>,<var>z</var>,<var>t</var>)
      * transform as an aggregation of 3 simpler transforms operating on (<var>x</var>,<var>y</var>), (<var>z</var>)
@@ -443,7 +484,8 @@ public final class MathTransforms extend
             return ((AbstractMathTransform) transform).transform(srcPts, srcOff, dstPts, dstOff, true);
         }
         // Must be calculated before to transform the coordinate.
-        final Matrix derivative = transform.derivative(new DirectPositionView(srcPts, srcOff, transform.getSourceDimensions()));
+        final Matrix derivative = transform.derivative(
+                new DirectPositionView.Double(srcPts, srcOff, transform.getSourceDimensions()));
         if (dstPts != null) {
             transform.transform(srcPts, srcOff, dstPts, dstOff, 1);
         }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -318,7 +318,7 @@ public class PassThroughTransform extend
     {
         Matrix derivative = null;
         if (derivate) {
-            derivative = derivative(new DirectPositionView(srcPts, srcOff, getSourceDimensions()));
+            derivative = derivative(new DirectPositionView.Double(srcPts, srcOff, getSourceDimensions()));
         }
         if (dstPts != null) {
             transform(srcPts, srcOff, dstPts, dstOff, 1);

Copied: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java (from r1825995, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java?p2=sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java&p1=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java&r1=1825995&r2=1826248&rev=1826248&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -23,7 +23,7 @@ import java.io.Serializable;
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
-import org.opengis.geometry.MismatchedReferenceSystemException;
+import org.apache.sis.geometry.MismatchedReferenceSystemException;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.TransformException;

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -61,7 +61,7 @@
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Adrian Custer (Geomatys)
- * @version 0.7
+ * @version 1.0
  * @since   0.5
  * @module
  */

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractDirectPositionTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractDirectPositionTest.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractDirectPositionTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractDirectPositionTest.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -26,17 +26,52 @@ import static org.apache.sis.test.Assert
  * Tests the static methods provided in {@link AbstractDirectPosition}.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
  * @since   0.3
  * @module
  */
 public final strictfp class AbstractDirectPositionTest extends TestCase {
     /**
-     * Tests {@link AbstractDirectPosition#isSimplePrecision(double[])}.
+     * Tests {@link AbstractDirectPosition#parse(CharSequence)}.
      */
     @Test
-    public void testIsSimplePrecision() {
-        assertTrue (AbstractDirectPosition.isSimplePrecision(2, 0.5, 0.25, Double.NaN, Double.POSITIVE_INFINITY));
-        assertFalse(AbstractDirectPosition.isSimplePrecision(2, 0.5, 1.0 / 3));
+    public void testParse() {
+        assertArrayEquals(new double[] {6, 10, 2}, AbstractDirectPosition.parse("POINT(6 10 2)"),       STRICT);
+        assertArrayEquals(new double[] {3, 14, 2}, AbstractDirectPosition.parse("POINT M [ 3 14 2 ] "), STRICT);
+        assertArrayEquals(new double[] {2, 10, 8}, AbstractDirectPosition.parse("POINT Z 2 10 8"),      STRICT);
+        assertArrayEquals(new double[] {},         AbstractDirectPosition.parse("POINT()"),             STRICT);
+        assertArrayEquals(new double[] {},         AbstractDirectPosition.parse("POINT ( ) "),          STRICT);
+    }
+
+    /**
+     * Tests {@link AbstractDirectPosition#parse(CharSequence)} with invalid input strings.
+     */
+    @Test
+    public void testParsingFailures() {
+        try {
+            AbstractDirectPosition.parse("POINT(6 10 2");
+            fail("Parsing should fails because of missing parenthesis.");
+        } catch (IllegalArgumentException e) {
+            // This is the expected exception.
+            final String message = e.getMessage();
+            assertTrue(message, message.contains("POINT(6 10 2"));
+            assertTrue(message, message.contains("‘)’"));
+        }
+        try {
+            AbstractDirectPosition.parse("POINT 6 10 2)");
+            fail("Parsing should fails because of missing parenthesis.");
+        } catch (IllegalArgumentException e) {
+            // This is the expected exception.
+        }
+        try {
+            AbstractDirectPosition.parse("POINT(6 10 2) x");
+            fail("Parsing should fails because of extra characters.");
+        } catch (IllegalArgumentException e) {
+            // This is the expected exception.
+            final String message = e.getMessage();
+            assertTrue(message, message.contains("POINT(6 10 2) x"));
+            assertTrue(message, message.contains("“x”") ||                  // English locale
+                                message.contains("« x »"));                 // French locale
+        }
     }
 }

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/ArrayEnvelopeTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/ArrayEnvelopeTest.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/ArrayEnvelopeTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/ArrayEnvelopeTest.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -16,11 +16,12 @@
  */
 package org.apache.sis.geometry;
 
+import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
@@ -28,7 +29,7 @@ import static org.junit.Assert.*;
  * This is the base class of {@link GeneralEnvelope} and {@link ImmutableEnvelope}.
  *
  * @author  Michael Hausegger
- * @version 0.8
+ * @version 1.0
  * @since   0.8
  * @module
  */
@@ -64,6 +65,21 @@ public final strictfp class ArrayEnvelop
     }
 
     /**
+     * Tests the {@link ArrayEnvelope#formatTo(Formatter)} method.
+     * Contrarily to {@code toString()}, the precision depends on the CRS.
+     */
+    @Test
+    public void testFormatWKT() {
+        ArrayEnvelope envelope = new ArrayEnvelope(new double[] {4, -10, 50, 2});
+        assertMultilinesEquals("BOX[ 4 -10,\n" +
+                               "    50   2]", envelope.toWKT());
+        envelope.crs = AbstractEnvelopeTest.WGS84;
+        assertMultilinesEquals("BOX[ 4.00000000 -10.00000000,\n" +
+                               "    50.00000000   2.00000000]", envelope.toWKT());
+
+    }
+
+    /**
      * Tests envelope construction from a the pseudo-Well Known Text (WKT) representation of a Bounding Box (BBOX).
      */
     @Test

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -17,6 +17,7 @@
 package org.apache.sis.geometry;
 
 import java.util.Arrays;
+import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
@@ -30,7 +31,7 @@ import static org.apache.sis.geometry.Ab
  * Tests the {@link GeneralDirectPosition} class.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
  * @since   0.3
  * @module
  */
@@ -49,10 +50,23 @@ public final strictfp class GeneralDirec
     }
 
     /**
+     * Tests the {@link GeneralDirectPosition#formatTo(Formatter)} method.
+     * Contrarily to {@code toString()}, the precision depends on the CRS.
+     */
+    @Test
+    public void testFormatWKT() {
+        final GeneralDirectPosition position = new GeneralDirectPosition(6, 10);
+        assertEquals("POINT[6 10]", position.toWKT());
+        position.setCoordinateReferenceSystem(WGS84);
+        assertEquals("POINT[6.00000000 10.00000000]", position.toWKT());        // 1 cm precision on Earth.
+        validate(position);
+    }
+
+    /**
      * Tests the {@link GeneralDirectPosition#toString()} method.
      */
     @Test
-    public void testWktFormatting() {
+    public void testToString() {
         final GeneralDirectPosition position = new GeneralDirectPosition(6, 10, 2);
         assertEquals("POINT(6 10 2)", position.toString());
         validate(position);
@@ -62,7 +76,7 @@ public final strictfp class GeneralDirec
      * Tests the {@link GeneralDirectPosition#GeneralDirectPosition(CharSequence)} constructor.
      */
     @Test
-    public void testWktParsing() {
+    public void testConstructor() {
         assertEquals("POINT(6 10 2)", new GeneralDirectPosition("POINT(6 10 2)").toString());
         assertEquals("POINT(3 14 2)", new GeneralDirectPosition("POINT M [ 3 14 2 ] ").toString());
         assertEquals("POINT(2 10 8)", new GeneralDirectPosition("POINT Z 2 10 8").toString());
@@ -71,40 +85,6 @@ public final strictfp class GeneralDirec
     }
 
     /**
-     * Tests the {@link GeneralDirectPosition#GeneralDirectPosition(CharSequence)} constructor
-     * with invalid input strings.
-     */
-    @Test
-    @SuppressWarnings("ResultOfObjectAllocationIgnored")
-    public void testWktParsingFailures() {
-        try {
-            new GeneralDirectPosition("POINT(6 10 2");
-            fail("Parsing should fails because of missing parenthesis.");
-        } catch (IllegalArgumentException e) {
-            // This is the expected exception.
-            final String message = e.getMessage();
-            assertTrue(message, message.contains("POINT(6 10 2"));
-            assertTrue(message, message.contains("‘)’"));
-        }
-        try {
-            new GeneralDirectPosition("POINT 6 10 2)");
-            fail("Parsing should fails because of missing parenthesis.");
-        } catch (IllegalArgumentException e) {
-            // This is the expected exception.
-        }
-        try {
-            new GeneralDirectPosition("POINT(6 10 2) x");
-            fail("Parsing should fails because of extra characters.");
-        } catch (IllegalArgumentException e) {
-            // This is the expected exception.
-            final String message = e.getMessage();
-            assertTrue(message, message.contains("POINT(6 10 2) x"));
-            assertTrue(message, message.contains("“x”") ||  // English locale
-                                message.contains("« x »")); // French locale
-        }
-    }
-
-    /**
      * Tests {@link GeneralDirectPosition#clone()}.
      */
     @Test

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/FormulasTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/FormulasTest.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/FormulasTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/FormulasTest.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -18,6 +18,7 @@ package org.apache.sis.internal.referenc
 
 import org.apache.sis.internal.metadata.ReferencingServices;
 import org.apache.sis.measure.Longitude;
+import org.apache.sis.referencing.datum.HardCodedDatum;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -28,7 +29,7 @@ import static org.junit.Assert.*;
  * Tests {@link Formulas}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
  * @since   0.4
  * @module
  */
@@ -90,6 +91,14 @@ public final strictfp class FormulasTest
     }
 
     /**
+     * Tests {@link Formulas#scaleComparedToEarth(Ellipsoid)}.
+     */
+    @Test
+    public void testScaleComparedToEarth() {
+        assertEquals(1, Formulas.scaleComparedToEarth(HardCodedDatum.WGS84.getEllipsoid()), 1E-14);
+    }
+
+    /**
      * Tests {@link Formulas#getSemiMinor(double, double)}.
      */
     @Test

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -39,7 +39,7 @@ import static org.apache.sis.internal.re
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
- * @since   0.5 (derived from 0.4)
+ * @since   0.4
  * @module
  */
 public final strictfp class ReferencingUtilitiesTest extends TestCase {

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTUtilitiesTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTUtilitiesTest.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTUtilitiesTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTUtilitiesTest.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -17,6 +17,7 @@
 package org.apache.sis.internal.referencing;
 
 import org.opengis.referencing.cs.*;
+import org.apache.sis.referencing.crs.HardCodedCRS;
 import org.apache.sis.internal.metadata.WKTKeywords;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -30,7 +31,7 @@ import static org.apache.sis.internal.re
  * Tests {@link WKTUtilities}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
  * @since   0.7
  * @module
  */
@@ -55,4 +56,15 @@ public final strictfp class WKTUtilities
         assertEquals(WKTKeywords.temporal,    toType(CoordinateSystem.class, TimeCS          .class));
         assertEquals(WKTKeywords.vertical,    toType(CoordinateSystem.class, VerticalCS      .class));
     }
+
+    /**
+     * Tests {@link WKTUtilities#suggestFractionDigits(CoordinateReferenceSystem, double[]...)}.
+     */
+    @Test
+    public void testSuggestFractionDigits() {
+        assertArrayEquals(new int[] {8, 9}, WKTUtilities.suggestFractionDigits(HardCodedCRS.WGS84, new double[][] {
+            {40, -10},
+            {50, -10.000000001}
+        }));
+    }
 }

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -32,7 +32,7 @@ import org.apache.sis.referencing.datum.
  * This class can generate random number suitable for their domain.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 1.0
  * @since   0.5
  * @module
  */
@@ -215,6 +215,14 @@ public strictfp class CoordinateDomain {
             -10, 10);
 
     /**
+     * Values in the -100 to 100 range in all dimensions.
+     */
+    public static final CoordinateDomain RANGE_100 = new CoordinateDomain(
+            -100, 100,
+            -100, 100,
+            -100, 100);
+
+    /**
      * The domain of the coordinates to test.
      */
     final double xmin, xmax, ymin, ymax, zmin, zmax;

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PseudoTransform.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PseudoTransform.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PseudoTransform.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PseudoTransform.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -96,7 +96,7 @@ strictfp class PseudoTransform extends A
                             final boolean derivate) throws TransformException
     {
         final Matrix derivative = derivate ? derivative(
-                new DirectPositionView(srcPts, srcOff, getSourceDimensions())) : null;
+                new DirectPositionView.Double(srcPts, srcOff, getSourceDimensions())) : null;
         System.arraycopy(srcPts, srcOff, buffer, 0, sourceDimension);
         for (int i=0; i<targetDimension; i++) {
             double v = buffer[i % sourceDimension];

Copied: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java (from r1825995, sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java?p2=sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java&p1=sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java&r1=1825995&r2=1826248&rev=1826248&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -133,7 +133,6 @@ public final strictfp class Specializabl
     public void testForwardConsistency() throws TransformException {
         transform = create(false);
         tolerance = 1E-14;
-        isDerivativeSupported = false;          // Actually supported, but our test transform has discontinuities.
         verifyInDomain(CoordinateDomain.RANGE_10, -672445632505596619L);
     }
 
@@ -150,7 +149,6 @@ public final strictfp class Specializabl
     public void testInverseConsistency() throws TransformException {
         transform = create(false).inverse();
         tolerance = 1E-12;
-        isDerivativeSupported = false;          // Actually supported, but our test transform has discontinuities.
         verifyInDomain(CoordinateDomain.RANGE_100, 4308397764777385180L);
     }
 

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -25,7 +25,7 @@ import org.junit.BeforeClass;
  * All tests from the {@code sis-referencing} module, in approximative dependency order.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.3
  * @module
  */
@@ -131,6 +131,7 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.operation.transform.PolarToCartesianTest.class,
     org.apache.sis.referencing.operation.transform.CartesianToPolarTest.class,
     org.apache.sis.referencing.operation.transform.CoordinateSystemTransformTest.class,
+    org.apache.sis.referencing.operation.transform.SpecializableTransformTest.class,
     org.apache.sis.referencing.operation.DefaultFormulaTest.class,
     org.apache.sis.referencing.operation.DefaultOperationMethodTest.class,
     org.apache.sis.referencing.operation.AbstractSingleOperationTest.class,

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -21,6 +21,8 @@ import java.util.HashMap;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.ComparisonMode;
+import org.apache.sis.math.DecimalFunctions;
+import org.opengis.referencing.operation.Matrix;    // For javadoc
 
 import static java.lang.Math.max;
 import static java.lang.Math.abs;
@@ -30,7 +32,7 @@ import static java.lang.Math.abs;
  * Miscellaneous utilities methods working on floating point numbers.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.3
  * @module
  */
@@ -156,6 +158,22 @@ public final class Numerics extends Stat
     }
 
     /**
+     * Returns {@code true} if every values in the given {@code double} array could be casted to the
+     * {@code float} type without precision lost. This method treats all {@code NaN} values as equal.
+     *
+     * @param  values  the value to test for their precision.
+     * @return {@code true} if every values can be casted to the {@code float} type without precision lost.
+     */
+    public static boolean isSimplePrecision(final double... values) {
+        for (final double value : values) {
+            if (Double.doubleToLongBits(value) != Double.doubleToLongBits((float) value)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
      * Returns a copy of the given array where each value has been casted to the {@code float} type.
      *
      * @param  data  the array to copy, or {@code null}.
@@ -428,4 +446,51 @@ public final class Numerics extends Stat
         }
         return bits;
     }
+
+    /**
+     * Suggests an amount of fraction digits to use for formatting numbers in each column of the given matrix.
+     * The number of fraction digits may be negative if we could round the numbers to 10, 100, <i>etc</i>.
+     *
+     * @param  rows  the matrix rows. It is not required that each row has the same length.
+     * @return suggested amount of fraction digits as an array as long as the longest row.
+     *
+     * @see org.apache.sis.referencing.operation.matrix.Matrices#toString(Matrix)
+     */
+    public static int[] suggestFractionDigits(final double[][] rows) {
+        int length = 0;
+        final int n = rows.length - 1;
+        for (int j=0; j <= n; j++) {
+            final int rl = rows[j].length;
+            if (rl > length) length = rl;
+        }
+        final int[] fractionDigits = new int[length];
+        for (int i=0; i<length; i++) {
+            double min = Double.POSITIVE_INFINITY;
+            double max = Double.NEGATIVE_INFINITY;
+            boolean isInteger = true;
+            for (final double[] row : rows) {
+                if (row.length > i) {
+                    final double value = row[i];
+                    if (value < min) min = value;
+                    if (value > max) max = value;
+                    if (isInteger && Math.floor(value) != value && !Double.isNaN(value)) {
+                        isInteger = false;
+                    }
+                }
+            }
+            if (!isInteger) {
+                final double  delta;
+                final boolean strict;
+                if (min < max) {
+                    delta  = (max - min) / n;
+                    strict = (n == 1);
+                } else {
+                    delta  = Math.max(Math.abs(min), Math.abs(max)) * 1E-6;     // The 1E-6 factor is arbitrary.
+                    strict = false;
+                }
+                fractionDigits[i] = DecimalFunctions.fractionDigitsForDelta(delta, strict);
+            }
+        }
+        return fractionDigits;
+    }
 }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -40,6 +40,8 @@ import org.apache.sis.util.CharSequences
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.internal.util.MetadataServices;
+import org.apache.sis.measure.RangeFormat;
+import org.apache.sis.measure.Range;
 
 
 /**
@@ -68,7 +70,7 @@ import org.apache.sis.internal.util.Meta
  * multiple threads.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.3
  * @module
  */
@@ -418,6 +420,9 @@ public class IndexedResourceBundle exten
                 replacement = Classes.getShortName(getPublicType((Class<?>) element));
             } else if (element instanceof CodeList<?>) {
                 replacement = MetadataServices.getInstance().getCodeTitle((CodeList<?>) element, getLocale());
+            } else if (element instanceof Range<?>) {
+                final Range<?> range = (Range<?>) element;
+                replacement = new RangeFormat(getLocale(), range.getElementType()).format(range);
             }
             /*
              * No need to check for Numbers or Dates instances, since they are

Modified: sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -34,7 +34,7 @@ import static org.junit.Assert.*;
  * Tests the {@link Numerics} class.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 1.0
  * @since   0.3
  * @module
  */
@@ -69,6 +69,15 @@ public final strictfp class NumericsTest
     }
 
     /**
+     * Tests {@link Numerics#isSimplePrecision(double[])}.
+     */
+    @Test
+    public void testIsSimplePrecision() {
+        assertTrue (Numerics.isSimplePrecision(2, 0.5, 0.25, Double.NaN, Double.POSITIVE_INFINITY));
+        assertFalse(Numerics.isSimplePrecision(2, 0.5, 1.0 / 3));
+    }
+
+    /**
      * Tests the {@link Numerics#epsilonEqual(double, double, ComparisonMode)} method.
      */
     @Test
@@ -162,4 +171,17 @@ public final strictfp class NumericsTest
         final float recomposed = StrictMath.scalb((float) expected, e);
         assertEquals(value, StrictMath.copySign(recomposed, value), 0f);
     }
+
+    /**
+     * Tests {@link Numerics#suggestFractionDigits(double[][])}.
+     */
+    @Test
+    public void testSuggestFractionDigits() {
+        final int[] f = Numerics.suggestFractionDigits(new double[][] {
+            {10, 100,   0.1, 1000.1},
+            {15, 140.1, 0.4, Double.NaN},
+            {20, 400,   0.5, Double.NaN}
+        });
+        assertArrayEquals(new int[] {0, -2, 1, 3}, f);
+    }
 }



Mime
View raw message