diff --git a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateGeometry.java b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateGeometry.java index 610726fb80..262e4bced8 100644 --- a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateGeometry.java +++ b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateGeometry.java @@ -245,11 +245,32 @@ public int locateWithDim(Coordinate pt) { return loc; } - public boolean isPointsOrPolygons() { - return geom instanceof Point + /** + * Indicates whether the geometry requires self-noding + * for correct evaluation of specific spatial predicates. + * Self-noding is required for geometries which may self-cross + * - i.e. lines, and overlapping polygons in GeometryCollections. + * Self-noding is not required for polygonal geometries, + * since they can only touch at vertices. + * This ensures that the coordinates of nodes created by + * crossing segments are computed explicitly. + * This ensures that node locations match in situations + * where a self-crossing and mutual crossing occur at the same logical location. + * E.g. a self-crossing line tested against a single segment + * identical to one of the crossed segments. + * + * @return true if self-noding is required for this geometry + */ + public boolean isSelfNodingRequired() { + if (geom instanceof Point || geom instanceof MultiPoint || geom instanceof Polygon - || geom instanceof MultiPolygon; + || geom instanceof MultiPolygon) + return false; + //-- GC with a single polygon does not need noding + if (hasAreas && geom.getNumGeometries() == 1) + return false; + return true; } /** diff --git a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyComputer.java b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyComputer.java index b9e12fb927..6e04d0e504 100644 --- a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyComputer.java +++ b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyComputer.java @@ -119,8 +119,9 @@ public boolean isAreaArea() { * for correct evaluation of specific spatial predicates. * Self-noding is required for geometries which may self-cross * - i.e. lines, and overlapping polygons in GeometryCollections. - * Self-noding is not required for polygonal geometries. - * This ensures that the locations of nodes created by + * Self-noding is not required for polygonal geometries, + * since they can only touch at vertices. + * This ensures that the coordinates of nodes created by * crossing segments are computed explicitly. * This ensures that node locations match in situations * where a self-crossing and mutual crossing occur at the same logical location. @@ -130,9 +131,8 @@ public boolean isAreaArea() { * @return true if self-noding is required */ public boolean isSelfNodingRequired() { - //TODO: change to testing for lines or GC with > 1 polygon - if (geomA.isPointsOrPolygons()) return false; - if (geomB.isPointsOrPolygons()) return false; + if (geomA.isSelfNodingRequired()) return true; + if (geomB.isSelfNodingRequired()) return true; return predicate.requireSelfNoding(); } @@ -141,6 +141,7 @@ public boolean isExteriorCheckRequired(boolean isA) { } private void updateDim(int locA, int locB, int dimension) { + //System.out.println(Location.toLocationSymbol(locA) + "/" + Location.toLocationSymbol(locB) + ": " + dimension); predicate.updateDimension(locA, locB, dimension); } diff --git a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyPredicateTracer.java b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyPredicateTracer.java index 1fb3f69cb8..46d1c3ac7a 100644 --- a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyPredicateTracer.java +++ b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyPredicateTracer.java @@ -51,6 +51,10 @@ public boolean requireSelfNoding() { return pred.requireSelfNoding(); } + public boolean requireInteraction() { + return pred.requireInteraction(); + } + @Override public boolean requireCovers(boolean isSourceA) { return pred.requireCovers(isSourceA); diff --git a/modules/core/src/test/java/org/locationtech/jts/operation/relateng/RelateNGGCTest.java b/modules/core/src/test/java/org/locationtech/jts/operation/relateng/RelateNGGCTest.java index b63193f174..18be3890f7 100644 --- a/modules/core/src/test/java/org/locationtech/jts/operation/relateng/RelateNGGCTest.java +++ b/modules/core/src/test/java/org/locationtech/jts/operation/relateng/RelateNGGCTest.java @@ -214,5 +214,17 @@ public void testEmptyMultiPointElements() { checkIntersectsDisjoint(a, b, true); } + public void testPolygonContainingPointsInBoundary() { + String a = "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))"; + String b = "GEOMETRYCOLLECTION (POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0)), MULTIPOINT ((0 2), (0 5)))"; + checkEquals(a, b, true); + } + + public void testPolygonContainingLineInBoundary() { + String a = "POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))"; + String b = "GEOMETRYCOLLECTION (POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0)), LINESTRING (0 2, 0 5))"; + checkEquals(a, b, true); + } + }