sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1801833 [1/4] - in /sis/trunk: ./ core/sis-feature/ core/sis-feature/src/main/java/org/apache/sis/feature/ core/sis-feature/src/main/java/org/apache/sis/feature/builder/ core/sis-feature/src/main/java/org/apache/sis/internal/feature/ core/...
Date Thu, 13 Jul 2017 12:45:04 GMT
Author: desruisseaux
Date: Thu Jul 13 12:45:03 2017
New Revision: 1801833

URL: http://svn.apache.org/viewvc?rev=1801833&view=rev
Log:
Merge from JDK7 branch.

Added:
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/DateList.java
      - copied unchanged from r1801832, sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/internal/feature/DateList.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/MovingFeature.java
      - copied, changed from r1801832, sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/internal/feature/MovingFeature.java
    sis/trunk/storage/sis-gdal/
      - copied from r1801832, sis/branches/JDK7/storage/sis-gdal/
    sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GridGeometry.java
      - copied unchanged from r1801832, sis/branches/JDK7/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GridGeometry.java
Modified:
    sis/trunk/   (props changed)
    sis/trunk/core/sis-feature/pom.xml
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/builder/FeatureTypeBuilder.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureUtilities.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/RecordSchemaSIS.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.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/referencing/factory/GeodeticObjectFactory.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/LocalizationGridBuilder.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/Spliterator.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/Stream.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/OS.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/math/ArrayVector.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/math/Fraction.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/math/MathFunctions.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/math/PackedVector.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/math/SequenceVector.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/math/Vector.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/iso/Names.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/math/MathFunctionsTest.java
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/math/VectorTest.java
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/iso/SerializableRecordSchema.java
    sis/trunk/ide-project/NetBeans/build.xml
    sis/trunk/ide-project/NetBeans/nbproject/build-impl.xml
    sis/trunk/ide-project/NetBeans/nbproject/genfiles.properties
    sis/trunk/ide-project/NetBeans/nbproject/project.properties
    sis/trunk/ide-project/NetBeans/nbproject/project.xml
    sis/trunk/pom.xml
    sis/trunk/storage/pom.xml
    sis/trunk/storage/sis-gdal/pom.xml
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Axis.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/CRS.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/EPSGFactory.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Operation.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ParameterGroup.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ReferencingFactory.java
    sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/TransformFactory.java
    sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
    sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties
    sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties
    sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java
    sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
    sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Tags.java
    sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/package-info.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/DiscreteSampling.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/FeaturesInfo.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/FeaturesWrapper.java
    sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
    sis/trunk/storage/sis-shapefile/pom.xml
    sis/trunk/storage/sis-storage/pom.xml
    sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
    sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/GeometryParser.java
    sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
    sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java
    sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
    sis/trunk/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
    sis/trunk/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java
    sis/trunk/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Types.java
    sis/trunk/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxStreamReader.java

Propchange: sis/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Jul 13 12:45:03 2017
@@ -1,5 +1,5 @@
 /sis/branches/Android:1430670-1480699
 /sis/branches/JDK6:1394364-1758914
-/sis/branches/JDK7:1394913-1799891
-/sis/branches/JDK8:1584960-1799886
+/sis/branches/JDK7:1394913-1801832
+/sis/branches/JDK8:1584960-1801831
 /sis/branches/JDK9:1773327-1789983

Modified: sis/trunk/core/sis-feature/pom.xml
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/pom.xml?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/pom.xml (original)
+++ sis/trunk/core/sis-feature/pom.xml Thu Jul 13 12:45:03 2017
@@ -122,7 +122,7 @@ Representations of geographic features.
     <dependency>
       <groupId>com.esri.geometry</groupId>
       <artifactId>esri-geometry-api</artifactId>
-      <scope>provided</scope>
+      <optional>true</optional>
     </dependency>
 
     <!-- Test dependencies -->

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -311,7 +311,7 @@ public abstract class AbstractAttribute<
      *     Example:
      *
      *     {@preformat java
-     *       Attribute<?> accuracy = ...; // To be created by the caller.
+     *       Attribute<?> accuracy = ...;                               // To be created by the caller.
      *       characteristics.put("accuracy", accuracy);
      *     }</li>
      *
@@ -321,7 +321,7 @@ public abstract class AbstractAttribute<
      *     Example:
      *
      *     {@preformat java
-     *       Attribute<?> accuracy = ...; // To be created by the caller.
+     *       Attribute<?> accuracy = ...;                               // To be created by the caller.
      *       characteristics.values().add(accuracy);
      *     }</li>
      *
@@ -330,9 +330,9 @@ public abstract class AbstractAttribute<
      *     Example:
      *
      *     {@preformat java
-     *       characteristics.keySet().add("accuracy"); // Ensure that an entry will exist for that name.
+     *       characteristics.keySet().add("accuracy");                  // Ensure that an entry will exist for that name.
      *       Attribute<?> accuracy = characteristics.get("accuracy");
-     *       Features.cast(accuracy, Float.class).setValue(...); // Set new accuracy value here as a float.
+     *       Features.cast(accuracy, Float.class).setValue(...);        // Set new accuracy value here as a float.
      *     }</li>
      * </ol>
      *

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAttributeType.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -189,6 +189,7 @@ public class DefaultAttributeType<V> ext
      *
      * @see org.apache.sis.feature.builder.AttributeTypeBuilder
      */
+    @SuppressWarnings("ThisEscapedInObjectConstruction")    // Okay because used only in package-private class.
     public DefaultAttributeType(final Map<String,?> identification, final Class<V> valueClass,
             final int minimumOccurs, final int maximumOccurs, final V defaultValue,
             final DefaultAttributeType<?>... characterizedBy)

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -65,7 +65,7 @@ final class DenseFeature extends Abstrac
     /**
      * Creates a new feature of the given type.
      *
-     * @param type Information about the feature (name, characteristics, <i>etc.</i>).
+     * @param type  information about the feature (name, characteristics, <i>etc.</i>).
      */
     public DenseFeature(final DefaultFeatureType type) {
         super(type);

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -43,6 +43,7 @@ import org.apache.sis.util.resources.Err
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.math.MathFunctions;
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk8.UncheckedIOException;
@@ -487,8 +488,32 @@ public class FeatureFormat extends Tabul
                                         if (value == null) continue;
                                     }
                                 } else if (format != null && valueClass.isInstance(value)) {    // Null safe because of getFormat(valueClass) contract.
-                                    value = format.format(value, buffer, dummyFP);
+                                    /*
+                                     * Convert numbers, dates, angles, etc. to character sequences before to append them in the table.
+                                     * Note that DecimalFormat writes Not-a-Number as "NaN" in some locales and as "�" in other locales
+                                     * (U+FFFD - Unicode replacement character). The "�" seems to be used mostly for historical reasons;
+                                     * as of 2017 the Unicode Common Locale Data Repository (CLDR) seems to define "NaN" for all locales.
+                                     * We could configure DecimalFormatSymbols for using "NaN", but (for now) we rather substitute "�" by
+                                     * "NaN" here for avoiding to change the DecimalFormat configuration and for distinguishing the NaNs.
+                                     */
+                                    final StringBuffer t = format.format(value, buffer, dummyFP);
+                                    if (value instanceof Number) {
+                                        final float f = ((Number) value).floatValue();
+                                        if (Float.isNaN(f)) {
+                                            if ("�".contentEquals(t)) {
+                                                t.setLength(0);
+                                                t.append("NaN");
+                                            }
+                                            final int n = MathFunctions.toNanOrdinal(f);
+                                            if (n > 0) buffer.append(" #").append(n);
+                                        }
+                                    }
+                                    value = t;
                                 }
