diff --git a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateGeometry.java b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateGeometry.java index 7fc6dbb8b..005ddd618 100644 --- a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateGeometry.java +++ b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateGeometry.java @@ -49,7 +49,6 @@ public static String name(boolean isA) { private boolean isPrepared = false; private int geomDim = Dimension.FALSE; - private List pts; private Set uniquePoints; private BoundaryNodeRule boundaryNodeRule; private RelatePointLocator locator; @@ -120,28 +119,32 @@ private void analyzeDimensions() { } /** - * Tests if geometry linear elements are zero-length. - * The test is optimized to - * avoid computing length in the common case, since that is expensive. + * Tests if all geometry linear elements are zero-length. + * For efficiency the test avoids computing actual length. * * @param geom * @return */ - private boolean isZeroLength(Geometry geom) { + private static boolean isZeroLength(Geometry geom) { Iterator geomi = new GeometryCollectionIterator(geom); while (geomi.hasNext()) { Geometry elem = (Geometry) geomi.next(); if (elem instanceof LineString) { - LineString line = (LineString) elem; - if (line.getNumPoints() >= 2) { - Coordinate p0 = line.getCoordinateN(0); - Coordinate p1 = line.getCoordinateN(1); - //-- the usual non-zero-length case will have first two points non-equal - if (! p0.equals2D(p1) - || line.getLength() > 0) { - return false; - } - } + if (! isZeroLength((LineString) elem)) + return false; + } + } + return true; + } + + private static boolean isZeroLength(LineString line) { + if (line.getNumPoints() >= 2) { + Coordinate p0 = line.getCoordinateN(0); + for (int i = 0 ; i < line.getNumPoints(); i++) { + Coordinate pi = line.getCoordinateN(1); + //-- most non-zero-len lines will trigger this right away + if (! p0.equals2D(pi)) + return false; } } return true; @@ -173,7 +176,7 @@ public boolean hasDimension(int dim) { return false; } - public int getDimensionEffective() { + public int getDimensionReal() { if (isGeomEmpty) return Dimension.FALSE; if (getDimension() == 1 && isLineZeroLen) return Dimension.P; @@ -274,7 +277,7 @@ private Set createUniquePoints() { public List getEffectivePoints() { List ptListAll = PointExtracter.getPoints(geom); - if (getDimensionEffective() <= Dimension.P) + if (getDimensionReal() <= Dimension.P) return ptListAll; //-- only return Points not covered by another element diff --git a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateNG.java b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateNG.java index 756281122..6fb4cf3d5 100644 --- a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateNG.java +++ b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelateNG.java @@ -227,8 +227,8 @@ public boolean evaluate(Geometry b, TopologyPredicate predicate) { //TODO: what if predicate is disjoint? Perhaps use result on disjoint envs? return finishValue(predicate); } - int dimA = geomA.getDimensionEffective(); - int dimB = geomB.getDimensionEffective(); + int dimA = geomA.getDimensionReal(); + int dimB = geomB.getDimensionReal(); //-- check if predicate is determined by dimension or envelope predicate.init(dimA, dimB); @@ -307,19 +307,19 @@ private void computePP(RelateGeometry geomB, TopologyComputer topoComputer) { } } - private void computeAtPoints(RelateGeometry geomSrc, boolean isA, + private void computeAtPoints(RelateGeometry geom, boolean isA, RelateGeometry geomTarget, TopologyComputer topoComputer) { boolean isResultKnown = false; - isResultKnown = computePoints(geomSrc, isA, geomTarget, topoComputer); + isResultKnown = computePoints(geom, isA, geomTarget, topoComputer); if (isResultKnown) return; - isResultKnown = computeLineEnds(geomSrc, isA, geomTarget, topoComputer); + isResultKnown = computeLineEnds(geom, isA, geomTarget, topoComputer); if (isResultKnown) return; - computeAreaVertices(geomSrc, isA, geomTarget, topoComputer); + computeAreaVertex(geom, isA, geomTarget, topoComputer); } private boolean computePoints(RelateGeometry geom, boolean isA, RelateGeometry geomTarget, @@ -364,7 +364,7 @@ private boolean computeLineEnds(RelateGeometry geom, boolean isA, RelateGeometry continue; if (elem instanceof LineString) { - //-- once an intersection with target exterior is recorded, skip further known exterior points + //-- once an intersection with target exterior is recorded, skip further known-exterior points if (hasExteriorIntersection && elem.getEnvelopeInternal().disjoint(geomTarget.getEnvelope())) continue; @@ -400,7 +400,7 @@ private boolean computeLineEnd(RelateGeometry geom, boolean isA, Coordinate pt, return locTarget == Location.EXTERIOR; } - private boolean computeAreaVertices(RelateGeometry geom, boolean isA, RelateGeometry geomTarget, TopologyComputer topoComputer) { + private boolean computeAreaVertex(RelateGeometry geom, boolean isA, RelateGeometry geomTarget, TopologyComputer topoComputer) { if (! geom.hasDimension(Dimension.A)) { return false; } @@ -416,7 +416,7 @@ private boolean computeAreaVertices(RelateGeometry geom, boolean isA, RelateGeom continue; if (elem instanceof Polygon) { - //-- once an intersection with target exterior is recorded, skip further known exterior points + //-- once an intersection with target exterior is recorded, skip further known-exterior points if (hasExteriorIntersection && elem.getEnvelopeInternal().disjoint(geomTarget.getEnvelope())) continue; diff --git a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyComputer.java b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyComputer.java index e72e19094..06f686ed8 100644 --- a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyComputer.java +++ b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/TopologyComputer.java @@ -39,44 +39,44 @@ public TopologyComputer(TopologyPredicate predicate, RelateGeometry geomA, Relat } /** - * Determine partial topology in the EXTERIORs a priori. + * Determine a priori partial EXTERIOR topology based on dimensions. */ private void initExteriorDims() { - int dimAEff = geomA.getDimensionEffective(); - int dimBEff = geomB.getDimensionEffective(); + int dimRealA = geomA.getDimensionReal(); + int dimRealB = geomB.getDimensionReal(); /** * For P/L case, P exterior intersects L interior */ - if (dimAEff == Dimension.P && dimBEff == Dimension.L) { + if (dimRealA == Dimension.P && dimRealB == Dimension.L) { updateDim(Location.EXTERIOR, Location.INTERIOR, Dimension.L); } - else if (dimAEff == Dimension.L && dimBEff == Dimension.P) { + else if (dimRealA == Dimension.L && dimRealB == Dimension.P) { updateDim(Location.INTERIOR, Location.EXTERIOR, Dimension.L); } /** * For P/A case, the Area Int and Bdy intersect the Point exterior. */ - else if (dimAEff == Dimension.P && dimBEff == Dimension.A) { + else if (dimRealA == Dimension.P && dimRealB == Dimension.A) { updateDim(Location.EXTERIOR, Location.INTERIOR, Dimension.A); updateDim(Location.EXTERIOR, Location.BOUNDARY, Dimension.L); } - else if (dimAEff == Dimension.A && dimBEff == Dimension.P) { + else if (dimRealA == Dimension.A && dimRealB == Dimension.P) { updateDim(Location.INTERIOR, Location.EXTERIOR, Dimension.A); updateDim(Location.BOUNDARY, Location.EXTERIOR, Dimension.L); } - else if (dimAEff == Dimension.L && dimBEff == Dimension.A) { + else if (dimRealA == Dimension.L && dimRealB == Dimension.A) { updateDim(Location.EXTERIOR, Location.INTERIOR, Dimension.A); } - else if (dimAEff == Dimension.A && dimBEff == Dimension.L) { + else if (dimRealA == Dimension.A && dimRealB == Dimension.L) { updateDim(Location.INTERIOR, Location.EXTERIOR, Dimension.A); } //-- cases where one geom is EMPTY - else if (dimAEff == Dimension.FALSE || dimBEff == Dimension.FALSE) { - if (dimAEff != Dimension.FALSE) { + else if (dimRealA == Dimension.FALSE || dimRealB == Dimension.FALSE) { + if (dimRealA != Dimension.FALSE) { initExteriorEmpty(RelateGeometry.GEOM_A); } - if (dimBEff != Dimension.FALSE) { + if (dimRealB != Dimension.FALSE) { initExteriorEmpty(RelateGeometry.GEOM_B); } }