This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 15377fcb44 refactor(Geometry): remove MultiMeshPrimitive, replaced by
GeometryCollection
15377fcb44 is described below
commit 15377fcb4437f2f5f59276eebc7e709260ccc28e
Author: jsorel <[email protected]>
AuthorDate: Tue Nov 3 14:37:55 2026 +0100
refactor(Geometry): remove MultiMeshPrimitive, replaced by
GeometryCollection
---
.../main/org/apache/sis/geometries/Geometries.java | 35 ++-
.../apache/sis/geometries/GeometryCollection.java | 4 +-
.../apache/sis/geometries/adapter/JTSAdapter.java | 25 +-
.../geometries/mesh/MeshPrimitiveComparator.java | 9 +-
.../sis/geometries/mesh/MeshPrimitiveVisitor.java | 15 +-
.../sis/geometries/mesh/MultiMeshPrimitive.java | 96 ------
.../sis/geometries/operation/ComputeAttribute.java | 30 +-
.../geometries/operation/GeometryProcessor.java | 13 +-
.../sis/geometries/operation/Intersection.java | 5 +-
.../sis/geometries/operation/ToPrimitive.java | 41 +--
.../apache/sis/geometries/operation/Transform.java | 22 +-
.../operation/extrude/TerrainExtruder.java | 13 +-
.../main/org/apache/sis/geometries/summary.adoc | 323 ++++++++++++++-------
.../sis/geometries/GeometryCollectionTest.java | 34 +++
.../sis/geometries/adapter/JTSAdapterTest.java | 68 +++++
.../sis/geometries/operation/ToPrimitiveTest.java | 15 +-
.../sis/geometries/operation/TransformTest.java | 7 +-
.../operation/extrude/TerrainExtruderTest.java | 8 +-
18 files changed, 467 insertions(+), 296 deletions(-)
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometries.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometries.java
index f4c610a684..176da49173 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometries.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/Geometries.java
@@ -49,7 +49,6 @@ import org.apache.sis.geometries.adapter.JTSAdapter;
import org.apache.sis.geometries.adapter.ShapeAdapter;
import org.apache.sis.geometries.adapter.ShapeConverter;
import org.apache.sis.geometries.mesh.MeshPrimitive;
-import org.apache.sis.geometries.mesh.MultiMeshPrimitive;
import org.apache.sis.geometry.wrapper.jts.JTS;
import org.apache.sis.maths.Array;
import org.apache.sis.maths.Matrix3D;
@@ -390,9 +389,9 @@ public final class Geometries {
*
* @param mesh not null
*/
- public static void smoothVertices(MultiMeshPrimitive<?> mesh) {
+ public static void smoothVertices(GeometryCollection<? extends
MeshPrimitive> mesh) {
ArgumentChecks.ensureNonNull("mesh", mesh);
- for (MeshPrimitive p : mesh.getComponents()) {
+ for (MeshPrimitive p : mesh) {
p.removeDuplicatesByPosition();
}
}
@@ -660,6 +659,36 @@ public final class Geometries {
primitive.setIndex(NDArrays.ofUnsigned(primitive.getIndex().getSampleSystem(),
index));
}
+ /**
+ * Check geometry definition.
+ */
+ public static void validate(GeometryCollection<? extends MeshPrimitive>
collection) {
+ for (MeshPrimitive p : collection) {
+ p.validate();
+ }
+ }
+
+ /**
+ * Set each vertex normal by computing the normal of the triangle
+ * where it is used.
+ * This method should not be used if vertices are shared by multiple
+ * triangles or it will cause visual glitches.
+ */
+ public static void computeFaceNormals(GeometryCollection<? extends
MeshPrimitive> collection) {
+ for (MeshPrimitive p : collection) {
+ p.computeFaceNormals();
+ }
+ }
+
+ /**
+ * Set each vertex normal by computing the normal of the triangle
+ * where it is used.
+ */
+ public static void computeSmoothNormals(GeometryCollection<? extends
MeshPrimitive> collection) {
+ for (MeshPrimitive p : collection) {
+ p.computeSmoothNormals();
+ }
+ }
public static MeshPrimitive.Triangles
toPrimitive(List<org.locationtech.jts.geom.Polygon> triangles,
CoordinateReferenceSystem crs) {
final int dimension = crs.getCoordinateSystem().getDimension();
final float[] values = new float[Math.multiplyExact(triangles.size(),
3 * dimension)];
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryCollection.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryCollection.java
index e2a888a6d4..f74ad8d24d 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryCollection.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/GeometryCollection.java
@@ -413,14 +413,14 @@ public sealed interface GeometryCollection<T extends
Geometry> extends Geometry,
if (index >= count) {
throw new NoSuchElementException();
}
- return getGeometryN(index);
+ return getGeometryN(index++);
}
@Override
public void forEachRemaining(final Consumer<? super T> action) {
Objects.requireNonNull(action);
while (index < count) {
- action.accept(getGeometryN(index));
+ action.accept(getGeometryN(index++));
}
}
};
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/JTSAdapter.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/JTSAdapter.java
index ba8fa4a965..4e1ffebd06 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/JTSAdapter.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/adapter/JTSAdapter.java
@@ -222,15 +222,18 @@ public final class JTSAdapter {
private static class JTSDataPoints implements DataPoints {
private final CoordinateSequence jts;
- private final CoordinateReferenceSystem crs;
private final int dim;
- private final DataPointsType type;
+ private CoordinateReferenceSystem crs;
+ private DataPointsType type;
private JTSDataPoints(CoordinateSequence jts,
CoordinateReferenceSystem crs) {
this.jts = jts;
- this.crs = crs;
this.dim = jts.getDimension();
+ setCRS(crs);
+ }
+ private void setCRS(CoordinateReferenceSystem crs) {
+ this.crs = crs;
final DataPointsType.Template at = new DataPointsType.Template();
at.addOrReplaceAttribute(DataPointsType.ATT_POSITION,
SampleSystem.of(crs), DataType.DOUBLE);
type = at;
@@ -241,9 +244,18 @@ public final class JTSAdapter {
return crs;
}
+ /**
+ * Relabels the positions with the given CRS, the JTS coordinates are
not modified.
+ *
+ * @throws IllegalArgumentException if the CRS dimension differs from
the current one.
+ */
@Override
public void setCoordinateReferenceSystem(CoordinateReferenceSystem cs)
throws IllegalArgumentException {
- throw new UnsupportedOperationException("Not supported.");
+ final int dimension = crs.getCoordinateSystem().getDimension();
+ if (cs.getCoordinateSystem().getDimension() != dimension) {
+ throw new IllegalArgumentException("Coordinate reference
system must have " + dimension + " dimensions.");
+ }
+ setCRS(cs);
}
@Override
@@ -263,8 +275,9 @@ public final class JTSAdapter {
@Override
public Vector getPosition(int index) {
+ // The JTS sequence may have more ordinates than the CRS, for
example an unused z.
final double[] v = new
double[crs.getCoordinateSystem().getDimension()];
- for (int i = 0; i < dim; i++) {
+ for (int i = 0, n = Math.min(dim, v.length); i < n; i++) {
v[i] = jts.getOrdinate(index, i);
}
return Vectors.create(v, DataType.DOUBLE);
@@ -272,7 +285,7 @@ public final class JTSAdapter {
@Override
public void setPosition(int index, Vector value) {
- for (int i = 0; i < dim; i++) {
+ for (int i = 0, n = Math.min(dim, value.getDimension()); i < n;
i++) {
jts.setOrdinate(index, i, value.get(i));
}
}
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveComparator.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveComparator.java
index 678efce761..c39d080231 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveComparator.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveComparator.java
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Objects;
import org.apache.sis.geometries.DataPoints;
import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryCollection;
import org.apache.sis.geometries.Point;
import org.apache.sis.geometries.curve.LineString;
import org.apache.sis.geometries.internal.shared.ArrayDataPoints;
@@ -157,10 +158,10 @@ public final class MeshPrimitiveComparator {
}
/**
- * Compare two multi-primitive.
+ * Compare two collections of primitives.
* @throws IllegalArgumentException if they are not equal
*/
- public void compare(MultiMeshPrimitive expected, MultiMeshPrimitive
candidate) throws IllegalArgumentException {
+ public void compare(GeometryCollection<? extends MeshPrimitive> expected,
GeometryCollection<? extends MeshPrimitive> candidate) throws
IllegalArgumentException {
if (compareCrs) {
if (!CRS.equivalent(expected.getCoordinateReferenceSystem(),
candidate.getCoordinateReferenceSystem())) {
@@ -168,8 +169,8 @@ public final class MeshPrimitiveComparator {
}
}
- final List<? extends MeshPrimitive> expectedPrimitives =
expected.getComponents();
- final List<? extends MeshPrimitive> candidatePrimitives =
candidate.getComponents();
+ final List<? extends MeshPrimitive> expectedPrimitives =
expected.stream().toList();
+ final List<? extends MeshPrimitive> candidatePrimitives =
candidate.stream().toList();
int size = expectedPrimitives.size();
if (expectedPrimitives.size() != candidatePrimitives.size()) {
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveVisitor.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveVisitor.java
index f1e66cbcc5..c2d3089aea 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveVisitor.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MeshPrimitiveVisitor.java
@@ -19,6 +19,7 @@ package org.apache.sis.geometries.mesh;
import java.util.HashSet;
import org.apache.sis.geometries.DataPoints;
import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryCollection;
import org.apache.sis.geometries.GeometryFactory;
import org.apache.sis.geometries.Point;
import org.apache.sis.geometries.curve.LineString;
@@ -39,7 +40,7 @@ import org.apache.sis.util.ArgumentChecks;
public abstract class MeshPrimitiveVisitor {
private final HashSet visited = new HashSet();
- private MultiMeshPrimitive<?> geometry;
+ private GeometryCollection<? extends MeshPrimitive> geometry;
private MeshPrimitive primitive;
@@ -51,11 +52,11 @@ public abstract class MeshPrimitiveVisitor {
*/
public MeshPrimitiveVisitor(Geometry geometry) {
if (geometry instanceof MeshPrimitive p) {
- reset(new MultiMeshPrimitive(p));
- } else if (geometry instanceof MultiMeshPrimitive mp) {
- reset(mp);
+ reset(GeometryFactory.DEFAULT.createGeometryCollection(p));
+ } else if (geometry instanceof GeometryCollection<?> c &&
c.stream().allMatch(MeshPrimitive.class::isInstance)) {
+ reset((GeometryCollection<? extends MeshPrimitive>) c);
} else {
- throw new IllegalArgumentException("Geometry is not a primitive");
+ throw new IllegalArgumentException("Geometry is not a primitive or
a collection of primitives");
}
}
@@ -64,7 +65,7 @@ public abstract class MeshPrimitiveVisitor {
*
* @param geometry not null
*/
- public void reset(MultiMeshPrimitive geometry) {
+ public void reset(GeometryCollection<? extends MeshPrimitive> geometry) {
ArgumentChecks.ensureNonNull("geometry", geometry);
this.geometry = geometry;
visited.clear();
@@ -74,7 +75,7 @@ public abstract class MeshPrimitiveVisitor {
* Loop on all primitives in the geometry.
*/
public void visit() {
- for (MeshPrimitive p : geometry.getComponents()) {
+ for (MeshPrimitive p : geometry) {
visit(p);
}
}
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MultiMeshPrimitive.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MultiMeshPrimitive.java
deleted file mode 100644
index ac99004fa9..0000000000
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/mesh/MultiMeshPrimitive.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.geometries.mesh;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.apache.sis.geometries.Geometries;
-import org.apache.sis.geometries.GeometryType;
-import org.apache.sis.geometries.internal.shared.DefaultGeometryCollection;
-
-
-/**
- * MultiPrimitive is a group of primitive defining a more complex geometry.
- * A primitive mimics the natural structures used by GPUs.
- *
- * @author Johann Sorel (Geomatys)
- */
-public final class MultiMeshPrimitive<T extends MeshPrimitive> extends
DefaultGeometryCollection<T> {
-
- /**
- * Create a geometry with right hand 3D CRS.
- */
- public MultiMeshPrimitive() {
- this(Geometries.RIGHT_HAND_3D);
- }
-
- public MultiMeshPrimitive(CoordinateReferenceSystem crs) {
- super(GeometryType.GEOMETRY, crs, null);
- }
-
- public MultiMeshPrimitive(MeshPrimitive ... primitives) {
- this(primitives[0].getCoordinateReferenceSystem());
- append(Arrays.asList(primitives));
- }
-
- public boolean isEmpty() {
- for (MeshPrimitive p : geometries) {
- if (!p.isEmpty()) {
- return false;
- }
- }
- return true;
- }
-
- public List<T> getComponents() {
- return Collections.unmodifiableList(geometries);
- }
-
- /**
- * Check geometry definition.
- */
- public void validate() {
- for (MeshPrimitive p : geometries) {
- p.validate();
- }
- }
-
- /**
- * Set each vertex normal by computing the normal of the triangle
- * where it is used.
- * This method should not be used if vertices are shared by multiple
- * triangles or it will cause visual glitches.
- */
- public void computeFaceNormals() {
- for (MeshPrimitive p : geometries) {
- p.computeFaceNormals();
- }
- }
-
- /**
- * Set each vertex normal by computing the normal of the triangle
- * where it is used.
- */
- public void computeSmoothNormals() {
- for (MeshPrimitive p : geometries) {
- p.computeSmoothNormals();
- }
- }
-
-}
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/ComputeAttribute.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/ComputeAttribute.java
index 340e5eeb6b..a19bd20d82 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/ComputeAttribute.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/ComputeAttribute.java
@@ -16,16 +16,15 @@
*/
package org.apache.sis.geometries.operation;
-import java.util.ArrayList;
-import java.util.List;
import java.util.function.Function;
import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryCollection;
+import org.apache.sis.geometries.GeometryFactory;
import org.apache.sis.geometries.Point;
import org.apache.sis.geometries.internal.shared.ArrayDataPoints;
import org.apache.sis.geometries.internal.shared.Vertex;
import org.apache.sis.geometries.mesh.MeshPrimitive;
import org.apache.sis.geometries.mesh.MeshPrimitiveVisitor;
-import org.apache.sis.geometries.mesh.MultiMeshPrimitive;
import org.apache.sis.maths.Array;
import org.apache.sis.maths.DataType;
import org.apache.sis.maths.NDArrays;
@@ -69,21 +68,20 @@ public final class ComputeAttribute {
/**
- * Compute attribute on MultiPrimitive.
- * Also works for ModelPrimitive.
+ * Compute attribute on each primitive of a collection.
+ *
+ * @throws UnsupportedOperationException if an element of the collection
is not a mesh primitive.
*/
- public static MultiMeshPrimitive compute(MultiMeshPrimitive base, String
attributeName, SampleSystem attributeSystem, DataType attributeType,
Function<Point,Vector> valueGenerator) {
- final List<org.apache.sis.geometries.mesh.MeshPrimitive> news = new
ArrayList<>();
- for (int i = 0, n = base.getNumGeometries(); i < n; i++) {
- Geometry p = base.getGeometryN(i);
- p = compute((MeshPrimitive)p, attributeName, attributeSystem,
attributeType, valueGenerator);
- news.add((org.apache.sis.geometries.mesh.MeshPrimitive) p);
+ public static GeometryCollection<MeshPrimitive>
compute(GeometryCollection<?> base, String attributeName, SampleSystem
attributeSystem, DataType attributeType, Function<Point,Vector> valueGenerator)
{
+ final MeshPrimitive[] news = new
MeshPrimitive[base.getNumGeometries()];
+ for (int i = 0; i < news.length; i++) {
+ final Geometry p = base.getGeometryN(i);
+ if (!(p instanceof MeshPrimitive mp)) {
+ throw new UnsupportedOperationException("Collection element is
not a mesh primitive : " + p.getGeometryType());
+ }
+ news[i] = compute(mp, attributeName, attributeSystem,
attributeType, valueGenerator);
}
-
- final org.apache.sis.geometries.mesh.MultiMeshPrimitive copy3d = new
org.apache.sis.geometries.mesh.MultiMeshPrimitive(base.getCoordinateReferenceSystem());
- copy3d.append(news);
-
- return copy3d;
+ return
GeometryFactory.DEFAULT.createGeometryCollection(base.getCoordinateReferenceSystem(),
news);
}
}
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java
index 387630f3ab..10cb6cdbda 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/GeometryProcessor.java
@@ -47,7 +47,6 @@ import
org.apache.sis.geometries.internal.shared.ArrayDataPoints;
import org.apache.sis.geometries.internal.shared.Vertex;
import org.apache.sis.geometries.mesh.MeshPrimitive;
import org.apache.sis.geometries.mesh.MeshPrimitiveVisitor;
-import org.apache.sis.geometries.mesh.MultiMeshPrimitive;
import org.apache.sis.geometries.solid.Polyhedron;
import org.apache.sis.geometries.surface.Polygon;
import org.apache.sis.geometries.surface.PolyhedralSurface;
@@ -506,8 +505,8 @@ public final class GeometryProcessor {
public Geometry compute(Geometry geom, String attributeName, SampleSystem
attributeSystem, DataType attributeType, Function<Point,Vector> valueGenerator)
{
if (geom instanceof MeshPrimitive mp) {
return ComputeAttribute.compute(mp, attributeName,
attributeSystem, attributeType, valueGenerator);
- } else if (geom instanceof MultiMeshPrimitive<?> mp) {
- return ComputeAttribute.compute(mp, attributeName,
attributeSystem, attributeType, valueGenerator);
+ } else if (geom instanceof GeometryCollection<?> c) {
+ return ComputeAttribute.compute(c, attributeName, attributeSystem,
attributeType, valueGenerator);
}
throw new UnsupportedOperationException();
}
@@ -528,8 +527,9 @@ public final class GeometryProcessor {
* can be a Primitive or MultiPrimitive
*/
public Geometry toPrimitive(Geometry geom, Quantity<?> spacing,
Quantity<?> offset) {
- if (geom instanceof MeshPrimitive || geom instanceof
MultiMeshPrimitive) {
+ if (geom instanceof MeshPrimitive) {
//Does nothing, geometry is already a Primitive.
+ //Collections of primitives are handled by the collection case
below.
return geom;
} else if (geom instanceof Point cdt) {
return ToPrimitive.toPrimitive(cdt);
@@ -578,10 +578,11 @@ public final class GeometryProcessor {
return Transform.transform(cdt, crs, transform);
} else if (geom instanceof Polygon cdt) {
return Transform.transform(cdt, crs, transform);
- } else if (geom instanceof MultiMeshPrimitive<?> cdt) {
- return Transform.transform(cdt, crs, transform);
} else if (geom instanceof MeshPrimitive cdt) {
return Transform.transform(cdt, crs, transform);
+ } else if (geom instanceof GeometryCollection<?> cdt) {
+ // Checked after mesh primitives because the points and lines
primitives are also collections.
+ return Transform.transform(cdt, crs, transform);
}
throw new UnsupportedOperationException();
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Intersection.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Intersection.java
index f27490fb05..47539c4f32 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Intersection.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Intersection.java
@@ -37,7 +37,6 @@ import
org.apache.sis.geometries.internal.shared.DefaultNurbSurface;
import org.apache.sis.geometries.internal.shared.Vertex;
import org.apache.sis.geometries.mesh.MeshPrimitive;
import org.apache.sis.geometries.mesh.MeshPrimitiveVisitor;
-import org.apache.sis.geometries.mesh.MultiMeshPrimitive;
import org.apache.sis.geometries.surface.PreparedTIN;
import org.apache.sis.geometries.surface.Triangle;
import org.apache.sis.maths.Array;
@@ -71,8 +70,8 @@ public final class Intersection {
* Inherit attributes from TIN.
* The POSITION attribute is ignored.
*/
- private static void copyAttributes(PreparedTIN tin, MultiMeshPrimitive<?>
primitives) {
- for (MeshPrimitive primitive : primitives.getComponents()) {
+ private static void copyAttributes(PreparedTIN tin, GeometryCollection<?
extends MeshPrimitive> primitives) {
+ for (MeshPrimitive primitive : primitives) {
copyAttributes(tin, primitive);
}
}
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/ToPrimitive.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/ToPrimitive.java
index b1579b30d6..459f13393a 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/ToPrimitive.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/ToPrimitive.java
@@ -17,7 +17,6 @@
package org.apache.sis.geometries.operation;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -27,13 +26,13 @@ import javax.measure.Quantity;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.apache.sis.geometries.DataPoints;
import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryFactory;
import org.apache.sis.geometries.GeometryCollection;
import org.apache.sis.geometries.Point;
import org.apache.sis.geometries.DataPointsType;
import org.apache.sis.geometries.curve.LineString;
import org.apache.sis.geometries.internal.shared.ArrayDataPoints;
import org.apache.sis.geometries.mesh.MeshPrimitive;
-import org.apache.sis.geometries.mesh.MultiMeshPrimitive;
import org.apache.sis.geometries.operation.triangulate.EarClipping;
import org.apache.sis.geometries.solid.Polyhedron;
import org.apache.sis.geometries.surface.Polygon;
@@ -223,16 +222,11 @@ public final class ToPrimitive {
}
return primitive;
} else {
- final MultiMeshPrimitive<MeshPrimitive> mp = new
MultiMeshPrimitive(geometry.getCoordinateReferenceSystem());
+ final List<MeshPrimitive> primitives = new
ArrayList<>(numGeometries);
for (int i = 0; i < numGeometries; i++) {
- final Geometry p =
toPrimitive(geometry.getGeometryN(i).asLine(spacing, offset));
- if (p instanceof
org.apache.sis.geometries.mesh.MultiMeshPrimitive<?> subm) {
- mp.append(subm.getComponents());
- } else if (p instanceof
org.apache.sis.geometries.mesh.MeshPrimitive cd){
- mp.append(Collections.singletonList(cd));
- }
+ addPrimitives(primitives,
toPrimitive(geometry.getGeometryN(i).asLine(spacing, offset)));
}
- return mp;
+ return
GeometryFactory.DEFAULT.createGeometryCollection(geometry.getCoordinateReferenceSystem(),
primitives.toArray(MeshPrimitive[]::new));
}
}
@@ -242,19 +236,30 @@ public final class ToPrimitive {
* @param spacing maximal distance along a curve between two points of its
line strip, or zero or {@code null}.
* @param offset maximal distance between a curve and its line strip, or
zero or {@code null}.
*/
- public static MultiMeshPrimitive toPrimitive(GeometryCollection geometry,
Quantity<?> spacing, Quantity<?> offset)
+ public static GeometryCollection<MeshPrimitive>
toPrimitive(GeometryCollection<?> geometry, Quantity<?> spacing, Quantity<?>
offset)
throws OperationException
{
- final MultiMeshPrimitive<MeshPrimitive> mp = new
MultiMeshPrimitive(geometry.getCoordinateReferenceSystem());
+ final GeometryProcessor processor = new GeometryProcessor();
+ final List<MeshPrimitive> primitives = new ArrayList<>();
for (int i = 0, n = geometry.getNumGeometries(); i < n; i++) {
- final Geometry p = new
GeometryProcessor().toPrimitive(geometry.getGeometryN(i), spacing, offset);
- if (p instanceof
org.apache.sis.geometries.mesh.MultiMeshPrimitive<?> subm) {
- mp.append(subm.getComponents());
- } else if (p instanceof
org.apache.sis.geometries.mesh.MeshPrimitive cd){
- mp.append(Collections.singletonList(cd));
+ addPrimitives(primitives,
processor.toPrimitive(geometry.getGeometryN(i), spacing, offset));
+ }
+ return
GeometryFactory.DEFAULT.createGeometryCollection(geometry.getCoordinateReferenceSystem(),
primitives.toArray(MeshPrimitive[]::new));
+ }
+
+ /**
+ * Adds the given primitive, or the primitives of the given collection, to
the list.
+ * Collections of collections are flattened.
+ */
+ private static void addPrimitives(List<MeshPrimitive> primitives, Geometry
geometry) {
+ // Checked first because the points and lines primitives are also
collections.
+ if (geometry instanceof MeshPrimitive p) {
+ primitives.add(p);
+ } else if (geometry instanceof GeometryCollection<?> c) {
+ for (Geometry element : c) {
+ addPrimitives(primitives, element);
}
}
- return mp;
}
}
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
index 72f5ddf72f..bbfd21e2a3 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/Transform.java
@@ -24,12 +24,13 @@ import
org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.apache.sis.geometries.DataPoints;
+import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryCollection;
import org.apache.sis.geometries.GeometryFactory;
import org.apache.sis.geometries.DataPointsType;
import org.apache.sis.geometries.curve.LinearRing;
import org.apache.sis.geometries.internal.shared.ArrayDataPoints;
import org.apache.sis.geometries.mesh.MeshPrimitive;
-import org.apache.sis.geometries.mesh.MultiMeshPrimitive;
import org.apache.sis.geometries.surface.Polygon;
import org.apache.sis.geometries.surface.Triangle;
import org.apache.sis.maths.Array;
@@ -103,14 +104,19 @@ public final class Transform {
return GeometryFactory.DEFAULT.createPolygon(exterior, interiors);
}
- public static MultiMeshPrimitive<?> transform(MultiMeshPrimitive<?> mp,
CoordinateReferenceSystem crs, MathTransform transform) throws
OperationException {
- final MultiMeshPrimitive<?> copy = new MultiMeshPrimitive<>(crs);
- final List<MeshPrimitive> primitives = new ArrayList<>();
- for (MeshPrimitive p : mp.getComponents()) {
- primitives.add(transform(p, crs, transform));
+ /**
+ * Transform each element of the collection.
+ * The elements are transformed by {@link
GeometryProcessor#transform(Geometry, CoordinateReferenceSystem,
MathTransform)}.
+ *
+ * @return a new collection with the same element type.
+ */
+ public static GeometryCollection<Geometry> transform(GeometryCollection<?>
collection, CoordinateReferenceSystem crs, MathTransform transform) throws
OperationException {
+ final GeometryProcessor processor = new GeometryProcessor();
+ final Geometry[] elements = new
Geometry[collection.getNumGeometries()];
+ for (int i = 0; i < elements.length; i++) {
+ elements[i] = processor.transform(collection.getGeometryN(i), crs,
transform);
}
- copy.append(primitives);
- return copy;
+ return
GeometryFactory.DEFAULT.createGeometryCollection(collection.getElementType(),
crs, elements);
}
/**
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/extrude/TerrainExtruder.java
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/extrude/TerrainExtruder.java
index 26a73a4ad1..9bfe4bfc8a 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/extrude/TerrainExtruder.java
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/operation/extrude/TerrainExtruder.java
@@ -30,6 +30,7 @@ import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.index.quadtree.Quadtree;
import org.apache.sis.geometries.DataPointsType;
import org.apache.sis.geometries.GeometryCollection;
+import org.apache.sis.geometries.GeometryFactory;
import org.apache.sis.geometries.curve.LineString;
import org.apache.sis.geometries.internal.shared.Planar;
import org.apache.sis.geometries.internal.shared.Planar.DoubleList;
@@ -37,7 +38,6 @@ import
org.apache.sis.geometries.internal.shared.Planar.IntList;
import org.apache.sis.geometries.internal.shared.Planar.XY;
import org.apache.sis.geometries.mesh.MeshPrimitive;
import org.apache.sis.geometries.mesh.MeshPrimitiveIndexes;
-import org.apache.sis.geometries.mesh.MultiMeshPrimitive;
import org.apache.sis.geometries.operation.Intersection;
import org.apache.sis.geometries.operation.OperationException;
import org.apache.sis.geometries.operation.ProcessorUtils;
@@ -268,7 +268,7 @@ public final class TerrainExtruder {
*
* @return new meshes, with positions only
*/
- public MultiMeshPrimitive<MeshPrimitive.Triangles> getResult() {
+ public GeometryCollection<MeshPrimitive.Triangles> getResult() {
final IntList terrainFaces = new IntList(), roofFaces = new IntList(),
wallFaces = new IntList();
for (int i = 0; i < nbTriangle; i++) {
if (triangles[i*3] >= 0) {
@@ -302,19 +302,20 @@ public final class TerrainExtruder {
}
}
}
- final MultiMeshPrimitive<MeshPrimitive.Triangles> result = new
MultiMeshPrimitive<>(terrain.getCoordinateReferenceSystem());
+ final List<MeshPrimitive.Triangles> parts = new ArrayList<>(3);
if (separateParts) {
for (IntList faces : List.of(terrainFaces, roofFaces, wallFaces)) {
final MeshPrimitive.Triangles part = toPrimitive(faces);
- if (part != null) result.append(List.of(part));
+ if (part != null) parts.add(part);
}
} else {
terrainFaces.add(roofFaces.toArray());
terrainFaces.add(wallFaces.toArray());
final MeshPrimitive.Triangles part = toPrimitive(terrainFaces);
- if (part != null) result.append(List.of(part));
+ if (part != null) parts.add(part);
}
- return result;
+ return
GeometryFactory.DEFAULT.createGeometryCollection(terrain.getCoordinateReferenceSystem(),
+ parts.toArray(MeshPrimitive.Triangles[]::new));
}
/**
diff --git
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/summary.adoc
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/summary.adoc
index 387feed3b6..dfa764184d 100644
---
a/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/summary.adoc
+++
b/incubator/src/org.apache.sis.geometry/main/org/apache/sis/geometries/summary.adoc
@@ -5,18 +5,19 @@ Overview of the geometry types defined in the
`org.apache.sis.geometry` module
== Interface hierarchy
-The 56 interfaces of the `Geometry` hierarchy are shown below, split by theme.
-`Geometry` and most of its subtypes are `sealed`, so their permitted subtypes
are fixed
-at compile time and a `switch` over them can be exhaustive.
+The 55 interfaces of the `Geometry` hierarchy are shown below, split by theme.
+All of them are `sealed`, so their permitted subtypes are fixed at compile time
+and a `switch` over them can be exhaustive.
Implementation classes are omitted; see the `internal.shared` package.
+A few analytic shapes (`BBox`, `OBBox`, `Plane`, `HyperPlane`, `Frustrum`) are
classes
+implementing `Geometry` directly, without an interface of their own.
-Colours: white is a `sealed` type; *yellow* is `non-sealed`, still open for
extension
-because it has no implementation yet; *blue-grey* is a type detailed in
another diagram
+Colours: white is a type of this diagram; *blue-grey* is a type detailed in
another diagram
here, repeated only to anchor it; *grey* is a type declared outside this
module.
=== Core types
-The spine of the hierarchy. `Geometry` splits into a single `Primitive`, a
`GeometryCollection` of geometries, an analytic `OrientedGeometry`, the `Empty`
set, an extruded `Prism` and a GPU-oriented `MeshPrimitive` batch. Each leaf
below is detailed in one of the following diagrams.
+The spine of the hierarchy. `Geometry` splits into a single `Primitive`, a
`GeometryCollection` of geometries, the `Empty` set, an extruded `Prism` and a
GPU-oriented `MeshPrimitive` batch. Each leaf below is detailed in one of the
following diagrams.
[plantuml,geometry-core,svg]
....
@@ -27,10 +28,6 @@ skinparam interface {
BackgroundColor #FDFDFD
BorderColor #4A6785
}
-skinparam interface<<open>> {
- BackgroundColor #FFF6E0
- BorderColor #C9A227
-}
skinparam interface<<context>> {
BackgroundColor #EEF3F8
BorderColor #93A9C0
@@ -46,17 +43,15 @@ interface Geometry
interface "GeometryCollection<T extends Geometry>" as GeometryCollection
interface MeshPrimitive
interface Orientable
-interface OrientedGeometry
interface Point
interface Primitive
-interface Prism <<open>>
+interface Prism
interface Solid
interface Surface
Geometry <|-- Empty
Geometry <|-- GeometryCollection
Geometry <|-- MeshPrimitive
-Geometry <|-- OrientedGeometry
Geometry <|-- Primitive
Geometry <|-- Prism
Orientable <|-- Curve
@@ -69,7 +64,8 @@ Primitive <|-- Solid
=== Curves
-Subtypes of `Curve` that interpolate a stored sequence of points, plus the
conic family.
+Subtypes of `Curve` that interpolate a stored sequence of points, plus the
conic family
+and the curves defined by a construction (geodesic, rhumb line, ray, offset).
[plantuml,geometry-curves,svg]
....
@@ -80,10 +76,6 @@ skinparam interface {
BackgroundColor #FDFDFD
BorderColor #4A6785
}
-skinparam interface<<open>> {
- BackgroundColor #FFF6E0
- BorderColor #C9A227
-}
skinparam interface<<context>> {
BackgroundColor #EEF3F8
BorderColor #93A9C0
@@ -96,17 +88,19 @@ skinparam interface<<external>> {
interface Arc
interface ArcByBulge
interface ArcByCenterPoint
-interface Circle <<open>>
+interface Circle
interface CircularString
-interface Clothoid <<open>>
+interface Clothoid
interface CompoundCurve
interface Conic
interface Curve <<context>>
-interface EllipticArc <<open>>
+interface EllipticArc
interface Geodesic
+interface Line
interface LineString
interface LinearRing
-interface OffsetCurve <<open>>
+interface OffsetCurve
+interface Ray
interface Rhumb
interface Spiral
@@ -119,8 +113,10 @@ Curve <|-- CircularString
Curve <|-- CompoundCurve
Curve <|-- Conic
Curve <|-- Geodesic
+Curve <|-- Line
Curve <|-- LineString
Curve <|-- OffsetCurve
+Curve <|-- Ray
Curve <|-- Rhumb
Curve <|-- Spiral
LineString <|-- LinearRing
@@ -141,10 +137,6 @@ skinparam interface {
BackgroundColor #FDFDFD
BorderColor #4A6785
}
-skinparam interface<<open>> {
- BackgroundColor #FFF6E0
- BorderColor #C9A227
-}
skinparam interface<<context>> {
BackgroundColor #EEF3F8
BorderColor #93A9C0
@@ -155,8 +147,8 @@ skinparam interface<<external>> {
}
interface BSplineCurve
-interface Bezier <<open>>
-interface CubicSpline <<open>>
+interface Bezier
+interface CubicSpline
interface Curve <<context>>
interface "FunctionCurve<T extends FunctionArc>" as FunctionCurve
interface NurbCurve
@@ -178,7 +170,7 @@ SplineCurve <|-- PolynomialSpline
=== Surfaces
-Subtypes of `Surface`: polygonal, patch-based and parametric.
+Subtypes of `Surface`: polygonal, patch-based, parametric and implicit shapes.
[plantuml,geometry-surfaces,svg]
....
@@ -189,10 +181,6 @@ skinparam interface {
BackgroundColor #FDFDFD
BorderColor #4A6785
}
-skinparam interface<<open>> {
- BackgroundColor #FFF6E0
- BorderColor #C9A227
-}
skinparam interface<<context>> {
BackgroundColor #EEF3F8
BorderColor #93A9C0
@@ -203,13 +191,17 @@ skinparam interface<<external>> {
}
interface BSplineSurface
-interface BilinearGrid <<open>>
+interface BilinearGrid
+interface Capsule
interface CurvePolygon
+interface Cylinder
+interface Ellipsoid
interface NurbSurface
interface ParametricCurveSurface
interface Polygon
interface "PolyhedralSurface<T extends Polygon>" as PolyhedralSurface
interface PreparedTIN
+interface Sphere
interface Surface <<context>>
interface TIN
interface Triangle
@@ -220,10 +212,14 @@ interface ReferenceSystem <<external>>
BSplineSurface <|-- NurbSurface
ParametricCurveSurface <|-- BSplineSurface
ParametricCurveSurface <|-- BilinearGrid
+ParametricCurveSurface <|-- Ellipsoid
+ParametricCurveSurface <|-- Sphere
Polygon <|-- Triangle
PolyhedralSurface <|-- TriangulatedSurface
ReferenceSystem <|-- ParametricCurveSurface
+Surface <|-- Capsule
Surface <|-- CurvePolygon
+Surface <|-- Cylinder
Surface <|-- ParametricCurveSurface
Surface <|-- Polygon
Surface <|-- PolyhedralSurface
@@ -245,10 +241,6 @@ skinparam interface {
BackgroundColor #FDFDFD
BorderColor #4A6785
}
-skinparam interface<<open>> {
- BackgroundColor #FFF6E0
- BorderColor #C9A227
-}
skinparam interface<<context>> {
BackgroundColor #EEF3F8
BorderColor #93A9C0
@@ -258,12 +250,12 @@ skinparam interface<<external>> {
BorderColor #999999
}
-interface BSolidSpline <<open>>
+interface BSplineSolid
interface ParametricCurveSolid
interface Polyhedron
interface Solid <<context>>
-ParametricCurveSolid <|-- BSolidSpline
+ParametricCurveSolid <|-- BSplineSolid
Solid <|-- ParametricCurveSolid
Solid <|-- Polyhedron
@enduml
@@ -271,7 +263,12 @@ Solid <|-- Polyhedron
=== Collections
-Subtypes of `GeometryCollection`, each restricting its elements to one
geometry kind. `ProductCurve` appears here because it is both a collection and
a `Curve`.
+`GeometryCollection` has a single interface subtype, `ProductCurve`, which is
both a collection and a `Curve`.
+Multi-geometries have no interface of their own: they are `GeometryCollection`
instances whose
+`getElementType()` restricts the elements, created by the `GeometryFactory`
methods
+`createMultiPoint`, `createMultiCurve`, `createMultiLineString`,
`createMultiSurface`, `createMultiPolygon`
+and `createMultiPolyhedron`. Several mesh primitives are grouped in a
`GeometryCollection<MeshPrimitive>`.
+The `Points` and `Lines` mesh primitives are themselves collections of points
and of line segments.
[plantuml,geometry-collections,svg]
....
@@ -282,39 +279,20 @@ skinparam interface {
BackgroundColor #FDFDFD
BorderColor #4A6785
}
-skinparam interface<<open>> {
- BackgroundColor #FFF6E0
- BorderColor #C9A227
-}
skinparam interface<<context>> {
BackgroundColor #EEF3F8
BorderColor #93A9C0
}
-skinparam interface<<external>> {
- BackgroundColor #F0F0F0
- BorderColor #999999
-}
interface Curve <<context>>
interface "GeometryCollection<T extends Geometry>" as GeometryCollection
<<context>>
-interface "MultiCurve<T extends Curve>" as MultiCurve
-interface MultiLineString
-interface "MultiPoint<T extends Point>" as MultiPoint
-interface MultiPolygon
-interface MultiPolyhedron
-interface "MultiSurface<T extends Surface>" as MultiSurface
-interface ProductCurve <<open>>
+interface ProductCurve
Curve <|-- ProductCurve
-GeometryCollection <|-- MultiCurve
-GeometryCollection <|-- MultiPoint
-GeometryCollection <|-- MultiPolyhedron : Polyhedron
-GeometryCollection <|-- MultiSurface
GeometryCollection <|-- ProductCurve : Curve
-MultiCurve <|-- MultiLineString : LineString
-MultiSurface <|-- MultiPolygon : Polygon
@enduml
....
+
== Format mapping
[cols="2,3,2,2,2,2,2,6", options="header"]
@@ -415,6 +393,15 @@ MultiSurface <|-- MultiPolygon : Polygon
|—
|`LineString` that is both closed and simple.
+|Line
+|`curve`
+|—
+|—
+|—
+|—
+|—
+|Curve with linear interpolation between consecutive points, each pair
defining a line segment.
+
|CompoundCurve
|`curve`
|—
@@ -432,6 +419,7 @@ MultiSurface <|-- MultiPolygon : Polygon
|—
|—
|Curve derived from a base curve by applying a lateral offset distance.
+The offset of a `LineString` is computed by `DefaultOffsetLineString`.
|ProductCurve
|`curve`
@@ -443,7 +431,7 @@ MultiSurface <|-- MultiPolygon : Polygon
|Collection of curves treated as one continuous curve.
|Ray
-|—
+|`curve`
|—
|—
|—
@@ -461,7 +449,7 @@ MultiSurface <|-- MultiPolygon : Polygon
|Curve of constant bearing (loxodrome) crossing all meridians at the same
angle.
|Bearing
-|—
+|`cs`
|—
|—
|—
@@ -592,14 +580,14 @@ MultiSurface <|-- MultiPolygon : Polygon
|—
|Solid defined by a parametric function.
-|BSolidSpline
+|BSplineSolid
|`solid`
|—
|—
|—
|—
|—
-|`ParametricCurveSolid` defined by a B-spline volumetric representation.
+|`ParametricCurveSolid` defined by a B-spline volumetric representation (ISO
19107 `BSolidSpline`).
|ConstructiveSolidGeometry
|`csg`
@@ -610,29 +598,20 @@ MultiSurface <|-- MultiPolygon : Polygon
|—
|Placeholder type for boolean-combined solids (union, intersection,
difference).
-// --- Oriented / analytic shapes ------------------------------------------
-8+| *Oriented / analytic shapes*
-
-|OrientedGeometry
-|—
-|—
-|—
-|—
-|—
-|—
-|Base type for named analytic shapes carrying their own rotation and
translation.
+// --- Analytic shapes ----------------------------------------------------
+8+| *Analytic shapes*
|Cylinder
-|`solid`
+|`surface`
|—
|—
|—
|—
|cylinder, cone
-|Oriented geometry describing a tube shape with a radius and a height.
+|Surface along the axis joining two positions, with a radius at each end. A
cone when one radius is zero.
|Sphere
-|`solid`
+|`surface`
|—
|—
|—
@@ -640,6 +619,15 @@ MultiSurface <|-- MultiPolygon : Polygon
|sphere
|Parametric surface made of the set of points equidistant from a center.
+|Ellipsoid
+|`surface`
+|—
+|—
+|—
+|—
+|—
+|Parametric surface defined by a center and one semi-axis length per axis.
+
|Frustrum
|`solid`
|—
@@ -647,16 +635,16 @@ MultiSurface <|-- MultiPolygon : Polygon
|—
|—
|—
-|Oriented geometry describing a cone or pyramid with its top cut off.
+|Space delimited by one or more planes, used for example to clip what lies
outside a camera view.
|Capsule
-|`solid`
+|`surface`
|—
|—
|—
|—
|—
-|Oriented geometry describing a cylinder capped with two hemispherical ends.
+|Surface of a cylinder capped with two hemispherical ends, defined by the two
capping spheres.
|Plane
|—
@@ -665,7 +653,7 @@ MultiSurface <|-- MultiPolygon : Polygon
|—
|—
|quad
-|Oriented geometry describing a flat surface.
+|Plane centered on a position and perpendicular to a normal, optionally with
finite extents.
|HyperPlane
|—
@@ -674,7 +662,7 @@ MultiSurface <|-- MultiPolygon : Polygon
|—
|—
|—
-|Oriented geometry dividing the coordinate space in two half-spaces.
+|Plane dividing the coordinate space in two half-spaces, defined by a position
and a normal.
|BBox
|—
@@ -706,59 +694,59 @@ MultiSurface <|-- MultiPolygon : Polygon
|—
|Collection of an arbitrary number of geometric objects sharing the same
spatial reference system.
-|MultiPoint
-|`point`
+|GeometryCollection<Point>
+|—
|MultiPoint
|MultiPoint
|MultiPoint
|—
|—
-|0-dimensional `GeometryCollection` whose elements are restricted to `Point`.
+|MultiPoint: collection of element type `POINT`, created by
`GeometryFactory.createMultiPoint`. `DefaultMultiPoint` stores all the points
in a single `DataPoints`.
-|MultiCurve
-|`curve`
+|GeometryCollection<Curve>
+|—
|MultiCurve
|—
|MultiCurve
|—
|—
-|1-dimensional `GeometryCollection` whose elements are `Curve`.
+|MultiCurve: collection of element type `CURVE`, created by
`GeometryFactory.createMultiCurve`.
-|MultiLineString
-|`curve`
+|GeometryCollection<LineString>
+|—
|MultiLineString
|MultiLineString
|MultiLineString
|—
|—
-|`MultiCurve` whose elements are `LineString`.
+|MultiLineString: collection of element type `LINESTRING`, created by
`GeometryFactory.createMultiLineString`.
-|MultiSurface
-|`surface`
+|GeometryCollection<Surface>
+|—
|MultiSurface
|—
|MultiSurface
|—
|—
-|2-dimensional `GeometryCollection` whose elements are `Surface`.
+|MultiSurface: collection of element type `SURFACE`, created by
`GeometryFactory.createMultiSurface`.
-|MultiPolygon
-|`surface`
+|GeometryCollection<Polygon>
+|—
|MultiPolygon
|MultiPolygon
|MultiPolygon
|—
|—
-|`MultiSurface` whose elements are `Polygon`.
+|MultiPolygon: collection of element type `POLYGON`, created by
`GeometryFactory.createMultiPolygon`.
-|MultiPolyhedron
-|`solid`
+|GeometryCollection<Polyhedron>
+|—
|—
|—
|MultiPolyhedron
|—
|—
-|Arbitrary aggregation of `Polyhedron` solids.
+|MultiPolyhedron: collection of element type `POLYHEDRON`, created by
`GeometryFactory.createMultiPolyhedron`.
// --- Mesh -----------------------------------------------------------------
8+| *Mesh*
@@ -772,14 +760,14 @@ MultiSurface <|-- MultiPolygon : Polygon
|triangle
|GPU-like batch of simple geometries (points, lines or triangles), inspired by
glTF 2.0.
-|MultiMeshPrimitive
-|`mesh`
+|GeometryCollection<MeshPrimitive>
+|—
|—
|—
|—
|Mesh
|—
-|`GeometryCollection` of `MeshPrimitive` batches.
+|Several `MeshPrimitive` batches, like the primitives of a glTF mesh.
// --- Regular polyhedra ------------------------------------------------
8+| *Regular polyhedra*
@@ -1109,3 +1097,126 @@ MultiSurface <|-- MultiPolygon : Polygon
|Implicit surface extracted from a scalar field at given iso-values
(marching-cubes style)
|===
+
+== JTS backend
+
+The methods below still delegate their computation to the
https://locationtech.github.io/jts/[JTS Topology Suite]
+(packages `org.locationtech.jts`). The geometry is viewed as a JTS geometry by
`adapter.JTSAdapter`,
+which supports only points, line strings, linear rings, polygons and
collections of them:
+other geometry types make those methods throw `UnsupportedOperationException`
or `IllegalArgumentException`.
+A geometry computed by JTS is converted back with the coordinate reference
system of the operand,
+but its points keep no attribute other than the position.
+
+The conversions between both models (`adapter.JTSAdapter`, `Geometries.asJTS`,
`Geometries.fromJTS`,
+`adapter.Wrapper.asJTS`) are not listed: converting is their purpose.
+
+[cols="3,3,3,5", options="header"]
+|===
+|Method |Implemented in |Computed without JTS |Notes
+
+4+| *Spatial operations*, declared by `Geometry` and implemented by
`operation.GeometryProcessor`
+
+|`buffer`
+|`GeometryProcessor.buffer`
+|Empty geometry.
+|Attributes of the result are lost.
+
+|`convexHull`
+|`GeometryProcessor.convexHull`
+|Empty geometry.
+|Attributes of the result are lost.
+
+|`difference`, `symDifference`, `union`
+|`GeometryProcessor`
+|Empty operands.
+|Attributes of the result are lost.
+
+|`intersection`
+|`GeometryProcessor.intersection`
+|Empty operands; mesh `Triangles` with mesh `Points` or `Lines`
(`operation.Intersection`).
+|Attributes of the result are lost, except in the mesh cases.
+
+|`distance`
+|`GeometryProcessor.distance`
+|Empty operands; point to point (`operation.Distance`).
+|
+
+|`contains`
+|`GeometryProcessor.contains`
+|Empty operands; polygon containing a point (`operation.Contains`).
+|
+
+|`crosses`, `disjoint`, `equal`, `intersects`, `overlaps`, `touches`,
`within`, `withinDistance`
+|`GeometryProcessor`
+|Empty operands.
+|
+
+|`relate`
+|`GeometryProcessor.relate`
+|Empty operands.
+|The DE-9IM matrix of non-empty operands is computed by JTS.
+
+4+| *Measures and properties*, implemented by the classes of `internal.shared`
+
+|`getLength`
+|`DefaultLineString`, also inherited by `DefaultLinearRing`
+|—
+|Other curves compute their length natively.
+
+|`getPerimeter`
+|`DefaultPolygon`, also inherited by `DefaultTriangle`
+|—
+|
+
+|`getBoundary`
+|`DefaultPolygon`, `DefaultGeometryCollection`, `DefaultMultiPoint`
+|Empty geometry.
+|`DefaultTriangle` inherits the JTS version of `DefaultPolygon` instead of the
`Triangle` default, which returns the exterior ring.
+
+|`isSimple`, `isValid`
+|`DefaultLineString`, `DefaultPolygon`, `DefaultGeometryCollection`,
`DefaultMultiPoint`
+|—
+|Also inherited by `DefaultLinearRing` and `DefaultTriangle`.
+
+|`getLength`, `getCentroid`, `isSimple`, `isValid`
+|`DefaultLine`
+|Empty geometry (`getCentroid`).
+|Always unsupported: `JTSAdapter` cannot convert a `Line`, which is not a
`LineString`.
+The `Curve` default of `getCentroid` would compute it natively.
+
+4+| *SQL/MM functions*, implemented by `adapter.Wrapper`
+
+|`ST_Simplify`
+|`Wrapper.operationSameCRS`
+|—
+|JTS `DouglasPeuckerSimplifier`.
+
+|`ST_SimplifyPreserveTopology`
+|`Wrapper.operationSameCRS`
+|—
+|JTS `TopologyPreservingSimplifier`.
+
+4+| The other SQL/MM functions call the `Geometry` methods above.
+
+4+| *JTS classes used internally*
+
+|`ISOBand.create`
+|`operation.spatialanalysis2d.ISOBand`
+|Band polygons of each triangle.
+|Returns JTS polygons. The bands are merged with JTS `union()`, retried after
`buffer(0)` on topology errors.
+
+|`ISOLine.createMesh`
+|`operation.spatialanalysis2d.ISOLine`
+|Everything.
+|JTS `Coordinate` is used only to hold interpolated positions.
+
+|`PreparedTIN.getPatches`
+|`surface.PreparedTIN`
+|Everything.
+|The triangles are indexed in a JTS `Quadtree`, queried with JTS `Envelope`.
+
+|`TerrainExtruder`
+|`operation.extrude.TerrainExtruder`
+|Everything.
+|The terrain triangles are indexed in a JTS `Quadtree`, queried with JTS
`Envelope`.
+|===
diff --git
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/GeometryCollectionTest.java
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/GeometryCollectionTest.java
index 6f2f2c2fe6..3af5e652f6 100644
---
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/GeometryCollectionTest.java
+++
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/GeometryCollectionTest.java
@@ -16,8 +16,16 @@
*/
package org.apache.sis.geometries;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
// Test dependencies
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -58,6 +66,32 @@ public class GeometryCollectionTest extends GeometryTest {
public void testGetNumGeometries() {
}
+ /**
+ * Tests that the iterator and the stream return each element once, in
order.
+ */
+ @Test
+ public void testIterator() {
+ final Geometry point = GeometryFactory.DEFAULT.createPoint(CRS_2D, 1,
2);
+ final Geometry line = GeometryFactory.DEFAULT.createLineString(
+ GeometryFactory.DEFAULT.createDataPoints(CRS_2D, 0,0, 10,0));
+ final GeometryCollection<Geometry> collection =
GeometryFactory.DEFAULT.createGeometryCollection(CRS_2D, point, line);
+ final List<Geometry> iterated = new ArrayList<>();
+ for (Geometry g : collection) {
+ iterated.add(g);
+ }
+ assertEquals(List.of(point, line), iterated);
+
+ final List<Geometry> remaining = new ArrayList<>();
+ final Iterator<Geometry> it = collection.iterator();
+ assertSame(point, it.next());
+ it.forEachRemaining(remaining::add);
+ assertEquals(List.of(line), remaining);
+ assertFalse(it.hasNext());
+ assertThrows(NoSuchElementException.class, it::next);
+
+ assertEquals(List.of(point, line), collection.stream().toList());
+ }
+
@Test
@Disabled("Not implemented yet.")
public void testGetGeometryN() {
diff --git
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/JTSAdapterTest.java
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/JTSAdapterTest.java
new file mode 100644
index 0000000000..f901bbaabd
--- /dev/null
+++
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/adapter/JTSAdapterTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.geometries.adapter;
+
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.apache.sis.geometries.DataPointsType;
+import org.apache.sis.geometries.Geometries;
+import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.curve.LineString;
+import org.apache.sis.referencing.CommonCRS;
+
+// Test dependencies
+import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.Test;
+
+
+/**
+ * Tests {@link JTSAdapter}.
+ *
+ * @author Johann Sorel (Geomatys)
+ */
+public class JTSAdapterTest {
+
+ private static final GeometryFactory GF = new GeometryFactory();
+
+ /**
+ * Tests that the CRS of a view over a JTS geometry can be relabeled,
+ * without modifying the coordinates nor the JTS geometry.
+ */
+ @Test
+ public void testRelabelView() {
+ final org.locationtech.jts.geom.LineString jts =
GF.createLineString(new Coordinate[] {
+ new Coordinate(1, 2), new Coordinate(3, 4)});
+ final Geometry view = JTSAdapter.fromJTS(jts, false);
+ assertInstanceOf(LineString.class, view);
+
assertTrue(Geometries.isUndefined(view.getCoordinateReferenceSystem()));
+
+
view.setCoordinateReferenceSystem(CommonCRS.WGS84.normalizedGeographic());
+ assertEquals(CommonCRS.WGS84.normalizedGeographic(),
view.getCoordinateReferenceSystem());
+ assertEquals(CommonCRS.WGS84.normalizedGeographic(),
+
view.getDataPoints().getType().getAttributeSystem(DataPointsType.ATT_POSITION).getCoordinateReferenceSystem());
+ assertArrayEquals(new double[] {1, 2, 3, 4},
+
view.getDataPoints().getAttributeArray(DataPointsType.ATT_POSITION).toArrayDouble());
+ assertNull(jts.getUserData());
+
+ // The view still reflects the JTS coordinates.
+ jts.getCoordinateSequence().setOrdinate(0, 0, 10);
+ assertEquals(10, view.getDataPoints().getPosition(0).get(0));
+
+ assertThrows(IllegalArgumentException.class,
+ () ->
view.setCoordinateReferenceSystem(CommonCRS.WGS84.geographic3D()));
+ }
+}
diff --git
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/ToPrimitiveTest.java
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/ToPrimitiveTest.java
index 71d17b02b0..9f83e4597e 100644
---
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/ToPrimitiveTest.java
+++
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/ToPrimitiveTest.java
@@ -35,7 +35,6 @@ import org.apache.sis.geometries.solid.polyhedron.Hexahedron;
import org.apache.sis.geometries.solid.polyhedron.Icosahedron;
import org.apache.sis.geometries.solid.polyhedron.Tetrahedron;
import org.apache.sis.geometries.mesh.MeshPrimitive;
-import org.apache.sis.geometries.mesh.MultiMeshPrimitive;
import org.apache.sis.maths.NDArrays;
import org.apache.sis.maths.Array;
import org.apache.sis.measure.NumberRange;
@@ -105,8 +104,8 @@ public class ToPrimitiveTest {
final var arc2 = f.createCircularString(f.createDataPoints(CRS2D,
20,0, 25,5, 30,0));
final Geometry result = new
GeometryProcessor().toPrimitive(f.createMultiCurve(CRS2D, arc1, arc2),
Quantities.create(1, Units.DEGREE), null);
- assertTrue(result instanceof MultiMeshPrimitive);
- for (final Object component : ((MultiMeshPrimitive<?>)
result).getComponents()) {
+ assertTrue(result instanceof GeometryCollection);
+ for (final Object component : (GeometryCollection<?>) result) {
final Array positions = ((MeshPrimitive) component).getPositions();
// A half circle of radius 5 is 15.7 long, so a spacing of 1 needs
at least 16 segments.
assertTrue(positions.getLength() >= 17, "Spacing not applied: " +
positions.getLength() + " points.");
@@ -124,8 +123,8 @@ public class ToPrimitiveTest {
f.createLineString(f.createDataPoints(CRS2D, 0,5, 10,5)));
assertEquals(MeshPrimitive.Type.LINES, ((MeshPrimitive) new
GeometryProcessor().toPrimitive(lines, null, null)).getType());
final Geometry result = new GeometryProcessor().toPrimitive(lines,
Quantities.create(2.5, Units.DEGREE), null);
- assertTrue(result instanceof MultiMeshPrimitive);
- for (final Object component : ((MultiMeshPrimitive<?>)
result).getComponents()) {
+ assertTrue(result instanceof GeometryCollection);
+ for (final Object component : (GeometryCollection<?>) result) {
assertEquals(5, ((MeshPrimitive)
component).getPositions().getLength());
}
}
@@ -499,8 +498,8 @@ public class ToPrimitiveTest {
final GeometryCollection<LineString> mlines =
GeometryFactory.DEFAULT.createMultiLineString(line1, line2);
final Geometry result = new
GeometryProcessor().toPrimitive(mlines, null, null);
- assertTrue(result instanceof MultiMeshPrimitive);
- final MultiMeshPrimitive mp = (MultiMeshPrimitive) result;
+ assertTrue(result instanceof GeometryCollection);
+ final GeometryCollection<?> mp = (GeometryCollection<?>) result;
assertEquals(2, mp.getNumGeometries());
assertTrue(mp.getGeometryN(0) instanceof MeshPrimitive);
assertTrue(mp.getGeometryN(1) instanceof MeshPrimitive);
@@ -594,7 +593,7 @@ public class ToPrimitiveTest {
result = processor.toPrimitive(f.createMultiLineString(CRS2D,
f.createLineString(attributedPoints(0,0, 1,1, 2,0)),
f.createLineString(attributedPoints(3,0, 4,1, 5,0))), null,
null);
- final MultiMeshPrimitive<?> multi =
assertInstanceOf(MultiMeshPrimitive.class, result);
+ final GeometryCollection<?> multi =
assertInstanceOf(GeometryCollection.class, result);
assertEquals(2, multi.getNumGeometries());
for (int i = 0; i < 2; i++) {
assertAttributes((MeshPrimitive) multi.getGeometryN(i), 3);
diff --git
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/TransformTest.java
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/TransformTest.java
index b1655ccc17..f9a27ae8fc 100644
---
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/TransformTest.java
+++
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/TransformTest.java
@@ -21,8 +21,9 @@ import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.opengis.util.FactoryException;
import org.apache.sis.geometries.Geometry;
+import org.apache.sis.geometries.GeometryCollection;
+import org.apache.sis.geometries.GeometryFactory;
import org.apache.sis.geometries.mesh.MeshPrimitive;
-import org.apache.sis.geometries.mesh.MultiMeshPrimitive;
import org.apache.sis.maths.NDArrays;
import org.apache.sis.referencing.CRS;
import org.apache.sis.referencing.CommonCRS;
@@ -122,8 +123,8 @@ public class TransformTest extends AbstractD9IMTest {
@Test
public void MultiPrimitive() throws FactoryException, TransformException {
- final MultiMeshPrimitive mp = new
MultiMeshPrimitive(createPrimitive());
- final MultiMeshPrimitive result = (MultiMeshPrimitive) new
GeometryProcessor().transform(mp, CRS_TARGET, TRANSFORM);
+ final GeometryCollection<MeshPrimitive> mp =
GeometryFactory.DEFAULT.createGeometryCollection(createPrimitive());
+ final GeometryCollection<?> result = (GeometryCollection<?>) new
GeometryProcessor().transform(mp, CRS_TARGET, TRANSFORM);
assertEquals(1, result.getNumGeometries());
testPrimitive((MeshPrimitive) result.getGeometryN(0));
}
diff --git
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/extrude/TerrainExtruderTest.java
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/extrude/TerrainExtruderTest.java
index e6dfc22cc0..770096fc59 100644
---
a/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/extrude/TerrainExtruderTest.java
+++
b/incubator/src/org.apache.sis.geometry/test/org/apache/sis/geometries/operation/extrude/TerrainExtruderTest.java
@@ -25,10 +25,10 @@ import java.util.Set;
import java.util.function.DoubleBinaryOperator;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.apache.sis.geometries.Geometries;
+import org.apache.sis.geometries.GeometryCollection;
import org.apache.sis.geometries.GeometryFactory;
import org.apache.sis.geometries.curve.LinearRing;
import org.apache.sis.geometries.mesh.MeshPrimitive;
-import org.apache.sis.geometries.mesh.MultiMeshPrimitive;
import
org.apache.sis.geometries.operation.extrude.TerrainExtruder.HeightReference;
import org.apache.sis.geometries.surface.Polygon;
import org.apache.sis.maths.Maths;
@@ -118,7 +118,7 @@ public class TerrainExtruderTest {
final TerrainExtruder extruder = new TerrainExtruder(terrain());
extruder.setSeparateParts(true);
extruder.appendFlatConstraint(polygon(FOOTPRINT), 20, 23,
HeightReference.ABSOLUTE, true);
- final MultiMeshPrimitive<MeshPrimitive.Triangles> result =
extruder.getResult();
+ final GeometryCollection<MeshPrimitive.Triangles> result =
extruder.getResult();
assertEquals(3, result.getNumGeometries());
final Mesh ground = new Mesh(result.getGeometryN(0));
final Mesh roof = new Mesh(result.getGeometryN(1));
@@ -322,7 +322,7 @@ public class TerrainExtruderTest {
final double[] positions;
final int[] index;
- Mesh(final MultiMeshPrimitive<MeshPrimitive.Triangles> result) {
+ Mesh(final GeometryCollection<MeshPrimitive.Triangles> result) {
this(single(result));
}
@@ -331,7 +331,7 @@ public class TerrainExtruderTest {
index = mesh.getIndex().toArrayInt();
}
- private static MeshPrimitive.Triangles single(final
MultiMeshPrimitive<MeshPrimitive.Triangles> result) {
+ private static MeshPrimitive.Triangles single(final
GeometryCollection<MeshPrimitive.Triangles> result) {
assertEquals(1, result.getNumGeometries(), "Parts are not
separated by default.");
return result.getGeometryN(0);
}