You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by am...@apache.org on 2019/11/12 16:44:55 UTC
[sis] 28/45: feat(Feature): ends Envelope to geometry feature
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 <am...@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);