forked from locationtech/jts
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Martin Davis <[email protected]> Move to src dir Signed-off-by: Martin Davis <[email protected]> More code Signed-off-by: Martin Davis <[email protected]> Get it running Signed-off-by: Martin Davis <[email protected]> Fix conflict Add more short-circuits Signed-off-by: Martin Davis <[email protected]> Refactoring, add collinear intersection Signed-off-by: Martin Davis <[email protected]> Add license, more predicates Signed-off-by: Martin Davis <[email protected]> Renaming Signed-off-by: Martin Davis <[email protected]> Renaming, fix L/L short-circuit Signed-off-by: Martin Davis <[email protected]> WIP - more detailed intersection info Signed-off-by: Martin Davis <[email protected]> Add geometry dimensionality checks Signed-off-by: Martin Davis <[email protected]> Add LinearBoundary Signed-off-by: Martin Davis <[email protected]> Add header, fix imports Rename IMPredicate methods Refactoring Refactoring remove dead code Refactor predicate model Refactor predicate model refactoring Add point support Simplify builder logic Fix proper intersection logic renaming code reorg Refactoring refactoring Fix order of EdgeIntersector comparison Add AreaArea crossing test Enhance PolygonNodeTopology to handle collinear Add predicates Javadoc Add node edge handling cleanup fix imports Add node evaluation Various improvements Various improvements Fix touches bug Renaming, fixes Renaming, fixes Improve tests Improve perf test Add PredicateTracer Add short-circuit Fix some bugs Renaming Refactoring refactoring Avoid check for empty element Fix area-vertex evaluation Remove unused import Renaming Renames Renames Refactor constants Renaming, refactoring refactoring refactoring rename TopologyPredicateValue renaming use constant renaming initial commit for self-noding Add RelateNG functions Refactor addAreaEdge Add AB geometry edge intersection test formatting Refactoring to simplify Remove single-call method Refactoring Renaming various improvements typo in comment various improvements refactoring Chg addEdge method sig Fix unit test Improve tracing output Finish self-intersection handling Expose constants javadoc, refactoring Switch to HPRtree Refactoring formatting Refactor predicate logic functions Improve predicate logic shortcut methods simplify code add method improve msg add tests Add relate function Various fixes change evaluation order Rework point topology evaluation refactoring refactoring javadoc, renaming remove dead code Improve relate predicate code improve internal API rename TopologyPredicate.value add perf tests refactoring Add BoundaryNodeRule support Fix SegmentString method usage Align with master Align with master
- Loading branch information
Showing
25 changed files
with
3,917 additions
and
0 deletions.
There are no files selected for viewing
60 changes: 60 additions & 0 deletions
60
modules/app/src/main/java/org/locationtech/jtstest/function/SelectionNGFunctions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
* 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.RelateNG; | ||
import org.locationtech.jts.operation.relateng.TopologyPredicateFactory; | ||
|
||
public class SelectionNGFunctions | ||
{ | ||
public static Geometry intersectsNG(Geometry a, final Geometry mask) | ||
{ | ||
return SelectionFunctions.select(a, new GeometryPredicate() { | ||
public boolean isTrue(Geometry g) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.intersects(), mask, g); | ||
} | ||
}); | ||
} | ||
|
||
public static Geometry intersectsNGPrep(Geometry a, final Geometry mask) | ||
{ | ||
RelateNG relateNG = new RelateNG(mask, true); | ||
return SelectionFunctions.select(a, new GeometryPredicate() { | ||
public boolean isTrue(Geometry g) { | ||
return relateNG.evaluate(TopologyPredicateFactory.intersects(), g); | ||
} | ||
}); | ||
} | ||
|
||
public static Geometry coversNG(Geometry a, final Geometry mask) | ||
{ | ||
return SelectionFunctions.select(a, new GeometryPredicate() { | ||
public boolean isTrue(Geometry g) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.covers(), mask, g); | ||
} | ||
}); | ||
} | ||
|
||
public static Geometry coversNGPrep(Geometry a, final Geometry mask) | ||
{ | ||
RelateNG relateNG = new RelateNG(mask, true); | ||
return SelectionFunctions.select(a, new GeometryPredicate() { | ||
public boolean isTrue(Geometry g) { | ||
return relateNG.evaluate(TopologyPredicateFactory.covers(), g); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
|
53 changes: 53 additions & 0 deletions
53
modules/app/src/main/java/org/locationtech/jtstest/function/SpatialPredicateNGFunctions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/* | ||
* 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.geom.Geometry; | ||
import org.locationtech.jts.operation.relateng.RelateNG; | ||
import org.locationtech.jts.operation.relateng.TopologyPredicateFactory; | ||
|
||
public class SpatialPredicateNGFunctions { | ||
public static boolean contains(Geometry a, Geometry b) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.contains(), a, b); | ||
} | ||
public static boolean covers(Geometry a, Geometry b) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.covers(), a, b); | ||
} | ||
public static boolean coveredBy(Geometry a, Geometry b) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.coveredBy(), a, b); | ||
} | ||
public static boolean disjoint(Geometry a, Geometry b) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.disjoint(), a, b); | ||
} | ||
public static boolean equals(Geometry a, Geometry b) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.equalsTopo(), a, b); | ||
} | ||
public static boolean intersects(Geometry a, Geometry b) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.intersects(), a, b); | ||
} | ||
public static boolean overlaps(Geometry a, Geometry b) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.overlaps(), a, b); | ||
} | ||
public static boolean touches(Geometry a, Geometry b) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.touches(), a, b); | ||
} | ||
public static boolean within(Geometry a, Geometry b) { | ||
return RelateNG.evaluate(TopologyPredicateFactory.within(), a, b); | ||
} | ||
public static boolean relate(Geometry a, Geometry b, String mask) { | ||
return RelateNG.relate(a, b, mask); | ||
} | ||
public static String relateIM(Geometry a, Geometry b) { | ||
return RelateNG.relate(a, b).toString(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
207 changes: 207 additions & 0 deletions
207
...es/core/src/main/java/org/locationtech/jts/operation/relateng/EdgeSegmentIntersector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
/* | ||
* Copyright (c) 2022 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.operation.relateng; | ||
|
||
import org.locationtech.jts.algorithm.RobustLineIntersector; | ||
import org.locationtech.jts.geom.Coordinate; | ||
import org.locationtech.jts.noding.SegmentIntersector; | ||
import org.locationtech.jts.noding.SegmentString; | ||
import org.locationtech.jts.noding.SegmentStringUtil; | ||
|
||
public class EdgeSegmentIntersector implements SegmentIntersector | ||
{ | ||
private RobustLineIntersector li = new RobustLineIntersector(); | ||
private TopologyBuilder topoBuilder; | ||
|
||
public EdgeSegmentIntersector(TopologyBuilder topoBuilder) { | ||
this.topoBuilder = topoBuilder; | ||
} | ||
|
||
@Override | ||
public boolean isDone() { | ||
return topoBuilder.isResultKnown(); | ||
} | ||
|
||
public void processIntersections(SegmentString ss0, int segIndex0, SegmentString ss1, int segIndex1) { | ||
if (isAB(ss0, ss1)) { | ||
if (isA(ss0)) { | ||
processIntersectionAB(ss0, segIndex0, ss1, segIndex1); | ||
} | ||
else { | ||
processIntersectionAB(ss1, segIndex1, ss0, segIndex0); | ||
} | ||
} | ||
else { | ||
processSelfIntersection(ss0, segIndex0, ss1, segIndex1); | ||
} | ||
} | ||
|
||
private void processSelfIntersection(SegmentString ss0, int segIndex0, SegmentString ss1, int segIndex1) { | ||
// don't intersect a segment with itself | ||
if (ss0 == ss1 && segIndex0 == segIndex1) return; | ||
|
||
//TODO: skip intersections between adjacent segments? | ||
|
||
Coordinate p00 = ss0.getCoordinate(segIndex0); | ||
Coordinate p01 = ss0.getCoordinate(segIndex0 + 1); | ||
Coordinate p10 = ss1.getCoordinate(segIndex1); | ||
Coordinate p11 = ss1.getCoordinate(segIndex1 + 1); | ||
|
||
li.computeIntersection(p00, p01, p10, p11); | ||
|
||
if (! li.hasIntersection()) | ||
return; | ||
|
||
boolean isA = isA(ss0); | ||
if (li.getIntersectionNum() == 2) { | ||
//-- intersection is collinear | ||
topoBuilder.addSelfIntersectionCollinear(isA, p00, p01, p10, p11, li.getIntersection(0), li.getIntersection(1)); | ||
} | ||
else if (li.isProper()) { | ||
//-- intersection is proper | ||
topoBuilder.addSelfIntersectionProper(isA, p00, p01, p10, p11, li.getIntersection(0)); | ||
} | ||
else { | ||
//-- non-proper intersection (at least one segment intersects at endpoint) | ||
addSelfIntersectionNonProper(isA, ss0, segIndex0, ss1, segIndex1, li.getIntersection(0)); | ||
} | ||
} | ||
|
||
private boolean isAB(SegmentString ss0, SegmentString ss1) { | ||
RelateGeometry geom0 = (RelateGeometry) ss0.getData(); | ||
RelateGeometry geom1 = (RelateGeometry) ss1.getData(); | ||
return geom0 != geom1; | ||
} | ||
|
||
private boolean isA(SegmentString ss0) { | ||
return topoBuilder.isA((RelateGeometry) ss0.getData()); | ||
} | ||
|
||
private void processIntersectionAB(SegmentString ssA, int segIndexA, SegmentString ssB, int segIndexB) { | ||
|
||
Coordinate a0 = ssA.getCoordinate(segIndexA); | ||
Coordinate a1 = ssA.getCoordinate(segIndexA + 1); | ||
Coordinate b0 = ssB.getCoordinate(segIndexB); | ||
Coordinate b1 = ssB.getCoordinate(segIndexB + 1); | ||
|
||
li.computeIntersection(a0, a1, b0, b1); | ||
|
||
if (! li.hasIntersection()) | ||
return; | ||
|
||
if (li.getIntersectionNum() == 2) { | ||
//-- intersection is collinear | ||
topoBuilder.addIntersectionCollinear(a0, a1, b0, b1, li.getIntersection(0), li.getIntersection(1)); | ||
} | ||
else if (li.isProper()) { | ||
//-- intersection is proper | ||
topoBuilder.addIntersectionProper(a0, a1, b0, b1, li.getIntersection(0)); | ||
} | ||
else { | ||
//-- non-proper intersection (at least one segment intersects at endpoint) | ||
addIntersectionNonProper(ssA, segIndexA, ssB, segIndexB, li.getIntersection(0)); | ||
} | ||
} | ||
|
||
private void addSelfIntersectionNonProper(boolean isA, SegmentString ss0, int segIndex0, SegmentString ss1, int segIndex1, Coordinate intPt) { | ||
//-- this handles A/L, L/A, and L/L | ||
addIntersectionEdges(isA, ss0, segIndex0, intPt); | ||
addIntersectionEdges(isA, ss1, segIndex1, intPt); | ||
} | ||
|
||
private void addIntersectionNonProper(SegmentString ssA, int segIndexA, SegmentString ssB, int segIndexB, Coordinate intPt) { | ||
if (topoBuilder.isAreaArea()) { | ||
addNonProperAreaArea(ssA, segIndexA, ssB, segIndexB, intPt); | ||
return; | ||
} | ||
//-- this handles A/L, L/A, and L/L | ||
addIntersectionEdges(RelateGeometry.GEOM_A, ssA, segIndexA, intPt); | ||
addIntersectionEdges(RelateGeometry.GEOM_B, ssB, segIndexB, intPt); | ||
|
||
//TODO: more logic required? | ||
//TODO: move to topoBuilder | ||
topoBuilder.addEdgeIntersectionNode(intPt); | ||
} | ||
|
||
private void addIntersectionEdges(boolean isA, SegmentString ss, int segIndex, Coordinate intPt) { | ||
Coordinate nextVertex = nextVertex(ss, segIndex, intPt); | ||
topoBuilder.addEdge(isA, intPt, nextVertex, RelateEdge.IS_FORWARD); | ||
Coordinate prevVertex = prevVertex(ss, segIndex, intPt); | ||
topoBuilder.addEdge(isA, intPt, prevVertex, RelateEdge.IS_REVERSE); | ||
} | ||
|
||
/** | ||
* | ||
* @param ss | ||
* @param segIndex | ||
* @param pt | ||
* @return the previous vertex, or null if none exists | ||
*/ | ||
private static Coordinate prevVertex(SegmentString ss, int segIndex, Coordinate pt) { | ||
Coordinate segStart = ss.getCoordinate(segIndex); | ||
if (! segStart.equals2D(pt)) | ||
return segStart; | ||
//-- pt is at segment start, so get previous vertex | ||
if (segIndex > 0) | ||
return ss.getCoordinate(segIndex - 1); | ||
if (ss.isClosed()) | ||
return ss.prevInRing(segIndex); | ||
return null; | ||
} | ||
|
||
/** | ||
* | ||
* @param ss | ||
* @param segIndex | ||
* @param pt | ||
* @return the next vertex, or null if none exists | ||
*/ | ||
private static Coordinate nextVertex(SegmentString ss, int segIndex, Coordinate pt) { | ||
Coordinate segEnd = ss.getCoordinate(segIndex + 1); | ||
if (! segEnd.equals2D(pt)) | ||
return segEnd; | ||
//-- pt is at seg end, so get next vertex | ||
if (segIndex < ss.size() - 2) | ||
return ss.getCoordinate(segIndex + 2); | ||
if (ss.isClosed()) | ||
return ss.nextInRing(segIndex); | ||
//-- segstring is not closed, so there is no next segment | ||
return null; | ||
} | ||
|
||
private void addNonProperAreaArea(SegmentString ssA, int segIndexA, SegmentString ssB, int segIndexB, | ||
Coordinate intPt) { | ||
Coordinate[] adjPtsA = adjacentRingVertices(ssA, segIndexA, intPt); | ||
Coordinate[] adjPtsB = adjacentRingVertices(ssB, segIndexB, intPt); | ||
topoBuilder.addAreaAreaIntersection(false, adjPtsA[0], adjPtsA[1], adjPtsB[0], adjPtsB[1], intPt); | ||
} | ||
|
||
private static Coordinate[] adjacentRingVertices(SegmentString ssRing, int segIndex, Coordinate intPt) { | ||
Coordinate p0 = ssRing.getCoordinate(segIndex); | ||
Coordinate p1 = ssRing.getCoordinate(segIndex + 1); | ||
Coordinate[] adjPts = new Coordinate[2]; | ||
if (intPt.equals2D(p0)) { | ||
adjPts[0] = ssRing.prevInRing(segIndex); | ||
adjPts[1] = p1; | ||
} | ||
else if (intPt.equals2D(p1)) { | ||
adjPts[0] = p0; | ||
adjPts[1] = ssRing.nextInRing(segIndex + 1); | ||
} | ||
else { | ||
//-- intersection is in interior of segment | ||
adjPts[0] = p0; | ||
adjPts[1] = p1; | ||
} | ||
return adjPts; | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
.../core/src/main/java/org/locationtech/jts/operation/relateng/EdgeSegmentOverlapAction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package org.locationtech.jts.operation.relateng; | ||
|
||
import org.locationtech.jts.index.chain.MonotoneChain; | ||
import org.locationtech.jts.index.chain.MonotoneChainOverlapAction; | ||
import org.locationtech.jts.noding.SegmentIntersector; | ||
import org.locationtech.jts.noding.SegmentString; | ||
|
||
public class EdgeSegmentOverlapAction | ||
extends MonotoneChainOverlapAction | ||
{ | ||
private SegmentIntersector si = null; | ||
|
||
public EdgeSegmentOverlapAction(SegmentIntersector si) | ||
{ | ||
this.si = si; | ||
} | ||
|
||
public void overlap(MonotoneChain mc1, int start1, MonotoneChain mc2, int start2) | ||
{ | ||
SegmentString ss1 = (SegmentString) mc1.getContext(); | ||
SegmentString ss2 = (SegmentString) mc2.getContext(); | ||
si.processIntersections(ss1, start1, ss2, start2); | ||
} | ||
|
||
} |
Oops, something went wrong.