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
Show file tree
Hide file tree
Changes from all commits
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
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
Loading