diff --git a/USING.md b/USING.md
index 0dae801426..6e2dbdf677 100644
--- a/USING.md
+++ b/USING.md
@@ -123,6 +123,7 @@ module org.foo.baz {
## JTS System Properties
* `-Djts.overlay=ng` enables the use of OverlayNG in `Geometry` overlay methods. (*Note: in a future release this will become the default behaviour*)
+* `-Djts.relate=ng` enables the use of RelateNG in `Geometry` topological predicate methods. (*Note: in a future release this will become the default behaviour*)
## JTS Tools
diff --git a/modules/core/src/main/java/org/locationtech/jts/geom/Geometry.java b/modules/core/src/main/java/org/locationtech/jts/geom/Geometry.java
index ba0d353fb2..104a885c8e 100644
--- a/modules/core/src/main/java/org/locationtech/jts/geom/Geometry.java
+++ b/modules/core/src/main/java/org/locationtech/jts/geom/Geometry.java
@@ -713,10 +713,7 @@ public boolean disjoint(Geometry g) {
* Returns false
if both Geometry
s are points
*/
public boolean touches(Geometry g) {
- // short-circuit test
- if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
- return false;
- return relate(g).isTouches(getDimension(), g.getDimension());
+ return GeometryRelate.touches(this, g);
}
/**
@@ -771,18 +768,8 @@ public boolean intersects(Geometry g) {
if (g.isRectangle()) {
return RectangleIntersects.intersects((Polygon) g, this);
}
- if (isGeometryCollection() || g.isGeometryCollection()) {
- for (int i = 0 ; i < getNumGeometries() ; i++) {
- for (int j = 0 ; j < g.getNumGeometries() ; j++) {
- if (getGeometryN(i).intersects(g.getGeometryN(j))) {
- return true;
- }
- }
- }
- return false;
- }
- // general case
- return relate(g).isIntersects();
+
+ return GeometryRelate.intersects(this, g);
}
/**
@@ -845,7 +832,7 @@ public boolean crosses(Geometry g) {
* @see Geometry#coveredBy
*/
public boolean within(Geometry g) {
- return g.contains(this);
+ return GeometryRelate.within(this, g);
}
/**
@@ -876,25 +863,13 @@ public boolean within(Geometry g) {
* @see Geometry#covers
*/
public boolean contains(Geometry g) {
- // optimization - lower dimension cannot contain areas
- if (g.getDimension() == 2 && getDimension() < 2) {
- return false;
- }
- // optimization - P cannot contain a non-zero-length L
- // Note that a point can contain a zero-length lineal geometry,
- // since the line has no boundary due to Mod-2 Boundary Rule
- if (g.getDimension() == 1 && getDimension() < 1 && g.getLength() > 0.0) {
- return false;
- }
- // optimization - envelope test
- if (! getEnvelopeInternal().contains(g.getEnvelopeInternal()))
- return false;
+
// optimization for rectangle arguments
if (isRectangle()) {
return RectangleContains.contains((Polygon) this, g);
}
// general case
- return relate(g).isContains();
+ return GeometryRelate.contains(this, g);
}
/**
@@ -919,10 +894,7 @@ public boolean contains(Geometry g) {
*@return true
if the two Geometry
s overlap.
*/
public boolean overlaps(Geometry g) {
- // short-circuit test
- if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
- return false;
- return relate(g).isOverlaps(getDimension(), g.getDimension());
+ return GeometryRelate.overlaps(this, g);
}
/**
@@ -960,24 +932,7 @@ public boolean overlaps(Geometry g) {
* @see Geometry#coveredBy
*/
public boolean covers(Geometry g) {
- // optimization - lower dimension cannot cover areas
- if (g.getDimension() == 2 && getDimension() < 2) {
- return false;
- }
- // optimization - P cannot cover a non-zero-length L
- // Note that a point can cover a zero-length lineal geometry
- if (g.getDimension() == 1 && getDimension() < 1 && g.getLength() > 0.0) {
- return false;
- }
- // optimization - envelope test
- if (! getEnvelopeInternal().covers(g.getEnvelopeInternal()))
- return false;
- // optimization for rectangle arguments
- if (isRectangle()) {
- // since we have already tested that the test envelope is covered
- return true;
- }
- return relate(g).isCovers();
+ return GeometryRelate.covers(this, g);
}
/**
@@ -1010,7 +965,7 @@ public boolean covers(Geometry g) {
* @see Geometry#covers
*/
public boolean coveredBy(Geometry g) {
- return g.covers(this);
+ return GeometryRelate.coveredBy(this, g);
}
/**
@@ -1037,7 +992,7 @@ public boolean coveredBy(Geometry g) {
* @see IntersectionMatrix
*/
public boolean relate(Geometry g, String intersectionPattern) {
- return relate(g).matches(intersectionPattern);
+ return GeometryRelate.relate(this, g, intersectionPattern);
}
/**
@@ -1048,9 +1003,7 @@ public boolean relate(Geometry g, String intersectionPattern) {
* boundaries and exteriors of the two Geometry
s
*/
public IntersectionMatrix relate(Geometry g) {
- checkNotGeometryCollection(this);
- checkNotGeometryCollection(g);
- return RelateOp.relate(this, g);
+ return GeometryRelate.relate(this, g);
}
/**
@@ -1101,10 +1054,7 @@ public boolean equals(Geometry g) {
*/
public boolean equalsTopo(Geometry g)
{
- // short-circuit test
- if (! getEnvelopeInternal().equals(g.getEnvelopeInternal()))
- return false;
- return relate(g).isEquals(getDimension(), g.getDimension());
+ return GeometryRelate.equalsTopo(this, g);
}
/**
diff --git a/modules/core/src/main/java/org/locationtech/jts/geom/GeometryRelate.java b/modules/core/src/main/java/org/locationtech/jts/geom/GeometryRelate.java
new file mode 100644
index 0000000000..615e7d1ab8
--- /dev/null
+++ b/modules/core/src/main/java/org/locationtech/jts/geom/GeometryRelate.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2020 Martin Davis.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
+ * and the Eclipse Distribution License is available at
+ *
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ */
+package org.locationtech.jts.geom;
+
+import org.locationtech.jts.operation.relate.RelateOp;
+import org.locationtech.jts.operation.relateng.RelateNG;
+import org.locationtech.jts.operation.relateng.RelatePredicate;
+
+/**
+ * Internal class which encapsulates the runtime switch to use RelateNG.
+ *
+ * This class allows the {@link Geometry} predicate methods to be
+ * switched between the original {@link RelateOp} algorithm
+ * and the modern {@link RelateNG} codebase
+ * via a system property jts.relate
.
+ *
jts.relate=old
- (default) use original RelateOp algorithm
+ * jts.relate=ng
- use RelateNG
+ *