From dc8f9f582fb01b536299e752e89f61a645a2614c Mon Sep 17 00:00:00 2001 From: Jody Garnett Date: Fri, 23 Aug 2024 15:31:15 -0700 Subject: [PATCH] Add Coordinates.cast(coordinate,dim,measure) to help with mixed dimension operations --- .../jts/algorithm/LineIntersector.java | 14 ++- .../jts/algorithm/RobustLineIntersector.java | 10 ++- .../locationtech/jts/geom/Coordinates.java | 87 ++++++++++++++++++- .../jts/algorithm/IntersectionTest.java | 4 +- 4 files changed, 105 insertions(+), 10 deletions(-) diff --git a/modules/core/src/main/java/org/locationtech/jts/algorithm/LineIntersector.java b/modules/core/src/main/java/org/locationtech/jts/algorithm/LineIntersector.java index 4ec1190d5e..a9074e3851 100644 --- a/modules/core/src/main/java/org/locationtech/jts/algorithm/LineIntersector.java +++ b/modules/core/src/main/java/org/locationtech/jts/algorithm/LineIntersector.java @@ -15,6 +15,7 @@ * @version 1.7 */ import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Coordinates; import org.locationtech.jts.geom.PrecisionModel; import org.locationtech.jts.io.WKTWriter; import org.locationtech.jts.util.Assert; @@ -217,10 +218,15 @@ protected boolean isCollinear() { public void computeIntersection( Coordinate p1, Coordinate p2, Coordinate p3, Coordinate p4) { - inputLines[0][0] = p1; - inputLines[0][1] = p2; - inputLines[1][0] = p3; - inputLines[1][1] = p4; + + int dimension = Coordinates.dimension(p1,p2,p3,p4); + int measures = Coordinates.measures(p1,p2,p3,p4); + + inputLines[0][0] = p1 = Coordinates.cast(p1,dimension,measures); + inputLines[0][1] = p2 = Coordinates.cast(p2,dimension,measures); + inputLines[1][0] = p3 = Coordinates.cast(p3,dimension,measures); + inputLines[1][1] = p4 = Coordinates.cast(p4,dimension,measures); + result = computeIntersect(p1, p2, p3, p4); //numIntersects++; } 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 92ed60715f..f4a57a243d 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 @@ -215,8 +215,14 @@ 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) && Coordinates.hasZ(pCopy)) { - pCopy.setZ(z); + if (! Double.isNaN(z)) { + if (Coordinates.hasZ(pCopy)) { + pCopy.setZ(z); + } + else { + // warning: this value cannot be accessed + pCopy.z = 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 a7e79628f0..88f6b4cfd9 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 @@ -46,6 +46,39 @@ public static Coordinate create(int dimension, int measures) } return new Coordinate(); } + + /** + * Cast coordinate to required dimension and measure, only creating a new object if required. + * @param coordinate + * @param dimension + * @param measures + * @return coordinate of the requested dimension and measure + */ + public static Coordinate cast( Coordinate coordinate, int dimension, int measures ) + { + if (dimension == 2) { + if (coordinate instanceof CoordinateXY) + return coordinate; + else + return new CoordinateXY( coordinate.getX(), coordinate.getY() ); + } else if (dimension == 3 && measures == 0) { + if (coordinate.getClass() == Coordinate.class) + return coordinate; + else + return new Coordinate( coordinate.getX(), coordinate.getY(), coordinate.getZ() ); + } else if (dimension == 3 && measures == 1) { + if (coordinate instanceof CoordinateXYM) + return coordinate; + else + return new CoordinateXYM( coordinate.getX(), coordinate.getY(), coordinate.getM() ); + } else if (dimension == 4 && measures == 1) { + if (coordinate instanceof CoordinateXYZM) + return coordinate; + else + return new CoordinateXYZM(coordinate.getX(), coordinate.getY(), coordinate.getZ(), coordinate.getM() ); + } + return coordinate; + } /** * Determine dimension based on subclass of {@link Coordinate}. @@ -68,7 +101,22 @@ public static int dimension(Coordinate coordinate) } /** - * Check if coordinate can store Z valye, based on subclass of {@link Coordinate}. + * Determine dimension based on subclass of {@link Coordinate}. + * + * @param coordinates supplied coordinate + * @return number of ordinates recorded + */ + public static int dimension(Coordinate... coordinates) + { + int dimension = 2; + for (Coordinate coordinate : coordinates) { + dimension = Math.max(dimension,dimension(coordinate)); + } + return dimension; + } + + /** + * Check if coordinate can store Z ordinate, based on subclass of {@link Coordinate}. * * @param coordinate supplied coordinate * @return true if setZ is available @@ -87,6 +135,26 @@ public static boolean hasZ(Coordinate coordinate) return true; } + /** + * Check if coordinate can store M value, based on subclass of {@link Coordinate}. + * + * @param coordinate supplied coordinate + * @return true if setM is available + */ + public static boolean hasM(Coordinate coordinate) + { + if (coordinate instanceof CoordinateXY) { + return false; + } else if (coordinate instanceof CoordinateXYM) { + return true; + } else if (coordinate instanceof CoordinateXYZM) { + return true; + } else if (coordinate instanceof Coordinate) { + return false; + } + return false; + } + /** * Determine number of measures based on subclass of {@link Coordinate}. * @@ -106,5 +174,20 @@ public static int measures(Coordinate coordinate) } return 0; } - + + /** + * Determine dimension based on subclass of {@link Coordinate}. + * + * @param coordinates supplied coordinate + * @return number of ordinates recorded + */ + public static int measures(Coordinate... coordinates) + { + int measures = 0; + for (Coordinate coordinate : coordinates) { + measures = Math.max(measures,measures(coordinate)); + } + return measures; + } + } 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 be0785320a..a90f0d0dc9 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 @@ -85,7 +85,6 @@ public void testIntersectionXY() throws Exception { 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); - assertNotNull(clipped1); // intersection with dim 3, dim 2 GeometryFactory gf = poly1.getFactory(); @@ -111,7 +110,8 @@ public void testIntersectionXY() throws Exception { Polygon fence = gf.createPolygon(bounds, null); Geometry clipped2 = poly1.intersection(fence); - assertNotNull(clipped2); + + assertTrue( clipped1.equals(clipped2)); } //==================================================