sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1799964 - in /sis/branches/JDK8: ./ core/sis-feature/ storage/sis-shapefile/ storage/sis-storage/ storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/ storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/
Date Mon, 26 Jun 2017 17:45:23 GMT
Author: desruisseaux
Date: Mon Jun 26 17:45:23 2017
New Revision: 1799964

URL: http://svn.apache.org/viewvc?rev=1799964&view=rev
Log:
When parsing a Moving Feature CSV file, build trajectories as geometric objects (Polyline)
instead than a double[] array.

Modified:
    sis/branches/JDK8/core/sis-feature/pom.xml
    sis/branches/JDK8/pom.xml
    sis/branches/JDK8/storage/sis-shapefile/pom.xml
    sis/branches/JDK8/storage/sis-storage/pom.xml
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/GeometryParser.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java
    sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java

Modified: sis/branches/JDK8/core/sis-feature/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/pom.xml?rev=1799964&r1=1799963&r2=1799964&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/pom.xml (original)
+++ sis/branches/JDK8/core/sis-feature/pom.xml Mon Jun 26 17:45:23 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/branches/JDK8/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/pom.xml?rev=1799964&r1=1799963&r2=1799964&view=diff
==============================================================================
--- sis/branches/JDK8/pom.xml (original)
+++ sis/branches/JDK8/pom.xml Mon Jun 26 17:45:23 2017
@@ -409,6 +409,7 @@ Apache SIS is a free software, Java lang
         <groupId>com.esri.geometry</groupId>
         <artifactId>esri-geometry-api</artifactId>
         <version>1.2.1</version>
+        <optional>true</optional>
       </dependency>
       <dependency>
         <groupId>gov.nist.math</groupId>

Modified: sis/branches/JDK8/storage/sis-shapefile/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-shapefile/pom.xml?rev=1799964&r1=1799963&r2=1799964&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-shapefile/pom.xml (original)
+++ sis/branches/JDK8/storage/sis-shapefile/pom.xml Mon Jun 26 17:45:23 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/branches/JDK8/storage/sis-storage/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/pom.xml?rev=1799964&r1=1799963&r2=1799964&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/pom.xml (original)
+++ sis/branches/JDK8/storage/sis-storage/pom.xml Mon Jun 26 17:45:23 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/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/GeometryParser.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/GeometryParser.java?rev=1799964&r1=1799963&r2=1799964&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/GeometryParser.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/GeometryParser.java
[UTF-8] Mon Jun 26 17:45:23 2017
@@ -17,28 +17,55 @@
 package org.apache.sis.internal.storage.csv;
 
 import org.apache.sis.internal.converter.SurjectiveConverter;
+import org.apache.sis.internal.feature.Geometries;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.math.Vector;
 
 
 /**
- * The converter to use for converting a text into a geometry. In current implementation,
- * geometries are line strings represented by an array of ordinate values.
+ * The converter to use for converting a text into a geometry.
+ * The geometry class depends on the library available at runtime.
+ *
+ * @param  <G>  the geometry class. There is actually no easy way this class can ensure
that we comply
+ *              with this parameterized type. This class shall not be public in part for
that reason.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.8
  * @since   0.8
  * @module
  */
