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 7d72c08606 fix(JTS): compute 3D and 4D envelopes in JTS geometry
Wrapper.getEnvelope() method
7d72c08606 is described below
commit 7d72c0860651801a6f770a20c21265a62bc01a49
Author: jsorel <[email protected]>
AuthorDate: Wed Jun 10 14:44:04 2026 +0200
fix(JTS): compute 3D and 4D envelopes in JTS geometry Wrapper.getEnvelope()
method
---
.../apache/sis/geometry/wrapper/jts/Wrapper.java | 86 ++++++++++++++++------
.../apache/sis/geometry/wrapper/jts/JTSTest.java | 8 +-
2 files changed, 68 insertions(+), 26 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/geometry/wrapper/jts/Wrapper.java
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/geometry/wrapper/jts/Wrapper.java
index 3b1bc00fb5..cd670f0c8f 100644
---
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/geometry/wrapper/jts/Wrapper.java
+++
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/geometry/wrapper/jts/Wrapper.java
@@ -147,7 +147,7 @@ final class Wrapper extends GeometryWrapper {
*/
@Override
public int getCoordinateDimension() {
- return getCoordinatesDimension(geometry);
+ return getCoordinatesDimension(geometry, null);
}
/**
@@ -155,36 +155,64 @@ final class Wrapper extends GeometryWrapper {
* Note that this is different than the {@linkplain
Geometry#getDimension() geometry topological dimension},
* which can be 0, 1 or 2.
*
- * @param geometry the geometry for which to get <em>vertex</em> (not
topological) dimension.
+ * @param geometry the geometry for which to get <em>vertex</em> (not
topological) dimension.
+ * @param bounds if defined, compute bounds, array must be of size 8 for
[minX,minY,minZ,minM,maxX,maxY,maxZ,maxM]
* @return vertex dimension of the given geometry.
* @throws IllegalArgumentException if the type of the given geometry is
not recognized.
*/
- private static int getCoordinatesDimension(final Geometry geometry) {
- final CoordinateSequence cs;
+ private static int getCoordinatesDimension(final Geometry geometry,
Double[] bounds) {
+ int dim = 0;
if (geometry instanceof Point) {
// Most efficient method (no allocation) in JTS 1.18.
- cs = ((Point) geometry).getCoordinateSequence();
+ dim = getCoordinatesDimension(dim, ((Point)
geometry).getCoordinateSequence(), bounds);
} else if (geometry instanceof LineString) {
// Most efficient method (no allocation) in JTS 1.18.
- cs = ((LineString) geometry).getCoordinateSequence();
+ dim = getCoordinatesDimension(dim, ((LineString)
geometry).getCoordinateSequence(), bounds);
} else if (geometry instanceof Polygon) {
- return getCoordinatesDimension(((Polygon)
geometry).getExteriorRing());
+ final Polygon polygon = (Polygon) geometry;
+ dim = getCoordinatesDimension(dim, ((LineString)
polygon.getExteriorRing()).getCoordinateSequence(), bounds);
+ for (int i = 0, n = polygon.getNumInteriorRing(); i < n; i++) {
+ dim = getCoordinatesDimension(dim, ((LineString)
polygon.getInteriorRingN(i)).getCoordinateSequence(), bounds);
+ }
+
} else if (geometry instanceof GeometryCollection) {
final GeometryCollection gc = (GeometryCollection) geometry;
final int n = gc.getNumGeometries();
if (n == 0) {
- return Factory.TRIDIMENSIONAL; // Undefined coordinates,
JTS assumes 3 for empty geometries.
+ dim = Factory.TRIDIMENSIONAL;// Undefined coordinates, JTS
assumes 3 for empty geometries.
}
- for (int i=0; i<n; i++) {
- // If at least one geometry is 3D, consider the whole geometry
as 3D.
- final int d = getCoordinatesDimension(gc.getGeometryN(i));
- if (d > Factory.BIDIMENSIONAL) return d;
+ for (int i = 0; i < n; i++) {
+ dim = Math.max(dim,
getCoordinatesDimension(gc.getGeometryN(i), bounds));
}
- return Factory.BIDIMENSIONAL;
} else {
throw new
IllegalArgumentException(Errors.format(Errors.Keys.UnknownType_1,
geometry.getGeometryType()));
}
- return cs.getDimension();
+ return dim;
+ }
+
+ /**
+ * Get dimension and bounds of coordinate sequence.
+ *
+ * @param dim previously computed dimension
+ * @param cs the coordinate sequence for which to get <em>vertex</em> (not
topological) dimension and bounds
+ * @param bounds if defined, compute bounds, array must be of size 8 for
[minX,minY,minZ,minM,maxX,maxY,maxZ,maxM]
+ * @return coordinate sequence dimension or previous dimension, returning
the largest one.
+ */
+ private static int getCoordinatesDimension(int dim, CoordinateSequence cs,
Double[] bounds) {
+ final int dimension = cs.getDimension();
+ if (bounds != null) {
+ for (int i = 0, d = 0, n = cs.size(); i < n; d++) {
+ if (d == dimension) {d = -1; i++; continue;}
+ final double val = cs.getOrdinate(i, d);
+ //check min
+ if (bounds[d] == null) bounds[d] = val;
+ else if (!bounds[d].isNaN()) bounds[d] = Double.min(bounds[d],
val);
+ //check max
+ if (bounds[d+4] == null) bounds[d+4] = val;
+ else if (!bounds[d+4].isNaN()) bounds[d+4] =
Double.max(bounds[d+4], val);
+ }
+ }
+ return Math.max(dim, dimension);
}
/**
@@ -195,15 +223,29 @@ final class Wrapper extends GeometryWrapper {
*/
@Override
public GeneralEnvelope getEnvelope() {
- final Envelope bounds = geometry.getEnvelopeInternal();
- final CoordinateReferenceSystem crs = getCoordinateReferenceSystem();
- final var env = (crs != null) ? new GeneralEnvelope(crs) : new
GeneralEnvelope(Factory.BIDIMENSIONAL);
- env.setToNaN();
- if (!bounds.isNull()) {
- env.setRange(0, bounds.getMinX(), bounds.getMaxX());
- env.setRange(1, bounds.getMinY(), bounds.getMaxY());
+ if (crs != null && crs.getCoordinateSystem().getDimension() == 2) {
+ //we can use JTS envelope internal
+ final Envelope bounds = geometry.getEnvelopeInternal();
+ final var env = new GeneralEnvelope(crs);
+ env.setToNaN();
+ if (!bounds.isNull()) {
+ env.setRange(0, bounds.getMinX(), bounds.getMaxX());
+ env.setRange(1, bounds.getMinY(), bounds.getMaxY());
+ }
+ return env;
+ } else {
+ //geometry has unknown or more then 2 dimensions
+ final Double[] bounds = new Double[8];
+ final int dim = getCoordinatesDimension(geometry, bounds);
+ final var env = (crs != null) ? new GeneralEnvelope(crs) : new
GeneralEnvelope(dim);
+ env.setToNaN();
+ for (int i = 0, n = Math.min(dim, env.getDimension()); i < n; i++)
{
+ if (bounds[i] != null){
+ env.setRange(i, bounds[i], bounds[i+4]);
+ }
+ }
+ return env;
}
- return env;
}
/**
diff --git
a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/geometry/wrapper/jts/JTSTest.java
b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/geometry/wrapper/jts/JTSTest.java
index 2cd4f17eea..4c38c1cf32 100644
---
a/endorsed/src/org.apache.sis.feature/test/org/apache/sis/geometry/wrapper/jts/JTSTest.java
+++
b/endorsed/src/org.apache.sis.feature/test/org/apache/sis/geometry/wrapper/jts/JTSTest.java
@@ -161,8 +161,8 @@ public final class JTSTest extends TestCase {
{ /*
* Test 3D Envelope on a 3 dimensional geometry.
*
- * TODO: JTS does not set the Z values for geometry internal
envelope.
- * Should we loop over all coordinates in the geometry?
+ * JTS does not set the Z values for geometry internal envelope.
+ * Our implementation loops on the coordinates to find it
*/
final CoordinateReferenceSystem crs =
CommonCRS.WGS84.geographic3D();
final Geometry geometry = factory.createPoint(new Coordinate(5, 6,
7));
@@ -170,8 +170,8 @@ public final class JTSTest extends TestCase {
wrapper.setCoordinateReferenceSystem(crs);
final GeneralEnvelope envelope = wrapper.getEnvelope();
assertEquals(crs, envelope.getCoordinateReferenceSystem());
- assertArrayEquals(new double[] {5, 6, Double.NaN},
envelope.getLowerCorner().getCoordinates());
- assertArrayEquals(new double[] {5, 6, Double.NaN},
envelope.getUpperCorner().getCoordinates());
+ assertArrayEquals(new double[] {5, 6, 7},
envelope.getLowerCorner().getCoordinates());
+ assertArrayEquals(new double[] {5, 6, 7},
envelope.getUpperCorner().getCoordinates());
}
}