Skip to content

Commit

Permalink
RelateNG algorithm for DE-9IM relationship evaluation (#1052)
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-jts authored May 16, 2024
1 parent 7ef2b9d commit 773ee33
Show file tree
Hide file tree
Showing 44 changed files with 7,845 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2024 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.jtstest.function;

import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.operation.relateng.IntersectionMatrixPattern;
import org.locationtech.jts.operation.relateng.RelateNG;
import org.locationtech.jts.operation.relateng.RelatePredicate;

public class SelectionNGFunctions
{
public static Geometry intersects(Geometry a, final Geometry mask)
{
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
return RelateNG.relate(mask, g, RelatePredicate.intersects());
}
});
}

public static Geometry intersectsPrep(Geometry a, final Geometry mask)
{
RelateNG relateNG = RelateNG.prepare(mask);
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
return relateNG.evaluate(g, RelatePredicate.intersects());
}
});
}

public static Geometry contains(Geometry a, final Geometry mask)
{
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
return RelateNG.relate(mask, g, RelatePredicate.contains());
}
});
}

public static Geometry covers(Geometry a, final Geometry mask)
{
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
return RelateNG.relate(mask, g, RelatePredicate.covers());
}
});
}

public static Geometry coversPrep(Geometry a, final Geometry mask)
{
RelateNG relateNG = RelateNG.prepare(mask);
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
return relateNG.evaluate(g, RelatePredicate.covers());
}
});
}

public static Geometry adjacent(Geometry a, final Geometry mask)
{
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
return RelateNG.relate(mask, g, RelatePredicate.matches(IntersectionMatrixPattern.ADJACENT));
}
});
}

public static Geometry adjacentPrep(Geometry a, final Geometry mask)
{
RelateNG relateNG = RelateNG.prepare(mask);
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
return relateNG.evaluate(g, RelatePredicate.matches(IntersectionMatrixPattern.ADJACENT));
}
});
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import org.locationtech.jts.algorithm.BoundaryNodeRule;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.operation.relate.RelateOp;
import org.locationtech.jts.operation.relateng.IntersectionMatrixPattern;
import org.locationtech.jts.operation.relateng.RelateNG;

