sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1801833 [3/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
Modified: sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java [UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/OperationFactory.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -17,14 +17,13 @@
 package org.apache.sis.storage.gdal;
 
 import java.util.Map;
-import org.opengis.metadata.Identifier;
-import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.CoordinateOperationFactory;
 import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.util.FactoryException;
 
 import org.apache.sis.util.iso.AbstractFactory;
@@ -69,7 +68,7 @@ final class OperationFactory extends Abs
                                                final CoordinateReferenceSystem targetCRS)
             throws FactoryException
     {
-        Identifier id;
+        ReferenceIdentifier id;
         String src=null, tgt=null, space=null;
         if ((id = sourceCRS.getName()) != null) {
             src = id.getCode();
@@ -137,26 +136,4 @@ final class OperationFactory extends Abs
     {
         throw Proj4.unsupportedOperation();
     }
-
-    /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
-     *
-     * @throws FactoryException alway thrown.
-     */
-    @Override
-    public OperationMethod createOperationMethod(Map<String,?> properties, Integer sourceDimension,
-            Integer targetDimension, ParameterDescriptorGroup parameters) throws FactoryException
-    {
-        throw Proj4.unsupportedOperation();
-    }
-
-    /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
-     *
-     * @throws FactoryException alway thrown.
-     */
-    @Override
-    public OperationMethod getOperationMethod(String name) throws FactoryException {
-        throw Proj4.unsupportedOperation();
-    }
 }

Modified: sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java [UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -21,9 +21,9 @@ import java.util.Objects;
 import javax.measure.Unit;
 import javax.measure.quantity.Angle;
 import javax.measure.quantity.Length;
-import org.opengis.metadata.Identifier;
 import org.opengis.metadata.extent.Extent;
 import org.opengis.util.InternationalString;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.GeodeticDatum;
 import org.opengis.referencing.datum.PrimeMeridian;
@@ -79,7 +79,7 @@ final class PJ extends PJObject implemen
      * @param  definition  the Proj4 definition string.
      * @throws InvalidGeodeticParameterException if the PJ structure can not be created from the given string.
      */
-    public PJ(Identifier name, final String definition) throws InvalidGeodeticParameterException {
+    public PJ(ReferenceIdentifier name, final String definition) throws InvalidGeodeticParameterException {
         super(name != null ? name : identifier(definition, "+datum="));
         Objects.requireNonNull(definition);
         ptr = allocatePJ(definition);

Modified: sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java [UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJObject.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -21,9 +21,9 @@ import java.util.Collection;
 import java.util.Collections;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
 import org.opengis.metadata.extent.Extent;
 import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.simple.SimpleIdentifier;
 
 
@@ -39,7 +39,7 @@ class PJObject implements IdentifiedObje
     /**
      * The name of this referencing object, or {@code null} if none.
      */
-    final Identifier name;
+    final ReferenceIdentifier name;
 
     /**
      * The aliases, or an empty list if none.
@@ -51,7 +51,7 @@ class PJObject implements IdentifiedObje
      *
      * @param name  the name of the new object, or {@code null} if none.
      */
-    PJObject(final Identifier name) {
+    PJObject(final ReferenceIdentifier name) {
         this.name    = name;
         this.aliases = Collections.emptyList();
     }
@@ -61,7 +61,7 @@ class PJObject implements IdentifiedObje
      *
      * @param name  the name of the new object, or {@code null} if none.
      */
-    PJObject(final Identifier name, final Collection<GenericName> aliases) {
+    PJObject(final ReferenceIdentifier name, final Collection<GenericName> aliases) {
         this.name    = name;
         this.aliases = aliases;
     }
@@ -84,7 +84,7 @@ class PJObject implements IdentifiedObje
      * @param  key         the parameter name.
      * @return the parameter value as an identifier.
      */
-    static Identifier identifier(final String definition, final String key) {
+    static ReferenceIdentifier identifier(final String definition, final String key) {
         int i = definition.indexOf(key);
         if (i >= 0) {
             i += key.length();
@@ -103,7 +103,7 @@ class PJObject implements IdentifiedObje
      * simple Proj.4 wrapper is lenient about that.
      */
     @Override
-    public Identifier getName() {
+    public ReferenceIdentifier getName() {
         return name;
     }
 
@@ -113,7 +113,7 @@ class PJObject implements IdentifiedObje
      * rather the name which is quite inaccurate.
      */
     @Override
-    public Set<Identifier> getIdentifiers() {
+    public Set<ReferenceIdentifier> getIdentifiers() {
         return Collections.singleton(name);
     }
 

Modified: sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java [UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Parameter.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -23,13 +23,11 @@ import javax.measure.Unit;
 import javax.measure.IncommensurableException;
 
 import org.opengis.util.GenericName;
-import org.opengis.util.InternationalString;
-import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterValue;
 import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.parameter.ParameterDirection;
 import org.opengis.parameter.InvalidParameterTypeException;
 import org.opengis.parameter.InvalidParameterValueException;
+import org.opengis.referencing.ReferenceIdentifier;
 
 import org.apache.sis.measure.Units;
 
@@ -57,7 +55,7 @@ final class Parameter extends PJObject i
     /**
      * Creates a new parameter with the given identifier and aliases.
      */
-    Parameter(final Identifier identifier, final Collection<GenericName> aliases) {
+    Parameter(final ReferenceIdentifier identifier, final Collection<GenericName> aliases) {
         super(identifier, aliases);
     }
 
@@ -78,22 +76,6 @@ final class Parameter extends PJObject i
     }
 
     /**
-     * Returns {@code null}, since this simple class does not provide parameter description.
-     */
-    @Override
-    public InternationalString getDescription() {
-        return null;
-    }
-
-    /**
-     * Returns {@code this}, since this simple class is used only as input parameter.
-     */
-    @Override
-    public ParameterDirection getDirection() {
-        return ParameterDirection.IN;
-    }
-
-    /**
      * Returns the minimum number of times that values for this parameter are required.
      * This method returns 1, meaning that a value shall alway be supplied
      * (the {@link #getValue()} method never return {@code null}).

Modified: sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ParameterGroup.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ParameterGroup.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ParameterGroup.java [UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ParameterGroup.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -25,7 +25,6 @@ import java.util.MissingResourceExceptio
 
 import org.opengis.util.GenericName;
 import org.opengis.util.FactoryException;
-import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
@@ -33,8 +32,8 @@ import org.opengis.parameter.GeneralPara
 import org.opengis.parameter.ParameterValue;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.GeneralParameterValue;
-import org.opengis.parameter.ParameterDirection;
 import org.opengis.parameter.ParameterNotFoundException;
+import org.opengis.referencing.ReferenceIdentifier;
 
 import org.apache.sis.referencing.NamedIdentifier;
 
@@ -71,7 +70,7 @@ final class ParameterGroup extends PJObj
     /**
      * Creates a new parameter group for the given identifier.
      */
-    ParameterGroup(final Identifier identifier, final Collection<GenericName> aliases) {
+    ParameterGroup(final ReferenceIdentifier identifier, final Collection<GenericName> aliases) {
         super(identifier, aliases);
         parameters = new ArrayList<>();
         unmodifiable = Collections.unmodifiableList(parameters);
@@ -80,7 +79,7 @@ final class ParameterGroup extends PJObj
     /**
      * Creates a new parameter group for the given identifier and parameters.
      */
-    ParameterGroup(final Identifier identifier, final Collection<GenericName> aliases, final Parameter... param) {
+    ParameterGroup(final ReferenceIdentifier identifier, final Collection<GenericName> aliases, final Parameter... param) {
         super(identifier, aliases);
         parameters = new ArrayList<>(Arrays.asList(param));
         unmodifiable = Collections.unmodifiableList(parameters);
@@ -111,22 +110,6 @@ final class ParameterGroup extends PJObj
     }
 
     /**
-     * Returns {@code null}, since this simple class does not provide parameters description.
-     */
-    @Override
-    public InternationalString getDescription() {
-        return null;
-    }
-
-    /**
-     * Returns {@code this}, since this simple class is used only as input parameters.
-     */
-    @Override
-    public ParameterDirection getDirection() {
-        return ParameterDirection.IN;
-    }
-
-    /**
      * Returns the minimum number of times that values for this group are required.
      * This method returns 1, meaning that this group shall alway be supplied at least once.
      */

Modified: sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java [UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/Proj4.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -16,8 +16,8 @@
  */
 package org.apache.sis.storage.gdal;
 
-import org.opengis.metadata.Identifier;
 import org.opengis.util.FactoryException;
+import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.apache.sis.internal.system.Modules;
@@ -90,8 +90,8 @@ public final class Proj4 extends Static
      * @throws NullPointerException if the definition string is {@code null}.
      * @throws FactoryException if one of the given argument has an invalid value.
      */
-    public static CoordinateReferenceSystem createCRS(final Identifier crsId,
-            final Identifier datumId, String definition, final int dimension)
+    public static CoordinateReferenceSystem createCRS(final ReferenceIdentifier crsId,
+            final ReferenceIdentifier datumId, String definition, final int dimension)
             throws FactoryException
     {
         if ((definition = definition.trim()).isEmpty()) {
@@ -151,7 +151,7 @@ public final class Proj4 extends Static
      * @return a coordinate operation for transforming coordinates from the given source CRS to the given target CRS.
      * @throws ClassCastException if the given CRS are not instances created by this class.
      */
-    public static CoordinateOperation createOperation(final Identifier identifier,
+    public static CoordinateOperation createOperation(final ReferenceIdentifier identifier,
             final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS)
             throws ClassCastException
     {

Modified: sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ReferencingFactory.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ReferencingFactory.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ReferencingFactory.java [UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/ReferencingFactory.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -25,10 +25,10 @@ import org.opengis.referencing.crs.*;
 import org.opengis.referencing.datum.*;
 import org.opengis.referencing.operation.*;
 import org.opengis.util.FactoryException;
-import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterValue;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.GeneralParameterValue;
+import org.opengis.referencing.ReferenceIdentifier;
 
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.util.iso.AbstractFactory;
@@ -122,7 +122,7 @@ final class ReferencingFactory extends A
             final GeodeticDatum datum, final CoordinateSystem cs) throws FactoryException
     {
         final int           dimension  = cs.getDimension();
-        final Identifier    name       = new ImmutableIdentifier(properties);
+        final ReferenceIdentifier name = new ImmutableIdentifier(properties);
         final Ellipsoid     ellipsoid  = datum.getEllipsoid();
         final StringBuilder definition = new StringBuilder(100);
         definition.append("+proj=").append(type)
@@ -197,7 +197,7 @@ final class ReferencingFactory extends A
             final Conversion conversionFromBase, final CartesianCS derivedCS) throws FactoryException
     {
         final int                 dimension  = derivedCS.getDimension();
-        final Identifier          name       = new ImmutableIdentifier(properties);
+        final ReferenceIdentifier name       = new ImmutableIdentifier(properties);
         final EllipsoidalCS       baseCS     = baseCRS.getCoordinateSystem();
         final GeodeticDatum       datum      = baseCRS.getDatum();
         final Ellipsoid           ellipsoid  = datum.getEllipsoid();
@@ -254,16 +254,6 @@ final class ReferencingFactory extends A
         throw Proj4.unsupportedOperation();
     }
 
-    /**
-     * Unconditionally throws an exception, since this functionality is not supported yet.
-     *
-     * @throws FactoryException always thrown.
-     */
-    @Override
-    public ParametricCRS createParametricCRS(Map<String, ?> properties, ParametricDatum datum, ParametricCS cs) throws FactoryException {
-        throw Proj4.unsupportedOperation();
-    }
-
     /**
      * Unconditionally throws an exception, since this functionality is not supported yet.
      *

Modified: sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/TransformFactory.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/TransformFactory.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/TransformFactory.java [UTF-8] (original)
+++ sis/trunk/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/TransformFactory.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -25,7 +25,7 @@ import org.opengis.parameter.*;
 import org.opengis.referencing.cs.*;
 import org.opengis.referencing.crs.*;
 import org.opengis.referencing.operation.*;
-import org.opengis.metadata.Identifier;
+import org.opengis.referencing.ReferenceIdentifier;
 
 import org.apache.sis.util.iso.AbstractFactory;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
@@ -56,7 +56,7 @@ final class TransformFactory extends Abs
     /**
      * Useful constant.
      */
-    private static final Identifier WGS84 = new ImmutableIdentifier(null, null, "WGS84");
+    private static final ReferenceIdentifier WGS84 = new ImmutableIdentifier(null, null, "WGS84");
 
     /**
      * Creates a new coordinate operation factory.
@@ -131,7 +131,7 @@ final class TransformFactory extends Abs
                 }
             }
         }
-        final Identifier id = parameters.getDescriptor().getName();
+        final ReferenceIdentifier id = parameters.getDescriptor().getName();
         final CoordinateReferenceSystem targetCRS = Proj4.createCRS(id, id, definition.toString(), 2);
         final CoordinateReferenceSystem sourceCRS = (targetCRS instanceof ProjectedCRS)
                 ? ((ProjectedCRS) targetCRS).getBaseCRS()

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java [UTF-8] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -146,6 +146,11 @@ public final class Resources extends Ind
         public static final short RandomizedProcessApplied = 15;
 
         /**
+         * The “{0}” GeoTIFF file does not specify the values format.
+         */
+        public static final short UndefinedDataFormat_1 = 25;
+
+        /**
          * A single value was expected for the “{0}” key but {1} values have been found.
          */
         public static final short UnexpectedListOfValues_2 = 16;

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties [ISO-8859-1] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties [ISO-8859-1] Thu Jul 13 12:45:03 2017
@@ -35,6 +35,7 @@ MissingGeoValue_1                 = No v
 MissingValue_2                    = Can not read TIFF image from \u201c{0}\u201d because the \u201c{1}\u201d tag is missing.
 NotTheEpsgValue_5                 = The file defines \u201c{2}\u201d with value {3}{4}, but that value should be {1}{4} according parent definition ({0}).
 RandomizedProcessApplied          = A randomized process such as error diffusion has been applied to the image data.
+UndefinedDataFormat_1             = The \u201c{0}\u201d GeoTIFF file does not specify the values format.
 UnexpectedListOfValues_2          = A single value was expected for the \u201c{0}\u201d key but {1} values have been found.
 UnexpectedParameter_2             = The \u201c{1}\u201d parameter was not expected for the \u201c{0}\u201d projection method.
 UnexpectedTileCount_3             = Found {2} tiles or strips in the \u201c{0}\u201d file while {1} were expected.

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties [ISO-8859-1] Thu Jul 13 12:45:03 2017
@@ -40,6 +40,7 @@ MissingGeoValue_1                 = Aucu
 MissingValue_2                    = Ne peut pas lire l\u2019image TIFF provenant de \u00ab\u202f{0}\u202f\u00bb car le tag \u00ab\u202f{1}\u202f\u00bb est manquant.
 NotTheEpsgValue_5                 = Le fichier d\u00e9finit \u00ab\u202f{2}\u202f\u00bb avec la valeur {3}{4}, mais cette valeur devrait \u00eatre {1}{4} pour \u00eatre en accord avec la d\u00e9finition du parent {0}.
 RandomizedProcessApplied          = Un processus randomis\u00e9 comme la diffusion d\u2019erreur a \u00e9t\u00e9 appliqu\u00e9.
+UndefinedDataFormat_1             = Le fichier GeoTIFF \u00ab\u202f{0}\u202f\u00bb ne sp\u00e9cifie pas le format de ses valeurs.
 UnexpectedListOfValues_2          = Une seule valeur \u00e9tait attendue pour la cl\u00e9 \u00ab\u202f{0}\u202f\u00bb, mais on en a trouv\u00e9es {1}.
 UnexpectedParameter_2             = Le param\u00e8tre \u00ab\u202f{1}\u202f\u00bb est inattendu pour la m\u00e9thode de projection \u00ab\u202f{0}\u202f\u00bb.
 UnexpectedTileCount_3             = {2} tuiles ont \u00e9t\u00e9 trouv\u00e9es dans le fichier \u00ab\u202f{0}\u202f\u00bb alors qu\u2019on en attendait {1}.

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java [UTF-8] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -745,6 +745,8 @@ final class CRSBuilder {
      * <ul>
      *   <li>{@link #build(Vector, Vector, String)} must have been invoked before this method.</li>
      *   <li>{@link ImageFileDirectory} must have filled its part of metadata before to invoke this method.</li>
+     *   <li>{@link MetadataBuilder#newGridRepresentation(MetadataBuilder.GridType)} should have been invoked
+     *       with the appropriate {@code GEORECTIFIED} or {@code GEOREFERENCEABLE} type.</li>
      * </ul>
      *
      * After execution, this method emits a warning for unprocessed GeoTIFF tags.
@@ -753,7 +755,6 @@ final class CRSBuilder {
      * @throws NumberFormatException if a numeric value was stored as a string and can not be parsed.
      */
     final void complete(final MetadataBuilder metadata) {
-        metadata.newGridRepresentation(MetadataBuilder.GridType.GEORECTIFIED);
         /*
          * ASCII reference to published documentation on the overall configuration of the GeoTIFF file.
          * Often the projected CRS name, despite GeoKeys.PCSCitation being already for that purpose.
@@ -921,13 +922,13 @@ final class CRSBuilder {
     private PrimeMeridian createPrimeMeridian(final String[] names, final Unit<Angle> unit) throws FactoryException {
         final int epsg = getAsInteger(GeoKeys.PrimeMeridian);
         switch (epsg) {
-            case GeoCodes.undefined: {
-                break;                      // If not specified, default to Greenwich.
-            }
+            case GeoCodes.undefined:      // If not specified, should default to Greenwich but we nevertheless verify.
             case GeoCodes.userDefined: {
                 final double longitude = getAsDouble(GeoKeys.PrimeMeridianLong);
                 if (Double.isNaN(longitude)) {
-                    missingValue(GeoKeys.PrimeMeridianLong);
+                    if (epsg != GeoCodes.undefined) {
+                        missingValue(GeoKeys.PrimeMeridianLong);
+                    }
                 } else if (longitude != 0) {
                     /*
                      * If the prime meridian is not Greenwich, create that meridian but do not use the

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java [UTF-8] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/ImageFileDirectory.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -31,11 +31,15 @@ import org.opengis.util.FactoryException
 import org.opengis.util.NoSuchIdentifierException;
 import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.referencing.NoSuchAuthorityCodeException;
+import org.opengis.referencing.operation.TransformException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.referencing.operation.matrix.Matrices;
+import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.internal.geotiff.Resources;
+import org.apache.sis.internal.storage.MetadataBuilder;
 import org.apache.sis.internal.storage.io.ChannelDataInput;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
-import org.apache.sis.internal.storage.MetadataBuilder;
 import org.apache.sis.math.Vector;
 import org.apache.sis.measure.Units;
 
@@ -66,6 +70,13 @@ final class ImageFileDirectory {
     private static final byte TILE = 1, STRIP = 2;
 
     /**
+     * Possible value for {@link #sampleFormat} specifying how to interpret each data sample in a pixel.
+     * Those values are not necessarily the same than the ones documented in {@link Tags#SampleFormat}.
+     * Default value is {@link #UNSIGNED}.
+     */
+    private static final byte SIGNED = 1, UNSIGNED = 0, FLOAT = 3;
+
+    /**
      * The GeoTIFF reader which contain this {@code ImageFileDirectory}.
      * Used for fetching information like the input channel and where to report warnings.
      */
@@ -159,6 +170,12 @@ final class ImageFileDirectory {
     private boolean isPlanar;
 
     /**
+     * How to interpret each data sample in a pixel.
+     * Possible values are {@link #SIGNED}, {@link #UNSIGNED} or {@link #FLOAT}.
+     */
+    private byte sampleFormat;
+
+    /**
      * Whether the bit order should be reversed. This boolean value is determined from the {@code FillOrder} TIFF tag.
      *
      * <ul>
@@ -268,9 +285,10 @@ final class ImageFileDirectory {
     private short cellWidth = -1, cellHeight = -1;
 
     /**
-     * The minimum or maximum sample value found in the image, or {@code NaN} if unspecified.
+     * The minimum or maximum sample value found in the image, with one value per band.
+     * May be a vector of length 1 if the same single value applies to all bands.
      */
-    private double minValue = Double.NaN, maxValue = Double.NaN;
+    private Vector minValues, maxValues;
 
     /**
      * The number of pixels per {@link #resolutionUnit} in the {@link #imageWidth} and the {@link #imageHeight}
@@ -314,6 +332,38 @@ final class ImageFileDirectory {
     private String asciiGeoParameters;
 
     /**
+     * Raster model tie points. This vector contains ordinate values structured as (I,J,K, X,Y,Z) records.
+     * The (I,J,K) ordinate values specify the point at location (I,J) in raster space with pixel-value K,
+     * and (X,Y,Z) ordinate values specify the point in the Coordinate Reference System. In most cases the
+     * coordinate system is only two-dimensional, in which case both K and Z should be set to zero.
+     */
+    private Vector modelTiePoints;
+
+    /**
+     * The conversion from grid coordinates to CRS coordinates. It can be determined in different ways,
+     * from simpler to more complex:
+     *
+     * <ul>
+     *   <li>By a combination of a single {@link #modelTiePoints} with the 3 values given in
+     *       {@link Tags#ModelPixelScaleTag} as documented in the Javadoc of that tag.</li>
+     *   <li>By a {@link Tags#ModelTransformation} giving all coefficients of the 4×4 matrix}.
+     *       Note that the third row and the third column have all their value set to 0 if the
+     *       space model (or the coordinate reference system) should be two-dimensional.</li>
+     *   <li>By building a non-linear transformation from all {@link #modelTiePoints}.
+     *       Such transformation can not be stored in a matrix, so will leave this field {@code null}.</li>
+     * </ul>
+     *
+     * By convention, the translation column is set to NaN values if it needs to be computed from the tie point.
+     */
+    private MatrixSIS gridToCRS;
+
+    /**
+     * {@code true} if {@link #gridToCRS} has been specified by a complete matrix ({@link Tags#ModelTransformation}),
+     * or {@code false} if it has been specified by the scale factors only ({@link Tags#ModelPixelScaleTag}).
+     */
+    private boolean completeMatrixSpecified;
+
+    /**
      * Creates a new image file directory.
      *
      * @param reader  information about the input stream to read, the metadata and the character encoding.
@@ -332,6 +382,13 @@ final class ImageFileDirectory {
     /**
      * Shortcut for a frequently requested information.
      */
+    private String filename() {
+        return input().filename;
+    }
+
+    /**
+     * Shortcut for a frequently requested information.
+     */
     private Charset encoding() {
         return reader.owner.encoding;
     }
@@ -486,6 +543,21 @@ final class ImageFileDirectory {
                 break;
             }
             /*
+             * How to interpret each data sample in a pixel. The size of data samples is still
+             * specified by the BitsPerSample field.
+             */
+            case Tags.SampleFormat: {
+                final int value = type.readInt(input(), count);
+                switch (value) {
+                    default: return value;                          // Warning to be reported by the caller.
+                    case 1: sampleFormat = UNSIGNED; break;         // Unsigned integer data (default).
+                    case 2: sampleFormat = SIGNED;   break;         // Two’s complement signed integer data.
+                    case 3: sampleFormat = FLOAT;    break;         // IEEE floating point data.
+                    case 4: warning(Level.WARNING, Resources.Keys.UndefinedDataFormat_1, filename()); break;
+                }
+                break;
+            }
+            /*
              * Number of bits per component. The array length should be the number of components in a
              * pixel (e.g. 3 for RGB values). Typically, all components have the same number of bits.
              * But the TIFF specification allows different values.
@@ -502,7 +574,7 @@ final class ImageFileDirectory {
                 for (int i = 1; i < length; i++) {
                     if (values.shortValue(i) != bitsPerSample) {
                         throw new DataStoreContentException(reader.resources().getString(
-                                Resources.Keys.ConstantValueRequired_3, "BitsPerSample", input().filename, values));
+                                Resources.Keys.ConstantValueRequired_3, "BitsPerSample", filename(), values));
                     }
                 }
                 break;
@@ -559,11 +631,12 @@ final class ImageFileDirectory {
                 break;
             }
             /*
-             * The minimum component value used. Default is 0.
+             * The minimum component value used. MinSampleValue is a single value that apply to all bands
+             * while SMinSampleValue lists separated values for each band. Default is 0.
              */
-            case Tags.MinSampleValue: {
-                final double v = type.readDouble(input(), count);
-                if (Double.isNaN(minValue) || v < minValue) minValue = v;
+            case Tags.MinSampleValue:
+            case Tags.SMinSampleValue: {
+                minValues = extremum(minValues, type.readVector(input(), count), false);
                 break;
             }
             /*
@@ -571,9 +644,9 @@ final class ImageFileDirectory {
              * This field is for statistical purposes and should not to be used to affect the
              * visual appearance of an image, unless a map styling is applied.
              */
-            case Tags.MaxSampleValue: {
-                final double v = type.readDouble(input(), count);
-                if (Double.isNaN(maxValue) || v > maxValue) maxValue = v;
+            case Tags.MaxSampleValue:
+            case Tags.SMaxSampleValue: {
+                maxValues = extremum(maxValues, type.readVector(input(), count), true);
                 break;
             }
 
@@ -651,6 +724,58 @@ final class ImageFileDirectory {
                 // TODO
                 break;
             }
+            /*
+             * The "grid to CRS" conversion as a 4×4 matrix in row-major fashion. The third matrix row and
+             * the third matrix column may contain only zero values; this block does not reduce the number
+             * of dimensions from 3 to 2.
+             */
+            case Tags.ModelTransformation: {
+                final Vector m = type.readVector(input(), count);
+                final int size = m.size();
+                final int n;
+                switch (size) {
+                    case  6:                    // Assume 2D model with implicit [0 0 1] last row.
+                    case  9: n = 3; break;      // Assume 2D model with full 3×3 matrix.
+                    case 12:                    // Assume 3D model with implicit [0 0 0 1] last row.
+                    case 16: n = 4; break;      // 3D model with full 4×4 matrix, as required by GeoTIFF spec.
+                    default: return m;
+                }
+                completeMatrixSpecified = true;
+                gridToCRS = Matrices.createZero(n, n);
+                gridToCRS.setElement(n-1, n-1, 1);
+                for (int i=0; i<size; i++) {
+                    gridToCRS.setElement(i / n, i % n, m.doubleValue(i));
+                }
+                break;
+            }
+            /*
+             * The "grid to CRS" conversion with only the scale factor specified. This block sets the
+             * translation column to NaN, meaning that it will need to be computed from the tie point.
+             */
+            case Tags.ModelPixelScaleTag: {
+                final Vector m = type.readVector(input(), count);
+                final int size = m.size();
+                if (size < 2 || size > 3) {     // Length should be exactly 3, but we make this reader tolerant.
+                    return m;
+                }
+                completeMatrixSpecified = false;
+                gridToCRS = Matrices.createZero(size+1, size+1);
+                gridToCRS.setElement(size, size, 1);
+                for (int i=0; i<size; i++) {
+                    double e = m.doubleValue(i);
+                    if (i == 1) e = -e;                             // Make y scale factor negative.
+                    gridToCRS.setElement(i, i, e);
+                    gridToCRS.setElement(i, size, Double.NaN);
+                }
+                break;
+            }
+            /*
+             * The mapping from pixel coordinates to CRS coordinates as a sequence of (I,J,K, X,Y,Z) records.
+             */
+            case Tags.ModelTiePoints: {
+                modelTiePoints = type.readVector(input(), count);
+                break;
+            }
 
             ////////////////////////////////////////////////////////////////////////////////////////////////
             ////                                                                                        ////
@@ -831,12 +956,39 @@ final class ImageFileDirectory {
     private void setTileTagFamily(final byte family) throws DataStoreContentException {
         if (tileTagFamily != family && tileTagFamily != 0) {
             throw new DataStoreContentException(reader.resources().getString(
-                    Resources.Keys.InconsistentTileStrip_1, input().filename));
+                    Resources.Keys.InconsistentTileStrip_1, filename()));
         }
         tileTagFamily = family;
     }
 
     /**
+     * Computes the minimal or maximal values of the given vector. Those vectors do not need to have the same length.
+     * One of those two vector will be modified in-place.
+     *
+     * @param  a    the first vector, or {@code null} if none.
+     * @param  b    the new vector to combine with the existing one. Can not be null.
+     * @param  max  {@code true} for computing the maximal values, or {@code false} for the minimal value.
+     */
+    private static Vector extremum(Vector a, Vector b, final boolean max) {
+        if (a != null) {
+            int s = b.size();
+            int i = a.size();
+            if (i > s) {                            // If a vector is longer than b, swap a and b.
+                i = s;
+                final Vector t = a; a = b; b = t;
+            }
+            while (--i >= 0) {                      // At this point, 'b' shall be the longest vector.
+                final double va = a.doubleValue(i);
+                final double vb = b.doubleValue(i);
+                if (Double.isNaN(vb) || (max ? va > vb : va < vb)) {
+                    b.set(i, va);
+                }
+            }
+        }
+        return b;
+    }
+
+    /**
      * Multiplies the given value by the number of bytes in one pixel,
      * or return -1 if the result is not an integer.
      *
@@ -904,7 +1056,7 @@ final class ImageFileDirectory {
             }
             default: {
                 throw new DataStoreContentException(reader.resources().getString(
-                        Resources.Keys.InconsistentTileStrip_1, input().filename));
+                        Resources.Keys.InconsistentTileStrip_1, filename()));
             }
         }
         if (tileOffsets == null) {
@@ -921,8 +1073,25 @@ final class ImageFileDirectory {
         if (colorMap != null) {
             ensureSameLength(Tags.ColorMap, Tags.BitsPerSample, colorMap.size(),  3 * (1 << bitsPerSample));
         }
-        if (Double.isNaN(minValue)) minValue = 0;
-        if (Double.isNaN(maxValue)) maxValue = (1 << bitsPerSample) - 1;
+        if (sampleFormat != FLOAT) {
+            long minValue, maxValue;
+            if (sampleFormat == UNSIGNED) {
+                minValue =  0L;
+                maxValue = -1L;                 // All bits set to 1.
+            } else {
+                minValue = Long.MIN_VALUE;
+                maxValue = Long.MAX_VALUE;
+            }
+            final int shift = Long.SIZE - bitsPerSample;
+            if (shift >= 0 && shift < Long.SIZE) {
+                minValue >>>= shift;
+                maxValue >>>= shift;
+                if (minValue < maxValue) {      // Exclude the unsigned long case since we can not represent it.
+                    minValues = extremum(minValues, Vector.createSequence(minValue, 0, samplesPerPixel), false);
+                    maxValues = extremum(maxValues, Vector.createSequence(maxValue, 0, samplesPerPixel), true);
+                }
+            }
+        }
         /*
          * All of tile width, height and length information should be provided. But if only one of them is missing,
          * we can compute it provided that the file does not use any compression method. If there is a compression,
@@ -967,9 +1136,9 @@ final class ImageFileDirectory {
             }
         }
         /*
-         * Log a warning if the tile offset and tile byte count vectors do not have the same length. Then
-         * ensure that the number of tiles is equal to the expected number.  The formula below is the one
-         * documented in the TIFF specification and reproduced in tileWidth & tileHeight fields javadoc.
+         * Report an error if the tile offset and tile byte count vectors do not have the same length.
+         * Then ensure that the number of tiles is equal to the expected number. The formula below is the
+         * one documented in the TIFF specification and reproduced in tileWidth & tileHeight fields javadoc.
          */
         ensureSameLength(offsetsTag, byteCountsTag, tileOffsets.size(), tileByteCounts.size());
         long expectedCount = JDK8.multiplyExact(
@@ -981,7 +1150,16 @@ final class ImageFileDirectory {
         final int actualCount = Math.min(tileOffsets.size(), tileByteCounts.size());
         if (actualCount != expectedCount) {
             throw new DataStoreContentException(reader.resources().getString(Resources.Keys.UnexpectedTileCount_3,
-                    input().filename, expectedCount, actualCount));
+                    filename(), expectedCount, actualCount));
+        }
+        /*
+         * If a "grid to CRS" conversion has been specified with only the scale factor, we need to compute
+         * the translation terms now.
+         */
+        if (gridToCRS != null && !completeMatrixSpecified) {
+            if (!GridGeometry.setTranslationTerms(gridToCRS, modelTiePoints)) {
+                throw missingTag(Tags.ModelTiePoints);
+            }
         }
     }
 
@@ -1002,10 +1180,13 @@ final class ImageFileDirectory {
         if (compression != null) {
             metadata.addCompression(compression.name().toLowerCase(locale));
         }
-        // TODO: set band name and repeat for each band.
-        metadata.setBitPerSample(bitsPerSample);
-        metadata.addMinimumSampleValue(minValue);
-        metadata.addMaximumSampleValue(maxValue);
+        for (int band = 0; band < samplesPerPixel;) {
+            metadata.newSampleDimension();
+            metadata.setBitPerSample(bitsPerSample);
+            if (minValues != null) metadata.addMinimumSampleValue(minValues.doubleValue(Math.min(band, minValues.size()-1)));
+            if (maxValues != null) metadata.addMaximumSampleValue(maxValues.doubleValue(Math.min(band, maxValues.size()-1)));
+            metadata.setBandIdentifier(++band);
+        }
         /*
          * Add the resolution into the metadata. Our current ISO 19115 implementation restricts
          * the resolution unit to metres, but it may be relaxed in a future SIS version.
@@ -1043,10 +1224,16 @@ final class ImageFileDirectory {
          * in which case the CRS builder returns null. This is safe since all MetadataBuilder methods
          * ignore null values (a design choice because this pattern come very often).
          */
+        final boolean isGeorectified = (modelTiePoints == null) || (gridToCRS != null);
+        metadata.newGridRepresentation(isGeorectified ? MetadataBuilder.GridType.GEORECTIFIED
+                                                      : MetadataBuilder.GridType.GEOREFERENCEABLE);
+        metadata.setGeoreferencingAvailability(gridToCRS != null, false, false);
+        CoordinateReferenceSystem crs = null;
         if (geoKeyDirectory != null) {
             final CRSBuilder helper = new CRSBuilder(reader);
             try {
-                metadata.addReferenceSystem(helper.build(geoKeyDirectory, numericGeoParameters, asciiGeoParameters));
+                crs = helper.build(geoKeyDirectory, numericGeoParameters, asciiGeoParameters);
+                metadata.addReferenceSystem(crs);
                 helper.complete(metadata);
             } catch (NoSuchIdentifierException | ParameterNotFoundException e) {
                 short key = Resources.Keys.UnsupportedProjectionMethod_1;
@@ -1059,10 +1246,18 @@ final class ImageFileDirectory {
                     reader.owner.warning(null, e);
                 }
             }
-            geoKeyDirectory      = null;            // Not needed anymore, so let GC do its work.
-            numericGeoParameters = null;
-            asciiGeoParameters   = null;
         }
+        try {
+            if (!isGeorectified) {
+                metadata.addGeolocation(new GridGeometry(filename(), crs, modelTiePoints));
+            }
+        } catch (TransformException e) {
+            reader.owner.warning(null, e);
+        }
+        geoKeyDirectory      = null;            // Not needed anymore, so let GC do its work.
+        numericGeoParameters = null;
+        asciiGeoParameters   = null;
+        modelTiePoints       = null;
     }
 
     /**
@@ -1106,6 +1301,6 @@ final class ImageFileDirectory {
      */
     private DataStoreContentException missingTag(final short missing) {
         return new DataStoreContentException(reader.resources().getString(
-                Resources.Keys.MissingValue_2, input().filename, Tags.name(missing)));
+                Resources.Keys.MissingValue_2, filename(), Tags.name(missing)));
     }
 }

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Tags.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Tags.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Tags.java [UTF-8] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Tags.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -161,6 +161,35 @@ final class Tags {
     public static final short GeoAsciiParams = (short) 0x87B1;            // 34737
 
     /**
+     * The tie points as (I,J,K,X,Y,Z) records in an array of floating-point numbers.
+     * This tag is also known as {@code Georeference}.
+     */
+    public static final short ModelTiePoints = (short) 0x8482;            // 33922
+
+    /**
+     * A vector of 3 floating-point values defining the "grid to CRS" conversion without rotation.
+     * The conversion is defined as below, when (I,J,K,X,Y,Z) is the tie point singleton record:
+     *
+     * ┌                       ┐
+     * │   Sx   0    0    Tx   │       Tx = X - I/Sx
+     * │   0   -Sy   0    Ty   │       Ty = Y + J/Sy
+     * │   0    0    Sz   Tz   │       Tz = Z - K/Sz  (if not 0)
+     * │   0    0    0    1    │
+     * └                       ┘
+     *
+     * Only one of {@code ModelPixelScaleTag} and {@link #ModelTransformation} should be used.
+     */
+    public static final short ModelPixelScaleTag = (short) 0x830E;        // 33550
+
+    /**
+     * Specifies the "grid to CRS" conversion (the transformation matrix between the raster space and the model space).
+     * If specified, the tag shall have the 16 values of a 4×4 matrix in row-major fashion. The last matrix row (i.e.
+     * the last 4 values) should be [0 0 0 1]. The row before should be [0 0 0 0] if the conversion is two-dimensional.
+     * Only one of {@link #ModelPixelScaleTag} and {@code ModelTransformation} should be used.
+     */
+    public static final short ModelTransformation = (short) 0x85D8;       // 34264
+
+    /**
      * Do not allow instantiation of this class.
      */
     private Tags() {

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/package-info.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/package-info.java [UTF-8] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/package-info.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -23,7 +23,7 @@
  *   <li><a href="http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf">TIFF specification</a>: baseline</li>
  *   <li><a href="http://partners.adobe.com/public/developer/en/tiff/TIFFphotoshop.pdf">TIFF Tecnical Notes</a>: add new compressions</li>
  *   <li><a href="http://www.awaresystems.be/imaging/tiff/tifftags.html">TIFF Tag Reference</a></li>
- *   <li><a href="http://www.remotesensing.org/geotiff/spec/contents.html">GeoTIFF specification</a></li>
+ *   <li><a href="http://download.osgeo.org/geotiff/spec/geotiff.rtf">GeoTIFF specification</a></li>
  * </ul>
  *
  * @author  Rémi Maréchal (Geomatys)

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -18,6 +18,7 @@ package org.apache.sis.internal.netcdf;
 
 import java.util.Date;
 import java.util.Objects;
+import java.util.Collection;
 import java.io.Closeable;
 import java.io.IOException;
 import javax.measure.Unit;
@@ -86,6 +87,13 @@ public abstract class Decoder implements
     public abstract String[] getSearchPath();
 
     /**
+     * Returns the names of all global attributes found in the file.
+     *
+     * @return names of all global attributes in the file.
+     */
+    public abstract Collection<String> getAttributeNames();
+
+    /**
      * Returns the value for the attribute of the given name, or {@code null} if none.
      * This method searches in the groups specified by the last call to {@link #setSearchPath(String[])}.
      * Null values and empty strings are ignored.

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/DiscreteSampling.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/DiscreteSampling.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/DiscreteSampling.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/DiscreteSampling.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -16,6 +16,10 @@
  */
 package org.apache.sis.internal.netcdf;
 
+// Branch-dependent imports
+import org.apache.sis.internal.jdk8.Stream;
+import org.apache.sis.feature.AbstractFeature;
+
 
 /**
  * Returns the features encoded in the NetCDF files when they are encoded as discrete sampling.
@@ -34,4 +38,11 @@ public abstract class DiscreteSampling {
      */
     protected DiscreteSampling() {
     }
+
+    /**
+     * Returns the stream of features.
+     *
+     * @return the stream of features.
+     */
+    public abstract Stream<AbstractFeature> features();
 }

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.netcdf;
 
+import java.util.Collection;
 import java.io.IOException;
 import java.awt.image.DataBuffer;
 import org.apache.sis.math.Vector;
@@ -154,6 +155,13 @@ public abstract class Variable extends N
     public abstract int[] getGridEnvelope();
 
     /**
+     * Returns the names of all attributes associated to this variable.
+     *
+     * @return names of all attributes associated to this variable.
+     */
+    public abstract Collection<String> getAttributeNames();
+
+    /**
      * Returns the sequence of values for the given attribute, or an empty array if none.
      * The elements will be of class {@link String} if {@code numeric} is {@code false},
      * or {@link Number} if {@code numeric} is {@code true}.

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/ChannelDecoder.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -18,6 +18,8 @@ package org.apache.sis.internal.netcdf.i
 
 import java.util.Set;
 import java.util.Map;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.AbstractMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedHashMap;
@@ -650,6 +652,8 @@ public final class ChannelDecoder extend
      *
      * @param  name  the name of the attribute to search, or {@code null}.
      * @return the attribute value, or {@code null} if none.
+     *
+     * @see #getAttributeNames()
      */
     private Object findAttribute(final String name) {
         Object value = attributeMap.get(name);
@@ -664,6 +668,16 @@ public final class ChannelDecoder extend
     }
 
     /**
+     * Returns the names of all global attributes found in the file.
+     *
+     * @return names of all global attributes in the file.
+     */
+    @Override
+    public Collection<String> getAttributeNames() {
+        return Collections.unmodifiableSet(attributeMap.keySet());
+    }
+
+    /**
      * Returns the value for the attribute of the given name, or {@code null} if none.
      *
      * @param  name  the name of the attribute to search, or {@code null}.

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/FeaturesInfo.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/FeaturesInfo.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/FeaturesInfo.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/FeaturesInfo.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -16,16 +16,34 @@
  */
 package org.apache.sis.internal.netcdf.impl;
 
-import java.util.ArrayList;
+import java.util.Map;
 import java.util.List;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.io.IOException;
 import org.apache.sis.math.Vector;
 import org.apache.sis.internal.netcdf.DataType;
 import org.apache.sis.internal.netcdf.DiscreteSampling;
 import org.apache.sis.internal.netcdf.Resources;
+import org.apache.sis.internal.feature.Geometries;
+import org.apache.sis.internal.feature.MovingFeature;
 import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.util.collection.BackingStoreException;
 import ucar.nc2.constants.CF;
 
+// Branch-dependent imports
+import org.apache.sis.internal.jdk8.Spliterator;
+import org.apache.sis.internal.jdk8.Stream;
+import org.apache.sis.internal.jdk8.StreamSupport;
+import org.apache.sis.internal.jdk8.Consumer;
+import org.apache.sis.internal.jdk8.JDK8;
+import org.apache.sis.feature.AbstractFeature;
+import org.apache.sis.feature.DefaultFeatureType;
+import org.apache.sis.feature.DefaultAttributeType;
+import org.apache.sis.feature.AbstractIdentifiedType;
+
 
 /**
  * Implementations of the discrete sampling features decoder. This implementation shall be able to decode at least the
@@ -44,18 +62,85 @@ final class FeaturesInfo extends Discret
 
     /**
      * The moving feature identifiers ("mfIdRef").
+     * The amount of identifiers shall be the same than the length of the {@link #counts} vector.
      */
     private final VariableInfo identifiers;
 
     /**
+     * The variable that contains time.
+     */
+    private final VariableInfo time;
+
+    /**
+     * The variable that contains <var>x</var> and <var>y</var> ordinate values (typically longitudes and latitudes).
+     * All variables in this array shall have the same length, and that length shall be the same than {@link #time}.
+     */
+    private final VariableInfo[] coordinates;
+
+    /**
+     * Any custom properties.
+     */
+    private final VariableInfo[] properties;
+
+    /**
+     * The type of all features to be read by this {@code FeaturesInfo}.
+     */
+    private final DefaultFeatureType type;
+
+    private final Geometries<?> factory = Geometries.implementation(null);          // TODO: shall be given by the store.
+
+    /**
      * Creates a new discrete sampling parser for features identified by the given variable.
      *
      * @param  counts       the count of instances per feature.
      * @param  identifiers  the feature identifiers.
      */
-    private FeaturesInfo(final Vector counts, final VariableInfo identifiers) {
+    @SuppressWarnings("rawtypes")                               // Because of generic array creation.
+    private FeaturesInfo(final Vector counts, final VariableInfo identifiers, final VariableInfo time,
+            final Collection<VariableInfo> coordinates, final Collection<VariableInfo> properties)
+    {
         this.counts      = counts;
         this.identifiers = identifiers;
+        this.coordinates = coordinates.toArray(new VariableInfo[coordinates.size()]);
+        this.properties  = properties .toArray(new VariableInfo[properties .size()]);
+        this.time        = time;
+        /*
+         * Creates a description of the features to be read.
+         */
+        final Map<String,Object> info = new HashMap<>(4);
+        final AbstractIdentifiedType[] pt = new AbstractIdentifiedType[this.properties.length + 2];
+        DefaultAttributeType[] characteristics = null;
+        for (int i=0; i<pt.length; i++) {
+            final VariableInfo variable;
+            final Class<?> valueClass;
+            int minOccurs = 1;
+            int maxOccurs = 1;
+            switch (i) {
+                case 0: {
+                    variable        = identifiers;
+                    valueClass      = Integer.class;
+                    break;
+                }
+                case 1: {
+                    variable        = null;
+                    valueClass      = factory.polylineClass;
+                    characteristics = new DefaultAttributeType[] {MovingFeature.TIME};
+                    break;
+                }
+                default: {
+                    variable        = this.properties[i-2];
+                    valueClass      = Number.class;           // TODO: use more accurate value class.
+                    minOccurs       = 0;
+                    maxOccurs       = Integer.MAX_VALUE;
+                    break;
+                }
+            }
+            info.put(DefaultAttributeType.NAME_KEY, (variable != null) ? variable.getName() : "trajectory");
+            // TODO: add description.
+            pt[i] = new DefaultAttributeType<>(info, valueClass, minOccurs, maxOccurs, null, characteristics);
+        }
+        info.put(DefaultAttributeType.NAME_KEY, "Feature");     // TODO: find a better name.
+        type = new DefaultFeatureType(info, false, null, pt);
     }
 
     /**
@@ -148,12 +233,159 @@ search: for (final VariableInfo counts :
                         }
                     }
                     /*
-                     * At this point, all information have been verified as valid.
+                     * At this point, all information have been verified as valid. Now search all variables having
+                     * the expected sample dimension. Those variable contains the actual data. For example if the
+                     * sample dimension name is "points", then we may have:
+                     *
+                     *     double longitude(points);
+                     *         longitude:axis = "X";
+                     *         longitude:standard_name = "longitude";
+                     *         longitude:units = "degrees_east";
+                     *     double latitude(points);
+                     *         latitude:axis = "Y";
+                     *         latitude:standard_name = "latitude";
+                     *         latitude:units = "degrees_north";
+                     *     double time(points);
+                     *         time:axis = "T";
+                     *         time:standard_name = "time";
+                     *         time:units = "minutes since 2014-11-29 00:00:00";
+                     *     short myCustomProperty(points);
                      */
-                    features.add(new FeaturesInfo(counts.read().compress(0), identifiers));
+                    final Map<String,VariableInfo> coordinates = new LinkedHashMap<>();
+                    final List<VariableInfo> properties  = new ArrayList<>();
+                    for (final VariableInfo data : decoder.variables) {
+                        if (data.dimensions.length == 1 && data.dimensions[0] == sampleDimension) {
+                            final Object axisType = data.getAttributeValue(CF.AXIS);
+                            if (axisType == null) {
+                                properties.add(data);
+                            } else if (coordinates.put(axisType.toString(), data) != null) {
+                                continue search;    // Two axes of the same type: abort.
+                            }
+                        }
+                    }
+                    final VariableInfo time = coordinates.remove("T");
+                    if (time != null) {
+                        features.add(new FeaturesInfo(counts.read().compress(0), identifiers, time, coordinates.values(), properties));
+                    }
                 }
             }
         }
         return features.toArray(new FeaturesInfo[features.size()]);
     }
+
+    /**
+     * Returns the stream of features.
+     */
+    @Override
+    public Stream<AbstractFeature> features() {
+        return StreamSupport.stream(new Iter(), false);
+    }
+
+    /**
+     * Implementation of the iterator returned by {@link #features()}.
+     */
+    private final class Iter implements Spliterator<AbstractFeature> {
+        /**
+         * Index of the next feature to read.
+         */
+        private int index;
+
+        /**
+         * Position in the data vectors of the next feature to read.
+         * This is the sum of the length of data in all previous features.
+         */
+        private int position;
+
+        /**
+         * Creates a new iterator.
+         */
+        Iter() {
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super AbstractFeature> action) {
+            while (tryAdvance(action));
+        }
+
+        /**
+         * Executes the given action only on the next feature, if any.
+         *
+         * @todo current reading process implies lot of seeks, which is inefficient.
+         */
+        @Override
+        public boolean tryAdvance(final Consumer<? super AbstractFeature> action) {
+            final int   length = counts.intValue(index);
+            final int[] lower  = {position};
+            final int[] upper  = {position + length};
+            final int[] step   = {1};
+            final Vector   id, t;
+            final Vector[] coords = new Vector[coordinates.length];
+            final Vector[] props  = new Vector[properties.length];
+            try {
+                id = identifiers.read();                    // Efficiency should be okay because of cached value.
+                t = time.read(lower, upper, step);
+                for (int i=0; i<coordinates.length; i++) {
+                    coords[i] = coordinates[i].read(lower, upper, step);
+                }
+                for (int i=0; i<properties.length; i++) {
+                    props[i] = properties[i].read(lower, upper, step);
+                }
+            } catch (IOException | DataStoreException e) {
+                throw new BackingStoreException(canNotReadFile(), e);
+            }
+            final AbstractFeature feature = type.newInstance();
+            feature.setPropertyValue(identifiers.getName(), id.intValue(index));
+            for (int i=0; i<properties.length; i++) {
+                feature.setPropertyValue(properties[i].getName(), props[i]);
+                // TODO: set time characteristic.
+            }
+            // TODO: temporary hack - to be replaced by support in Vector.
+            final int dimension = coordinates.length;
+            final double[] tmp = new double[length * dimension];
+            for (int i=0; i<tmp.length; i++) {
+                tmp[i] = coords[i % dimension].doubleValue(i / dimension);
+            }
+            feature.setPropertyValue("trajectory", factory.createPolyline(dimension, Vector.create(tmp, false)));
+            action.accept(feature);
+            position = JDK8.addExact(position, length);
+            return ++index < counts.size();
+        }
+
+        /**
+         * Current implementation can not split this iterator.
+         */
+        @Override
+        public Spliterator<AbstractFeature> trySplit() {
+            return null;
+        }
+
+        /**
+         * Returns the number of features.
+         */
+        @Override
+        public long estimateSize() {
+            return counts.size();
+        }
+
+        /**
+         * Returns the characteristics of the iteration over feature instances.
+         * The iteration is assumed {@link #ORDERED} in the declaration order in the NetCDF file.
+         * The iteration is {@link #NONNULL} (i.e. {@link #tryAdvance(Consumer)} is not allowed
+         * to return null value) and {@link #IMMUTABLE} (i.e. we do not support modification of
+         * the NetCDF file while an iteration is in progress).
+         *
+         * @return characteristics of iteration over the features in the NetCDF file.
+         */
+        @Override
+        public int characteristics() {
+            return ORDERED | NONNULL | IMMUTABLE | SIZED;
+        }
+    }
+
+    /**
+     * Returns the error message for a file that can not be read.
+     */
+    final String canNotReadFile() {
+        return null;    // TODO
+    }
 }

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/impl/VariableInfo.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -17,6 +17,8 @@
 package org.apache.sis.internal.netcdf.impl;
 
 import java.util.Map;
+import java.util.Collection;
+import java.util.Collections;
 import java.io.IOException;
 import java.lang.reflect.Array;
 import ucar.nc2.constants.CF;
@@ -271,6 +273,16 @@ final class VariableInfo extends Variabl
     }
 
     /**
+     * Returns the names of all attributes associated to this variable.
+     *
+     * @return names of all attributes associated to this variable.
+     */
+    @Override
+    public Collection<String> getAttributeNames() {
+        return Collections.unmodifiableSet(attributes.keySet());
+    }
+
+    /**
      * Returns the value of the given attribute, or {@code null} if none.
      * This method should be invoked only for hard-coded names that mix lower-case and upper-case letters.
      *

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/DecoderWrapper.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -20,6 +20,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.EnumSet;
 import java.util.Formatter;
+import java.util.Collection;
 import java.io.IOException;
 import ucar.nc2.Group;
 import ucar.nc2.Attribute;
@@ -170,6 +171,16 @@ public final class DecoderWrapper extend
     }
 
     /**
+     * Returns the names of all global attributes found in the file.
+     *
+     * @return names of all global attributes in the file.
+     */
+    @Override
+    public Collection<String> getAttributeNames() {
+        return VariableWrapper.toNames(file.getGlobalAttributes());
+    }
+
+    /**
      * Returns the NetCDF attribute of the given name in the given group, or {@code null} if none.
      * This method is invoked for every global and group attributes to be read by this class (but
      * not {@linkplain ucar.nc2.VariableSimpleIF variable} attributes), thus providing a single point

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/FeaturesWrapper.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/FeaturesWrapper.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/FeaturesWrapper.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/FeaturesWrapper.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -19,6 +19,10 @@ package org.apache.sis.internal.netcdf.u
 import org.apache.sis.internal.netcdf.DiscreteSampling;
 import ucar.nc2.ft.FeatureCollection;
 
+// Branch-dependent imports
+import org.apache.sis.internal.jdk8.Stream;
+import org.apache.sis.feature.AbstractFeature;
+
 
 /**
  * A wrapper around the UCAR {@code ucar.nc2.ft} package.
@@ -41,5 +45,12 @@ final class FeaturesWrapper extends Disc
         this.features = features;
     }
 
-    // TODO
+
+    /**
+     * Returns the stream of features.
+     */
+    @Override
+    public Stream<AbstractFeature> features() {
+        throw new UnsupportedOperationException();      // TODO
+    }
 }

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/ucar/VariableWrapper.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -18,6 +18,7 @@ package org.apache.sis.internal.netcdf.u
 
 import java.util.List;
 import java.io.IOException;
+import java.util.Collection;
 import ucar.ma2.Array;
 import ucar.ma2.Section;
 import ucar.ma2.InvalidRangeException;
@@ -27,6 +28,7 @@ import ucar.nc2.VariableIF;
 import org.apache.sis.math.Vector;
 import org.apache.sis.internal.netcdf.DataType;
 import org.apache.sis.internal.netcdf.Variable;
+import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
 
@@ -130,6 +132,16 @@ final class VariableWrapper extends Vari
     }
 
     /**
+     * Returns the names of all attributes associated to this variable.
+     *
+     * @return names of all attributes associated to this variable.
+     */
+    @Override
+    public Collection<String> getAttributeNames() {
+        return toNames(variable.getAttributes());
+    }
+
+    /**
      * Returns the sequence of values for the given attribute, or an empty array if none.
      * The elements will be of class {@link String} if {@code numeric} is {@code false},
      * or {@link Number} if {@code numeric} is {@code true}.
@@ -164,6 +176,17 @@ final class VariableWrapper extends Vari
     }
 
     /**
+     * Returns the names of all attributes in the given list.
+     */
+    static List<String> toNames(final List<Attribute> attributes) {
+        final String[] names = new String[attributes.size()];
+        for (int i=0; i<names.length; i++) {
+            names[i] = attributes.get(i).getShortName();
+        }
+        return UnmodifiableArrayList.wrap(names);
+    }
+
+    /**
      * Reads all the data for this variable and returns them as an array of a Java primitive type.
      * Multi-dimensional variables are flattened as a one-dimensional array (wrapped in a vector).
      * This method may cache the returned vector, at UCAR library choice.

Modified: sis/trunk/storage/sis-shapefile/pom.xml
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-shapefile/pom.xml?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-shapefile/pom.xml (original)
+++ sis/trunk/storage/sis-shapefile/pom.xml Thu Jul 13 12:45:03 2017
@@ -124,7 +124,7 @@ Read and write files in the Shapefile fo
     <dependency>
       <groupId>com.esri.geometry</groupId>
       <artifactId>esri-geometry-api</artifactId>
-      <scope>compile</scope>
+      <optional>false</optional>
     </dependency>
   </dependencies>
 

Modified: sis/trunk/storage/sis-storage/pom.xml
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/pom.xml?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/pom.xml (original)
+++ sis/trunk/storage/sis-storage/pom.xml Thu Jul 13 12:45:03 2017
@@ -135,6 +135,11 @@ Provides the interfaces and base classes
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.esri.geometry</groupId>
+      <artifactId>esri-geometry-api</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
 </project>

Modified: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java?rev=1801833&r1=1801832&r2=1801833&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java [UTF-8] Thu Jul 13 12:45:03 2017
@@ -34,10 +34,12 @@ import org.opengis.metadata.citation.Rol
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
+import org.opengis.metadata.spatial.GCP;
 import org.opengis.metadata.spatial.Dimension;
 import org.opengis.metadata.spatial.DimensionNameType;
 import org.opengis.metadata.spatial.CellGeometry;
 import org.opengis.metadata.spatial.PixelOrientation;
+import org.opengis.metadata.spatial.GeolocationInformation;
 import org.opengis.metadata.spatial.SpatialRepresentationType;
 import org.opengis.metadata.constraint.Restriction;
 import org.opengis.metadata.content.TransferFunctionType;
@@ -48,6 +50,8 @@ import org.opengis.metadata.identificati
 import org.opengis.metadata.identification.KeywordType;
 import org.opengis.metadata.identification.TopicCategory;
 import org.opengis.metadata.distribution.Format;
+import org.opengis.metadata.quality.Element;
+import org.opengis.geometry.DirectPosition;
 import org.opengis.referencing.crs.VerticalCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.TransformException;
@@ -64,6 +68,8 @@ import org.apache.sis.metadata.iso.spati
 import org.apache.sis.metadata.iso.spatial.DefaultDimension;
 import org.apache.sis.metadata.iso.spatial.DefaultGeorectified;
 import org.apache.sis.metadata.iso.spatial.DefaultGeoreferenceable;
+import org.apache.sis.metadata.iso.spatial.DefaultGCPCollection;
+import org.apache.sis.metadata.iso.spatial.DefaultGCP;
 import org.apache.sis.metadata.iso.content.DefaultAttributeGroup;
 import org.apache.sis.metadata.iso.content.DefaultSampleDimension;
 import org.apache.sis.metadata.iso.content.DefaultCoverageDescription;
@@ -97,6 +103,7 @@ import org.apache.sis.metadata.sql.Metad
 import org.apache.sis.metadata.sql.MetadataSource;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.iso.Names;
 import org.apache.sis.util.iso.Types;
 
 import static java.util.Collections.singleton;
@@ -125,6 +132,11 @@ import org.apache.sis.metadata.iso.citat
  */
 public class MetadataBuilder {
     /**
+     * Band numbers, created when first needed.
+     */
+    private static final MemberName[] BAND_NUMBERS = new MemberName[16];
+
+    /**
      * Whether the next party to create should be an instance of {@link DefaultIndividual} or {@link DefaultOrganisation}.
      *
      * @see #party()
@@ -438,6 +450,23 @@ public class MetadataBuilder {
     }
 
     /**
+     * Collection of ground control points.
+     */
+    private DefaultGCPCollection groundControlPoints;
+
+    /**
+     * Creates the collection of ground control points if it does not already exists, then returns it.
+     *
+     * @return the ground control points (never {@code null}).
+     */
+    private DefaultGCPCollection groundControlPoints() {
+        if (groundControlPoints == null) {
+            groundControlPoints = new DefaultGCPCollection();
+        }
+        return groundControlPoints;
+    }
+
+    /**
      * Information about the distributor of and options for obtaining the resource.
      */
     private DefaultDistribution distribution;
@@ -752,6 +781,10 @@ public class MetadataBuilder {
             if (n != 0) {
                 gridRepresentation.setNumberOfDimensions(shared(n));
             }
+            if (groundControlPoints != null && gridRepresentation instanceof DefaultGeoreferenceable) {
+                addIfNotPresent(((DefaultGeoreferenceable) gridRepresentation).getGeolocationInformation(), groundControlPoints);
+                groundControlPoints = null;
+            }
             addIfNotPresent(metadata.getSpatialRepresentationInfo(), gridRepresentation);
             gridRepresentation = null;
         }
@@ -1808,7 +1841,98 @@ parse:      for (int i = 0; i < length;)
      */
     public final void setPointInPixel(final PixelOrientation value) {
         if (value != null) {
-            ((DefaultGeorectified) gridRepresentation()).setPointInPixel(value);
+            final DefaultGridSpatialRepresentation gridRepresentation = gridRepresentation();
+            if (gridRepresentation instanceof DefaultGeorectified) {
+                ((DefaultGeorectified) gridRepresentation).setPointInPixel(value);
+            }
+        }
+    }
+
+    /**
+     * Sets whether parameters for transformation, control/check point(s) or orientation parameters are available.
+     * Storage location are:
+     *
+     * <ul>
+     *   <li>If georeferenceable:<ul>
+     *     <li>{@code metadata/spatialRepresentationInfo/transformationParameterAvailability}</li>
+     *     <li>{@code metadata/spatialRepresentationInfo/controlPointAvailability}</li>
+     *     <li>{@code metadata/spatialRepresentationInfo/orientationParameterAvailability}</li>
+     *   </ul></li>
+     *   <li>If georeferenced:<ul>
+     *     <li>{@code metadata/spatialRepresentationInfo/transformationParameterAvailability}</li>
+     *     <li>{@code metadata/spatialRepresentationInfo/checkPointAvailability}</li>
+     *   </ul></li>
+     * </ul>
+     *
+     * @param  transformationParameterAvailability  indication of whether or not parameters for transformation exists.
+     * @param  controlPointAvailability             indication of whether or not control or check point(s) exists.
+     * @param  orientationParameterAvailability     indication of whether or not orientation parameters are available.
+     */
+    public final void setGeoreferencingAvailability(final boolean transformationParameterAvailability,
+                                                    final boolean controlPointAvailability,
+                                                    final boolean orientationParameterAvailability)
+    {
+        final DefaultGridSpatialRepresentation gridRepresentation = gridRepresentation();
+        gridRepresentation.setTransformationParameterAvailable(transformationParameterAvailability);
+        if (gridRepresentation instanceof DefaultGeorectified) {
+            ((DefaultGeorectified) gridRepresentation).setCheckPointAvailable(controlPointAvailability);
+        } else if (gridRepresentation instanceof DefaultGeoreferenceable) {
+            ((DefaultGeoreferenceable) gridRepresentation).setControlPointAvailable(controlPointAvailability);
+            ((DefaultGeoreferenceable) gridRepresentation).setOrientationParameterAvailable(orientationParameterAvailability);
+        }
+    }
+
+    /**
+     * Adds information about the geolocation of an image.
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/spatialRepresentationInfo/geolocationInformation}</li>
+     * </ul>
+     *
+     * @param  info  the geolocation information to add, or {@code null} if none.
+     */
+    public final void addGeolocation(final GeolocationInformation info) {
+        if (info != null) {
+            final DefaultGridSpatialRepresentation gridRepresentation = gridRepresentation();
+            if (gridRepresentation instanceof DefaultGeoreferenceable) {
+                addIfNotPresent(((DefaultGeoreferenceable) gridRepresentation).getGeolocationInformation(), info);
+            }
+        }
+    }
+
+    /**
+     * Adds <cite>check points</cite> (if georectified) or <cite>ground control points</cite> (if georeferenceable).
+     * Ground control points (GCP) are large marked targets on the ground. GCP should not be used for storing the
+     * localization grid (e.g. "model tie points" in a GeoTIFF file).
+     * Storage location is:
+     *
+     * <ul>
+     *   <li>{@code metadata/spatialRepresentationInfo/checkPoint/geographicCoordinates} if georectified</li>
+     *   <li>{@code metadata/spatialRepresentationInfo/geolocationInformation/gcp/geographicCoordinates} if georeferenceable</li>
+     * </ul>
+     *
+     * @param  geographicCoordinates  the geographic or map position of the control point, in either two or three dimensions.
+     * @param  accuracyReport         the accuracy of a ground control point, or {@code null} if none.
+     *                                Ignored if {@code geographicCoordinates} is null.
+     */
+    public final void addControlPoints(final DirectPosition geographicCoordinates, final Element accuracyReport) {
+        if (geographicCoordinates != null) {
+            final DefaultGridSpatialRepresentation gridRepresentation = gridRepresentation();
+            final Collection<GCP> points;
+            if (gridRepresentation instanceof DefaultGeorectified) {
+                points = ((DefaultGeorectified) gridRepresentation).getCheckPoints();
+            } else if (gridRepresentation instanceof DefaultGeoreferenceable) {
+                points = groundControlPoints().getGCPs();
+            } else {
+                return;
+            }
+            final DefaultGCP gcp = new DefaultGCP();
+            gcp.setGeographicCoordinates(geographicCoordinates);
+            if (accuracyReport != null) {
+                addIfNotPresent(gcp.getAccuracyReports(), accuracyReport);
+            }
+            addIfNotPresent(points, gcp);
         }
     }
 
@@ -1825,7 +1949,10 @@ parse:      for (int i = 0; i < length;)
     public final void setGridToCRS(final CharSequence value) {
         final InternationalString i18n = trim(value);
         if (i18n != null) {
-            ((DefaultGeorectified) gridRepresentation()).setTransformationDimensionDescription(i18n);
+            final DefaultGridSpatialRepresentation gridRepresentation = gridRepresentation();
+            if (gridRepresentation instanceof DefaultGeorectified) {
+                ((DefaultGeorectified) gridRepresentation).setTransformationDimensionDescription(i18n);
+            }
         }
     }
 
@@ -1908,6 +2035,34 @@ parse:      for (int i = 0; i < length;)
         }
     }
 
+    /**
+     * Sets the number that uniquely identifies instances of bands of wavelengths on which a sensor operates.
+     * This is a convenience method for {@link #setBandIdentifier(MemberName)} when the band is specified only
+     * by a number.
+     *
+     * @param  sequenceIdentifier  the band number, or 0 or negative if none.
+     */
+    public final void setBandIdentifier(final int sequenceIdentifier) {
+        if (sequenceIdentifier > 0) {
+            final boolean cached = (sequenceIdentifier <= BAND_NUMBERS.length);
+            MemberName name = null;
+            if (cached) synchronized (BAND_NUMBERS) {
+                name = BAND_NUMBERS[sequenceIdentifier - 1];
+            }
+            if (name == null) {
+                name = Names.createMemberName(null, null, String.valueOf(sequenceIdentifier), Integer.class);
+                if (cached) synchronized (BAND_NUMBERS) {
+                    /*
+                     * No need to check if a value has been set concurrently because Names.createMemberName(…)
+                     * already checked if an equal instance exists in the current JVM.
+                     */
+                    BAND_NUMBERS[sequenceIdentifier - 1] = name;
+                }
+            }
+            setBandIdentifier(name);
+        }
+    }
+
     /**
      * Adds an identifier for the current band.
      * These identifiers can be use to provide names for the attribute from a standard set of names.



Mime
View raw message