sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1826248 [1/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
Author: desruisseaux
Date: Thu Mar  8 15:44:56 2018
New Revision: 1826248

URL: http://svn.apache.org/viewvc?rev=1826248&view=rev
Log:
Merge GeoTIFF Sentinel 1 support from JDK8 branch.

Added:
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
      - copied, changed from r1825995, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform1D.txt
      - copied unchanged from r1825995, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform1D.txt
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform2D.java
      - copied unchanged from r1825995, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/SpecializableTransform2D.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java
      - copied, changed from r1825995, sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/SpecializableTransformTest.java
Modified:
    sis/trunk/   (props changed)
    sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Symbols.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/ZonedGridSystem.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/package-info.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform1D.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform2D.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransform.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform2D.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/IterationStrategy.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/LinearInterpolator1D.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/package-info.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/AbstractDirectPositionTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/ArrayEnvelopeTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/geometry/GeneralDirectPositionTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/FormulasTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ReferencingUtilitiesTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTUtilitiesTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/PseudoTransform.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java
    sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GridGeometry.java

Propchange: sis/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Mar  8 15:44:56 2018
@@ -2,5 +2,5 @@
 /sis/branches/ISO-19115-3:1804459-1825252
 /sis/branches/JDK6:1394364-1758914
 /sis/branches/JDK7:1394913-1822221
-/sis/branches/JDK8:1584960-1825489
+/sis/branches/JDK8:1584960-1825995
 /sis/branches/JDK9:1773327-1803064

Modified: sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java
URL: http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java [UTF-8] (original)
+++ sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -586,7 +586,7 @@ final class TransformCommand extends For
         if (toDomainOfValidity != null && (bbox = CRS.getGeographicBoundingBox(operation)) != null) {
             domainOfValidity = new ImmutableEnvelope(bbox);
             domainCoordinate = new double[toDomainOfValidity.getTargetDimensions()];
-            positionInDomain = new DirectPositionView(domainCoordinate, 0, domainCoordinate.length);
+            positionInDomain = new DirectPositionView.Double(domainCoordinate, 0, domainCoordinate.length);
         } else {
             domainOfValidity = null;
             domainCoordinate = null;

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -83,7 +83,8 @@ public class ReferencingServices extends
 
     /**
      * The GRS80 {@linkplain org.apache.sis.referencing.datum.DefaultEllipsoid#getAuthalicRadius() authalic radius},
-     * which is {@value} metres.
+     * which is {@value} metres. This is close to the WGS84 authalic radius, which is about 6371007.180918474 when
+     * computed with {@code double} precision.
      */
     public static final double AUTHALIC_RADIUS = 6371007;
 

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -35,7 +35,7 @@ import org.apache.sis.util.Static;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 0.7
+ * @version 1.0
  *
  * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
  * @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>
@@ -214,4 +214,10 @@ public final class WKTKeywords extends S
             spherical   = "spherical",
             temporal    = "temporal",
             vertical    = "vertical";
+
+    /**
+     * Geometries.
+     */
+    public static final String
+            Point       = "Point";
 }

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -35,6 +35,7 @@ import java.math.RoundingMode;
 import javax.measure.Unit;
 import javax.measure.Quantity;
 
+import org.opengis.util.CodeList;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
@@ -54,7 +55,6 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.ConcatenatedOperation;
 import org.opengis.referencing.operation.MathTransform;
-import org.opengis.util.CodeList;
 
 import org.apache.sis.measure.Units;
 import org.apache.sis.math.DecimalFunctions;
@@ -69,7 +69,9 @@ import org.apache.sis.util.CharSequences
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.util.collection.IntegerList;
 import org.apache.sis.internal.util.X364;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.util.Citations;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.StandardDateFormat;
@@ -98,7 +100,7 @@ import org.apache.sis.metadata.iso.exten
  * </ul>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.0
  *
  * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
  * @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>
@@ -147,9 +149,9 @@ public class Formatter implements Locali
 
     /**
      * The value of {@link Symbols#getSeparator()} without trailing spaces, followed by the system line separator.
-     * Computed by {@link Symbols#lineSeparator()} and stored for reuse.
+     * Computed by {@link Symbols#separatorNewLine()} and stored for reuse.
      */
-    private final String lineSeparator;
+    private final String separatorNewLine;
 
     /**
      * The colors to use for this formatter, or {@code null} for no syntax coloring.
@@ -288,6 +290,14 @@ public class Formatter implements Locali
     private int margin;
 
     /**
+     * Indices where to insert additional margin, or {@code null} if none. The margin to insert will be
+     * the the width of the keyword (e.g. {@code "BOX"}), which is usually unknown to {@code Formatter}
+     * until {@link FormattableObject} finished to write the element. This field is usually {@code null},
+     * unless formatting geometries.
+     */
+    private IntegerList keywordSpaceAt;
+
+    /**
      * {@code true} if a new line were requested during the execution of {@link #append(FormattableObject)}.
      * This is used to determine if the next {@code UNIT} and {@code ID} elements shall appear on a new line.
      */
@@ -338,16 +348,16 @@ public class Formatter implements Locali
         ArgumentChecks.ensureNonNull("convention",  convention);
         ArgumentChecks.ensureNonNull("symbols",     symbols);
         ArgumentChecks.ensureBetween("indentation", WKTFormat.SINGLE_LINE, Byte.MAX_VALUE, indentation);
-        this.locale        = Locale.getDefault(Locale.Category.DISPLAY);
-        this.convention    = convention;
-        this.authority     = convention.getNameAuthority();
-        this.symbols       = symbols.immutable();
-        this.lineSeparator = this.symbols.lineSeparator();
-        this.indentation   = (byte) indentation;
-        this.numberFormat  = symbols.createNumberFormat();
-        this.dateFormat    = new StandardDateFormat(symbols.getLocale());
-        this.unitFormat    = new UnitFormat(symbols.getLocale());
-        this.buffer        = new StringBuffer();
+        this.locale           = Locale.getDefault(Locale.Category.DISPLAY);
+        this.convention       = convention;
+        this.authority        = convention.getNameAuthority();
+        this.symbols          = symbols.immutable();
+        this.separatorNewLine = this.symbols.separatorNewLine();
+        this.indentation      = (byte) indentation;
+        this.numberFormat     = symbols.createNumberFormat();
+        this.dateFormat       = new StandardDateFormat(symbols.getLocale());
+        this.unitFormat       = new UnitFormat(symbols.getLocale());
+        this.buffer           = new StringBuffer();
         unitFormat.setStyle(UnitFormat.Style.NAME);
         if (convention.usesCommonUnits) {
             unitFormat.setLocale(Locale.US);
@@ -361,15 +371,15 @@ public class Formatter implements Locali
     Formatter(final Locale locale, final Symbols symbols, final NumberFormat numberFormat,
             final DateFormat dateFormat, final UnitFormat unitFormat)
     {
-        this.locale        = locale;
-        this.convention    = Convention.DEFAULT;
-        this.authority     = Convention.DEFAULT.getNameAuthority();
-        this.symbols       = symbols;
-        this.lineSeparator = this.symbols.lineSeparator();
-        this.indentation   = Constants.DEFAULT_INDENTATION;
-        this.numberFormat  = numberFormat;                      // No clone needed.
-        this.dateFormat    = dateFormat;
-        this.unitFormat    = unitFormat;
+        this.locale           = locale;
+        this.convention       = Convention.DEFAULT;
+        this.authority        = Convention.DEFAULT.getNameAuthority();
+        this.symbols          = symbols;
+        this.separatorNewLine = symbols.separatorNewLine();
+        this.indentation      = Constants.DEFAULT_INDENTATION;
+        this.numberFormat     = numberFormat;                      // No clone needed.
+        this.dateFormat       = dateFormat;
+        this.unitFormat       = unitFormat;
         // Do not set the buffer. It will be set by WKTFormat.format(…).
     }
 
@@ -558,7 +568,7 @@ public class Formatter implements Locali
     private void appendSeparator() {
         if (buffer.length() != elementStart) {
             if (requestNewLine) {
-                buffer.append(lineSeparator).append(CharSequences.spaces(margin));
+                buffer.append(separatorNewLine).append(CharSequences.spaces(margin));
             } else {
                 buffer.append(symbols.getSeparator());
             }
@@ -639,7 +649,7 @@ public class Formatter implements Locali
             }
         }
         enclosingElements.add(object);
-        if (hasContextualUnit < 0) { // Test if leftmost bit is set to 1.
+        if (hasContextualUnit < 0) {                            // Test if leftmost bit is set to 1.
             throw new IllegalStateException(Errors.getResources(locale).getString(Errors.Keys.TreeDepthExceedsMaximum));
         }
         hasContextualUnit <<= 1;
@@ -683,6 +693,24 @@ public class Formatter implements Locali
         highlightError = false;
         buffer.insert(base, keyword);
         /*
+         * When formatting geometry coordinates, we may need to shift all numbers by the width
+         * of the keyword inserted above in order to keep numbers properly aligned. Exemple:
+         *
+         *     BOX[ 4.000 -10.000
+         *         50.000   2.000]
+         */
+        if (keywordSpaceAt != null) {
+            final int length = keyword.length();
+            final CharSequence additionalMargin = CharSequences.spaces(keyword.codePointCount(0, length));
+            final int n = keywordSpaceAt.size();
+            for (int i=0; i<n;) {
+                int p = keywordSpaceAt.getInt(i);
+                p += (++i * length);                    // Take in account spaces added previously.
+                buffer.insert(p, additionalMargin);
+            }
+            keywordSpaceAt.clear();
+        }
+        /*
          * Format the SCOPE["…"], AREA["…"] and other elements. Some of those information
          * are available only for Datum, CoordinateOperation and ReferenceSystem objects.
          */
@@ -693,6 +721,9 @@ public class Formatter implements Locali
             appendComplement(info, (stackDepth >= 1) ? enclosingElements.get(stackDepth - 1) : null,
                                    (stackDepth >= 2) ? enclosingElements.get(stackDepth - 2) : null);
         }
+        /*
+         * Close the bracket, then update the queue of enclosed elements by removing this element.
+         */
         buffer.appendCodePoint(symbols.getClosingBracket(0));
         indent(-1);
         enclosingElements.remove(stackDepth);
@@ -1171,7 +1202,7 @@ public class Formatter implements Locali
              * maximum of 8 fraction digits, which is more than enough.
              */
             numberFormat.setMaximumFractionDigits(DecimalFunctions.fractionDigitsForValue(number, 2));
-            numberFormat.setMinimumFractionDigits(1); // Must be after setMaximumFractionDigits(…).
+            numberFormat.setMinimumFractionDigits(1);   // Must be after setMaximumFractionDigits(…).
             numberFormat.setRoundingMode(RoundingMode.HALF_EVEN);
             numberFormat.format(number, buffer, dummy);
         }
@@ -1179,6 +1210,124 @@ public class Formatter implements Locali
     }
 
     /**
+     * Appends rows of numbers. Each number is separated by a space, and each row is separated by a comma.
+     * This method is mostly for formatting geometries, but it could be used for other objects like matrix
+     * as well. Each row usually have the same length, but this is not mandatory.
+     *
+     * @param  rows            rows to append, or {@code null} if none.
+     * @param  fractionDigits  the number of fraction digits for each number in a row, or {@code null} for default.
+     *         If a row contains more numbers than {@code fractionDigits.length}, then the last value in this array
+     *         is repeated for all remaining row numbers.
+     *
+     * @since 1.0
+     */
+    public void append(final double[][] rows, int... fractionDigits) {
+        if (rows == null || rows.length == 0) {
+            return;
+        }
+        if (fractionDigits == null || fractionDigits.length == 0) {
+            fractionDigits = Numerics.suggestFractionDigits(rows);
+        }
+        numberFormat.setRoundingMode(RoundingMode.HALF_EVEN);
+        /*
+         * If the rows are going to be formatted on many lines, then we will need to put some margin before each row.
+         * If the first row starts on its own line, then the margin will be the usual indentation. But if the first
+         * row starts on the same line than previous elements (or the keyword of this element, e.g. "BOX["), then we
+         * will need a different amount of spaces if we want to have the numbers properly aligned.
+         */
+        final boolean isMultiLines = (indentation > WKTFormat.SINGLE_LINE) && (rows.length > 1);
+        final boolean needsAlignment = !requestNewLine;
+        final CharSequence marginBeforeRow;
+        if (isMultiLines) {
+            int currentLineLength = margin;
+            if (needsAlignment) {
+                final int length = buffer.length();
+                int i = length;
+                while (i > 0) {                                         // Locate beginning of current line.
+                    final int c = buffer.codePointBefore(i);
+                    if (Characters.isLineOrParagraphSeparator(c)) break;
+                    i -= Character.charCount(c);
+                }
+                currentLineLength = buffer.codePointCount(i, length);
+            }
+            marginBeforeRow = CharSequences.spaces(currentLineLength);
+        } else {
+            marginBeforeRow = "";
+        }
+        /*
+         * 'formattedNumberMarks' contains, for each number in each row, positions in the 'buffer' where
+         * the number starts and position where it ends. Those positions are stored as (start,end) pairs.
+         * We compute those marks unconditionally for simplicity, but will ignore them if formatting on
+         * a single line.
+         */
+        final int[][] formattedNumberMarks = new int[rows.length][];
+        int numColumns = 0;
+        for (int j=0; j<rows.length; j++) {
+            if (j == 0) {
+                appendSeparator();      // It is up to the caller to decide if we begin with a new line.
+            } else {
+                buffer.append(separatorNewLine).append(marginBeforeRow);
+            }
+            final double[] numbers = rows[j];
+            numColumns = Math.max(numColumns, numbers.length);      // Store the length of longest row.
+            final int[] marks = new int[numbers.length << 1];       // Positions where numbers are formatted.
+            formattedNumberMarks[j] = marks;
+            for (int i=0; i<numbers.length; i++) {
+                if (i != 0) buffer.append(Symbols.NUMBER_SEPARATOR);
+                if (i < fractionDigits.length) {                    // Otherwise, same than previous number.
+                    final int f = fractionDigits[i];
+                    numberFormat.setMaximumFractionDigits(f);
+                    numberFormat.setMinimumFractionDigits(f);
+                }
+                marks[i << 1] = buffer.length();                    // Store the start position where number is formatted.
+                setColor(ElementKind.NUMBER);
+                numberFormat.format(numbers[i], buffer, dummy);
+                resetColor();
+                marks[(i << 1) | 1] = buffer.length();              // Store the end position where number is formatted.
+            }
+        }
+        /*
+         * If formatting on more than one line, insert the amount of spaces required for aligning numbers.
+         * This is possible because we wrote the coordinate values with fixed number of fraction digits.
+         */
+        if (isMultiLines) {
+            final int base = elementStart;
+            final String toWrite = buffer.substring(base);          // Save what we formatted in above loop.
+            buffer.setLength(base);                                 // Discard what we formatted - we will rewrite.
+            final int[] columnWidths = new int[numColumns];
+            for (final int[] marks : formattedNumberMarks) {        // Compute the maximal width of each column.
+                for (int i=0; i<marks.length; i += 2) {
+                    final int k = i >> 1;
+                    final int w = toWrite.codePointCount(marks[i  ] -= base,
+                                                         marks[i+1] -= base);
+                    if (w > columnWidths[k]) columnWidths[k] = w;
+                }
+            }
+            if (needsAlignment && keywordSpaceAt == null) {
+                keywordSpaceAt = new IntegerList(formattedNumberMarks.length, Integer.MAX_VALUE);
+            }
+            boolean requestAlignment = false;
+            int lastPosition = 0;
+            for (int[] marks : formattedNumberMarks) {              // Recopy the formatted text, with more spaces.
+                for (int i = 0; i<marks.length;) {
+                    final int w = columnWidths[i >> 1];
+                    final int s = marks[i++];
+                    final int e = marks[i++];
+                    buffer.append(toWrite, lastPosition, s)
+                          .append(CharSequences.spaces(w - toWrite.codePointCount(s, e)));
+                    if (requestAlignment) {
+                        requestAlignment = false;
+                        keywordSpaceAt.add(buffer.length());
+                    }
+                    buffer.append(toWrite, s, e);
+                    lastPosition = e;
+                }
+                requestAlignment = needsAlignment;
+            }
+        }
+    }
+
+    /**
      * Appends the given number without any change to the {@link NumberFormat} setting.
      * Caller shall ensure that the following method has been invoked prior this method call:
      *
@@ -1692,6 +1841,7 @@ public class Formatter implements Locali
         elementStart      = 0;
         colorApplied      = 0;
         margin            = 0;
+        keywordSpaceAt    = null;
         requestNewLine    = false;
         isComplement      = false;
         highlightError    = false;

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Symbols.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Symbols.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Symbols.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Symbols.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -67,7 +67,7 @@ import static org.apache.sis.util.Argume
  * Users can create their own {@code Symbols} instance for parsing or formatting a WKT with different symbols.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.6
+ * @version 1.0
  *
  * @see WKTFormat#getSymbols()
  * @see WKTFormat#setSymbols(Symbols)
@@ -92,6 +92,12 @@ public class Symbols implements Localize
     static final boolean SCIENTIFIC_NOTATION = true;
 
     /**
+     * Separator between numbers in a sequence of numbers.
+     * This is used for example between the coordinates of a point.
+     */
+    static final char NUMBER_SEPARATOR = ' ';
+
+    /**
      * The prefix character for the value of a WKT fragment.
      */
     static final char FRAGMENT_VALUE = '$';
