Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RelateNG algorithm for DE-9IM relationship evaluation #1052

Merged
merged 8 commits into from
May 16, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Add predicate metadata for Exterior check
  • Loading branch information
dr-jts committed May 16, 2024
commit 5b29e1d90814ef9c72d9bf973b63d8239c1bb372
Original file line number Diff line number Diff line change
@@ -43,6 +43,8 @@ public IMPatternMatcher(String imPattern) {

public String name() { return "IMPattern"; }

//TODO: implement requiresExteriorCheck by inspecting matrix entries for E

public void init(Envelope envA, Envelope envB) {
super.init(dimA, dimB);
//-- if pattern specifies any non-E/non-E interaction, envelopes must not be disjoint
Original file line number Diff line number Diff line change
@@ -315,6 +315,18 @@ private void computeAtPoints(RelateGeometry geom, boolean isA,
if (isResultKnown)
return;

/**
* Performance optimization: only check points against target
* if it has areas OR if the predicate requires checking for
* exterior interaction.
* In particular, this avoids testing line ends against lines
* for the intersects predicate.
*/
boolean checkDisjointPoints = geomTarget.hasDimension(Dimension.A)
|| topoComputer.isExteriorCheckRequired(isA);
if (! checkDisjointPoints)
return;

isResultKnown = computeLineEnds(geom, isA, geomTarget, topoComputer);
if (isResultKnown)
return;
Original file line number Diff line number Diff line change
@@ -52,11 +52,17 @@ public static TopologyPredicate intersects() {
public String name() { return "intersects"; }

@Override
public boolean isSelfNodingRequired() {
public boolean requiresSelfNoding() {
//-- self-noding is not required to check for a simple interaction
return false;
}

@Override
public boolean requiresExteriorCheck(boolean isSourceA) {
//-- intersects only requires testing interaction
return false;
}

@Override
public void init(Envelope envA, Envelope envB) {
require(envA.intersects(envB));
@@ -98,11 +104,17 @@ public static TopologyPredicate disjoint() {
public String name() { return "disjoint"; }

@Override
public boolean isSelfNodingRequired() {
public boolean requiresSelfNoding() {
//-- self-noding is not required to check for a simple interaction
return false;
}

@Override
public boolean requiresExteriorCheck(boolean isSourceA) {
//-- disjoint only requires testing interaction
return false;
}

@Override
public void init(Envelope envA, Envelope envB) {
setValueIf(true, envA.disjoint(envB));
@@ -151,6 +163,12 @@ public static TopologyPredicate contains() {

public String name() { return "contains"; }

@Override
public boolean requiresExteriorCheck(boolean isSourceA) {
//-- only need to check B against Exterior of A
return isSourceA == RelateGeometry.GEOM_B;
}

@Override
public void init(int dimA, int dimB) {
super.init(dimA, dimB);
@@ -202,7 +220,13 @@ public static TopologyPredicate within() {
return new IMPredicate() {

public String name() { return "within"; }


@Override
public boolean requiresExteriorCheck(boolean isSourceA) {
//-- only need to check A against Exterior of B
return isSourceA == RelateGeometry.GEOM_A;
}

@Override
public void init(int dimA, int dimB) {
super.init(dimA, dimB);
@@ -261,6 +285,12 @@ public static TopologyPredicate covers() {

public String name() { return "covers"; }

@Override
public boolean requiresExteriorCheck(boolean isSourceA) {
//-- only need to check B against Exterior of A
return isSourceA == RelateGeometry.GEOM_B;
}

@Override
public void init(int dimA, int dimB) {
super.init(dimA, dimB);
@@ -314,6 +344,12 @@ public static TopologyPredicate coveredBy() {
return new IMPredicate() {
public String name() { return "coveredBy"; }

@Override
public boolean requiresExteriorCheck(boolean isSourceA) {
//-- only need to check A against Exterior of B
return isSourceA == RelateGeometry.GEOM_A;
}

@Override
public void init(int dimA, int dimB) {
super.init(dimA, dimB);
Original file line number Diff line number Diff line change
@@ -133,7 +133,11 @@ public boolean isSelfNodingRequired() {
//TODO: change to testing for lines or GC with > 1 polygon
if (geomA.isPointsOrPolygons()) return false;
if (geomB.isPointsOrPolygons()) return false;
return predicate.isSelfNodingRequired();
return predicate.requiresSelfNoding();
}

public boolean isExteriorCheckRequired(boolean isA) {
return predicate.requiresExteriorCheck(isA);
}

private void updateDim(int locA, int locB, int dimension) {
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ public interface TopologyPredicate {
String name();

/**
* Tests whether this predicate requires self-noding for
* Reports whether this predicate requires self-noding for
* geometries which contain crossing edges
* (for example, {@link LineString}s, or {@line GeometryCollection}s
* containing lines or polygons which may self-intersect).
@@ -45,10 +45,22 @@ public interface TopologyPredicate {
*
* @return true if self-noding is required.
*/
default boolean isSelfNodingRequired() {
default boolean requiresSelfNoding() {
return true;
}

/**
* Reports whether this predicate requires checking if the source input intersects
* the Exterior of the target input.
* This allows some performance optimizations if not required.
*
* @param isSourceA
* @return true if the predicate requires checking whether the source intersects the target exterior
*/
default boolean requiresExteriorCheck(boolean isSourceA) {
return true;
}

/**
* Initializes the predicate for a specific geometric case.
* This may allow the predicate result to become known
Original file line number Diff line number Diff line change
@@ -47,8 +47,13 @@ private PredicateTracer(TopologyPredicate pred) {
public String name() { return pred.name(); }

@Override
public boolean isSelfNodingRequired() {
return pred.isSelfNodingRequired();
public boolean requiresSelfNoding() {
return pred.requiresSelfNoding();
}

@Override
public boolean requiresExteriorCheck(boolean isSourceA) {
return pred.requiresExteriorCheck(isSourceA);
}

@Override
Original file line number Diff line number Diff line change
@@ -184,6 +184,15 @@ public void testLinesTouchAtBdy() {
checkTouches(a, b, true);
}

public void testLinesOverlapWithDisjointLine() {
String a = "LINESTRING (1 1, 9 9)";
String b = "MULTILINESTRING ((2 2, 8 8), (6 2, 8 4))";
checkRelate(a, b, "101FF0102");
checkIntersectsDisjoint(a, b, true);
checkContainsWithin(a, b, false);
checkOverlaps(a, b, true);
}

public void testLinesDisjointOverlappingEnvelopes() {
String a = "LINESTRING (60 0, 20 80, 100 80, 80 120, 40 140)";
String b = "LINESTRING (60 40, 140 40, 140 160, 0 160)";
Loading