Skip to content

Commit

Permalink
Imrove GC point locating
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-jts committed Jan 30, 2024
1 parent e785ed0 commit a7ad1ff
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

import org.locationtech.jts.algorithm.RobustLineIntersector;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Dimension;
import org.locationtech.jts.noding.SegmentIntersector;
import org.locationtech.jts.noding.SegmentString;
import org.locationtech.jts.noding.SegmentStringUtil;

class EdgeSegmentIntersector implements SegmentIntersector
{
Expand Down Expand Up @@ -61,29 +61,36 @@ private void processSelfIntersection(SegmentString ss0, int segIndex0, SegmentSt
if (! li.hasIntersection())
return;

//-- both segStrings are in same geom
boolean isA = isA(ss0);
int dim0 = dim(ss0);
int dim1 = dim(ss1);
if (li.getIntersectionNum() == 2) {
//-- intersection is collinear
topoBuilder.addSelfIntersectionCollinear(isA, p00, p01, p10, p11, li.getIntersection(0), li.getIntersection(1));
topoBuilder.addSelfIntersectionCollinear(isA, dim0, p00, p01, dim1, 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));
topoBuilder.addSelfIntersectionProper(isA, dim0, p00, p01, dim1, 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));
addSelfIntersectionNonProper(isA, dim0, ss0, segIndex0, dim1, ss1, segIndex1, li.getIntersection(0));
}
}