+                                /*
+                                 * All values: the numbers, dates, angles, etc. formatted above, any other character sequences
+                                 * (e.g. InternationalString), or other kind of values - some of them handled in a special way.
+                                 */
                                 length = formatValue(value, table.append(separator), length);
                                 buffer.setLength(0);
                                 if (length < 0) break;      // Value is too long, abandon remaining iterations.

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -24,6 +24,7 @@ import org.opengis.parameter.ParameterVa
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.apache.sis.internal.feature.FeatureUtilities;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -42,11 +43,6 @@ final class LinkOperation extends Abstra
     private static final long serialVersionUID = 765096861589501215L;
 
     /**
-     * The parameter descriptor for the "Link" operation, which does not take any parameter.
-     */
-    private static final ParameterDescriptorGroup EMPTY_PARAMS = FeatureUtilities.parameters("Link");
-
-    /**
      * The type of the result.
      */
     private final AbstractIdentifiedType result;
@@ -66,9 +62,13 @@ final class LinkOperation extends Abstra
         super(identification);
         if (referent instanceof LinkOperation) {
             referent = ((LinkOperation) referent).result;
+            // Avoiding links to links may help performance and reduce the risk of circular references.
         }
         result = referent;
         referentName = referent.getName().toString();
+        if (referentName.equals(getName().toString())) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.CircularReference));
+        }
     }
 
     /**
@@ -76,7 +76,7 @@ final class LinkOperation extends Abstra
      */
     @Override
     public ParameterDescriptorGroup getParameters() {
-        return EMPTY_PARAMS;
+        return FeatureUtilities.LINK_PARAMS;
     }
 
     /**

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -52,7 +52,7 @@ final class SparseFeature extends Abstra
     /**
      * A {@link #valuesKind} flag meaning that the {@link #properties} map contains raw values.
      */