-final class GeometryParser extends SurjectiveConverter<String,double[]> {
+final class GeometryParser<G> extends SurjectiveConverter<String,G> {
+    /**
+     * The unique instance using the default geometry library.
+     */
+    private static final GeometryParser<?> INSTANCE = new GeometryParser<>(Geometries.implementation(null),
(short) 2);
+
     /**
-     * The unique instance.
+     * The factory to use for creating polylines.
      */
-    static final GeometryParser INSTANCE = new GeometryParser();
+    private final Geometries geometries;
+
+    /**
+     * The number of dimensions other than time in the coordinate reference system.
+     * Shall be 2 or 3 according Moving Features CSV encoding specification, but Apache SIS
+     * may be tolerant to other values (depending on the backing geometry library).
+     */
+    private final short spatialDimensionCount;
+
+    /**
+     * Creates a new converter from CSV encoded trajectories to geometries.
+     */
+    private GeometryParser(final Geometries geometries, final short spatialDimensionCount)
{
+        this.geometries = geometries;
+        this.spatialDimensionCount = spatialDimensionCount;
+    }
 
     /**
-     * For the singleton instance.
+     * Returns a parser instance for the given geometry factory.
      */
-    private GeometryParser() {
+    static GeometryParser<?> instance(final Geometries geometries, final short spatialDimensionCount)
{
+        return (spatialDimensionCount == 2 && INSTANCE.geometries == geometries)
+               ? INSTANCE : new GeometryParser<>(geometries, spatialDimensionCount);
     }
 
     /**
@@ -50,18 +77,27 @@ final class GeometryParser extends Surje
     }
 
     /**
-     * Returns the type of converted elements.
+     * Returns the type of converted elements. The returned type shall be the same than
+     * the type selected by {@code Store.parseFeatureType(…)} for the "trajectory" column.
      */
     @Override
-    public Class<double[]> getTargetClass() {
-        return double[].class;
+    @SuppressWarnings("unchecked")
+    public Class<G> getTargetClass() {
+        return (Class<G>) geometries.polylineClass;
     }
 
     /**
-     * Converts an element from the CSV file to our current pseudo-geometry type.
+     * Converts an element from the CSV file to the geometry type.
      */
     @Override
-    public double[] apply(final String text) {
-        return CharSequences.parseDoubles(text, Store.ORDINATE_SEPARATOR);
+    @SuppressWarnings("unchecked")
+    public G apply(final String text) {
+        /*
+         * We could avoid the "unchecked" warning by using getTargetClass().cast(…), but
it would be
+         * a false sense of safety since 'getTargetClass()' is itself unchecked. The real
check will
+         * be performed by DefaultFeatureType.setPropertyValue(…) anyway.
+         */
+        return (G) geometries.createPolyline(spatialDimensionCount,
+                Vector.create(CharSequences.parseDoubles(text, Store.ORDINATE_SEPARATOR),
false));
     }
 }

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java?rev=1799964&r1=1799963&r2=1799964&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
[UTF-8] Mon Jun 26 17:45:23 2017
@@ -45,10 +45,11 @@ import org.apache.sis.referencing.Common
 import org.apache.sis.internal.referencing.GeodeticObjectBuilder;
 import org.apache.sis.internal.storage.MetadataBuilder;
 import org.apache.sis.internal.storage.io.IOUtilities;
+import org.apache.sis.internal.storage.FeatureStore;
+import org.apache.sis.internal.feature.Geometries;
 import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.metadata.sql.MetadataStoreException;
-import org.apache.sis.internal.storage.FeatureStore;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.storage.DataStoreReferencingException;
@@ -157,6 +158,18 @@ public final class Store extends Feature
     private boolean hasTrajectories;
 
     /**
+     * The number of dimensions other than time in the coordinate reference system.
+     * Shall be 2 or 3 according Moving Features CSV encoding specification, but Apache SIS
+     * may be tolerant to other values (depending on the backing geometry library).
+     */
+    private short spatialDimensionCount;
+
+    /**
+     * The factory to use for creating geometries.
+     */
+    private final Geometries geometries;
+
+    /**
      * Appearing order of trajectories (time or sequential), or {@code null} if unspecified.
      *
      * @see #parseFoliation(List)
@@ -186,6 +199,7 @@ public final class Store extends Feature
             throw new DataStoreException(Errors.format(Errors.Keys.CanNotOpen_1, super.getDisplayName()));
         }
         source = (r instanceof BufferedReader) ? (BufferedReader) r : new LineNumberReader(r);
+        geometries = Geometries.implementation(connector.getOption(OptionKey.GEOMETRY_LIBRARY));
         GeneralEnvelope envelope    = null;
         FeatureType     featureType = null;
         Foliation       foliation   = null;
@@ -236,11 +250,11 @@ public final class Store extends Feature
             }
             source.reset();
         } catch (IOException e) {
-            throw new DataStoreException(getLocale(), "CSV", super.getDisplayName(), source).initCause(e);
+            throw new DataStoreException(getLocale(), StoreProvider.NAME, super.getDisplayName(),
source).initCause(e);
         } catch (FactoryException e) {
-            throw new DataStoreReferencingException(getLocale(), "CSV", super.getDisplayName(),
source).initCause(e);
+            throw new DataStoreReferencingException(getLocale(), StoreProvider.NAME, super.getDisplayName(),
source).initCause(e);
         } catch (IllegalArgumentException | DateTimeException e) {
-            throw new DataStoreContentException(getLocale(), "CSV", super.getDisplayName(),
source).initCause(e);
+            throw new DataStoreContentException(getLocale(), StoreProvider.NAME, super.getDisplayName(),
source).initCause(e);
         }
         this.encoding    = connector.getOption(OptionKey.ENCODING);
         this.envelope    = envelope;
@@ -264,6 +278,7 @@ public final class Store extends Feature
     private GeneralEnvelope parseEnvelope(final List<String> elements) throws DataStoreException,
FactoryException {
         CoordinateReferenceSystem crs = null;
         int spatialDimensionCount = 2;
+        boolean    isDimExplicit  = false;
         double[]   lowerCorner    = ArraysExt.EMPTY_DOUBLE;
         double[]   upperCorner    = ArraysExt.EMPTY_DOUBLE;
         Instant    startTime      = null;
@@ -278,8 +293,9 @@ public final class Store extends Feature
                     case 0: continue;                                       // The "@stboundedby"
header.
                     case 1: crs = CRS.forCode(element); continue;
                     case 2: if (element.length() == 2 && Character.toUpperCase(element.charAt(1))
== 'D') {
+                                isDimExplicit = true;
                                 spatialDimensionCount = element.charAt(0) - '0';
-                                if (spatialDimensionCount < 2 || spatialDimensionCount
> 3) {
+                                if (spatialDimensionCount < 1 || spatialDimensionCount
> 3) {
                                     throw new DataStoreReferencingException(errors().getString(
                                         Errors.Keys.IllegalCoordinateSystem_1, element));
                                 }
@@ -326,12 +342,33 @@ public final class Store extends Feature
             int count = 0;
             final CoordinateReferenceSystem[] components = new CoordinateReferenceSystem[3];
             components[count++] = crs;
-
-            // If the coordinates are three-dimensional but the CRS is 2D, add a vertical
axis.
-            if (spatialDimensionCount >= 3 && crs.getCoordinateSystem().getDimension()
== 2) {
-                components[count++] = CommonCRS.Vertical.MEAN_SEA_LEVEL.crs();
+            /*
+             * If the coordinates are three-dimensional but the CRS is 2D, add a vertical
axis.
+             * The vertical axis shall be the third one, however we do not enforce that rule
+             * since Apache SIS should work correctly even if the vertical axis is elsewhere.
+             */
+            int dimension = crs.getCoordinateSystem().getDimension();
+            if (isDimExplicit) {
+                if (spatialDimensionCount > dimension) {
+                    components[count++] = CommonCRS.Vertical.MEAN_SEA_LEVEL.crs();
+                    dimension++;
+                }
+                if (dimension != spatialDimensionCount) {
+                    throw new DataStoreReferencingException(errors().getString(
+                            Errors.Keys.MismatchedDimension_3, "@stboundedby(CRS)", spatialDimensionCount,
dimension));
+                }
+            }
+            if (dimension > Short.MAX_VALUE) {
+                throw new DataStoreReferencingException(errors().getString(
+                        Errors.Keys.ExcessiveNumberOfDimensions_1, dimension));
             }
-            // Add a temporal axis if we have a start time (no need for end time).
+            spatialDimensionCount = dimension;
+            /*
+             * Add a temporal axis if we have a start time (no need for end time).
+             * This block presumes that the CRS does not already have a time axis.
+             * If a time axis was already present, an exception will be thrown at
+             * builder.createCompoundCRS(…) invocation time.
+             */
             final GeodeticObjectBuilder builder = new GeodeticObjectBuilder();
             String name = crs.getName().getCode();
             if (startTime != null) {
@@ -366,7 +403,7 @@ public final class Store extends Feature
             (dim = upperCorner.length) != spatialDimensionCount)
         {
             throw new DataStoreReferencingException(errors().getString(
-                    Errors.Keys.MismatchedDimension_2, dim, spatialDimensionCount));
+                    Errors.Keys.MismatchedDimension_3, "@stboundedby(BBOX)", spatialDimensionCount,
dim));
         }
         for (int i=0; i<spatialDimensionCount; i++) {
             envelope.setRange(i, lowerCorner[i], upperCorner[i]);
@@ -375,6 +412,7 @@ public final class Store extends Feature
             envelope.setRange(spatialDimensionCount, timeEncoding.toCRS(startTime.toEpochMilli()),
                     (endTime == null) ? Double.NaN : timeEncoding.toCRS(endTime.toEpochMilli()));
         }
+        this.spatialDimensionCount = (short) spatialDimensionCount;
         return envelope;
     }
 
@@ -434,7 +472,7 @@ public final class Store extends Feature
                                 properties.add(createProperty("startTime", Instant.class,
1));
                                 properties.add(createProperty(  "endTime", Instant.class,
1));
                             }