@@ -541,7 +547,7 @@ public class Symbols implements Localize
      * Returns the value of {@link #getSeparator()} without trailing spaces,
      * followed by the system line separator.
      */
-    final String lineSeparator() {
+    final String separatorNewLine() {
         final String separator = getSeparator();
         return separator.substring(0, CharSequences.skipTrailingWhitespaces(separator, 0, separator.length()))
                 .concat(System.lineSeparator());

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -106,7 +106,7 @@ import org.apache.sis.internal.util.Stan
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Rémi Eve (IRD)
- * @version 0.8
+ * @version 1.0
  *
  * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
  * @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -82,7 +82,7 @@
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Rémi Eve (IRD)
  * @author  Rueben Schulz (UBC)
- * @version 0.6
+ * @version 1.0
  *
  * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
  * @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractDirectPosition.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -34,6 +34,10 @@ import org.apache.sis.util.Utilities;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.internal.metadata.WKTKeywords;
+import org.apache.sis.internal.referencing.WKTUtilities;
+import org.apache.sis.io.wkt.FormattableObject;
+import org.apache.sis.io.wkt.Formatter;
 
 import static java.lang.Double.doubleToLongBits;
 import static org.apache.sis.util.StringBuilders.trimFractionalPart;
@@ -52,11 +56,11 @@ import static org.apache.sis.util.Argume
  * serializable, is left to subclasses.</p>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
  * @since   0.3
  * @module
  */
-public abstract class AbstractDirectPosition implements DirectPosition {
+public abstract class AbstractDirectPosition extends FormattableObject implements DirectPosition {
     /**
      * Constructs a direct position.
      */
@@ -64,6 +68,24 @@ public abstract class AbstractDirectPosi
     }
 
     /**
+     * Returns the given position as an {@code AbstractDirectPosition} instance.
+     * If the given position is already an instance of {@code AbstractDirectPosition},
+     * then it is returned unchanged. Otherwise the coordinate values and the CRS
+     * of the given position are copied in a new position.
+     *
+     * @param  position  the position to cast, or {@code null}.
+     * @return the values of the given position as an {@code AbstractDirectPosition} instance.
+     *
+     * @since 1.0
+     */
+    public static AbstractDirectPosition castOrCopy(final DirectPosition position) {
+        if (position == null || position instanceof AbstractDirectPosition) {
+            return (AbstractDirectPosition) position;
+        }
+        return new GeneralDirectPosition(position);
+    }
+
+    /**
      * Returns always {@code this}, the direct position for this
      * {@linkplain org.opengis.geometry.coordinate.Position position}.
      *
@@ -180,22 +202,28 @@ public abstract class AbstractDirectPosi
     }
 
     /**
-     * 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.
-     *
-     * @see #toString(DirectPosition, boolean)
-     */
-    static boolean isSimplePrecision(final double... values) {
-        for (final double value : values) {
-            if (Double.doubleToLongBits(value) != Double.doubleToLongBits((float) value)) {
-                return false;
-            }
-        }
-        return true;
+     * Formats this position in the <cite>Well Known Text</cite> (WKT) format.
+     * The format is like below, where {@code x₀}, {@code x₁}, {@code x₂}, <i>etc.</i>
+     * are the ordinate values at index 0, 1, 2, <i>etc.</i>:
+     *
+     * {@preformat wkt
+     *   POINT[x₀ x₁ x₂ …]
+     * }
+     *
+     * If the coordinate reference system is geodetic or projected, then coordinate values are formatted
+     * with a precision equivalent to one centimetre on Earth (the actual number of fraction digits is
+     * adjusted for the axis unit of measurement and the planet size if different than Earth).
+     *
+     * @param  formatter  the formatter where to format the inner content of this point.
+     * @return the WKT keyword, which is {@code "Point"} for this element.
+     *
+     * @since 1.0
+     */
+    @Override
+    protected String formatTo(final Formatter formatter) {
+        final double[][] points = new double[][] {getCoordinate()};
+        formatter.append(points, WKTUtilities.suggestFractionDigits(getCoordinateReferenceSystem(), points));
+        return WKTKeywords.Point;
     }
 
     /**
@@ -207,10 +235,11 @@ public abstract class AbstractDirectPosi
      *   POINT(x₀ x₁ x₂ …)
      * }
      *
+     * This method formats the numbers as with {@link Double#toString(double)} (i.e. without fixed number of fraction digits).
      * The string returned by this method can be {@linkplain GeneralDirectPosition#GeneralDirectPosition(CharSequence) parsed}
      * by the {@code GeneralDirectPosition} constructor.
      *
-     * @return This position as a {@code POINT} in <cite>Well Known Text</cite> (WKT) format.
+     * @return this position as a {@code POINT} in <cite>Well Known Text</cite> (WKT) format.
      */
     @Override
     public String toString() {
@@ -226,7 +255,7 @@ public abstract class AbstractDirectPosi
      * @param  isSimplePrecision  {@code true} if every ordinate values can be casted to {@code float}.
      * @return the point as a {@code POINT} in WKT format.
      *
-     * @see #isSimplePrecision(double[])
+     * @see Numerics#isSimplePrecision(double[])
      */
     static String toString(final DirectPosition position, final boolean isSimplePrecision) {
         final StringBuilder buffer = new StringBuilder(32).append("POINT");

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -38,6 +38,9 @@ import org.apache.sis.util.Emptiable;
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.io.wkt.FormattableObject;
+import org.apache.sis.internal.referencing.WKTUtilities;
 
 import static java.lang.Double.doubleToLongBits;
 import static org.apache.sis.internal.util.Numerics.SIGN_BIT_MASK;
@@ -107,12 +110,12 @@ import static org.apache.sis.math.MathFu
  * </ul>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.3
  * @module
  */
 @XmlTransient
-public abstract class AbstractEnvelope implements Envelope, Emptiable {
+public abstract class AbstractEnvelope extends FormattableObject implements Envelope, Emptiable {
     /**
      * An empty array of envelopes, to be returned by {@link #toSimpleEnvelopes()}
      * when en envelope is empty.
@@ -690,6 +693,7 @@ public abstract class AbstractEnvelope i
 
     /**
      * Tests if a specified coordinate is inside the boundary of this envelope.
+     * Both lower and upper values of this envelope are considered inclusive.
      * If it least one ordinate value in the given point is {@link Double#NaN NaN},
      * then this method returns {@code false}.
      *
@@ -705,7 +709,7 @@ public abstract class AbstractEnvelope i
      *
      * @param  position  the point to text.
      * @return {@code true} if the specified coordinate is inside the boundary of this envelope; {@code false} otherwise.
-     * @throws MismatchedDimensionException if the specified point doesn't have the expected dimension.
+     * @throws MismatchedDimensionException if the specified point does not have the expected number of dimensions.
      * @throws AssertionError if assertions are enabled and the envelopes have mismatched CRS.
      */
     public boolean contains(final DirectPosition position) throws MismatchedDimensionException {
@@ -1131,6 +1135,7 @@ public abstract class AbstractEnvelope i
      * The {@code BOX} element is not part of the standard <cite>Well Known Text</cite> (WKT) format.
      * However it is understood by many software libraries, for example GDAL and PostGIS.</div>
      *
+     * This method formats the numbers as with {@link Double#toString(double)} (i.e. without fixed number of fraction digits).
      * The string returned by this method can be {@linkplain GeneralEnvelope#GeneralEnvelope(CharSequence) parsed}
      * by the {@code GeneralEnvelope} constructor.
      *
@@ -1183,6 +1188,41 @@ public abstract class AbstractEnvelope i
     }
 
     /**
+     * Formats this envelope as a "{@code BOX}" element.
+     * The output is of the form "{@code BOX}<var>n</var>{@code D[}{@linkplain #getLowerCorner()
+     * lower corner}{@code ,}{@linkplain #getUpperCorner() upper corner}{@code ]}"
+     * where <var>n</var> is the {@linkplain #getDimension() number of dimensions}.
+     * The number of dimension is written only if different than 2.
+     *
+     * <div class="note"><b>Note:</b>
+     * The {@code BOX} element is not part of the standard <cite>Well Known Text</cite> (WKT) format.
+     * However it is understood by many software libraries, for example GDAL and PostGIS.</div>
+     *
+     * If the coordinate reference system is geodetic or projected, then coordinate values are formatted
+     * with a precision equivalent to one centimetre on Earth (the actual number of fraction digits is
+     * adjusted for the axis unit of measurement and the planet size if different than Earth).
+     *
+     * @param  formatter  the formatter where to format the inner content of this envelope.
+     * @return the pseudo-WKT keyword, which is {@code "Box"} for this element.
+     *
+     * @since 1.0
+     */
+    @Override
+    protected String formatTo(final Formatter formatter) {
+        final double[][] points = new double[][] {
+            getLowerCorner().getCoordinate(),
+            getUpperCorner().getCoordinate()
+        };
+        formatter.append(points, WKTUtilities.suggestFractionDigits(getCoordinateReferenceSystem(), points));
+        final int dimension = getDimension();
+        String keyword = "Box";
+        if (dimension != 2) {
+            keyword = new StringBuilder(keyword).append(dimension).append('D').toString();
+        }
+        return keyword;
+    }
+
+    /**
      * Base class for unmodifiable direct positions backed by the enclosing envelope.
      * Subclasses must override the {@link #getOrdinate(int)} method in order to delegate
      * the work to the appropriate {@link AbstractEnvelope} method.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/ArrayEnvelope.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -36,6 +36,7 @@ import org.apache.sis.referencing.Common
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.util.Numerics;
 
 import static org.apache.sis.util.ArgumentChecks.*;
 import static org.apache.sis.math.MathFunctions.isNegative;
@@ -55,7 +56,7 @@ import static org.apache.sis.internal.re
  * in {@link SubEnvelope}.</p>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
  * @since   0.3
  * @module
  */
@@ -592,6 +593,6 @@ scanNumber: while ((i += Character.charC
      */
     @Override
     public String toString() {
-        return toString(this, AbstractDirectPosition.isSimplePrecision(ordinates));
+        return toString(this, Numerics.isSimplePrecision(ordinates));
     }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -292,7 +292,7 @@ public class DirectPosition2D extends Po
      */
     @Override
     public String toString() {
-        return AbstractDirectPosition.toString(this, AbstractDirectPosition.isSimplePrecision(x, y));
+        return AbstractDirectPosition.toString(this, Numerics.isSimplePrecision(x, y));
     }
 
     /**

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelopes.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -131,7 +131,8 @@ public final class Envelopes extends Sta
             return ((AbstractMathTransform) transform).transform(srcPts, 0, dstPts, dstOff, derivate);
         }
         // Derivative must be calculated before to transform the coordinate.
-        final Matrix derivative = derivate ? transform.derivative(new DirectPositionView(srcPts, 0, transform.getSourceDimensions())) : null;
+        final Matrix derivative = derivate ? transform.derivative(
+                new DirectPositionView.Double(srcPts, 0, transform.getSourceDimensions())) : null;
         transform.transform(srcPts, 0, dstPts, dstOff, 1);
         return derivative;
     }
@@ -265,7 +266,7 @@ public final class Envelopes extends Sta
             sourcePt[i] = envelope.getMinimum(i);
         }
         // A window over a single coordinate in the 'ordinates' array.
-        final DirectPositionView ordinatesView = new DirectPositionView(ordinates, 0, targetDim);
+        final DirectPositionView ordinatesView = new DirectPositionView.Double(ordinates, 0, targetDim);
         /*
          * Iterates over every minimal, maximal and median ordinate values (3 points) along each
          * dimension. The total number of iterations is 3 ^ (number of source dimensions).
@@ -339,7 +340,7 @@ public final class Envelopes extends Sta
          * to avoid the need for storage.
          */
         DirectPosition temporary = null;
-        final DirectPositionView sourceView = new DirectPositionView(sourcePt, 0, sourceDim);
+        final DirectPositionView sourceView = new DirectPositionView.Double(sourcePt, 0, sourceDim);
         final CurveExtremum extremum = new CurveExtremum();
         for (pointIndex=0; pointIndex < derivatives.length; pointIndex++) {
             final Matrix D1 = derivatives[pointIndex];

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -30,6 +30,7 @@ import java.security.PrivilegedAction;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.ArgumentChecks.ensureDimensionMatches;
@@ -51,7 +52,7 @@ import static org.apache.sis.util.Argume
  * on the value of the containing object's {@code CoordinateReferenceSystem}.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.3
+ * @version 1.0
  *
  * @see DirectPosition1D
  * @see DirectPosition2D
@@ -282,7 +283,7 @@ public class GeneralDirectPosition exten
      */
     @Override
     public String toString() {
-        return toString(this, isSimplePrecision(ordinates));
+        return toString(this, Numerics.isSimplePrecision(ordinates));
     }
 
     /**

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

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/DirectPositionView.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -17,8 +17,8 @@
 package org.apache.sis.internal.referencing;
 
 import java.util.Arrays;
-import org.opengis.geometry.DirectPosition;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.geometry.AbstractDirectPosition;
 
 // Branch-dependent imports
 import org.apache.sis.geometry.UnmodifiableGeometryException;
@@ -29,19 +29,13 @@ import org.apache.sis.geometry.Unmodifia
  * This class shall be used for temporary objects only (it is not serializable for this reason).
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.5
+ * @version 1.0
  * @since   0.5
  * @module
  */
-public final class DirectPositionView implements DirectPosition {
+public abstract class DirectPositionView extends AbstractDirectPosition {
     /**
-     * The ordinate values. This is a direct reference to the array given to the constructor.
-     * The length of this array may be greater then the number of dimensions.
-     */
-    private final double[] ordinates;
-
-    /**
-     * The index of the first value in the {@linkplain #ordinates} array.
+     * The index of the first value in the ordinates array.
      * This field is non-final in order to allow the caller to move the view over an array of coordinates.
      */
     public int offset;
@@ -49,70 +43,129 @@ public final class DirectPositionView im
     /**
      * The number of valid ordinate values.
      */
-    private final int dimension;
+    final int dimension;
 
     /**
      * Creates a new direct position wrapping the given array.
      *
-     * @param  ordinates  the ordinate values.
      * @param  offset     the first value index in the ordinates array.
      * @param  dimension  the number of valid ordinate values.
      */
-    public DirectPositionView(final double[] ordinates, final int offset, final int dimension) {
-        this.ordinates = ordinates;
+    DirectPositionView(final int offset, final int dimension) {
         this.offset    = offset;
         this.dimension = dimension;
     }
 
     /**
      * Returns {@code null} since there is no CRS associated with this position.
+     *
+     * @return {@code null}.
      */
     @Override
-    public CoordinateReferenceSystem getCoordinateReferenceSystem() {
+    public final CoordinateReferenceSystem getCoordinateReferenceSystem() {
         return null;
     }
 
     /**
      * Returns the dimension given at construction time.
-     */
-    @Override
-    public int getDimension() {
-        return dimension;
-    }
-
-    /**
-     * Returns all ordinate values.
-     */
-    @Override
-    public double[] getCoordinate() {
-        return Arrays.copyOfRange(ordinates, offset, offset + dimension);
-    }
-
-    /**
-     * Returns the ordinate at the given index.
-     * <strong>This implementation does not check index validity</strong>, unless assertions are enabled.
      *
-     * @param  dim  the dimension of the ordinate to get fetch.
+     * @return number of dimensions.
      */
     @Override
-    public double getOrdinate(final int dim) {
-        assert dim >= 0 && dim < dimension : dim;
-        return ordinates[offset + dim];
+    public final int getDimension() {
+        return dimension;
     }
 
     /**
      * Do not allow any change.
+     *
+     * @param  dimension  ignored.
+     * @param  value      ignored.
      */
     @Override
-    public void setOrdinate(final int dimension, final double value) {
+    public final void setOrdinate(final int dimension, final double value) {
         throw new UnmodifiableGeometryException();
     }
 
     /**
-     * Returns the direct position, which is {@code this}.
+     * The double-precision version of {@link DirectPositionView}.
      */
-    @Override
-    public DirectPosition getDirectPosition() {
-        return this;
+    public static final class Double extends DirectPositionView {
+        /**
+         * The ordinate values. This is a direct reference to the array given to the constructor.
+         * The length of this array may be greater then the number of dimensions.
+         */
+        private final double[] ordinates;
+
+        /**
+         * Creates a new direct position wrapping the given array.
+         *
+         * @param  ordinates  the ordinate values.
+         * @param  offset     the first value index in the ordinates array.
+         * @param  dimension  the number of valid ordinate values.
+         */
+        public Double(final double[] ordinates, final int offset, final int dimension) {
+            super(offset, dimension);
+            this.ordinates = ordinates;
+        }
+
+        /**
+         * Returns the ordinate at the given index.
+         * <strong>This implementation does not check index validity</strong>, unless assertions are enabled.
+         *
+         * @param  dim  the dimension of the ordinate to get fetch.
+         * @return the coordinate value at the given dimension.
+         */
+        @Override
+        public double getOrdinate(final int dim) {
+            assert dim >= 0 && dim < dimension : dim;
+            return ordinates[offset + dim];
+        }
+
+        /**
+         * Returns all ordinate values.
+         *
+         * @return all coordinate values.
+         */
+        @Override
+        public double[] getCoordinate() {
+            return Arrays.copyOfRange(ordinates, offset, offset + dimension);
+        }
+    }
+
+    /**
+     * The single-precision version of {@link DirectPositionView}.
+     */
+    public static final class Float extends DirectPositionView {
+        /**
+         * The ordinate values. This is a direct reference to the array given to the constructor.
+         * The length of this array may be greater then the number of dimensions.
+         */
+        private final float[] ordinates;
+
+        /**
+         * Creates a new direct position wrapping the given array.
+         *
+         * @param  ordinates  the ordinate values.
+         * @param  offset     the first value index in the ordinates array.
+         * @param  dimension  the number of valid ordinate values.
+         */
+        public Float(final float[] ordinates, final int offset, final int dimension) {
+            super(offset, dimension);
+            this.ordinates = ordinates;
+        }
+
+        /**
+         * Returns the ordinate at the given index.
+         * <strong>This implementation does not check index validity</strong>, unless assertions are enabled.
+         *
+         * @param  dim  the dimension of the ordinate to get fetch.
+         * @return the coordinate value at the given dimension.
+         */
+        @Override
+        public double getOrdinate(final int dim) {
+            assert dim >= 0 && dim < dimension : dim;
+            return ordinates[offset + dim];
+        }
     }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Formulas.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -19,6 +19,7 @@ package org.apache.sis.internal.referenc
 import org.apache.sis.util.Static;
 import org.apache.sis.measure.Latitude;
 import org.apache.sis.internal.util.Numerics;
+import org.opengis.referencing.datum.Ellipsoid;
 
 import static java.lang.Math.*;
 import static org.apache.sis.math.MathFunctions.atanh;
@@ -31,7 +32,7 @@ import static org.apache.sis.internal.me
  * do not want to expose publicly those arbitrary values (or at least not in a too direct way).
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
  * @since   0.4
  * @module
  */
@@ -59,6 +60,13 @@ public final class Formulas extends Stat
     public static final double ANGULAR_TOLERANCE = LINEAR_TOLERANCE / (NAUTICAL_MILE * 60);
 
     /**
+     * Default tolerance threshold for comparing ordinate values in temporal CRS,
+     * assuming that the unit of measurement is second. Current value is arbitrary
+     * and may change in any future Apache SIS version.
+     */
+    public static final double TEMPORAL_TOLERANCE = 60;             // One minute.
+
+    /**
      * The maximal longitude value before normalization if a centimetric precision is desired.
      * This is about 4×10⁸ degrees.
      *
@@ -87,6 +95,19 @@ public final class Formulas extends Stat
     }
 
     /**
+     * Returns the size of a planet described by the given ellipsoid compared to earth.
+     * This method returns a ratio of given planet authalic radius compared to WGS84.
+     * This can be used for adjusting {@link #LINEAR_TOLERANCE} and {@link #ANGULAR_TOLERANCE} to another planet.
+     *
+     * @param  planet  ellipsoid of the other planet to compare to Earth.
+     * @return ratio of planet authalic radius on WGS84 authalic radius.
+     */
+    public static double scaleComparedToEarth(final Ellipsoid planet) {
+        return getAuthalicRadius(planet.getSemiMajorAxis(),
+                                 planet.getSemiMinorAxis()) / 6371007.180918474;
+    }
+
+    /**
      * Returns 3ⁿ for very small (less than 10) positive values of <var>n</var>.
      * Note that this method overflow for any value equals or greater than 20.
      *

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -31,8 +31,10 @@ import org.opengis.parameter.GeneralPara
 import org.opengis.referencing.cs.*;
 import org.opengis.referencing.crs.*;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.PrimeMeridian;
+import org.opengis.referencing.datum.GeodeticDatum;
 import org.opengis.referencing.datum.VerticalDatum;
 import org.opengis.referencing.datum.VerticalDatumType;
 import org.opengis.referencing.operation.CoordinateOperationFactory;
@@ -61,7 +63,7 @@ import static java.util.Collections.sing
  * <p><strong>Do not rely on this API!</strong> It may change in incompatible way in any future release.</p>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.5
  * @module
  */
@@ -111,7 +113,7 @@ public final class ReferencingUtilities
         if (cs != null) {
             for (int i=cs.getDimension(); --i>=0;) {
                 final CoordinateSystemAxis axis = cs.getAxis(i);
-                if (axis != null) {  // Paranoiac check.
+                if (axis != null) {                                         // Paranoiac check.
                     final Unit<?> candidate = axis.getUnit();
                     if (candidate != null) {
                         if (unit == null) {
@@ -137,7 +139,7 @@ public final class ReferencingUtilities
     public static int getDimension(final CoordinateReferenceSystem crs) {
         if (crs != null) {
             final CoordinateSystem cs = crs.getCoordinateSystem();
-            if (cs != null) {  // Paranoiac check.
+            if (cs != null) {                                               // Paranoiac check.
                 return cs.getDimension();
             }
         }
@@ -200,6 +202,31 @@ public final class ReferencingUtilities
     }
 
     /**
+     * Returns the ellipsoid used by the given coordinate reference system, or {@code null} if none.
+     *
+     * @param  crs  the coordinate reference system for which to get the ellipsoid.
+     * @return the ellipsoid, or {@code null} if none.
+     */
+    public static Ellipsoid getEllipsoid(final CoordinateReferenceSystem crs) {
+        if (crs != null) {
+            if (crs instanceof SingleCRS) {
+                final Datum datum = ((SingleCRS) crs).getDatum();
+                if (datum instanceof GeodeticDatum) {
+                    final Ellipsoid e = ((GeodeticDatum) datum).getEllipsoid();
+                    if (e != null) return e;
+                }
+            }
+            if (crs instanceof CompoundCRS) {
+                for (final CoordinateReferenceSystem c : ((CompoundCRS) crs).getComponents()) {
+                    final Ellipsoid e = getEllipsoid(c);
+                    if (e != null) return e;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
      * Returns the ellipsoid used by the specified coordinate reference system, provided that the two first dimensions
      * use an instance of {@link GeographicCRS}. Otherwise (i.e. if the two first dimensions are not geographic),
      * returns {@code null}.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -322,6 +322,11 @@ public final class Resources extends Ind
         public static final short MissingValueForParameter_1 = 44;
 
         /**
+         * The localization grid still have some undefined source or target coordinates.
+         */
+        public static final short MissingValuesInLocalizationGrid = 81;
+
+        /**
          * No vertical dimension found in “{0}”
          */
         public static final short MissingVerticalDimension_1 = 45;

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties [ISO-8859-1] Thu Mar  8 15:44:56 2018
@@ -80,6 +80,7 @@ MissingTemporalDimension_1        = No t
 MissingSpatioTemporalDimension_1  = No spatial or temporal dimension found in \u201c{0}\u201d
 MissingParameterValues_1          = Missing parameter values for \u201c{0}\u201d coordinate operation.
 MissingValueForParameter_1        = Missing value for \u201c{0}\u201d parameter.
+MissingValuesInLocalizationGrid   = The localization grid still have some undefined source or target coordinates.
 NoConvergence                     = No convergence.
 NoConvergenceForPoints_2          = No convergence for points {0} and {1}.
 NonHorizontalCRS_1                = No horizontal component found in the \u201c{0}\u201d coordinate reference system.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties [ISO-8859-1] Thu Mar  8 15:44:56 2018
@@ -85,6 +85,7 @@ MissingTemporalDimension_1        = Aucu
 MissingSpatioTemporalDimension_1  = Aucune dimension spatiale ou temporelle n\u2019a \u00e9t\u00e9 trouv\u00e9e dans \u00ab\u202f{0}\u202f\u00bb.
 MissingParameterValues_1          = Il manque les valeurs des param\u00e8tres pour l\u2019op\u00e9ration \u00ab\u202f{0}\u202f\u00bb.
 MissingValueForParameter_1        = Aucune valeur n\u2019a \u00e9t\u00e9 d\u00e9finie pour le param\u00e8tre \u00ab\u202f{0}\u202f\u00bb.
+MissingValuesInLocalizationGrid   = Il manque encore des coordonn\u00e9es sources ou destinations dans la grille de localisation.
 NoConvergence                     = Le calcul ne converge pas.
 NoConvergenceForPoints_2          = Le calcul ne converge pas pour les points {0} et {1}.
 NonHorizontalCRS_1                = Aucune composante horizontale n\u2019a \u00e9t\u00e9 trouv\u00e9e dans le syst\u00e8me de r\u00e9f\u00e9rence des coordonn\u00e9es \u00ab\u202f{0}\u202f\u00bb.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTUtilities.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -49,6 +49,8 @@ import org.apache.sis.util.Static;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.internal.util.Constants;
+import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.math.DecimalFunctions;
 
 
 /**
@@ -60,7 +62,7 @@ import org.apache.sis.internal.util.Cons
  * We need to be specific in order to select the right "aspect" of the given object.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.4
  * @module
  */
@@ -72,6 +74,39 @@ public final class WKTUtilities extends
     }
 
     /**
+     * Returns the WKT type of the given interface.
+     *
+     * For {@link CoordinateSystem} base type, the returned value shall be one of
+     * {@code affine}, {@code Cartesian}, {@code cylindrical}, {@code ellipsoidal}, {@code linear},
+     * {@code parametric}, {@code polar}, {@code spherical}, {@code temporal} or {@code vertical}.
+     *
+     * @param  base  the abstract base interface.
+     * @param  type  the interface or classes for which to get the WKT type.
+     * @return the WKT type for the given class or interface, or {@code null} if none.
+     *
+     * @see ReferencingUtilities#toPropertyName(Class, Class)
+     */
+    public static String toType(final Class<?> base, final Class<?> type) {
+        if (type != base) {
+            final StringBuilder name = ReferencingUtilities.toPropertyName(base, type);
+            if (name != null) {
+                int end = name.length() - 2;
+                if (CharSequences.regionMatches(name, end, "CS")) {
+                    name.setLength(end);
+                    if ("time".contentEquals(name)) {
+                        return "temporal";
+                    }
+                    if (CharSequences.regionMatches(name, 0, "cartesian")) {
+                        name.setCharAt(0, 'C');     // "Cartesian"
+                    }
+                    return name.toString();
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
      * Returns the given coordinate reference system as a formattable object.
      *
      * @param  object  the coordinate reference system, or {@code null}.
@@ -275,35 +310,44 @@ public final class WKTUtilities extends
     }
 
     /**
-     * Returns the WKT type of the given interface.
-     *
-     * For {@link CoordinateSystem} base type, the returned value shall be one of
-     * {@code affine}, {@code Cartesian}, {@code cylindrical}, {@code ellipsoidal}, {@code linear},
-     * {@code parametric}, {@code polar}, {@code spherical}, {@code temporal} or {@code vertical}.
+     * Suggests an amount of fraction digits to use for formatting numbers in each column of the given sequence
+     * of points. The number of fraction digits may be negative if we could round the numbers to 10, <i>etc</i>.
      *
-     * @param  base  the abstract base interface.
-     * @param  type  the interface or classes for which to get the WKT type.
-     * @return the WKT type for the given class or interface, or {@code null} if none.
-     *
-     * @see ReferencingUtilities#toPropertyName(Class, Class)
-     */
-    public static String toType(final Class<?> base, final Class<?> type) {
-        if (type != base) {
-            final StringBuilder name = ReferencingUtilities.toPropertyName(base, type);
-            if (name != null) {
-                int end = name.length() - 2;
-                if (CharSequences.regionMatches(name, end, "CS")) {
-                    name.setLength(end);
-                    if ("time".contentEquals(name)) {
-                        return "temporal";
-                    }
-                    if (CharSequences.regionMatches(name, 0, "cartesian")) {
-                        name.setCharAt(0, 'C');     // "Cartesian"
-                    }
-                    return name.toString();
+     * @param  crs     the coordinate reference system for each points, or {@code null} if unknown.
+     * @param  points  the sequence of points. It is not required that each point has the same dimension.
+     * @return suggested amount of fraction digits as an array as long as the longest row.
+     */
+    public static int[] suggestFractionDigits(final CoordinateReferenceSystem crs, final double[]... points) {
+        final int[] fractionDigits = Numerics.suggestFractionDigits(points);
+        final Ellipsoid ellipsoid = ReferencingUtilities.getEllipsoid(crs);
+        if (ellipsoid != null) {
+            /*
+             * Use heuristic precisions for geodetic or projected CRS. We do not apply those heuristics
+             * for other kind of CRS (e.g. engineering) because we do not know what could be the size
+             * of the object attached to the CRS.
+             */
+            final CoordinateSystem cs = crs.getCoordinateSystem();
+            final int dimension = Math.min(cs.getDimension(), fractionDigits.length);
+            final double scale = Formulas.scaleComparedToEarth(ellipsoid);
+            for (int i=0; i<dimension; i++) {
+                final Unit<?> unit = cs.getAxis(i).getUnit();
+                double precision;
+                if (Units.isLinear(unit)) {
+                    precision = Formulas.LINEAR_TOLERANCE * scale;                          // In metres
+                } else if (Units.isAngular(unit)) {
+                    precision = Formulas.ANGULAR_TOLERANCE * (Math.PI / 180) * scale;       // In radians
+                } else if (Units.isTemporal(unit)) {
+                    precision = Formulas.TEMPORAL_TOLERANCE;                                // In seconds
+                } else {
+                    continue;
+                }
+                precision /= Units.toStandardUnit(unit);                // In units used by the coordinates.
+                final int f = DecimalFunctions.fractionDigitsForDelta(precision, false);
+                if (f > fractionDigits[i]) {
+                    fractionDigits[i] = f;                              // Use at least the heuristic precision.
                 }
             }
         }
-        return null;
+        return fractionDigits;
     }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/package-info.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -24,7 +24,7 @@
  * may change in incompatible ways in any future version without notice.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.3
+ * @version 1.0
  * @since   0.3
  * @module
  */

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilder.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -20,11 +20,13 @@ import java.util.Map;
 import java.util.Arrays;
 import java.io.IOException;
 import org.opengis.util.FactoryException;
+import org.opengis.geometry.Envelope;
 import org.opengis.geometry.DirectPosition;
 import org.opengis.geometry.MismatchedDimensionException;
 import org.opengis.geometry.coordinate.Position;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransformFactory;
+import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.io.TableAppender;
 import org.apache.sis.math.Line;
 import org.apache.sis.math.Plane;
@@ -32,7 +34,9 @@ import org.apache.sis.math.Vector;
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.referencing.operation.transform.LinearTransform;
+import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
 import org.apache.sis.internal.referencing.ExtendedPrecisionMatrix;
+import org.apache.sis.internal.referencing.Resources;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
@@ -53,7 +57,7 @@ import org.apache.sis.util.Debug;
  * with the assumption that source positions are exact and all the uncertainty is in the target positions.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  *
  * @see LocalizationGridBuilder
  * @see LinearTransform
@@ -302,7 +306,7 @@ search: for (int j=0; j<numPoints; j++)
      * Returns the error message to be given to {@link IllegalStateException} when there is no data.
      */
     private static String noData() {
-        return Errors.format(Errors.Keys.MissingValueForProperty_1, "sourceToTarget");
+        return Resources.format(Resources.Keys.MissingValuesInLocalizationGrid);
     }
 
     /**
@@ -337,6 +341,64 @@ search: for (int j=0; j<numPoints; j++)
     }
 
     /**
+     * Returns the envelope of source points. The lower and upper values are inclusive.
+     *
+     * @return the envelope of source points.
+     * @throws IllegalStateException if the source points are not yet known.
+     *
+     * @since 1.0
+     */
+    public Envelope getSourceEnvelope() {
+        if (gridSize != null) {
+            final int dim = gridSize.length;
+            final GeneralEnvelope envelope = new GeneralEnvelope(dim);
+            for (int i=0; i <dim; i++) {
+                envelope.setRange(i, 0, gridSize[i] - 1);
+            }
+            return envelope;
+        } else {
+            return envelope(sources);
+        }
+    }
+
+    /**
+     * Returns the envelope of target points. The lower and upper values are inclusive.
+     *
+     * @return the envelope of target points.
+     * @throws IllegalStateException if the target points are not yet known.
+     *
+     * @since 1.0
+     */
+    public Envelope getTargetEnvelope() {
+        return envelope(targets);
+    }
+
+    /**
+     * Implementation of {@link #getSourceEnvelope()} and {@link #getTargetEnvelope()}.
+     */
+    private static Envelope envelope(final double[][] points) {
+        if (points == null) {
+            throw new IllegalStateException(noData());
+        }
+        final int dim = points.length;
+        final GeneralEnvelope envelope = new GeneralEnvelope(dim);
+        for (int i=0; i <dim; i++) {
+            final double[] data = points[i];
+            double lower = Double.POSITIVE_INFINITY;
+            double upper = Double.NEGATIVE_INFINITY;
+            for (final double value : data) {
+                if (value < lower) lower = value;
+                if (value > upper) upper = value;
+            }
+            if (lower > upper) {
+                lower = upper = Double.NaN;
+            }
+            envelope.setRange(i, lower, upper);
+        }
+        return envelope;
+    }
+
+    /**
      * Returns the direct position of the given position, or {@code null} if none.
      */
     private static DirectPosition position(final Position p) {
@@ -567,7 +629,7 @@ search: for (int j=0; j<numPoints; j++)
             final double[][] sources = this.sources;                    // Protect from changes.
             final double[][] targets = this.targets;
             if (targets == null) {
-                throw new FactoryException(noData());
+                throw new InvalidGeodeticParameterException(noData());
             }
             final int sourceDim = (sources != null) ? sources.length : gridSize.length;
             final int targetDim = targets.length;
@@ -610,7 +672,7 @@ search: for (int j=0; j<numPoints; j++)
                             c = plan.fit(gridSize[0], gridSize[1], Vector.create(targets[j], false));
                         } catch (IllegalArgumentException e) {
                             // This may happen if the z vector still contain some "NaN" values.
-                            throw new FactoryException(noData(), e);
+                            throw new InvalidGeodeticParameterException(noData(), e);
                         }
                         break;
                     }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -17,6 +17,7 @@
 package org.apache.sis.referencing.operation.builder;
 
 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;
@@ -27,10 +28,11 @@ import org.apache.sis.referencing.operat
 import org.apache.sis.referencing.operation.transform.LinearTransform;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
-import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.referencing.operation.matrix.Matrix3;
 import org.apache.sis.referencing.datum.DatumShiftGrid;
 import org.apache.sis.internal.referencing.Resources;
 import org.apache.sis.geometry.DirectPosition2D;
+import org.apache.sis.geometry.Envelopes;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.measure.NumberRange;
@@ -58,7 +60,7 @@ import org.apache.sis.math.Vector;
  * </ol>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  *
  * @see InterpolatedTransform
  * @see LinearTransform
@@ -128,7 +130,7 @@ public class LocalizationGridBuilder ext
      * @throws ArithmeticException if this constructor can not infer a reasonable grid size from the given vectors.
      */
     public LocalizationGridBuilder(final Vector sourceX, final Vector sourceY) {
-        final Matrix fromGrid = Matrices.createDiagonal(3,3);
+        final Matrix fromGrid = new Matrix3();
         linear = new LinearTransformBuilder(infer(sourceX, fromGrid, 0), infer(sourceY, fromGrid, 1));
         try {
             sourceToGrid = MathTransforms.linear(fromGrid).inverse();
@@ -171,10 +173,16 @@ public class LocalizationGridBuilder ext
                 }
             }
         }
+        /*
+         * Compute the size from the increment that we found. If the size is larger than the vector length,
+         * consider as too large. The rational is that attempt to create a localization grid with that size
+         * would fail anyway, because it would contain holes where no value is defined. A limit is important
+         * for preventing useless allocation of large arrays - https://issues.apache.org/jira/browse/SIS-407
+         */
         fromGrid.setElement(dim, dim, inc);
         fromGrid.setElement(dim,   2, min);
         final double n = span / inc;
-        if (n > 0.5 && n < 0.5 + Short.MAX_VALUE) {
+        if (n >= 0.5 && n < source.size() - 0.5) {          // Compare as 'double' in case the value is large.
             return ((int) Math.round(n)) + 1;
         }
         throw new ArithmeticException(Resources.format(Resources.Keys.CanNotInferGridSizeFromValues_1, range));
@@ -308,6 +316,25 @@ public class LocalizationGridBuilder ext
     }
 
     /**
+     * Returns the envelope of source coordinates. This is the envelope of the grid domain
+     * (i.e. the ranges of valid {@code gridX} and {@code gridY} argument values in calls
+     * to {@code get/setControlPoint(…)} methods) transformed by the inverse of
+     * {@linkplain #getSourceToGrid() source to grid} transform.
+     * The lower and upper values are inclusive.
+     *
+     * @return the envelope of grid points.
+     * @throws IllegalStateException if the grid points are not yet known.
+     * @throws TransformException if the envelope can not be calculated.
+     *
+     * @see LinearTransformBuilder#getSourceEnvelope()
+     *
+     * @since 1.0
+     */
+    public Envelope getSourceEnvelope() throws TransformException {
+        return Envelopes.transform(sourceToGrid.inverse(), linear.getSourceEnvelope());
+    }
+
+    /**
      * Creates a transform from the source points to the target points.
      * This method assumes that source points are precise and all uncertainty is in the target points.
      * If this transform is close enough to an affine transform, then an instance of {@link LinearTransform} is returned.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java?rev=1826248&r1=1826247&r2=1826248&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java [UTF-8] Thu Mar  8 15:44:56 2018
@@ -30,8 +30,8 @@
  * convenience.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.5
- * @since   0.8
+ * @version 1.0
+ * @since   0.5
  * @module
  */
 package org.apache.sis.referencing.operation.builder;



Mime
View raw message