-    private static final byte VALUES = 0; // Must be zero, because we want it to be 'valuesKind' default value.
+    private static final byte VALUES = 0;   // Must be zero, because we want it to be 'valuesKind' default value.
 
     /**
      * A {@link #valuesKind} flag meaning that the {@link #properties} map contains {@link Property} instances.
@@ -271,7 +271,7 @@ final class SparseFeature extends Abstra
              * a new value or a value of a different type, then we need to check the name and type validity.
              */
             if (!canSkipVerification(previous, value)) {
-                Object toStore = previous; // This initial value will restore the previous value if the check fail.
+                Object toStore = previous;  // This initial value will restore the previous value if the check fail.
                 try {
                     toStore = verifyPropertyValue(name, value);
                 } finally {

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/builder/FeatureTypeBuilder.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/builder/FeatureTypeBuilder.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/builder/FeatureTypeBuilder.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/builder/FeatureTypeBuilder.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -184,7 +184,7 @@ public class FeatureTypeBuilder extends
     /**
      * Provides method for creating geometric objects using the library specified by the user.
      */
-    private final Geometries geometries;
+    private final Geometries<?> geometries;
 
     /**
      * The object created by this builder, or {@code null} if not yet created.
@@ -207,8 +207,6 @@ public class FeatureTypeBuilder extends
      * will be defined in GeoAPI.</div>
      *
      * @param template  an existing feature type to use as a template, or {@code null} if none.
-     *
-     * @see #setAll(FeatureType)
      */
     public FeatureTypeBuilder(final DefaultFeatureType template) {
         this(null, null, null);
@@ -273,8 +271,6 @@ public class FeatureTypeBuilder extends
      *
      * @param  template  an existing feature type to use as a template, or {@code null} if none.
      * @return {@code this} for allowing method calls chaining.
-     *
-     * @see #FeatureTypeBuilder(FeatureType)
      */
     public FeatureTypeBuilder setAll(final DefaultFeatureType template) {
         clear();
@@ -287,8 +283,6 @@ public class FeatureTypeBuilder extends
     /**
      * Initializes this builder to the value of the given type.
      * The caller is responsible to invoke {@link #clear()} (if needed) before this method.
-     *
-     * @see #setAll(FeatureType)
      */
     private void initialize(final DefaultFeatureType template) {
         super.initialize(template);

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -28,6 +28,7 @@ import org.apache.sis.feature.AbstractAt
 import org.apache.sis.feature.AbstractIdentifiedType;
 import org.apache.sis.feature.AbstractOperation;
 import org.apache.sis.feature.DefaultAttributeType;
+import org.apache.sis.feature.DefaultFeatureType;
 
 
 /**
@@ -250,6 +251,25 @@ public final class AttributeConvention e
     }
 
     /**
+     * Returns the Coordinate Reference Systems characteristic for the given property type, or {@code null} if none.
+     * This method gets the default value from the characteristic named {@link #CRS_CHARACTERISTIC}.
+     * If the given property is a link, then this method follows the link in the given feature type (if non-null).
+     *
+     * <p>This method should be used only when the actual property instance is unknown.
+     * Otherwise, {@code getCRSCharacteristic(Property)} should be used because the CRS
+     * may vary for each property instance.</p>
+     *
+     * @param  feature    the feature type in which to follow links, or {@code null} if none.
+     * @param  attribute  the attribute type for which to get the CRS, or {@code null}.
+     * @return the Coordinate Reference System characteristic of the given property type, or {@code null} if none.
+     * @throws ClassCastException if {@link #CRS_CHARACTERISTIC} has been found but is associated
+     *         to an object which is not a {@link CoordinateReferenceSystem} instance.
+     */
+    public static CoordinateReferenceSystem getCRSCharacteristic(final DefaultFeatureType feature, final AbstractIdentifiedType attribute) {
+        return (CoordinateReferenceSystem) getCharacteristic(feature, attribute, CRS_CHARACTERISTIC.toString());
+    }
+
+    /**
      * Returns whether the given operation or attribute type is characterized by a maximal length.
      * This method verifies whether a characteristic named {@link #MAXIMAL_LENGTH_CHARACTERISTIC}
      * with values of class {@link Integer} exists (directly or indirectly) for the given type.
@@ -265,8 +285,8 @@ public final class AttributeConvention e
      * Returns the maximal length characteristic for the given attribute, or {@code null} if none.
      * This method gets the value or default value from the characteristic named {@link #MAXIMAL_LENGTH_CHARACTERISTIC}.
      *
-     * @param  attribute  the attribute for which to get the CRS, or {@code null}.
-     * @return the Coordinate Reference System characteristic of the given attribute, or {@code null} if none.
+     * @param  attribute  the attribute for which to get the maximal length, or {@code null}.
+     * @return the maximal length characteristic of the given attribute, or {@code null} if none.
      * @throws ClassCastException if {@link #MAXIMAL_LENGTH_CHARACTERISTIC} has been found but is associated
      *         to an object which is not an {@link Integer} instance.
      *
@@ -277,6 +297,25 @@ public final class AttributeConvention e
     }
 
     /**
+     * Returns the maximal length characteristic for the given property type, or {@code null} if none.
+     * This method gets the default value from the characteristic named {@link #MAXIMAL_LENGTH_CHARACTERISTIC}.
+     * If the given property is a link, then this method follows the link in the given feature type (if non-null).
+     *
+     * <p>This method should be used only when the actual property instance is unknown.
+     * Otherwise, {@code getMaximalLengthCharacteristic(Property)} should be used because
+     * the maximal length may vary for each property instance.</p>
+     *
+     * @param  feature    the feature type in which to follow links, or {@code null} if none.
+     * @param  attribute  the attribute type for which to get the maximal length, or {@code null}.
+     * @return the maximal length characteristic of the given property type, or {@code null} if none.
+     * @throws ClassCastException if {@link #MAXIMAL_LENGTH_CHARACTERISTIC} has been found but is associated
+     *         to an object which is not a {@link CoordinateReferenceSystem} instance.
+     */
+    public static Integer getMaximalLengthCharacteristic(final DefaultFeatureType feature, final AbstractIdentifiedType attribute) {
+        return (Integer) getCharacteristic(feature, attribute, MAXIMAL_LENGTH_CHARACTERISTIC.toString());
+    }
+
+    /**
      * Returns {@code true} if the given operation or attribute type has a characteristic of the given name,
      * and the values of that characteristic are assignable to the given {@code valueClass}.
      *
@@ -320,6 +359,30 @@ public final class AttributeConvention e
             if (type != null) {
                 return type.getDefaultValue();
             }
+        }
+        return null;
+    }
+
+    /**
+     * Fetches from the given property the default value of the characteristic of the given name.
+     * If the given property is a link, then this method follows the link in the given feature type
+     * (unless that feature type is null).
+     *
+     * @param  feature         the feature type in which to follow links, or {@code null} if none.
+     * @param  property        the property from which to get the characteristic value, or {@code null}.
+     * @param  characteristic  name of the characteristic from which to get the default value.
+     * @return the default value of the named characteristic in the given property, or {@code null} if none.
+     */
+    private static Object getCharacteristic(final DefaultFeatureType feature, AbstractIdentifiedType property, final String characteristic) {
+        final String referent = FeatureUtilities.linkOf(property);
+        if (referent != null && feature != null) {
+            property = feature.getProperty(referent);
+        }
+        if (property instanceof DefaultAttributeType<?>) {
+            final DefaultAttributeType<?> type = ((DefaultAttributeType<?>) property).characteristics().get(characteristic);
+            if (type != null) {
+                return type.getDefaultValue();
+            }
         }
         return null;
     }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -39,7 +39,7 @@ import org.apache.sis.math.Vector;
  * @since   0.7
  * @module
  */
-final class ESRI extends Geometries {
+final class ESRI extends Geometries<Geometry> {
     /**
      * Creates the singleton instance.
      */
@@ -107,23 +107,27 @@ final class ESRI extends Geometries {
      * The implementation returned by this method must be an instance of {@link #rootClass}.
      */
     @Override
-    public Object createPolyline(final int dimension, final Vector ordinates) {
+    public Geometry createPolyline(final int dimension, final Vector... ordinates) {
         if (dimension != 2) {
             throw unsupported(dimension);
         }
-        final Polyline path = new Polyline();
-        final int size = ordinates.size();
         boolean lineTo = false;
-        for (int i=0; i<size;) {
-            final double x = ordinates.doubleValue(i++);
-            final double y = ordinates.doubleValue(i++);
-            if (Double.isNaN(x) || Double.isNaN(y)) {
-                lineTo = false;
-            } else if (lineTo) {
-                path.lineTo(x, y);
-            } else {
-                path.startPath(x, y);
-                lineTo = true;
+        final Polyline path = new Polyline();
+        for (final Vector v : ordinates) {
+            if (v != null) {
+                final int size = v.size();
+                for (int i=0; i<size;) {
+                    final double x = v.doubleValue(i++);
+                    final double y = v.doubleValue(i++);
+                    if (Double.isNaN(x) || Double.isNaN(y)) {
+                        lineTo = false;
+                    } else if (lineTo) {
+                        path.lineTo(x, y);
+                    } else {
+                        path.startPath(x, y);
+                        lineTo = true;
+                    }
+                }
             }
         }
         return path;
@@ -135,7 +139,7 @@ final class ESRI extends Geometries {
      * @throws ClassCastException if an element in the iterator is not a JTS geometry.
      */
     @Override
-    final Object tryMergePolylines(Object next, final Iterator<?> polylines) {
+    final Geometry tryMergePolylines(Object next, final Iterator<?> polylines) {
         if (!(next instanceof MultiPath || next instanceof Point)) {
             return null;
         }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureUtilities.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureUtilities.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureUtilities.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureUtilities.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -23,8 +23,13 @@ import org.opengis.parameter.ParameterDe
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
 import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.feature.AbstractOperation;
+import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.util.Static;
 
+// Branch-dependent imports
+import org.apache.sis.feature.AbstractIdentifiedType;
+
 
 /**
  * Non-public utility methods for Apache SIS internal usage.
@@ -37,6 +42,13 @@ import org.apache.sis.util.Static;
  */
 public final class FeatureUtilities extends Static {
     /**
+     * The parameter descriptor for the "Link" operation, which does not take any parameter.
+     * We use those parameters as a way to identify the link operation without making the
+     * {@code LinkOperation} class public.
+     */
+    public static final ParameterDescriptorGroup LINK_PARAMS = parameters("Link");
+
+    /**
      * Do not allow instantiation of this class.
      */
     private FeatureUtilities() {
@@ -56,4 +68,26 @@ public final class FeatureUtilities exte
         properties.put(Identifier.AUTHORITY_KEY, Citations.SIS);
         return new DefaultParameterDescriptorGroup(properties, 1, 1);
     }
+
+    /**
+     * If the given property is a link, returns the name of the referenced property.
+     * Otherwise returns {@code null}.
+     *
+     * @param  property  the property to test, or {@code null} if none.
+     * @return the referenced property name, or {@code null} if none.
+     */
+    static String linkOf(final AbstractIdentifiedType property) {
+        if (property instanceof AbstractOperation) {
+            final AbstractOperation op = (AbstractOperation) property;
+            if (op.getParameters() == LINK_PARAMS) {
+                /*
+                 * The dependencies collection contains exactly one element on Apache SIS implementation.
+                 * However the user could define his own operation with the same parameter descriptor name.
+                 * This is unlikely since it would probably be a bug, but we are paranoiac.
+                 */
+                return CollectionsExt.first(op.getDependencies());
+            }
+        }
+        return null;
+    }
 }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -33,13 +33,15 @@ import org.apache.sis.math.Vector;
  * This gives us a single place to review if we want to support different geometry libraries,
  * or if Apache SIS come with its own implementation.
  *
+ * @param   <G>  the base class of all geometry objects (except point in some implementations).
+ *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
  * @since   0.7
  * @module
  */
-public abstract class Geometries {
+public abstract class Geometries<G> {
     /*
      * Registers all supported library implementations. Those libraries are optional
      * (users will typically put at most one on their classpath).
@@ -58,28 +60,33 @@ public abstract class Geometries {
     /**
      * The root geometry class.
      */
-    public final Class<?> rootClass;
+    public final Class<G> rootClass;
+
+    /**
+     * The class for points.
+     */
+    public final Class<?> pointClass;
 
     /**
-     * The class for a point, ployline and polygon.
+     * The class for polylines and polygons.
      */
-    public final Class<?> pointClass, polylineClass, polygonClass;
+    public final Class<? extends G> polylineClass, polygonClass;
 
     /**
      * The default geometry implementation to use. Unmodifiable after class initialization.
      */
-    private static Geometries implementation;
+    private static Geometries<?> implementation;
 
     /**
      * The fallback implementation to use if the default one is not available.
      */
-    private final Geometries fallback;
+    private final Geometries<?> fallback;
 
     /**
      * Creates a new adapter for the given root geometry class.
      */
-    Geometries(final GeometryLibrary library, final Class<?> rootClass, final Class<?> pointClass,
-            final Class<?> polylineClass, final Class<?> polygonClass)
+    Geometries(final GeometryLibrary library, final Class<G> rootClass, final Class<?> pointClass,
+            final Class<? extends G> polylineClass, final Class<? extends G> polygonClass)
     {
         this.library       = library;
         this.rootClass     = rootClass;
@@ -114,11 +121,11 @@ public abstract class Geometries {
      * @return the default geometry implementation.
      * @throws IllegalArgumentException if the given library is non-null but not available.
      */
-    public static Geometries implementation(final GeometryLibrary library) {
+    public static Geometries<?> implementation(final GeometryLibrary library) {
         if (library == null) {
             return implementation;
         }
-        for (Geometries g = implementation; g != null; g = g.fallback) {
+        for (Geometries<?> g = implementation; g != null; g = g.fallback) {
             if (g.library == library) return g;
         }
         throw new IllegalArgumentException(Resources.format(Resources.Keys.UnavailableGeometryLibrary_1, library));
@@ -131,7 +138,7 @@ public abstract class Geometries {
      * @return {@code true} if the given type is one of the geometry type known to SIS.
      */
     public static boolean isKnownType(final Class<?> type) {
-        for (Geometries g = implementation; g != null; g = g.fallback) {
+        for (Geometries<?> g = implementation; g != null; g = g.fallback) {
             if (g.rootClass.isAssignableFrom(type)) return true;
         }
         return false;
@@ -156,7 +163,7 @@ public abstract class Geometries {
      * @see #createPoint(double, double)
      */
     public static double[] getCoordinate(final Object point) {
-        for (Geometries g = implementation; g != null; g = g.fallback) {
+        for (Geometries<?> g = implementation; g != null; g = g.fallback) {
             double[] coord = g.tryGetCoordinate(point);
             if (coord != null) return coord;
         }
@@ -179,7 +186,7 @@ public abstract class Geometries {
      *         is not a recognized geometry or its envelope is empty.
      */
     public static GeneralEnvelope getEnvelope(final Object geometry) {
-        for (Geometries g = implementation; g != null; g = g.fallback) {
+        for (Geometries<?> g = implementation; g != null; g = g.fallback) {
             GeneralEnvelope env = g.tryGetEnvelope(geometry);
             if (env != null) return env;
         }
@@ -200,7 +207,9 @@ public abstract class Geometries {
 
     /**
      * Creates a path or polyline from the given ordinate values.
-     * Each {@link Double#NaN} ordinate value start a new path.
+     * The array of ordinate vectors will be handled as if all vectors were concatenated in a single vector,
+     * ignoring {@code null} array elements.
+     * Each {@link Double#NaN} ordinate value in the concatenated vector starts a new path.
      * The implementation returned by this method is an instance of {@link #rootClass}.
      *
      * @param  dimension  the number of dimensions (2 or 3).
@@ -208,7 +217,7 @@ public abstract class Geometries {
      * @return the geometric object for the given points.
      * @throws UnsupportedOperationException if the geometry library can not create the requested path.
      */
-    public abstract Object createPolyline(int dimension, Vector ordinates);
+    public abstract G createPolyline(int dimension, Vector... ordinates);
 
     /**
      * Merges a sequence of polyline instances if the first instance is an implementation of this library.
@@ -218,7 +227,7 @@ public abstract class Geometries {
      * @return the merged polyline, or {@code null} if the first instance is not an implementation of this library.
      * @throws ClassCastException if an element in the iterator is not an implementation of this library.
      */
-    abstract Object tryMergePolylines(Object first, Iterator<?> polylines);
+    abstract G tryMergePolylines(Object first, Iterator<?> polylines);
 
     /**
      * Merges a sequence of points or polylines into a single polyline instances.
@@ -233,7 +242,7 @@ public abstract class Geometries {
         while (paths.hasNext()) {
             final Object first = paths.next();
             if (first != null) {
-                for (Geometries g = implementation; g != null; g = g.fallback) {
+                for (Geometries<?> g = implementation; g != null; g = g.fallback) {
                     final Object merged = g.tryMergePolylines(first, paths);
                     if (merged != null) {
                         return merged;

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/JTS.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -37,7 +37,7 @@ import org.apache.sis.math.Vector;
  * @todo avoid use of reflection and use JTS API directly after JTS released
  *       a new version of the library under BSD-like license.
  */
-final class JTS extends Geometries {
+final class JTS extends Geometries<Object> {
     /**
      * Getter methods on JTS envelopes.
      * Each methods take no argument and return a {@code double} value.
@@ -49,7 +49,7 @@ final class JTS extends Geometries {
      */
     JTS() throws ClassNotFoundException, NoSuchMethodException {
         super(/*GeometryLibrary.JTS, */ null,                               // TODO
-              Class.forName("com.vividsolutions.jts.geom.Geometry"),
+              (Class) Class.forName("com.vividsolutions.jts.geom.Geometry"),    // TODO
               Class.forName("com.vividsolutions.jts.geom.Point"),
               Class.forName("com.vividsolutions.jts.geom.LineString"),
               Class.forName("com.vividsolutions.jts.geom.Polygon"));
@@ -123,7 +123,7 @@ final class JTS extends Geometries {
      * The implementation returned by this method must be an instance of {@link #rootClass}.
      */
     @Override
-    public Object createPolyline(final int dimension, final Vector ordinates) {
+    public Object createPolyline(final int dimension, final Vector... ordinates) {
         // TODO - see class javadoc
         throw unsupported(dimension);
     }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -23,6 +23,7 @@ import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import org.apache.sis.geometry.GeneralEnvelope;
+import org.apache.sis.internal.jdk8.JDK8;
 import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
 import org.apache.sis.math.Vector;
@@ -39,7 +40,7 @@ import org.apache.sis.math.Vector;
  * @since   0.7
  * @module
  */
-final class Java2D extends Geometries {
+final class Java2D extends Geometries<Shape> {
     /**
      * Creates the singleton instance.
      */
@@ -94,64 +95,71 @@ final class Java2D extends Geometries {
     }
 
     /**
-     * Returns {@code true} if all values in the given vector can be casted to {@code float} without precision lost.
-     *
-     * @param  data  the data to test.
-     * @return whether all the given data can be casted to {@code float} type.
-     */
-    private static boolean isConvertibleToFloats(final Vector data) {
-        for (int i=data.size(); --i >= 0;) {
-            final double value = data.doubleValue(i);
-            if (Double.doubleToRawLongBits(value) != Double.doubleToRawLongBits((float) value)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
      * Creates a path from the given ordinate values.
      * Each {@link Double#NaN} ordinate value start a new path.
      * The implementation returned by this method must be an instance of {@link #rootClass}.
      */
     @Override
-    public Object createPolyline(final int dimension, final Vector ordinates) {
+    public Shape createPolyline(final int dimension, final Vector... ordinates) {
         if (dimension != 2) {
             throw unsupported(dimension);
         }
-        final boolean isFloat = isConvertibleToFloats(ordinates);
-        final int size = ordinates.size();
+        /*
+         * Computes the total length of all vectors and verifies if all values
+         * can be casted to float without precision lost.
+         */
+        int length = 0;
+        boolean isFloat = true;
+        for (final Vector v : ordinates) {
+            if (v != null) {
+                length = JDK8.addExact(length, v.size());
+                if (isFloat) {
+                    for (int i=v.size(); --i >= 0;) {
+                        final double value = v.doubleValue(i);
+                        if (Double.doubleToRawLongBits(value) != Double.doubleToRawLongBits((float) value)) {
+                            isFloat = false;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
         /*
          * Note: Point2D is not an instance of Shape, so we can not make a special case for it.
          */
-        if (size == 4) {
+        length /= 2;
+        if (length == 2 && ordinates.length == 1) {
+            final Vector v = ordinates[0];
             final double x1, y1, x2, y2;
-            if (!Double.isNaN(x1 = ordinates.doubleValue(0)) &&
-                !Double.isNaN(y1 = ordinates.doubleValue(1)) &&
-                !Double.isNaN(x2 = ordinates.doubleValue(2)) &&
-                !Double.isNaN(y2 = ordinates.doubleValue(3)))
+            if (!Double.isNaN(x1 = v.doubleValue(0)) &&
+                !Double.isNaN(y1 = v.doubleValue(1)) &&
+                !Double.isNaN(x2 = v.doubleValue(2)) &&
+                !Double.isNaN(y2 = v.doubleValue(3)))
             {
                 final Line2D path = isFloat ? new Line2D.Float() : new Line2D.Double();
                 path.setLine(x1, y1, x2, y2);
                 return path;
             }
         }
-        final Path2D path = isFloat ? new Path2D.Float (Path2D.WIND_NON_ZERO, size/2)
-                                    : new Path2D.Double(Path2D.WIND_NON_ZERO, size/2);
+        final Path2D path = isFloat ? new Path2D.Float (Path2D.WIND_NON_ZERO, length)
+                                    : new Path2D.Double(Path2D.WIND_NON_ZERO, length);
         boolean lineTo = false;
-        for (int i=0; i<size;) {
-            final double x = ordinates.doubleValue(i++);
-            final double y = ordinates.doubleValue(i++);
-            if (Double.isNaN(x) || Double.isNaN(y)) {
-                lineTo = false;
-            } else if (lineTo) {
-                path.lineTo(x, y);
-            } else {
-                path.moveTo(x, y);
-                lineTo = true;
+        for (final Vector v : ordinates) {
+            final int size = v.size();
+            for (int i=0; i<size;) {
+                final double x = v.doubleValue(i++);
+                final double y = v.doubleValue(i++);
+                if (Double.isNaN(x) || Double.isNaN(y)) {
+                    lineTo = false;
+                } else if (lineTo) {
+                    path.lineTo(x, y);
+                } else {
+                    path.moveTo(x, y);
+                    lineTo = true;
+                }
             }
         }
-        return path;
+        return ShapeUtilities.toPrimitive(path);
     }
 
     /**
@@ -160,7 +168,7 @@ final class Java2D extends Geometries {
      * @throws ClassCastException if an element in the iterator is not a {@link Shape} or a {@link Point2D}.
      */
     @Override
-    final Object tryMergePolylines(Object next, final Iterator<?> polylines) {
+    final Shape tryMergePolylines(Object next, final Iterator<?> polylines) {
         if (!(next instanceof Shape || next instanceof Point2D)) {
             return null;
         }

Copied: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/MovingFeature.java (from r1801832, sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/internal/feature/MovingFeature.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/MovingFeature.java?p2=sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/MovingFeature.java&p1=sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/internal/feature/MovingFeature.java&r1=1801832&r2=1801833&rev=1801833&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/internal/feature/MovingFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/MovingFeature.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -26,16 +26,15 @@ import java.lang.reflect.Array;
 import org.opengis.util.LocalName;
 import org.apache.sis.math.Vector;
 import org.apache.sis.util.iso.Names;
-import org.apache.sis.feature.DefaultAttributeType;
 import org.apache.sis.util.CorruptedObjectException;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk8.Instant;
 import org.apache.sis.internal.jdk8.Consumer;
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
+import org.apache.sis.feature.AbstractFeature;
+import org.apache.sis.feature.AbstractAttribute;
+import org.apache.sis.feature.DefaultAttributeType;
 
 
 /**
@@ -52,7 +51,7 @@ public final class MovingFeature {
     /**
      * Definition of characteristics containing a list of time instants in chronological order, without duplicates.
      */
-    public static final AttributeType<Instant> TIME;
+    public static final DefaultAttributeType<Instant> TIME;
     static {
         final LocalName scope = Names.createLocalName("OGC", null, "MF");
         final Map<String,Object> properties = new HashMap<>(4);
@@ -128,7 +127,7 @@ public final class MovingFeature {
 
     /**
      * Adds a time range.
-     * The minimal and maximal values will be used by {@link #storeTimeRange(String, String, Feature)}.
+     * The minimal and maximal values will be used by {@code storeTimeRange(String, String, Feature)}.
      *
      * @param  startTime  beginning in milliseconds since Java epoch of the period when the property value is valid.
      * @param  endTime    end in milliseconds since Java epoch of the period when the the property value is valid.
@@ -163,7 +162,7 @@ public final class MovingFeature {
      * @param  endTime    name of the property where to store the end time.
      * @param  dest       feature where to store the start time and end time.
      */
-    public final void storeTimeRange(final String startTime, final String endTime, final Feature dest) {
+    public final void storeTimeRange(final String startTime, final String endTime, final AbstractFeature dest) {
         if (tmin < tmax) {
             final Instant t = Instant.ofEpochMilli(tmin);
             dest.setPropertyValue(startTime, t);
@@ -180,7 +179,7 @@ public final class MovingFeature {
      * @param  dest   attribute where to store the value.
      */
     @SuppressWarnings("unchecked")
-    public final <V> void storeAttribute(final int index, final Attribute<V> dest) {
+    public final <V> void storeAttribute(final int index, final AbstractAttribute<V> dest) {
         int n = count[index];
         final long[] times  = new long[n];
         final V[]    values = (V[]) Array.newInstance(dest.getType().getValueClass(), n);
@@ -193,7 +192,7 @@ public final class MovingFeature {
             throw new CorruptedObjectException();
         }
         dest.setValues(UnmodifiableArrayList.wrap(values));
-        final Attribute<Instant> c = TIME.newInstance();
+        final AbstractAttribute<Instant> c = TIME.newInstance();
         c.setValues(new DateList(times));
         dest.characteristics().values().add(c);
     }
@@ -212,7 +211,7 @@ public final class MovingFeature {
      *                          source method name and logger name, then forward to a {@code WarningListener}.
      */
     public final <G> void storeGeometry(final String featureName, final int index, final int dimension,
-            final Geometries<G> factory, final Attribute<G> dest, final Consumer<LogRecord> warningListener)
+            final Geometries<G> factory, final AbstractAttribute<G> dest, final Consumer<LogRecord> warningListener)
     {
         int n = count[index];
         final Vector[] vectors = new Vector[n];
@@ -292,7 +291,7 @@ public final class MovingFeature {
          * Store the geometry and characteristics in the attribute.
          */
         dest.setValue(factory.createPolyline(dimension, vectors));
-        final Attribute<Instant> c = TIME.newInstance();
+        final AbstractAttribute<Instant> c = TIME.newInstance();
         c.setValues(new DateList(times));
         dest.characteristics().values().add(c);
     }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -160,6 +160,11 @@ public final class Resources extends Ind
         public static final short UnexpectedNumberOfComponents_4 = 17;
 
         /**
+         * The “{0}” feature at {1} has a {3} ordinate values, while we expected a multiple of {2}.
+         */
+        public static final short UnexpectedNumberOfOrdinates_4 = 22;
+
+        /**
          * Feature named “{0}” has not yet been resolved.
          */
         public static final short UnresolvedFeatureName_1 = 18;

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties [ISO-8859-1] Thu Jul 13 12:45:03 2017
@@ -38,5 +38,6 @@ PropertyAlreadyExists_2           = Prop
 PropertyNotFound_2                = No property named \u201c{1}\u201d has been found in \u201c{0}\u201d feature.
 UnavailableGeometryLibrary_1      = The {0} geometry library is not available in current runtime environment.
 UnexpectedNumberOfComponents_4    = The \u201c{1}\u201d value given to \u201c{0}\u201d property should be separable in {2} components, but we got {3}.
+UnexpectedNumberOfOrdinates_4     = The \u201c{0}\u201d feature at {1} has a {3} ordinate values, while we expected a multiple of {2}.
 UnresolvedFeatureName_1           = Feature named \u201c{0}\u201d has not yet been resolved.
 UnsupportedGeometryObject_1       = Unsupported geometry {0}D object.

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties [ISO-8859-1] Thu Jul 13 12:45:03 2017
@@ -43,5 +43,6 @@ PropertyNotFound_2                = Aucu
 PropertyAlreadyExists_2           = La propri\u00e9t\u00e9 \u00ab\u202f{1}\u202f\u00bb existe d\u00e9j\u00e0 dans l\u2019entit\u00e9 \u00ab\u202f{0}\u202f\u00bb.
 UnavailableGeometryLibrary_1      = La biblioth\u00e8que de g\u00e9om\u00e9tries {0} n\u2019est pas disponible dans l\u2019environnement d\u2019ex\u00e9cution actuel.
 UnexpectedNumberOfComponents_4    = La valeur \u00ab\u202f{1}\u202f\u00bb donn\u00e9e \u00e0 la propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb devrait \u00eatre s\u00e9parable en {2} composantes, mais on en a obtenus {3}.
+UnexpectedNumberOfOrdinates_4     = L\u2019entit\u00e9 nomm\u00e9e \u00ab\u202f{0}\u202f\u00bb \u00e0 {1} contient {3} ordonn\u00e9es, alors qu\u2019on attendait un multiple de {2}.
 UnresolvedFeatureName_1           = L\u2019entit\u00e9 nomm\u00e9e \u00ab\u202f{0}\u202f\u00bb n\u2019a pas encore \u00e9t\u00e9 r\u00e9solue.
 UnsupportedGeometryObject_1       = Object g\u00e9om\u00e9trique {0}D non-support\u00e9.

Modified: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -149,6 +149,7 @@ public final strictfp class FeatureForma
         feature.setPropertyValue("city", "Tokyo");
         feature.setPropertyValue("population", 13185502);                               // In 2011.
         feature.setPropertyValue("universities", Arrays.asList("Waseda", "Keio"));
+        feature.setPropertyValue("temperature", Float.NaN);
 
         final FeatureFormat format = create();
         final String text = format.format(feature);
@@ -161,7 +162,7 @@ public final strictfp class FeatureForma
                 "│ region       │ InternationalString │ 0 ∉ [1 … 1] │              │                 │\n" +
                 "│ isGlobal     │ Boolean             │ 0 ∉ [1 … 1] │              │                 │\n" +
                 "│ universities │ String              │ 2 ∈ [0 … ∞] │ Waseda, Keio │                 │\n" +
-                "│ temperature  │ Float               │ 0 ∉ [1 … 1] │              │ accuracy, units │\n" +
+                "│ temperature  │ Float               │ 1 ∈ [1 … 1] │ NaN          │ accuracy, units │\n" +
                 "└──────────────┴─────────────────────┴─────────────┴──────────────┴─────────────────┘\n", text);
     }
 

Modified: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -22,12 +22,17 @@ import com.esri.core.geometry.Point;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.referencing.crs.HardCodedCRS;
 import org.apache.sis.feature.DefaultAttributeType;
+import org.apache.sis.feature.DefaultFeatureType;
+import org.apache.sis.feature.FeatureOperations;
 import org.apache.sis.util.iso.Names;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
 
+// Branch-dependent imports
+import org.apache.sis.feature.AbstractOperation;
+
 
 /**
  * Tests {@link AttributeConvention}.
@@ -84,6 +89,14 @@ public final strictfp class AttributeCon
         type = new DefaultAttributeType<>(properties, Point.class, 1, 1, null, characteristic);
         assertTrue("characterizedByCRS", AttributeConvention.characterizedByCRS(type));
         assertEquals(HardCodedCRS.WGS84, AttributeConvention.getCRSCharacteristic(type.newInstance()));
+        assertEquals(HardCodedCRS.WGS84, AttributeConvention.getCRSCharacteristic(null, type));
+        /*
+         * Test again AttributeConvention.getCRSCharacteristic(…, PropertyType), but following link.
+         */
+        final AbstractOperation link = FeatureOperations.link(Collections.singletonMap(DefaultAttributeType.NAME_KEY, "geom"), type);
+        final DefaultFeatureType feat = new DefaultFeatureType(Collections.singletonMap(DefaultAttributeType.NAME_KEY, "feat"), false, null, type, link);
+        assertEquals(HardCodedCRS.WGS84, AttributeConvention.getCRSCharacteristic(feat, link));
+        assertNull(                      AttributeConvention.getCRSCharacteristic(null, link));
     }
 
     /**

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/RecordSchemaSIS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/RecordSchemaSIS.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/RecordSchemaSIS.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/RecordSchemaSIS.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -30,13 +30,9 @@ import org.apache.sis.util.iso.DefaultRe
  * @since   0.7
  * @module
  */
+@SuppressWarnings("serial")  // serialVersionUID not needed because of writeReplace().
 final class RecordSchemaSIS extends DefaultRecordSchema implements Serializable {
     /**
-     * For cross-version compatibility.
-     */
-    private static final long serialVersionUID = 2708181165532467516L;
-
-    /**
      * The schema used in SIS for creating records.
      */
     static final DefaultRecordSchema INSTANCE = new RecordSchemaSIS();
@@ -51,7 +47,7 @@ final class RecordSchemaSIS extends Defa
     /**
      * On serialization, returns a proxy which will be resolved as {@link #INSTANCE} on deserialization.
      */
-    Object writeReplace() throws ObjectStreamException {
+    protected Object writeReplace() throws ObjectStreamException {
         return new Proxy();
     }
 

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -29,6 +29,8 @@ import org.apache.sis.xml.Namespaces;
 
 /**
  * Information on ground control point.
+ * Ground control points (GCP) are large marked targets on the ground,
+ * not to be confused with <cite>localization grid</cite> points embedded in some file formats like GeoTIFF or NetCDF.
  * The following property is mandatory in a well-formed metadata according ISO 19115:
  *
  * <div class="preformat">{@code MI_GCP}
@@ -46,7 +48,10 @@ import org.apache.sis.xml.Namespaces;
  * @author  Cédric Briançon (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.3
- * @since   0.3
+ *
+ * @see DefaultGCPCollection
+ *
+ * @since 0.3
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.

Modified: sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -51,7 +51,10 @@ import org.apache.sis.xml.Namespaces;
  * @author  Cédric Briançon (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.3
- * @since   0.3
+ *
+ * @see DefaultGCP
+ *
+ * @since 0.3
  * @module
  */
 @SuppressWarnings("CloneableClassWithoutClone")                 // ModifiableMetadata needs shallow clones.

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=1801833&r1=1801832&r2=1801833&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 Jul 13 12:45:03 2017
@@ -83,6 +83,11 @@ public final class Resources extends Ind
         public static final short CanNotCreateObjectAsInstanceOf_2 = 4;
 
         /**
+         * Can not infer a grid size from the given values in {0} range.
+         */
+        public static final short CanNotInferGridSizeFromValues_1 = 75;
+
+        /**
          * Can not instantiate geodetic object for “{0}”.
          */
         public static final short CanNotInstantiateGeodeticObject_1 = 5;

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=1801833&r1=1801832&r2=1801833&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 Jul 13 12:45:03 2017
@@ -45,6 +45,7 @@ NonConformCRS_3                   = The
 CanNotConcatenateTransforms_2     = Can not concatenate transforms \u201c{0}\u201d and \u201c{1}\u201d.
 CanNotComputeDerivative           = Can not compute the coordinate operation derivative.
 CanNotCreateObjectAsInstanceOf_2  = Can not create an object of group \u201c{1}\u201d as an instance of class \u2018{0}\u2019.
+CanNotInferGridSizeFromValues_1   = Can not infer a grid size from the given values in {0} range.
 CanNotInstantiateGeodeticObject_1 = Can not instantiate geodetic object for \u201c{0}\u201d.
 CanNotMapAxisToDirection_1        = Can not map an axis from the specified coordinate system to the \u201c{0}\u201d direction.
 CanNotSeparateTargetDimension_1   = Target dimension {0} depends on excluded source dimensions.

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=1801833&r1=1801832&r2=1801833&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 Jul 13 12:45:03 2017
@@ -50,6 +50,7 @@ NonConformCRS_3                   = La d
 CanNotConcatenateTransforms_2     = Les transformations \u00ab\u202f{0}\u202f\u00bb et \u00ab\u202f{1}\u202f\u00bb ne peuvent pas \u00eatre combin\u00e9es.
 CanNotComputeDerivative           = La d\u00e9riv\u00e9 de l\u2019op\u00e9ration sur les coordonn\u00e9es ne peut pas \u00eatre calcul\u00e9e.
 CanNotCreateObjectAsInstanceOf_2  = Ne peut pas cr\u00e9er un objet du groupe \u00ab\u202f{1}\u202f\u00bb comme une instance de la classe \u2018{0}\u2019.
+CanNotInferGridSizeFromValues_1   = Ne peut pas inf\u00e9rer une taille de grille \u00e0 partir des valeurs donn\u00e9es dans la plage {0}.
 CanNotInstantiateGeodeticObject_1 = Ne peut pas cr\u00e9er l\u2019objet g\u00e9od\u00e9tique pour \u00ab\u202f{0}\u202f\u00bb.
 CanNotMapAxisToDirection_1        = Aucun axe du syst\u00e8me de coordonn\u00e9es sp\u00e9cifi\u00e9 n\u2019a pu \u00eatre associ\u00e9 \u00e0 la direction \u00ab\u202f{0}\u202f\u00bb.
 CanNotSeparateTargetDimension_1   = La dimension de destination {0} d\u00e9pend de dimensions sources qui ont \u00e9t\u00e9 exclues.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -62,6 +62,7 @@ import org.apache.sis.util.resources.Err
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.io.wkt.Parser;
+import org.apache.sis.util.Exceptions;
 import org.apache.sis.xml.XML;
 
 
@@ -1565,7 +1566,26 @@ public class GeodeticObjectFactory exten
         try {
             object = XML.unmarshal(xml);
         } catch (JAXBException e) {
-            throw new FactoryException(e.getLocalizedMessage(), e);
+            /*
+             * The JAXB exception if often a wrapper around other exceptions, sometime InvocationTargetException.
+             * The exception cause is called "linked exception" by JAXB, presumably because it predates standard
+             * chained exception mechanism introduced in Java 1.4. The JAXB linked exceptions do not propagate the
+             * error message, so we have to take it from the cause, skipping InvocationTargetException since they
+             * are wrapper for other causes. If the cause is a JAXBException, we will keep it as the declared cause
+             * for simplifying the stack trace.
+             */
+            String message = e.getLocalizedMessage();
+            Throwable cause = e.getCause();
+            if (cause instanceof Exception) {
+                cause = Exceptions.unwrap((Exception) cause);
+                if (cause instanceof JAXBException) {
+                    e = (JAXBException) cause;
+                }
+                if (message == null) {
+                    message = cause.getLocalizedMessage();
+                }
+            }
+            throw new FactoryException(message, e);
         }
         if (object instanceof CoordinateReferenceSystem) {
             return (CoordinateReferenceSystem) object;

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -51,13 +51,9 @@ import org.apache.sis.util.Debug;
  * @since   0.7
  * @module
  */
+@SuppressWarnings("serial")   // serialVersionUID not needed because of writeReplace().
 final class AuthorityCodes extends AbstractMap<String,String> implements Serializable {
     /**
-     * For compatibility with different versions.
-     */
-    private static final long serialVersionUID = 6118171679321975503L;
-
-    /**
      * Highest code value (inclusive) that this {@code AuthorityCodes} support during iterations.
      * This is based on the upper value of the highest range of codes once used by EPSG.
      */

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=1801833&r1=1801832&r2=1801833&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 Jul 13 12:45:03 2017
@@ -18,18 +18,24 @@ package org.apache.sis.referencing.opera
 
 import org.opengis.util.FactoryException;
 import org.opengis.geometry.MismatchedDimensionException;
+import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.TransformException;
+import org.opengis.referencing.operation.NoninvertibleTransformException;
 import org.apache.sis.referencing.operation.transform.InterpolatedTransform;
 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.datum.DatumShiftGrid;
 import org.apache.sis.internal.referencing.Resources;
 import org.apache.sis.geometry.DirectPosition2D;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.measure.NumberRange;
 import org.apache.sis.math.MathFunctions;
+import org.apache.sis.math.Vector;
 
 
 /**
@@ -63,6 +69,11 @@ import org.apache.sis.math.MathFunctions
  */
 public class LocalizationGridBuilder extends TransformBuilder {
     /**
+     * Tolerance threshold for comparing pixel coordinates relative to integer values.
+     */
+    private static final double EPS = Numerics.COMPARISON_THRESHOLD;
+
+    /**
      * The transform for the linear part.
      */
     private final LinearTransformBuilder linear;
@@ -71,7 +82,7 @@ public class LocalizationGridBuilder ext
      * A temporary array for two-dimensional source coordinates.
      * Used for reducing object allocations.
      */
-    private final int[] tmp;
+    private final int[] tmp = new int[2];
 
     /**
      * Conversions from source real-world coordinates to grid indices before interpolation.
@@ -90,18 +101,86 @@ public class LocalizationGridBuilder ext
     static final double DEFAULT_PRECISION = 1E-7;
 
     /**
-     * Creates a new, initially empty, builder.
+     * Creates a new, initially empty, builder for a localization grid of the given size.
      *
      * @param width   the number of columns in the grid of target positions.
      * @param height  the number of rows in the grid of target positions.
      */
     public LocalizationGridBuilder(final int width, final int height) {
         linear       = new LinearTransformBuilder(width, height);
-        tmp          = new int[2];
         sourceToGrid = MathTransforms.identity(2);
     }
 
     /**
+     * Creates a new, initially empty, builder for a localization grid of a size inferred from the given points.
+     * This constructor uses the given vectors for computing a grid size and the following initial conversion:
+     *
+     * <blockquote>({@code sourceX}, {@code sourceY}) → ({@code gridX}, {@code gridY})</blockquote>
+     *
+     * Above conversion can be obtained by {@link #getSourceToGrid()}.
+     *
+     * <p>Values in the given vectors should be integers, but this constructor is tolerant to non-integer values
+     * if they have a constant offset (typically 0.5) relative to integer values. The two vectors do not need to
+     * have the same length (i.e. {@code sourceX[i]} are not necessarily related to {@code sourceY[i]}).</p>
+     *
+     * @param  sourceX  all possible <var>x</var> inputs before conversion to grid coordinates.
+     * @param  sourceY  all possible <var>y</var> inputs before conversion to grid coordinates.
+     * @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);
+        linear = new LinearTransformBuilder(infer(sourceX, fromGrid, 0), infer(sourceY, fromGrid, 1));
+        try {
+            sourceToGrid = MathTransforms.linear(fromGrid).inverse();
+        } catch (NoninvertibleTransformException e) {
+            // Should not happen because infer(…) verified that the coefficients are okay.
+            throw (ArithmeticException) new ArithmeticException(e.getLocalizedMessage()).initCause(e);
+        }
+    }
+
+    /**
+     * Infers a grid size by searching for the greatest common divisor (GCD) for values in the given vector.
+     * The vector values should be integers, but this method is tolerant to constant offsets (typically 0.5).
+     * The GCD is taken as a "grid to source" scale factor and the minimal value as the translation term.
+     * Those two values are stored in the {@code dim} row of the given matrix.
+     *
+     * @param  source    the vector of values for which to get the GCD and minimum value.
+     * @param  fromGrid  matrix where to store the minimum value and the GCD.
+     * @param  dim       index of the matrix row to update.
+     * @return grid size.
+     */
+    private static int infer(final Vector source, final Matrix fromGrid, final int dim) {
+        final NumberRange<?> range = source.range();
+        final double min  = range.getMinDouble(true);
+        final double span = range.getMaxDouble(true) - min;
+        final Number increment = source.increment(EPS * span);
+        double inc;
+        if (increment != null) {
+            inc = increment.doubleValue();
+        } else {
+            inc = span;
+            final int size = source.size();
+            for (int i=0; i<size; i++) {
+                double v = source.doubleValue(i) - min;
+                if (Math.abs(v % inc) > EPS) {
+                    do {
+                        final double r = (inc % v);     // Both 'inc' and 'v' are positive, so 'r' will be positive too.
+                        inc = v;
+                        v = r;
+                    } while (Math.abs(v) > EPS);
+                }
+            }
+        }
+        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) {
+            return ((int) Math.round(n)) + 1;
+        }
+        throw new ArithmeticException(Resources.format(Resources.Keys.CanNotInferGridSizeFromValues_1, range));
+    }
+
+    /**
      * Sets the desired precision of <em>inverse</em> transformations, in units of source coordinates.
      * If a conversion from "real world" to grid coordinates {@linkplain #setSourceToGrid has been specified},
      * then the given precision is in "real world" units. Otherwise the precision is in units of grid cells.
@@ -122,6 +201,16 @@ public class LocalizationGridBuilder ext
     }
 
     /**
+     * Returns the desired precision of <em>inverse</em> transformations, in units of source coordinates.
+     * This is the precision sets by the last call to {@link #setDesiredPrecision(double)}.
+     *
+     * @return desired precision of the results of inverse transformations.
+     */
+    public double getDesiredPrecision() {
+        return precision;
+    }
+
+    /**
      * Defines relationship between "real-world" source coordinates and grid coordinates.
      * The given transform is usually two-dimensional, in which case conversions from (<var>x</var>,<var>y</var>)
      * source coordinates to ({@code gridX}, {@code gridY}) indices can be done with the following formulas:
@@ -173,9 +262,25 @@ public class LocalizationGridBuilder ext
     }
 
     /**
+     * Returns the current relationship between "real-world" source coordinates and grid coordinates.
+     * This is the value set by the last call to {@link #setSourceToGrid(LinearTransform)}.
+     * If that setter method has never been invoked, then this is an automatically computed transform
+     * if the grid coordinates {@linkplain #LocalizationGridBuilder(Vector, Vector) have been specified
+     * to the constructor}, or the identity transform {@linkplain #LocalizationGridBuilder(int, int) otherwise}.
+     *
+     * @return the current relationship between "real-world" source coordinates and grid coordinates.
+     */
+    public LinearTransform getSourceToGrid() {
+        return sourceToGrid;
+    }
+
+    /**
      * Sets a single matching control point pair. Source position is assumed precise and target position is assumed uncertain.
      * If the given source position was already associated with another target position, then the old target position is discarded.
      *
+     * <p>If a {@linkplain #getSourceToGrid() source to grid} conversion exists, it shall have been applied
+     * by the caller for computing the ({@code gridX}, {@code gridY}) coordinates given to this method.</p>
+     *
      * @param  gridX   the column index in the grid where to store the given target position.
      * @param  gridY   the row index in the grid where to store the given target position.
      * @param  target  the target coordinates, assumed uncertain.
@@ -231,7 +336,7 @@ public class LocalizationGridBuilder ext
             }
         }
         if (isExact) {
-            return gridToCoord;
+            return MathTransforms.concatenate(sourceToGrid, gridToCoord);
         }
         final int      width    = linear.gridSize(0);
         final int      height   = linear.gridSize(1);
@@ -282,7 +387,7 @@ public class LocalizationGridBuilder ext
             throw new FactoryException(e);                                          // Should never happen.
         }
         if (isLinear) {
-            return gridToCoord;
+            return MathTransforms.concatenate(sourceToGrid, gridToCoord);
         }
         return InterpolatedTransform.createGeodeticTransformation(nonNull(factory),
                 new ResidualGrid(sourceToGrid, gridToCoord, width, height, tgtDim, residual,

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -189,6 +189,22 @@ public final class JDK8 {
      *
      * @since 0.8
      */
+    public static int addExact(final int x, final int y) {
+        final long r = x + y;
+        if ((r & 0xFFFFFFFF00000000L) == 0) return (int) r;
+        throw new ArithmeticException();
+    }
+
+    /**
+     * Safe sum of the given numbers.
+     *
+     * @param  x  first value to add.
+     * @param  y  second value to add.
+     * @return the sum.
+     * @throws ArithmeticException if the result overflows.
+     *
+     * @since 0.8
+     */
     public static long addExact(final long x, final long y) {
         final long r = x + y;
         if (((x ^ r) & (y ^ r)) >= 0) return r;

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/Spliterator.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/Spliterator.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/Spliterator.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/Spliterator.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -34,6 +34,11 @@ public interface Spliterator<T> {
     int ORDERED = 0x10;
 
     /**
+     * Flag for iterators that can provides accurate information about the number of elements.
+     */
+    int SIZED = 0x40;
+
+    /**
      * Flag for iterators that do not return null values.
      */
     int NONNULL = 0x100;



Mime
View raw message