This is an automated email from the ASF dual-hosted git repository. jsorel pushed a commit to branch fix/jts3d in repository https://gitbox.apache.org/repos/asf/sis.git
commit fbff2d9963e1a2ccbd519f390860b26ca66041d8 Author: jsorel <johann.so...@geomatys.com> AuthorDate: Wed Nov 24 15:50:43 2021 +0100 fix(JTS): check crs and geometry dimensions compatibility on affectation --- .../apache/sis/internal/feature/jts/Wrapper.java | 34 ++++++ .../apache/sis/internal/feature/jts/JTSTest.java | 114 +++++++++++++++++++++ 2 files changed, 148 insertions(+) diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/Wrapper.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/Wrapper.java index 5892025..5c52319 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/Wrapper.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/jts/Wrapper.java @@ -64,6 +64,7 @@ import org.locationtech.jts.simplify.TopologyPreservingSimplifier; // Branch-dependent imports import org.opengis.filter.SpatialOperatorName; import org.opengis.filter.DistanceOperatorName; +import org.opengis.geometry.MismatchedDimensionException; /** @@ -154,6 +155,11 @@ final class Wrapper extends GeometryWrapper<Geometry> { if (dimension != Factory.BIDIMENSIONAL) { ArgumentChecks.ensureDimensionMatches("crs", (dimension <= Factory.BIDIMENSIONAL) ? Factory.BIDIMENSIONAL : 3, crs); + final int coordsDim = getCoordinatesDimension(geometry); + if (coordsDim < dimension) { + throw new MismatchedDimensionException(Errors.format( + Errors.Keys.MismatchedDimension_3, "crs", coordsDim, dimension)); + } } JTS.setCoordinateReferenceSystem(geometry, crs); } @@ -692,4 +698,32 @@ add: for (Geometry next = geometry;;) { public String formatWKT(final double flatness) { return geometry.toText(); } + + /** + * Extract geometry coordinates dimension. + */ + private static int getCoordinatesDimension(Geometry geometry) { + switch (geometry.getGeometryType()) { + case Geometry.TYPENAME_POINT : + return ((Point) geometry).getCoordinateSequence().getDimension(); + case Geometry.TYPENAME_LINESTRING : + case Geometry.TYPENAME_LINEARRING : + return ((LineString) geometry).getCoordinateSequence().getDimension(); + case Geometry.TYPENAME_POLYGON : + return getCoordinatesDimension(((Polygon) geometry).getExteriorRing()); + case Geometry.TYPENAME_MULTIPOINT : + case Geometry.TYPENAME_MULTILINESTRING : + case Geometry.TYPENAME_MULTIPOLYGON : + case Geometry.TYPENAME_GEOMETRYCOLLECTION : + final GeometryCollection gc = (GeometryCollection) geometry; + if (gc.getNumGeometries() == 0) { + //undefined coordinates, JTS assume 3 for empty geometries. + return 3; + } else { + return getCoordinatesDimension(gc.getGeometryN(0)); + } + default : + throw new IllegalArgumentException("Unexpected JTS geometry type " + geometry.getGeometryType()); + } + } } diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/jts/JTSTest.java b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/jts/JTSTest.java index 3a1c386..265c58d 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/jts/JTSTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/jts/JTSTest.java @@ -17,14 +17,19 @@ package org.apache.sis.internal.feature.jts; import java.util.Collections; +import org.apache.sis.geometry.GeneralEnvelope; +import org.opengis.geometry.MismatchedDimensionException; import org.opengis.util.FactoryException; import org.opengis.referencing.operation.TransformException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.locationtech.jts.geom.Point; import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.CoordinateXY; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.GeometryFactory; import org.apache.sis.referencing.CommonCRS; +import org.apache.sis.internal.feature.Geometries; +import org.apache.sis.internal.feature.GeometryWrapper; import org.apache.sis.internal.referencing.j2d.AffineTransform2D; import org.apache.sis.test.TestCase; import org.junit.Test; @@ -72,6 +77,115 @@ public final strictfp class JTSTest extends TestCase { } /** + * Tests {@link Wrapper#setCoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem)}. + * + * @throws FactoryException if an EPSG code can not be resolved. + */ + @Test + public void testSetCoordinateReferenceSystem() throws FactoryException { + final GeometryFactory factory = new GeometryFactory(); + + { /* + * Test set a 2D CRS on a 2 dimensions geometry. + */ + final CoordinateReferenceSystem crs = CommonCRS.ED50.geographic(); + final Geometry geometry = factory.createPoint(new CoordinateXY(5, 6)); + final GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get(); + wrapper.setCoordinateReferenceSystem(crs); + assertEquals(crs, wrapper.getCoordinateReferenceSystem()); + } + + { /* + * Test set a 2D CRS on a 3 dimensions geometry. + * This case is tolerate for backward compatibility. + */ + final CoordinateReferenceSystem crs = CommonCRS.ED50.geographic(); + final Geometry geometry = factory.createPoint(new Coordinate(5, 6, 7)); + final GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get(); + wrapper.setCoordinateReferenceSystem(crs); + assertEquals(crs, wrapper.getCoordinateReferenceSystem()); + } + + { /* + * Test set a 3D CRS on a 3 dimensions geometry. + */ + final CoordinateReferenceSystem crs = CommonCRS.WGS84.geographic3D(); + final Geometry geometry = factory.createPoint(new Coordinate(5, 6, 7)); + final GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get(); + wrapper.setCoordinateReferenceSystem(crs); + assertEquals(crs, wrapper.getCoordinateReferenceSystem()); + } + + { /* + * Test set a 3D CRS on a 2 dimensions geometry. + */ + final CoordinateReferenceSystem crs = CommonCRS.WGS84.geographic3D(); + final Geometry geometry = factory.createPoint(new CoordinateXY(5, 6)); + GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get(); + try { + wrapper.setCoordinateReferenceSystem(crs); + fail("Setting a 3D crs on a 2D geometry must fail"); + } catch (MismatchedDimensionException ex) { + //ok + } + } + } + + /** + * Tests {@link Wrapper#getEnvelope()}. + * + * @throws FactoryException if an EPSG code can not be resolved. + */ + @Test + public void testGetEnvelope() throws FactoryException { + final GeometryFactory factory = new GeometryFactory(); + + { /* + * Test 2D Envelope on a 2 dimensions geometry. + */ + final CoordinateReferenceSystem crs = CommonCRS.ED50.geographic(); + final Geometry geometry = factory.createPoint(new CoordinateXY(5, 6)); + final GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get(); + wrapper.setCoordinateReferenceSystem(crs); + final GeneralEnvelope envelope = wrapper.getEnvelope(); + assertEquals(crs, envelope.getCoordinateReferenceSystem()); + assertArrayEquals(new double[]{5, 6}, envelope.getLowerCorner().getCoordinate(), STRICT); + assertArrayEquals(new double[]{5, 6}, envelope.getUpperCorner().getCoordinate(), STRICT); + } + + { /* + * Test 2D Envelope on a 3 dimensions geometry. + * This case is tolerate for backward compatibility. + */ + final CoordinateReferenceSystem crs = CommonCRS.ED50.geographic(); + final Geometry geometry = factory.createPoint(new Coordinate(5, 6, 7)); + final GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get(); + wrapper.setCoordinateReferenceSystem(crs); + final GeneralEnvelope envelope = wrapper.getEnvelope(); + assertEquals(crs, envelope.getCoordinateReferenceSystem()); + assertArrayEquals(new double[]{5, 6}, envelope.getLowerCorner().getCoordinate(), STRICT); + assertArrayEquals(new double[]{5, 6}, envelope.getUpperCorner().getCoordinate(), STRICT); + } + + { /* + * Test 3D Envelope on a 3 dimensions geometry. + * TODO : JTS do not return 3D envelopes for geoemtry internal envelope + * should we loop on the full geometry ? + */ + /* + final CoordinateReferenceSystem crs = CommonCRS.WGS84.geographic3D(); + final Geometry geometry = factory.createPoint(new Coordinate(5, 6, 7)); + final GeometryWrapper<?> wrapper = Geometries.wrap(geometry).get(); + wrapper.setCoordinateReferenceSystem(crs); + final GeneralEnvelope envelope = wrapper.getEnvelope(); + assertEquals(crs, envelope.getCoordinateReferenceSystem()); + assertArrayEquals(new double[]{5, 6, 7}, envelope.getLowerCorner().getCoordinate(), STRICT); + assertArrayEquals(new double[]{5, 6, 7}, envelope.getUpperCorner().getCoordinate(), STRICT); + */ + } + } + + /** * Tests various {@code transform} methods. This includes (sometime indirectly): * * <ul>