private boolean isAB(SegmentString ss0, SegmentString ss1) {
RelateGeometry geom0 = (RelateGeometry) ss0.getData();
RelateGeometry geom1 = (RelateGeometry) ss1.getData();
private int dim(SegmentString ss) {
return ((RelateSegmentString) ss).getDimension();
}

private static boolean isAB(SegmentString ss0, SegmentString ss1) {
RelateGeometry geom0 = ((RelateSegmentString) ss0).getGeometry();
RelateGeometry geom1 = ((RelateSegmentString) ss1).getGeometry();
return geom0 != geom1;
}

private boolean isA(SegmentString ss0) {
return topoBuilder.isA((RelateGeometry) ss0.getData());
private boolean isA(SegmentString ss) {
return topoBuilder.isA(((RelateSegmentString) ss).getGeometry());
}

private void processIntersectionAB(SegmentString ssA, int segIndexA, SegmentString ssB, int segIndexB) {
Expand All @@ -98,45 +105,48 @@ private void processIntersectionAB(SegmentString ssA, int segIndexA, SegmentStri
if (! li.hasIntersection())
return;

int dimA = dim(ssA);
int dimB = dim(ssB);

if (li.getIntersectionNum() == 2) {
//-- intersection is collinear
topoBuilder.addIntersectionCollinear(a0, a1, b0, b1, li.getIntersection(0), li.getIntersection(1));
topoBuilder.addABIntersectionCollinear(dimA, a0, a1, dimB, b0, b1, li.getIntersection(0), li.getIntersection(1));
}
else if (li.isProper()) {
//-- intersection is proper
topoBuilder.addIntersectionProper(a0, a1, b0, b1, li.getIntersection(0));
topoBuilder.addABIntersectionProper(dimA, a0, a1, dimB, b0, b1, li.getIntersection(0));
}
else {
//-- non-proper intersection (at least one segment intersects at endpoint)
addIntersectionNonProper(ssA, segIndexA, ssB, segIndexB, li.getIntersection(0));
addABIntersectionNonProper(dimA, ssA, segIndexA, dimB, ssB, segIndexB, li.getIntersection(0));
}
}

private void addSelfIntersectionNonProper(boolean isA, SegmentString ss0, int segIndex0, SegmentString ss1, int segIndex1, Coordinate intPt) {
private void addSelfIntersectionNonProper(boolean isA, int dim0, SegmentString ss0, int segIndex0, int dim1, 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);
addIntersectionEdges(isA, dim0, ss0, segIndex0, intPt);
addIntersectionEdges(isA, dim1, ss1, segIndex1, intPt);
}

private void addIntersectionNonProper(SegmentString ssA, int segIndexA, SegmentString ssB, int segIndexB, Coordinate intPt) {
private void addABIntersectionNonProper(int dimA, SegmentString ssA, int segIndexA, int dimB, 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);
addIntersectionEdges(RelateGeometry.GEOM_A, dimA, ssA, segIndexA, intPt);
addIntersectionEdges(RelateGeometry.GEOM_B, dimB, 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) {
private void addIntersectionEdges(boolean isA, int dim, SegmentString ss, int segIndex, Coordinate intPt) {
Coordinate nextVertex = nextVertex(ss, segIndex, intPt);
topoBuilder.addEdge(isA, intPt, nextVertex, RelateEdge.IS_FORWARD);
topoBuilder.addEdge(isA, dim, intPt, nextVertex, RelateEdge.IS_FORWARD);
Coordinate prevVertex = prevVertex(ss, segIndex, intPt);
topoBuilder.addEdge(isA, intPt, prevVertex, RelateEdge.IS_REVERSE);
topoBuilder.addEdge(isA, dim, intPt, prevVertex, RelateEdge.IS_REVERSE);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,20 +128,12 @@ public boolean isZeroLength() {
}

public int locateNode(Coordinate pt) {
switch (dim) {
case Dimension.P:
return Location.INTERIOR;
case Dimension.L:
return lineBoundary.isBoundary(pt) ? Location.BOUNDARY : Location.INTERIOR;
case Dimension.A:
return Location.BOUNDARY;
}
// Assert: should never reach here
return Location.NONE;
RelatePointLocator locator = new RelatePointLocator(geom);
return locator.locateNode(pt);
}

public int locate(Coordinate pt) {
//TODO: provide an indexed option
//TODO: provide an indexed option - or just always use indexed?
RelatePointLocator locator = new RelatePointLocator(geom);
int loc = locator.locate(pt);
/*
Expand All @@ -150,7 +142,7 @@ public int locate(Coordinate pt) {
throw new IllegalStateException("locations do not match");
}
*/
return RelatePointLocator.getLocation(loc);
return loc;
}

public int locateWithDim(Coordinate pt) {
Expand Down Expand Up @@ -189,7 +181,7 @@ private int locateOnLine(Coordinate pt) {
return lineLocator.locate(pt, geom);
}

public int locateOnArea(Coordinate pt) {
private int locateOnArea(Coordinate pt) {
//TODO: only create index after N queries
if (areaLocator == null) {
if (isPrepared) {
Expand All @@ -201,6 +193,33 @@ public int locateOnArea(Coordinate pt) {
}
return areaLocator.locate(pt);
}

public boolean isPointsOrPolygons() {
return geom instanceof Point
|| geom instanceof MultiPoint
|| geom instanceof Polygon
|| geom instanceof MultiPolygon;
}

public boolean hasAnyPoints() {
return getDimension() == Dimension.P;
}

public Set<Coordinate> getLineEnds() {
return lineBoundary.getEndPoints();
}

public int locateLineEnd(Coordinate p) {
return lineBoundary.isBoundary(p) ? Location.BOUNDARY : Location.INTERIOR;
}

public boolean isEmpty() {
return geom.isEmpty();
}

public boolean hasBoundary() {
return lineBoundary.hasBoundary();
}

private Set<Coordinate> createUniquePoints() {
//TODO: make more efficient (ie by scanning geometry?)
Expand Down Expand Up @@ -241,18 +260,6 @@ public List<Point> getPoints() {
return ptList;
}

public List<SegmentString> extractSegmentStringsOLD(Envelope env) {
List<LineString> lines = LinearComponentExtracter.getLines(geom);
List<SegmentString> segStrings = new ArrayList<SegmentString>();
for (LineString line : lines) {
if (env == null || env.intersects(line.getEnvelopeInternal())) {
SegmentString ss = new BasicSegmentString(line.getCoordinates(), null);
segStrings.add(ss);
}
}
return segStrings;
}

public List<SegmentString> extractSegmentStrings(Envelope env) {
List<SegmentString> segStrings = new ArrayList<SegmentString>();
for (int i = 0; i < geom.getNumGeometries(); i++) {
Expand All @@ -270,7 +277,7 @@ private void extractSegmentStrings(Geometry geom, Envelope env, List<SegmentStri
return;

if (geom instanceof LineString) {
SegmentString ss = createSegmentString(geom.getCoordinates());
SegmentString ss = createSegmentString(geom.getCoordinates(), Dimension.L);
segStrings.add(ss);
}
else if (geom instanceof Polygon) {
Expand All @@ -295,42 +302,15 @@ private void extractRingToSegmentString(LinearRing ring, boolean requireCW, Enve
pts = pts.clone();
CoordinateArrays.reverse(pts);
}
SegmentString ss = createSegmentString(pts);
SegmentString ss = createSegmentString(pts, Dimension.A);
segStrings.add(ss);
}

private SegmentString createSegmentString(Coordinate[] pts) {
SegmentString ss = new BasicSegmentString(pts, this);
private SegmentString createSegmentString(Coordinate[] pts, int dim) {
SegmentString ss = new RelateSegmentString(pts, dim, this);
return ss;
}

public boolean isPointsOrPolygons() {
return geom instanceof Point
|| geom instanceof MultiPoint
|| geom instanceof Polygon
|| geom instanceof MultiPolygon;
}

public boolean hasAnyPoints() {
return getDimension() == Dimension.P;
}

public Set<Coordinate> getLineEnds() {
return lineBoundary.getEndPoints();
}

public int locateLineEnd(Coordinate p) {
return lineBoundary.isBoundary(p) ? Location.BOUNDARY : Location.INTERIOR;
}

public boolean isEmpty() {
return geom.isEmpty();
}

public boolean hasBoundary() {
return lineBoundary.hasBoundary();
}

public String toString() {
return geom.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,8 @@ private boolean computePoints(RelateGeometry geom, boolean isA, RelateGeometry g
Coordinate p = pt.getCoordinate();
//TODO: break when all possible topo locations have been found
int locDimTarget = geomTarget.locateWithDim(p);
int locTarget = RelatePointLocator.getLocation(locDimTarget);
int dimTarget = locTarget == Location.EXTERIOR
? topoBuilder.dim(! isA)
: RelatePointLocator.dimension(locDimTarget);
int locTarget = RelatePointLocator.location(locDimTarget);
int dimTarget = RelatePointLocator.dimension(locDimTarget, topoBuilder.dim(! isA));
topoBuilder.addPointOnGeometry(isA, locTarget, dimTarget, p);
if (topoBuilder.isResultKnown()) {
return true;
Expand All @@ -245,10 +243,8 @@ private boolean computeLineEnds(RelateGeometry geom, boolean isA, RelateGeometry
//TODO: break when all possible locations have been found?
int locLineEnd = geom.locateLineEnd(p);
int locDimTarget = geomTarget.locateWithDim(p);
int locTarget = RelatePointLocator.getLocation(locDimTarget);
int dimTarget = locTarget == Location.EXTERIOR
? topoBuilder.dim(! isA)
: RelatePointLocator.dimension(locDimTarget);
int locTarget = RelatePointLocator.location(locDimTarget);
int dimTarget = RelatePointLocator.dimension(locDimTarget, topoBuilder.dim(! isA));
topoBuilder.addLineEndOnGeometry(isA, locLineEnd, locTarget, dimTarget, p);
if (topoBuilder.isResultKnown()) {
return true;
Expand Down Expand Up @@ -289,10 +285,8 @@ private boolean computeAreaNodes(RelateGeometry geom, boolean isA, RelateGeometr
private void computeAreaNode(LinearRing ring, boolean isA, RelateGeometry geomTarget, TopologyBuilder topoBuilder) {
Coordinate pt = ring.getCoordinate();
int locDimTarget = geomTarget.locateWithDim(pt);
int locTarget = RelatePointLocator.getLocation(locDimTarget);
int dimTarget = locTarget == Location.EXTERIOR
? topoBuilder.dim(! isA)
: RelatePointLocator.dimension(locDimTarget);
int locTarget = RelatePointLocator.location(locDimTarget);
int dimTarget = RelatePointLocator.dimension(locDimTarget, topoBuilder.dim(! isA));
//-- don't need to test against points, since they have already been tested against the area
topoBuilder.addAreaVertex(isA, locTarget, dimTarget, pt);
}
Expand Down
Loading

0 comments on commit a7ad1ff

Please sign in to comment.