-                            type = double[].class;
+                            type = geometries.polylineClass;
                             minOccurrence = 1;
                         }
                         break;
@@ -489,7 +527,7 @@ public final class Store extends Feature
         if (metadata == null) {
             final MetadataBuilder builder = new MetadataBuilder();
             try {
-                builder.setFormat(timeEncoding != null && hasTrajectories ? "CSV-MF"
: "CSV");
+                builder.setFormat(timeEncoding != null && hasTrajectories ? StoreProvider.MOVING
: StoreProvider.NAME);
             } catch (MetadataStoreException e) {
                 listeners.warning(null, e);
             }
@@ -498,7 +536,7 @@ public final class Store extends Feature
             try {
                 builder.addExtent(envelope);
             } catch (TransformException e) {
-                throw new DataStoreReferencingException(getLocale(), "CSV", getDisplayName(),
source).initCause(e);
+                throw new DataStoreReferencingException(getLocale(), StoreProvider.NAME,
getDisplayName(), source).initCause(e);
             } catch (UnsupportedOperationException e) {
                 /*
                  * Failed to set the temporal components if the sis-temporal module was
@@ -607,7 +645,7 @@ public final class Store extends Feature
                     }
                     case 3: {
                         if (hasTrajectories) {
-                            c = GeometryParser.INSTANCE;
+                            c = GeometryParser.instance(geometries, spatialDimensionCount);
                             break;
                         }
                         /*
@@ -797,7 +835,7 @@ public final class Store extends Feature
      * The error message will contain the line number if available.
      */
     final String canNotParseFile() {
-        final Object[] parameters = IOUtilities.errorMessageParameters("CSV", getDisplayName(),
source);
+        final Object[] parameters = IOUtilities.errorMessageParameters(StoreProvider.NAME,
getDisplayName(), source);
         return errors().getString(IOUtilities.errorMessageKey(parameters), parameters);
     }
 

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java?rev=1799964&r1=1799963&r2=1799964&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java
[UTF-8] Mon Jun 26 17:45:23 2017
@@ -42,6 +42,11 @@ import org.apache.sis.internal.storage.w
 @Capabilities(Capability.READ)
 public final class StoreProvider extends DataStoreProvider {
     /**
+     * The format names for static features and moving features.
+     */
+    static final String NAME = "CSV", MOVING = "CSV-MF";
+
+    /**
      * The object to use for verifying if the first keyword is the expected one.
      */
     private static final class Peek extends FirstKeywordPeek {
@@ -108,7 +113,7 @@ public final class StoreProvider extends
      */
     @Override
     public String getShortName() {
-        return "CSV";
+        return NAME;
     }
 
     /**

Modified: sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java?rev=1799964&r1=1799963&r2=1799964&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreTest.java
[UTF-8] Mon Jun 26 17:45:23 2017
@@ -25,6 +25,8 @@ import org.apache.sis.storage.DataStoreE
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
+import com.esri.core.geometry.Point2D;
+import com.esri.core.geometry.Polyline;
 
 import static org.junit.Assert.*;
 import static org.apache.sis.test.TestUtilities.date;
@@ -116,7 +118,7 @@ public final strictfp class StoreTest ex
         assertPropertyTypeEquals((AttributeType<?>) it.next(), "mfidref",       String.class,
  1);
         assertPropertyTypeEquals((AttributeType<?>) it.next(), "startTime",     Instant.class,
 1);
         assertPropertyTypeEquals((AttributeType<?>) it.next(), "endTime",       Instant.class,
 1);
-        assertPropertyTypeEquals((AttributeType<?>) it.next(), "trajectory",    double[].class,
1);
+        assertPropertyTypeEquals((AttributeType<?>) it.next(), "trajectory",    Polyline.class,
1);
         assertPropertyTypeEquals((AttributeType<?>) it.next(), "state",         String.class,
  0);
         assertPropertyTypeEquals((AttributeType<?>) it.next(), "\"type\" code", Integer.class,
 0);
         assertFalse(it.hasNext());
@@ -141,11 +143,17 @@ public final strictfp class StoreTest ex
             final String startTime, final String endTime, final double[] trajectory,
             final String state, final int typeCode)
     {
-        assertEquals     ("mfidref",    mfidref,               f.getPropertyValue("mfidref"));
-        assertEquals     ("startTime",  instant(startTime),    f.getPropertyValue("startTime"));
-        assertEquals     ("endTime",    instant(endTime),      f.getPropertyValue("endTime"));
-        assertEquals     ("state",      state,                 f.getPropertyValue("state"));
-        assertEquals     ("typeCode",   typeCode,              f.getPropertyValue("\"type\"
code"));
-        assertArrayEquals("trajectory", trajectory, (double[]) f.getPropertyValue("trajectory"),
STRICT);
+        assertEquals("mfidref",   mfidref,            f.getPropertyValue("mfidref"));
+        assertEquals("startTime", instant(startTime), f.getPropertyValue("startTime"));
+        assertEquals("endTime",   instant(endTime),   f.getPropertyValue("endTime"));
+        assertEquals("state",     state,              f.getPropertyValue("state"));
+        assertEquals("typeCode",  typeCode,           f.getPropertyValue("\"type\" code"));
+        final Polyline polyline = (Polyline)          f.getPropertyValue("trajectory");
+        assertEquals("pointCount", trajectory.length / 2, polyline.getPointCount());
+        for (int i=0; i < trajectory.length;) {
+            final Point2D xy = polyline.getXY(i / 2);
+            assertEquals("x", trajectory[i++], xy.x, STRICT);
+            assertEquals("y", trajectory[i++], xy.y, STRICT);
+        }
     }
 }



Mime
View raw message