/**
* Implementations for spatial predicate functions.
Expand All @@ -34,12 +36,24 @@ public class SpatialPredicateFunctions {
public static boolean overlaps(Geometry a, Geometry b) { return a.overlaps(b); }
public static boolean touches(Geometry a, Geometry b) { return a.touches(b); }

public static boolean interiorIntersects(Geometry a, Geometry b) { return a.relate(b, "T********"); }
public static boolean adjacentTo(Geometry a, Geometry b) { return a.relate(b, "F***T****"); }

public static String relate(Geometry a, Geometry b) {
public static boolean interiorIntersects(Geometry a, Geometry b) {
return a.relate(b, IntersectionMatrixPattern.INTERIOR_INTERSECTS);
}

public static boolean adjacent(Geometry a, Geometry b) {
return a.relate(b, IntersectionMatrixPattern.ADJACENT);
}

public static boolean containsProperly(Geometry a, Geometry b) {
return a.relate(b, IntersectionMatrixPattern.CONTAINS_PROPERLY);
}

public static String relateMatrix(Geometry a, Geometry b) {
return a.relate(b).toString();
}
public static boolean relate(Geometry a, Geometry b, String mask) {
return a.relate(b, mask);
}
public static String relateEndpoint(Geometry a, Geometry b) {
return RelateOp.relate(a, b, BoundaryNodeRule.ENDPOINT_BOUNDARY_RULE).toString();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2023 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.jtstest.function;

import org.locationtech.jts.algorithm.BoundaryNodeRule;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.operation.relateng.IntersectionMatrixPattern;
import org.locationtech.jts.operation.relateng.RelateNG;
import org.locationtech.jts.operation.relateng.RelatePredicate;

public class SpatialPredicateNGFunctions {
public static boolean contains(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.contains());
}
public static boolean covers(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.covers());
}
public static boolean coveredBy(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.coveredBy());
}
public static boolean disjoint(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.disjoint());
}
public static boolean equals(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.equalsTopo());
}
public static boolean equalsTopo(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.equalsTopo());
}
public static boolean intersects(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.intersects());
}
public static boolean crosses(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.crosses());
}
public static boolean overlaps(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.overlaps());
}
public static boolean touches(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.touches());
}
public static boolean within(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.within());
}

public static boolean adjacent(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.matches(IntersectionMatrixPattern.ADJACENT));
}

public static boolean containsProperly(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.matches(IntersectionMatrixPattern.CONTAINS_PROPERLY));
}

public static boolean interiorIntersects(Geometry a, Geometry b) {
return RelateNG.relate(a, b, RelatePredicate.matches(IntersectionMatrixPattern.INTERIOR_INTERSECTS));
}

public static boolean relate(Geometry a, Geometry b, String mask) {
return RelateNG.relate(a, b, mask);
}
public static String relateMatrix(Geometry a, Geometry b) {
return RelateNG.relate(a, b).toString();
}
public static String relateEndpoint(Geometry a, Geometry b) {
return RelateNG.relate(a, b, BoundaryNodeRule.ENDPOINT_BOUNDARY_RULE).toString();
}
public static String relateMultiValent(Geometry a, Geometry b) {
return RelateNG.relate(a, b, BoundaryNodeRule.MULTIVALENT_ENDPOINT_BOUNDARY_RULE).toString();
}
public static String relateMonoValent(Geometry a, Geometry b) {
return RelateNG.relate(a, b, BoundaryNodeRule.MONOVALENT_ENDPOINT_BOUNDARY_RULE).toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,13 @@
import org.locationtech.jtstest.function.PrecisionFunctions;
import org.locationtech.jtstest.function.PreparedGeometryFunctions;
import org.locationtech.jtstest.function.SelectionFunctions;
import org.locationtech.jtstest.function.SelectionNGFunctions;
import org.locationtech.jtstest.function.SimplificationFunctions;
import org.locationtech.jtstest.function.SnappingFunctions;
import org.locationtech.jtstest.function.SortingFunctions;
import org.locationtech.jtstest.function.SpatialIndexFunctions;
import org.locationtech.jtstest.function.SpatialPredicateFunctions;
import org.locationtech.jtstest.function.SpatialPredicateNGFunctions;
import org.locationtech.jtstest.function.TriangleFunctions;
import org.locationtech.jtstest.function.TriangulatePolyFunctions;
import org.locationtech.jtstest.function.TriangulationFunctions;
Expand Down Expand Up @@ -102,6 +104,7 @@ public static GeometryFunctionRegistry createTestBuilderRegistry()
funcRegistry.add(PrecisionFunctions.class);
funcRegistry.add(PreparedGeometryFunctions.class);
funcRegistry.add(SelectionFunctions.class);
funcRegistry.add(SelectionNGFunctions.class);
funcRegistry.add(SimplificationFunctions.class);
funcRegistry.add(AffineTransformationFunctions.class);
funcRegistry.add(DiffFunctions.class);
Expand All @@ -112,6 +115,7 @@ public static GeometryFunctionRegistry createTestBuilderRegistry()
funcRegistry.add(CreateRandomShapeFunctions.class);
funcRegistry.add(SpatialIndexFunctions.class);
funcRegistry.add(SpatialPredicateFunctions.class);
funcRegistry.add(SpatialPredicateNGFunctions.class);
funcRegistry.add(JTSFunctions.class);
//funcRegistry.add(MemoryFunctions.class);
funcRegistry.add(OffsetCurveFunctions.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ private static boolean isAngleGreater(Coordinate origin, Coordinate p, Coordinat
/**
* Compares the angles of two vectors
* relative to the positive X-axis at their origin.
* Angles increase CCW from the X-axis.
*
* @param origin the origin of the vectors
* @param p the endpoint of the vector P
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class MCIndexSegmentSetMutualIntersector implements SegmentSetMutualInter
*/
private STRtree index = new STRtree();
private double overlapTolerance = 0.0;
private Envelope envelope = null;

/**
* Constructs a new intersector for a given set of {@link SegmentString}s.
Expand All @@ -53,6 +54,12 @@ public MCIndexSegmentSetMutualIntersector(Collection baseSegStrings)
initBaseSegments(baseSegStrings);
}

public MCIndexSegmentSetMutualIntersector(Collection baseSegStrings, Envelope env)
{
this.envelope = env;
initBaseSegments(baseSegStrings);
}

public MCIndexSegmentSetMutualIntersector(Collection baseSegStrings, double overlapTolerance)
{
initBaseSegments(baseSegStrings);
Expand Down Expand Up @@ -84,7 +91,9 @@ private void addToIndex(SegmentString segStr)
List segChains = MonotoneChainBuilder.getChains(segStr.getCoordinates(), segStr);
for (Iterator i = segChains.iterator(); i.hasNext(); ) {
MonotoneChain mc = (MonotoneChain) i.next();
index.insert(mc.getEnvelope(overlapTolerance), mc);
if (envelope == null || envelope.intersects(mc.getEnvelope())) {
index.insert(mc.getEnvelope(overlapTolerance), mc);
}
}
}

Expand Down Expand Up @@ -114,7 +123,9 @@ private void addToMonoChains(SegmentString segStr, List monoChains)
List segChains = MonotoneChainBuilder.getChains(segStr.getCoordinates(), segStr);
for (Iterator i = segChains.iterator(); i.hasNext(); ) {
MonotoneChain mc = (MonotoneChain) i.next();
monoChains.add(mc);
if (envelope == null || envelope.intersects(mc.getEnvelope())) {
monoChains.add(mc);
}
}
}

Expand Down
Loading

0 comments on commit 773ee33

Please sign in to comment.