Skip to content

Commit

Permalink
Refactoring, add GC handling
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-jts committed Jan 25, 2024
1 parent 021d8fc commit 813f616
Show file tree
Hide file tree
Showing 15 changed files with 618 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

public class SelectionNGFunctions
{
public static Geometry intersectsNG(Geometry a, final Geometry mask)
public static Geometry intersects(Geometry a, final Geometry mask)
{
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
Expand All @@ -27,17 +27,17 @@ public boolean isTrue(Geometry g) {
});
}

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

public static Geometry coversNG(Geometry a, final Geometry mask)
public static Geometry covers(Geometry a, final Geometry mask)
{
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
Expand All @@ -46,12 +46,31 @@ public boolean isTrue(Geometry g) {
});
}

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

public static Geometry adjacentTo(Geometry a, final Geometry mask)
{
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
return RelateNG.evaluate(TopologyPredicateFactory.relate("****1****"), mask, g);
}
});
}

public static Geometry adjacentToPrep(Geometry a, final Geometry mask)
{
RelateNG relateNG = new RelateNG(mask);
return SelectionFunctions.select(a, new GeometryPredicate() {
public boolean isTrue(Geometry g) {
return relateNG.compute(TopologyPredicateFactory.relate("****1****"), g);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public static boolean touches(Geometry a, Geometry b) {
public static boolean within(Geometry a, Geometry b) {
return RelateNG.evaluate(TopologyPredicateFactory.within(), a, b);
}

public static boolean adjacentTo(Geometry a, Geometry b) {
return RelateNG.evaluate(TopologyPredicateFactory.relate("****1****"), a, b);
}

public static boolean relate(Geometry a, Geometry b, String mask) {
return RelateNG.relate(a, b, mask);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Martin Davis.
* 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
Expand All @@ -12,17 +12,17 @@
package org.locationtech.jts.operation.relateng;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.locationtech.jts.algorithm.BoundaryNodeRule;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.util.LinearComponentExtracter;

class LinearBoundary {

//TODO: handle BoundaryNodeRule

private Map<Coordinate, Integer> vertexDegree = new HashMap<Coordinate, Integer>();
private boolean hasBoundary;
Expand Down Expand Up @@ -54,8 +54,8 @@ public boolean isBoundary(Coordinate pt) {

private static Map<Coordinate, Integer> computeBoundaryPoints(Geometry geom) {
Map<Coordinate, Integer> vertexDegree = new HashMap<Coordinate, Integer>();
for (int i = 0; i < geom.getNumGeometries(); i++) {
LineString line = (LineString) geom.getGeometryN(i);
List<LineString> lines = LinearComponentExtracter.getLines(geom);
for (LineString line : lines) {
if (line.isEmpty())
continue;
addEndpoint(line.getCoordinateN(0), vertexDegree);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.util.ComponentCoordinateExtracter;
import org.locationtech.jts.geom.util.LinearComponentExtracter;
import org.locationtech.jts.geom.util.PointExtracter;
import org.locationtech.jts.noding.BasicSegmentString;
import org.locationtech.jts.noding.SegmentString;

Expand Down Expand Up @@ -76,7 +77,10 @@ public RelateGeometry(Geometry input, boolean isPrepared, BoundaryNodeRule bnRul
lineBoundary = new LinearBoundary(input, boundaryNodeRule);
}
}


public boolean isPrepared() {
return isPrepared;
}

public Envelope getEnvelope() {
return geom.getEnvelopeInternal();
Expand Down Expand Up @@ -137,6 +141,26 @@ public int locateNode(Coordinate pt) {
}

public int locate(Coordinate pt) {
//TODO: provide an indexed option
RelatePointLocator locator = new RelatePointLocator(geom);
int loc = locator.locate(pt);
/*
int locOLD = OLDlocate(pt);
if (loc != locOLD) {
throw new IllegalStateException("locations do not match");
}
*/
return RelatePointLocator.getLocation(loc);
}

public int locateWithDim(Coordinate pt) {
//TODO: provide an indexed option
RelatePointLocator locator = new RelatePointLocator(geom);
int loc = locator.locateWithDim(pt);
return loc;
}

public int OLDlocate(Coordinate pt) {
//TODO: to support mixed GCs all dimensions will have to be tested
switch (dim) {
case Dimension.A:
Expand Down Expand Up @@ -200,6 +224,10 @@ public List<Coordinate> getCoordinates() {
return pts;
}

public List<Point> getPoints() {
return PointExtracter.getPoints(geom);
}

public List<SegmentString> extractSegmentStringsOLD(Envelope env) {
List<LineString> lines = LinearComponentExtracter.getLines(geom);
List<SegmentString> segStrings = new ArrayList<SegmentString>();
Expand Down Expand Up @@ -290,4 +318,8 @@ public boolean hasBoundary() {
return lineBoundary.hasBoundary();
}

public String toString() {
return geom.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.IntersectionMatrix;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.Location;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.geom.prep.PreparedGeometry;
import org.locationtech.jts.noding.SegmentString;
Expand Down Expand Up @@ -55,17 +57,18 @@ public class RelateNG

public static boolean evaluate(TopologyPredicate pred, Geometry a, Geometry b) {
RelateNG rng = new RelateNG(a);
return rng.evaluate(pred, b);
return rng.compute(pred, b);
}

private static boolean evaluate(RelatePredicate pred, Geometry a, Geometry b, BoundaryNodeRule bnRule) {
RelateNG rng = new RelateNG(a, bnRule);
return rng.evaluate(pred, b);
public static boolean evaluate(RelatePredicate pred, Geometry a, Geometry b, BoundaryNodeRule bnRule) {
RelateNG rng = new RelateNG(bnRule);
return rng.compute(pred, a, b);
}

public static boolean relate(Geometry a, Geometry b, String mask) {
RelatePredicate rel = new RelatePredicate(mask);
return RelateNG.evaluate(rel, a, b);
RelateNG rng = new RelateNG();
return rng.compute(rel, a, b);
}

public static IntersectionMatrix relate(Geometry a, Geometry b) {
Expand All @@ -81,31 +84,34 @@ public static IntersectionMatrix relate(Geometry a, Geometry b, BoundaryNodeRule
}


private BoundaryNodeRule boundaryNodeRule;
private RelateGeometry geomA;
private boolean isPrepared = false;

private EdgeSetMutualIntersector edgeMutualInt;
private BoundaryNodeRule boundaryNodeRule;

public RelateNG(Geometry inputA) {
this(inputA, false, BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE);
public RelateNG() {
this(BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE);
}

public RelateNG(Geometry inputA, BoundaryNodeRule bnRule) {
this(inputA, false, bnRule);
public RelateNG(BoundaryNodeRule bnRule) {
this.boundaryNodeRule = bnRule;
}

public RelateNG(Geometry inputA, boolean isPrepared) {
this(inputA, isPrepared, BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE);
public RelateNG(Geometry inputA) {
this(inputA, BoundaryNodeRule.OGC_SFS_BOUNDARY_RULE);
}

public RelateNG(Geometry inputA, boolean isPrepared, BoundaryNodeRule bnRule) {
this.boundaryNodeRule = bnRule;
geomA = new RelateGeometry(inputA, isPrepared, boundaryNodeRule);
this.boundaryNodeRule = bnRule;
public RelateNG(Geometry inputA, BoundaryNodeRule bnRule) {
this(bnRule);
geomA = new RelateGeometry(inputA, true, boundaryNodeRule);
}

public boolean compute(TopologyPredicate predicate, Geometry inputA, Geometry inputB) {
geomA = new RelateGeometry(inputA, false, boundaryNodeRule);
return compute(predicate, inputB);
}

public boolean evaluate(TopologyPredicate predicate, Geometry inputB) {
public boolean compute(TopologyPredicate predicate, Geometry inputB) {

RelateGeometry geomB = new RelateGeometry(inputB, boundaryNodeRule);
int dimA = geomA.getDimension();
Expand Down Expand Up @@ -198,15 +204,19 @@ private void computeAtPoints(RelateGeometry geomSrc, boolean isA,

private boolean computePoints(RelateGeometry geom, boolean isA, RelateGeometry geomTarget,
TopologyBuilder topoBuilder) {
//TODO: handle mixed GCs
if (geom.getDimension() != Dimension.P)
return false;
//TODO: get Points only (i.e. from mixed GCs)
List<Coordinate> coords = geom.getCoordinates();
for (Coordinate p : coords) {
List<Point> points = geom.getPoints();
for (Point pt : points) {
if (pt.isEmpty())
continue;
Coordinate p = pt.getCoordinate();
//TODO: break when all possible topo locations have been found
int locOnLine = geomTarget.locate(p);
topoBuilder.addPointOnGeometry(isA, locOnLine, p);
int locDimTarget = geomTarget.locateWithDim(p);
int locTarget = RelatePointLocator.getLocation(locDimTarget);
int dimTarget = locTarget == Location.EXTERIOR
? topoBuilder.dim(! isA)
: RelatePointLocator.dimension(locDimTarget);
topoBuilder.addPointOnGeometry(isA, locTarget, dimTarget, p);
if (topoBuilder.isResultKnown()) {
return true;
}
Expand All @@ -224,16 +234,20 @@ private boolean computeLineEnds(RelateGeometry geom, boolean isA, RelateGeometry
for (Coordinate p : coords) {
//TODO: break when all possible locations have been found?
int locLineEnd = geom.locateLineEnd(p);
int locTarget = geomTarget.locate(p);
topoBuilder.addLineEndOnGeometry(isA, locLineEnd, locTarget, p);
int locDimTarget = geomTarget.locateWithDim(p);
int locTarget = RelatePointLocator.getLocation(locDimTarget);
int dimTarget = locTarget == Location.EXTERIOR
? topoBuilder.dim(! isA)
: RelatePointLocator.dimension(locDimTarget);
topoBuilder.addLineEndOnGeometry(isA, locLineEnd, locTarget, dimTarget, p);
if (topoBuilder.isResultKnown()) {
return true;
}
}
return false;
}

private boolean computeAreaNodes(RelateGeometry geom, boolean isAreaA, RelateGeometry geomTarget, TopologyBuilder topoBuilder) {
private boolean computeAreaNodes(RelateGeometry geom, boolean isA, RelateGeometry geomTarget, TopologyBuilder topoBuilder) {
//-- evaluate against line and area elements only
//TODO: handle mixed GCs
if (geomTarget.getDimension() < Dimension.L)
Expand All @@ -247,12 +261,12 @@ private boolean computeAreaNodes(RelateGeometry geom, boolean isAreaA, RelateGeo

if (elem instanceof Polygon) {
Polygon poly = (Polygon) elem;
computeAreaNode(poly.getExteriorRing(), isAreaA, geomTarget, topoBuilder);
computeAreaNode(poly.getExteriorRing(), isA, geomTarget, topoBuilder);
if (topoBuilder.isResultKnown()) {
return true;
}
for (int j = 0; j < poly.getNumInteriorRing(); j++) {
computeAreaNode(poly.getInteriorRingN(j), isAreaA, geomTarget, topoBuilder);
computeAreaNode(poly.getInteriorRingN(j), isA, geomTarget, topoBuilder);
if (topoBuilder.isResultKnown()) {
return true;
}
Expand All @@ -262,11 +276,15 @@ private boolean computeAreaNodes(RelateGeometry geom, boolean isAreaA, RelateGeo
return false;
}

private void computeAreaNode(LinearRing ring, boolean isAreaA, RelateGeometry geomTarget, TopologyBuilder topoBuilder) {
private void computeAreaNode(LinearRing ring, boolean isA, RelateGeometry geomTarget, TopologyBuilder topoBuilder) {
Coordinate pt = ring.getCoordinate();
int locOnTarget = geomTarget.locate(pt);
int locDimTarget = geomTarget.locateWithDim(pt);
int locTarget = RelatePointLocator.getLocation(locDimTarget);
int dimTarget = locTarget == Location.EXTERIOR
? topoBuilder.dim(! isA)
: RelatePointLocator.dimension(locDimTarget);
//-- don't need to test against points, since they have already been tested against the area
topoBuilder.addAreaVertexOnLineArea(isAreaA, locOnTarget, pt);
topoBuilder.addAreaVertex(isA, locTarget, dimTarget, pt);
}

private void computeEdges(RelateGeometry geomB, TopologyBuilder topoBuilder) {
Expand Down Expand Up @@ -299,7 +317,7 @@ private void computeEdgesAll(List<SegmentString> edgesB, Envelope envInt, EdgeSe
private void computeEdgesMutual(List<SegmentString> edgesB, Envelope envInt, EdgeSegmentIntersector intersector) {
//-- for prepared evaluation the A edge index is reused
if (edgeMutualInt == null) {
Envelope envTarget = isPrepared ? null : envInt;
Envelope envTarget = geomA.isPrepared() ? null : envInt;
List<SegmentString> edgesA = geomA.extractSegmentStrings(envTarget);
edgeMutualInt = new EdgeSetMutualIntersector(edgesA, envTarget);
}
Expand Down
Loading

0 comments on commit 813f616

Please sign in to comment.