From 61772006197f10f4ad0cbf075e79ac337c9e0b15 Mon Sep 17 00:00:00 2001 From: Jody Garnett Date: Fri, 23 Aug 2024 13:47:11 -0700 Subject: [PATCH] RobustLineIntersector defensive copyWithZ check Defensive check prevents copyWithZ, copyWithZInterpolate methods from throwing an exception when the target coordinate is CoordinateXY or CoordinateXYM. This is in addition to the existing defensive check to avoid doing anything if the z vale was Double.NaN. --- .../jts/algorithm/RobustLineIntersector.java | 8 +++- .../locationtech/jts/geom/Coordinates.java | 20 +++++++++ .../jts/algorithm/IntersectionTest.java | 43 +++++++++++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/locationtech/jts/algorithm/RobustLineIntersector.java b/modules/core/src/main/java/org/locationtech/jts/algorithm/RobustLineIntersector.java index 21a5891773..92ed60715f 100644 --- a/modules/core/src/main/java/org/locationtech/jts/algorithm/RobustLineIntersector.java +++ b/modules/core/src/main/java/org/locationtech/jts/algorithm/RobustLineIntersector.java @@ -15,6 +15,10 @@ *@version 1.7 */ import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.CoordinateXY; +import org.locationtech.jts.geom.CoordinateXYM; +import org.locationtech.jts.geom.CoordinateXYZM; +import org.locationtech.jts.geom.Coordinates; import org.locationtech.jts.geom.Envelope; /** @@ -211,8 +215,8 @@ private static Coordinate copyWithZInterpolate(Coordinate p, Coordinate p1, Coor private static Coordinate copyWithZ(Coordinate p, double z) { Coordinate pCopy = copy(p); - if (! Double.isNaN(z)) { - pCopy.setZ( z ); + if (! Double.isNaN(z) && Coordinates.hasZ(pCopy)) { + pCopy.setZ(z); } return pCopy; } diff --git a/modules/core/src/main/java/org/locationtech/jts/geom/Coordinates.java b/modules/core/src/main/java/org/locationtech/jts/geom/Coordinates.java index 71f5b186f9..a7e79628f0 100644 --- a/modules/core/src/main/java/org/locationtech/jts/geom/Coordinates.java +++ b/modules/core/src/main/java/org/locationtech/jts/geom/Coordinates.java @@ -67,6 +67,26 @@ public static int dimension(Coordinate coordinate) return 3; } + /** + * Check if coordinate can store Z valye, based on subclass of {@link Coordinate}. + * + * @param coordinate supplied coordinate + * @return true if setZ is available + */ + public static boolean hasZ(Coordinate coordinate) + { + if (coordinate instanceof CoordinateXY) { + return false; + } else if (coordinate instanceof CoordinateXYM) { + return false; + } else if (coordinate instanceof CoordinateXYZM) { + return true; + } else if (coordinate instanceof Coordinate) { + return true; + } + return true; + } + /** * Determine number of measures based on subclass of {@link Coordinate}. * diff --git a/modules/core/src/test/java/org/locationtech/jts/algorithm/IntersectionTest.java b/modules/core/src/test/java/org/locationtech/jts/algorithm/IntersectionTest.java index c26af8b92f..4bd8aa02c9 100644 --- a/modules/core/src/test/java/org/locationtech/jts/algorithm/IntersectionTest.java +++ b/modules/core/src/test/java/org/locationtech/jts/algorithm/IntersectionTest.java @@ -4,6 +4,14 @@ import junit.framework.TestCase; import junit.textui.TestRunner; +import org.locationtech.jts.geom.CoordinateSequence; +import org.locationtech.jts.geom.CoordinateSequenceFactory; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.LinearRing; +import org.locationtech.jts.geom.Polygon; +import org.locationtech.jts.geom.impl.CoordinateArraySequenceFactory; +import org.locationtech.jts.io.WKTReader; public class IntersectionTest extends TestCase { private static final double MAX_ABS_ERROR = 1e-5; @@ -71,6 +79,41 @@ public void testLineSegNone() { checkIntersectionLineSegmentNull( 0, 0, 0, 1, 2, 9, 1, 9 ); } + public void testIntersectionXY() throws Exception { + // intersection with dim 3 x dim3 + WKTReader reader = new WKTReader(); + Geometry poly1 = reader.read("POLYGON((0 0 0, 0 10000 2, 10000 10000 2, 10000 0 0, 0 0 0))"); + Geometry clipArea = reader.read("POLYGON((0 0, 0 2500, 2500 2500, 2500 0, 0 0))"); + Geometry clipped1 = poly1.intersection(clipArea); + + // intersection with dim 3 x dim 2 + GeometryFactory gf = poly1.getFactory(); + CoordinateSequenceFactory csf = gf.getCoordinateSequenceFactory(); + double xmin = 0.0; + double xmax = 2500.0; + double ymin = 0.0; + double ymax = 2500.0; + + CoordinateSequence cs = csf.create(5,2); + cs.setOrdinate(0, 0, xmin); + cs.setOrdinate(0, 1, ymin); + cs.setOrdinate(1, 0, xmin); + cs.setOrdinate(1, 1, ymax); + cs.setOrdinate(2, 0, xmax); + cs.setOrdinate(2, 1, ymax); + cs.setOrdinate(3, 0, xmax); + cs.setOrdinate(3, 1, ymin); + cs.setOrdinate(4, 0, xmin); + cs.setOrdinate(4, 1, ymin); + + LinearRing bounds = gf.createLinearRing(cs); + + Polygon fence = gf.createPolygon(bounds, null); + Geometry clipped2 = poly1.intersection(fence); + + assertTrue(clipped1.equals(clipped2)); + } + //================================================== private void checkIntersection(double p1x, double p1y, double p2x, double p2y,