diff --git a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/DimensionLocation.java b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/DimensionLocation.java index 2a64ca9c65..6aa32b286d 100644 --- a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/DimensionLocation.java +++ b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/DimensionLocation.java @@ -22,6 +22,29 @@ class DimensionLocation { public static final int LINE_BOUNDARY = 111; public static final int AREA_INTERIOR = 120; public static final int AREA_BOUNDARY = 121; + + public static int locationArea(int loc) { + switch (loc) { + case Location.INTERIOR: return AREA_INTERIOR; + case Location.BOUNDARY: return AREA_BOUNDARY; + } + return EXTERIOR; + } + + public static int locationLine(int loc) { + switch (loc) { + case Location.INTERIOR: return LINE_INTERIOR; + case Location.BOUNDARY: return LINE_BOUNDARY; + } + return EXTERIOR; + } + + public static int locationPoint(int loc) { + switch (loc) { + case Location.INTERIOR: return POINT_INTERIOR; + } + return EXTERIOR; + } public static int location(int dimLoc) { switch (dimLoc) { diff --git a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelatePointLocator.java b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelatePointLocator.java index 638621dc38..69c96f39b7 100644 --- a/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelatePointLocator.java +++ b/modules/core/src/main/java/org/locationtech/jts/operation/relateng/RelatePointLocator.java @@ -23,11 +23,9 @@ import org.locationtech.jts.algorithm.locate.SimplePointInAreaLocator; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.CoordinateSequence; -import org.locationtech.jts.geom.Dimension; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.GeometryCollection; import org.locationtech.jts.geom.LineString; -import org.locationtech.jts.geom.LinearRing; import org.locationtech.jts.geom.Location; import org.locationtech.jts.geom.MultiPolygon; import org.locationtech.jts.geom.Point; @@ -53,71 +51,6 @@ * */ class RelatePointLocator { - - private static class GeometryLocation { - private int elementDim = Dimension.FALSE; - private int numLineBoundaries = 0; // the number of sub-elements whose boundaries the point lies in - private int numAreaBoundaries = 0; - private int elementLocation = Location.EXTERIOR; - - public int getAreaBoundariesNum() { - return numAreaBoundaries; - } - - public boolean isLocated() { - return elementLocation != Location.EXTERIOR; - } - - public void updateLocationDim(int loc, int dimension) - { - if (loc == Location.EXTERIOR) { - return; - } - //-- locations in same or higher dimensions take precedence - if (dimension < elementDim) - return; - - elementDim = dimension; - - if (dimension == Dimension.A && elementLocation == Location.INTERIOR) { - /** - * Area interior takes precedence in overlaps, so don't change it - */ - return; - } - - if (loc == Location.BOUNDARY) { - switch (dimension) { - case Dimension.L: numLineBoundaries++; - case Dimension.A: numAreaBoundaries++; - } - } - elementLocation = loc; - } - - public int getDimLoc(BoundaryNodeRule boundaryRule) { - if (elementLocation == Location.EXTERIOR) - return DimensionLocation.EXTERIOR; - - if (elementDim == Dimension.P) { - return DimensionLocation.POINT_INTERIOR; - } - if (elementDim == Dimension.L) { - if (boundaryRule.isInBoundary(numLineBoundaries)) - return DimensionLocation.LINE_BOUNDARY; - return DimensionLocation.LINE_INTERIOR; - - } - if (elementDim == Dimension.A) { - if (elementLocation == Location.BOUNDARY) - return DimensionLocation.AREA_BOUNDARY; - if (elementLocation == Location.INTERIOR) - return DimensionLocation.AREA_INTERIOR; - } - - return DimensionLocation.EXTERIOR; - } - } private Geometry geom; private boolean isPrepared = false; @@ -265,84 +198,92 @@ private int locateWithDim(Coordinate p, boolean isNode, Geometry parentPolygonal if (isNode && (geom instanceof Polygon || geom instanceof MultiPolygon)) return DimensionLocation.AREA_BOUNDARY; - GeometryLocation geomLoc = new GeometryLocation(); - computeLocation(p, isNode, parentPolygonal, geomLoc); - return geomLoc.getDimLoc(boundaryRule); + int dimLoc = computeDimLocation(p, isNode, parentPolygonal); + return dimLoc; } - private void computeLocation(Coordinate p, boolean isNode, Geometry parentPolygonal, - GeometryLocation geomLoc) { + private int computeDimLocation(Coordinate p, boolean isNode, Geometry parentPolygonal) { + //-- check dimensions in order of precedence if (polygons != null) { - locateOnPolygons(p, isNode, parentPolygonal, geomLoc); - if (geomLoc.isLocated()) - return; + int locPoly = locateOnPolygons(p, isNode, parentPolygonal); + if (locPoly != Location.EXTERIOR) + return DimensionLocation.locationArea(locPoly); } if (lines != null) { - locateOnLines(p, isNode, geomLoc); - if (geomLoc.isLocated()) - return; + int locLine = locateOnLines(p, isNode); + if (locLine != Location.EXTERIOR) + return DimensionLocation.locationLine(locLine); } if (points != null) { - locateOnPoints(p, geomLoc); - if (geomLoc.isLocated()) - return; + int locPt = locateOnPoints(p); + if (locPt != Location.EXTERIOR) + return DimensionLocation.locationPoint(locPt); } + return DimensionLocation.EXTERIOR; } - private void locateOnPoints(Coordinate p, GeometryLocation geomLoc) { + private int locateOnPoints(Coordinate p) { if (points.contains(p)) { - geomLoc.updateLocationDim(Location.INTERIOR, Dimension.P); + return Location.INTERIOR; } + return Location.EXTERIOR; } - private void locateOnLines(Coordinate p, boolean isNode, GeometryLocation geomLoc) { + private int locateOnLines(Coordinate p, boolean isNode) { + if (lineBoundary != null + && lineBoundary.isBoundary(p)) { + return Location.BOUNDARY; + } + //-- must be on line, in interior + if (isNode) + return Location.INTERIOR; + //TODO: index the lines for (LineString line : lines) { //-- have to check every line, since any/all may contain point int loc = locateOnLine(p, isNode, line); - geomLoc.updateLocationDim(loc, Dimension.L); + if (loc != Location.EXTERIOR) + return loc; //TODO: minor optimization - some BoundaryNodeRules can short-circuit } + return Location.EXTERIOR; } private int locateOnLine(Coordinate p, boolean isNode, LineString l) { - CoordinateSequence seq = l.getCoordinateSequence(); - //-- check endpoints - if (p.equals(seq.getCoordinate(0)) - || p.equals(seq.getCoordinate(seq.size() - 1)) ) { - int boundaryCount = l.isClosed() ? 2 : 1; - int loc = boundaryRule.isInBoundary(boundaryCount) - ? Location.BOUNDARY : Location.INTERIOR; - return loc; - } - //-- must be on line, in interior - if (isNode) - return Location.INTERIOR; - // bounding-box check if (! l.getEnvelopeInternal().intersects(p)) return Location.EXTERIOR; + CoordinateSequence seq = l.getCoordinateSequence(); if (PointLocation.isOnLine(p, seq)) { return Location.INTERIOR; } return Location.EXTERIOR; } - private void locateOnPolygons(Coordinate p, boolean isNode, Geometry parentPolygonal, GeometryLocation geomLoc) { + private int locateOnPolygons(Coordinate p, boolean isNode, Geometry parentPolygonal) { + int numBdy = 0; for (int i = 0; i < polygons.size(); i++) { int loc = locateOnPolygonal(p, isNode, parentPolygonal, i); - geomLoc.updateLocationDim(loc, Dimension.A); + if (loc == Location.INTERIOR) { + return Location.INTERIOR; + } + if (loc == Location.BOUNDARY) { + numBdy += 1; + } + } + if (numBdy == 1) { + return Location.BOUNDARY; } - //-- check for points lying on adjacent boundaries - if (geomLoc.getAreaBoundariesNum() > 1) { + //-- check for point lying on adjacent boundaries + else if (numBdy > 1) { if (adjEdgeLocator == null) { adjEdgeLocator = new AdjacentEdgeLocator(geom); } - int loc = adjEdgeLocator.locate(p); - geomLoc.updateLocationDim(loc, Dimension.A); + return adjEdgeLocator.locate(p); } + return Location.EXTERIOR; } private int locateOnPolygonal(Coordinate p, boolean isNode, Geometry parentPolygonal, int index) {