sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ama...@apache.org
Subject [sis] 28/45: feat(Feature): ends Envelope to geometry feature
Date Tue, 12 Nov 2019 16:44:55 GMT
This is an automated email from the ASF dual-hosted git repository.

amanin pushed a commit to branch refactor/sql-store
in repository https://gitbox.apache.org/repos/asf/sis.git

commit dd658ab6ac026e6d48e30935aa22e46154903384
Author: Alexis Manin <amanin@apache.org>
AuthorDate: Tue Oct 8 15:29:35 2019 +0200

    feat(Feature): ends Envelope to geometry feature
---
 .../java/org/apache/sis/internal/feature/ESRI.java |  39 +++++---
 .../apache/sis/internal/feature/Geometries.java    |  15 +++
 .../org/apache/sis/internal/feature/Java2D.java    | 105 ++++++++++++++++++++-
 .../sis/internal/feature/GeometriesTestCase.java   |   3 +-
 4 files changed, 143 insertions(+), 19 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
index 05be9ff..ce05495 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/ESRI.java
@@ -23,18 +23,9 @@ import org.apache.sis.math.Vector;
 import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.util.Classes;
 
-import com.esri.core.geometry.Envelope2D;
-import com.esri.core.geometry.Geometry;
-import com.esri.core.geometry.MultiPath;
-import com.esri.core.geometry.OperatorExportToWkt;
-import com.esri.core.geometry.OperatorImportFromWkt;
-import com.esri.core.geometry.Point;
-import com.esri.core.geometry.Point2D;
-import com.esri.core.geometry.Point3D;
-import com.esri.core.geometry.Polygon;
-import com.esri.core.geometry.Polyline;
-import com.esri.core.geometry.WktExportFlags;
-import com.esri.core.geometry.WktImportFlags;
+import com.esri.core.geometry.*;
+
+import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 
 
 /**
@@ -198,12 +189,32 @@ add:    for (;;) {
 
     @Override
     double[] getPoints(Object geometry) {
-        throw new UnsupportedOperationException("Not supported yet"); // "Alexis Manin (Geomatys)"
on 07/10/2019
+        if (geometry instanceof GeometryWrapper) geometry = ((GeometryWrapper) geometry).geometry;
+        ensureNonNull("Geometry", geometry);
+        if (geometry instanceof MultiVertexGeometry) {
+            MultiVertexGeometry vertices = (MultiVertexGeometry) geometry;
+            final Point2D[] coords = vertices.getCoordinates2D();
+            final double[] ordinates = new double[coords.length*2];
+            int idx = 0;
+            for (Point2D coord : coords) {
+                ordinates[idx++] = coord.x;
+                ordinates[idx++] = coord.y;
+            }
+            return ordinates;
+        }
+        throw new UnsupportedOperationException("Unsupported geometry type: "+geometry.getClass().getCanonicalName());
     }
 
     @Override
     Object createMultiPolygonImpl(Object... polygonsOrLinearRings) {
-        throw new UnsupportedOperationException("Not supported yet"); // "Alexis Manin (Geomatys)"
on 07/10/2019
+        final Polygon poly = new Polygon();
+        for (final Object polr : polygonsOrLinearRings) {
+            if (polr instanceof MultiPath) {
+                poly.add((MultiPath) polr, false);
+            } else throw new UnsupportedOperationException("Unsupported geometry type: "+polr
== null? "null" : polr.getClass().getCanonicalName());
+        }
+
+        return poly;
     }
 
     /**
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
index 0688024..31094c9 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
@@ -157,6 +157,14 @@ public abstract class Geometries<G> {
         return false;
     }
 
+    /**
+     * Transforms an envelope to a polygon whose start point is lower corner, and points
composing result are the
+     * envelope corners in clockwise order.
+     * @param env The envelope to convert.
+     * @param wraparound How to resolve wrap-around ambiguities on the envelope.
+     * @return If any geometric implementation is installed, return a polygon (or two polygons
in case of
+     * {@link WrapResolution#SPLIT split handling of wrap-around}.
+     */
     public static Optional<Geometry> toGeometry(final Envelope env, WrapResolution
wraparound) {
         return findStrategy(g -> g.tryConvertToGeometry(env, wraparound))
                 .map(result -> new GeometryWrapper(result, env));
@@ -347,6 +355,9 @@ public abstract class Geometries<G> {
         return Optional.empty();
     }
 
+    /**
+     * See {@link Geometries#toGeometry(Envelope, WrapResolution)}.
+     */
     Object tryConvertToGeometry(final Envelope env, WrapResolution resolution) {
         // Ensure that we can isolate an horizontal part in the given envelope.
         final int x;
@@ -427,6 +438,10 @@ public abstract class Geometries<G> {
             return createMultiPolygonImpl(mainRect, secondRect);
         }
 
+        /* Geotk original method had an option to insert a median point on wrappped around
axis, but we have not ported
+         * it, because in an orthonormal space, I don't see any case where it could be useful.
However, in case it
+         * have to be added, we can do it here by amending created ring(s).
+         */
         return mainRect;
     }
 
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
index 58c7b29..38f78d8 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Java2D.java
@@ -16,20 +16,30 @@
  */
 package org.apache.sis.internal.feature;
 
-import java.util.Iterator;
 import java.awt.Shape;
 import java.awt.geom.Line2D;
 import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.stream.DoubleStream;
+import java.util.stream.StreamSupport;
+
 import org.apache.sis.geometry.GeneralEnvelope;
-import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.internal.feature.j2d.ShapeProperties;
 import org.apache.sis.internal.referencing.j2d.ShapeUtilities;
 import org.apache.sis.math.Vector;
+import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.Numbers;
 
+import static org.apache.sis.util.ArgumentChecks.ensureNonEmpty;
+import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
+
 
 /**
  * Centralizes usages of some (not all) Java2D geometry API by Apache SIS.
@@ -221,12 +231,25 @@ add:    for (;;) {
 
     @Override
     double[] getPoints(Object geometry) {
-        throw new UnsupportedOperationException("Not supported yet"); // "Alexis Manin (Geomatys)"
on 07/10/2019
+        if (geometry instanceof GeometryWrapper) geometry = ((GeometryWrapper) geometry).geometry;
+        ensureNonNull("Geometry", geometry);
+        if (geometry instanceof Point2D) return getCoordinate(geometry);
+        if (geometry instanceof Shape) {
+            final PathIterator it = ((Shape) geometry).getPathIterator(null);
+            return StreamSupport.stream(new PathSpliterator(it), false)
+                    .flatMapToDouble(Segment::ordinates)
+                    .toArray();
+        }
+
+        throw new UnsupportedOperationException("Unsupported geometry type: "+geometry.getClass().getCanonicalName());
     }
 
     @Override
     Object createMultiPolygonImpl(Object... polygonsOrLinearRings) {
-        throw new UnsupportedOperationException("Not supported yet"); // "Alexis Manin (Geomatys)"
on 07/10/2019
+        ensureNonEmpty("Polygons or linear rings to merge", polygonsOrLinearRings);
+        if (polygonsOrLinearRings.length == 1) return polygonsOrLinearRings[0];
+        final Iterator<Object> it = Arrays.asList(polygonsOrLinearRings).iterator();
+        return tryMergePolylines(it.next(), it);
     }
 
     /**
@@ -248,4 +271,78 @@ add:    for (;;) {
     public Object parseWKT(final String wkt) {
         throw unsupported(2);
     }
+
+    /**
+     * An abstraction over {@link PathIterator} to use it in a streaming context.
+     */
+    private static class PathSpliterator implements Spliterator<Segment> {
+
+        private final PathIterator source;
+
+        private PathSpliterator(PathIterator source) {
+            this.source = source;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super Segment> action) {
+            if (source.isDone()) return false;
+            final double[] coords = new double[6];
+            final int segmentType = source.currentSegment(coords);
+            action.accept(new Segment(segmentType, coords));
+            source.next();
+            return true;
+        }
+
+        @Override
+        public Spliterator<Segment> trySplit() {
+            return null;
+        }
+
+        @Override
+        public long estimateSize() {
+            return Long.MAX_VALUE;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.NONNULL | Spliterator.ORDERED | Spliterator.IMMUTABLE;
+        }
+    }
+
+    /**
+     * Describe a path segment as described by {@link PathIterator#currentSegment(double[])
AWT path iteration API}.
+     * Basically, the awt abstraction is really poor, so we made a wrapper around it to describe
segments.
+     */
+    private static class Segment {
+        /**
+         * This segment type ({@link PathIterator#SEG_CLOSE}, etc.).
+         */
+        final int type;
+        /**
+         * Brut points composing the segment, as returned by {@link PathIterator#currentSegment(double[])}.
+         */
+        private final double[] points;
+
+        Segment(int type, double[] points) {
+            this.type = type;
+            this.points = points;
+        }
+
+        /**
+         *
+         * @return points composing this segment, as a contiguous set of ordinates. Points
are all 2D, so every two
+         * elements in backed stream describe a point. Can be empty in case of {@link PathIterator#SEG_CLOSE
closing segment}.
+         */
+        DoubleStream ordinates() {
+            switch (type) {
+                case PathIterator.SEG_CLOSE: return DoubleStream.empty();
+                case PathIterator.SEG_QUADTO: return Arrays.stream(points, 0, 4);
+                case PathIterator.SEG_CUBICTO: return Arrays.stream(points);
+                case PathIterator.SEG_LINETO:
+                case PathIterator.SEG_MOVETO:
+                        return Arrays.stream(points, 0, 2);
+                default: throw new IllegalStateException("Unknown segment type: "+type);
+            }
+        }
+    }
 }
diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java
b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java
index dc67d01..7aa7a44 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometriesTestCase.java
@@ -186,7 +186,8 @@ public abstract strictfp class GeometriesTestCase extends TestCase {
         Stream.of(CONTIGUOUS, EXPAND, SPLIT)
                 .forEach(method
                         -> expectFailFast(()
-                        -> factory.tryConvertToGeometry(wrapped, method), IllegalArgumentException.class)
+                                -> factory.tryConvertToGeometry(wrapped, method)
+                        , IllegalArgumentException.class)
                 );
 
         final GeneralEnvelope wrapped3d = new GeneralEnvelope(3);


Mime
View raw message