mirror of https://github.com/apache/lucene.git
LUCENE-7250: Handle holes properly for distance and relationship calculation.
This commit is contained in:
parent
bb2293cf7e
commit
5d1b3baecd
|
@ -142,7 +142,7 @@ public final class Geo3DPoint extends Field {
|
||||||
}
|
}
|
||||||
final GeoShape shape;
|
final GeoShape shape;
|
||||||
if (polygons.length == 1) {
|
if (polygons.length == 1) {
|
||||||
final GeoShape component = fromPolygon(polygons[0], false);
|
final GeoShape component = fromPolygon(polygons[0]);
|
||||||
if (component == null) {
|
if (component == null) {
|
||||||
// Polygon is degenerate
|
// Polygon is degenerate
|
||||||
shape = new GeoCompositePolygon();
|
shape = new GeoCompositePolygon();
|
||||||
|
@ -152,7 +152,7 @@ public final class Geo3DPoint extends Field {
|
||||||
} else {
|
} else {
|
||||||
final GeoCompositePolygon poly = new GeoCompositePolygon();
|
final GeoCompositePolygon poly = new GeoCompositePolygon();
|
||||||
for (final Polygon p : polygons) {
|
for (final Polygon p : polygons) {
|
||||||
final GeoPolygon component = fromPolygon(p, false);
|
final GeoPolygon component = fromPolygon(p);
|
||||||
if (component != null) {
|
if (component != null) {
|
||||||
poly.addShape(component);
|
poly.addShape(component);
|
||||||
}
|
}
|
||||||
|
@ -192,17 +192,16 @@ public final class Geo3DPoint extends Field {
|
||||||
* Convert a Polygon object into a GeoPolygon.
|
* Convert a Polygon object into a GeoPolygon.
|
||||||
* This method uses
|
* This method uses
|
||||||
* @param polygon is the Polygon object.
|
* @param polygon is the Polygon object.
|
||||||
* @param reverseMe is true if the order of the points should be reversed.
|
|
||||||
* @return the GeoPolygon.
|
* @return the GeoPolygon.
|
||||||
*/
|
*/
|
||||||
private static GeoPolygon fromPolygon(final Polygon polygon, final boolean reverseMe) {
|
private static GeoPolygon fromPolygon(final Polygon polygon) {
|
||||||
// First, assemble the "holes". The geo3d convention is to use the same polygon sense on the inner ring as the
|
// First, assemble the "holes". The geo3d convention is to use the same polygon sense on the inner ring as the
|
||||||
// outer ring, so we process these recursively with reverseMe flipped.
|
// outer ring, so we process these recursively with reverseMe flipped.
|
||||||
final Polygon[] theHoles = polygon.getHoles();
|
final Polygon[] theHoles = polygon.getHoles();
|
||||||
final List<GeoPolygon> holeList = new ArrayList<>(theHoles.length);
|
final List<GeoPolygon> holeList = new ArrayList<>(theHoles.length);
|
||||||
for (final Polygon hole : theHoles) {
|
for (final Polygon hole : theHoles) {
|
||||||
//System.out.println("Hole: "+hole);
|
//System.out.println("Hole: "+hole);
|
||||||
final GeoPolygon component = fromPolygon(hole, !reverseMe);
|
final GeoPolygon component = fromPolygon(hole);
|
||||||
if (component != null) {
|
if (component != null) {
|
||||||
holeList.add(component);
|
holeList.add(component);
|
||||||
}
|
}
|
||||||
|
@ -216,12 +215,8 @@ public final class Geo3DPoint extends Field {
|
||||||
final List<GeoPoint> points = new ArrayList<>(polyLats.length-1);
|
final List<GeoPoint> points = new ArrayList<>(polyLats.length-1);
|
||||||
// We skip the last point anyway because the API requires it to be repeated, and geo3d doesn't repeat it.
|
// We skip the last point anyway because the API requires it to be repeated, and geo3d doesn't repeat it.
|
||||||
for (int i = 0; i < polyLats.length - 1; i++) {
|
for (int i = 0; i < polyLats.length - 1; i++) {
|
||||||
if (reverseMe) {
|
final int index = polyLats.length - 2 - i;
|
||||||
points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[i]), fromDegrees(polyLons[i])));
|
points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
|
||||||
} else {
|
|
||||||
final int index = polyLats.length - 2 - i;
|
|
||||||
points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//System.err.println(" building polygon with "+points.size()+" points...");
|
//System.err.println(" building polygon with "+points.size()+" points...");
|
||||||
final GeoPolygon rval = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, points, holeList);
|
final GeoPolygon rval = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, points, holeList);
|
||||||
|
|
|
@ -224,8 +224,25 @@ class GeoConcavePolygon extends GeoBasePolygon {
|
||||||
eitherBounds.put(edge, new EitherBound(invertedEdges[legalIndex(bound1Index)], invertedEdges[legalIndex(bound2Index)]));
|
eitherBounds.put(edge, new EitherBound(invertedEdges[legalIndex(bound1Index)], invertedEdges[legalIndex(bound2Index)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick an edge point arbitrarily
|
// Pick an edge point arbitrarily from the outer polygon. Glom this together with all edge points from
|
||||||
edgePoints = new GeoPoint[]{points.get(0)};
|
// inner polygons.
|
||||||
|
int edgePointCount = 1;
|
||||||
|
if (holes != null) {
|
||||||
|
for (final GeoPolygon hole : holes) {
|
||||||
|
edgePointCount += hole.getEdgePoints().length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
edgePoints = new GeoPoint[edgePointCount];
|
||||||
|
edgePointCount = 0;
|
||||||
|
edgePoints[edgePointCount++] = points.get(0);
|
||||||
|
if (holes != null) {
|
||||||
|
for (final GeoPolygon hole : holes) {
|
||||||
|
final GeoPoint[] holeEdgePoints = hole.getEdgePoints();
|
||||||
|
for (final GeoPoint p : holeEdgePoints) {
|
||||||
|
edgePoints[edgePointCount++] = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isWithinHoles(points.get(0))) {
|
if (isWithinHoles(points.get(0))) {
|
||||||
throw new IllegalArgumentException("Polygon edge intersects a polygon hole; not allowed");
|
throw new IllegalArgumentException("Polygon edge intersects a polygon hole; not allowed");
|
||||||
|
@ -240,7 +257,7 @@ class GeoConcavePolygon extends GeoBasePolygon {
|
||||||
protected boolean isWithinHoles(final GeoPoint point) {
|
protected boolean isWithinHoles(final GeoPoint point) {
|
||||||
if (holes != null) {
|
if (holes != null) {
|
||||||
for (final GeoPolygon hole : holes) {
|
for (final GeoPolygon hole : holes) {
|
||||||
if (hole.isWithin(point)) {
|
if (!hole.isWithin(point)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,7 +285,7 @@ class GeoConcavePolygon extends GeoBasePolygon {
|
||||||
}
|
}
|
||||||
if (holes != null) {
|
if (holes != null) {
|
||||||
for (final GeoPolygon polygon : holes) {
|
for (final GeoPolygon polygon : holes) {
|
||||||
if (polygon.isWithin(x, y, z)) {
|
if (!polygon.isWithin(x, y, z)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,6 +422,14 @@ class GeoConcavePolygon extends GeoBasePolygon {
|
||||||
minimumDistance = newDist;
|
minimumDistance = newDist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (holes != null) {
|
||||||
|
for (final GeoPolygon hole : holes) {
|
||||||
|
double holeDistance = hole.computeOutsideDistance(distanceStyle, x, y, z);
|
||||||
|
if (holeDistance != 0.0 && holeDistance < minimumDistance) {
|
||||||
|
minimumDistance = holeDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return minimumDistance;
|
return minimumDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,8 +219,25 @@ class GeoConvexPolygon extends GeoBasePolygon {
|
||||||
eitherBounds.put(edge, new EitherBound(edges[legalIndex(bound1Index)], edges[legalIndex(bound2Index)]));
|
eitherBounds.put(edge, new EitherBound(edges[legalIndex(bound1Index)], edges[legalIndex(bound2Index)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick an edge point arbitrarily
|
// Pick an edge point arbitrarily from the outer polygon. Glom this together with all edge points from
|
||||||
edgePoints = new GeoPoint[]{points.get(0)};
|
// inner polygons.
|
||||||
|
int edgePointCount = 1;
|
||||||
|
if (holes != null) {
|
||||||
|
for (final GeoPolygon hole : holes) {
|
||||||
|
edgePointCount += hole.getEdgePoints().length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
edgePoints = new GeoPoint[edgePointCount];
|
||||||
|
edgePointCount = 0;
|
||||||
|
edgePoints[edgePointCount++] = points.get(0);
|
||||||
|
if (holes != null) {
|
||||||
|
for (final GeoPolygon hole : holes) {
|
||||||
|
final GeoPoint[] holeEdgePoints = hole.getEdgePoints();
|
||||||
|
for (final GeoPoint p : holeEdgePoints) {
|
||||||
|
edgePoints[edgePointCount++] = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isWithinHoles(points.get(0))) {
|
if (isWithinHoles(points.get(0))) {
|
||||||
throw new IllegalArgumentException("Polygon edge intersects a polygon hole; not allowed");
|
throw new IllegalArgumentException("Polygon edge intersects a polygon hole; not allowed");
|
||||||
|
@ -235,7 +252,7 @@ class GeoConvexPolygon extends GeoBasePolygon {
|
||||||
protected boolean isWithinHoles(final GeoPoint point) {
|
protected boolean isWithinHoles(final GeoPoint point) {
|
||||||
if (holes != null) {
|
if (holes != null) {
|
||||||
for (final GeoPolygon hole : holes) {
|
for (final GeoPolygon hole : holes) {
|
||||||
if (hole.isWithin(point)) {
|
if (!hole.isWithin(point)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -263,7 +280,7 @@ class GeoConvexPolygon extends GeoBasePolygon {
|
||||||
}
|
}
|
||||||
if (holes != null) {
|
if (holes != null) {
|
||||||
for (final GeoPolygon polygon : holes) {
|
for (final GeoPolygon polygon : holes) {
|
||||||
if (polygon.isWithin(x, y, z)) {
|
if (!polygon.isWithin(x, y, z)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -393,6 +410,14 @@ class GeoConvexPolygon extends GeoBasePolygon {
|
||||||
minimumDistance = newDist;
|
minimumDistance = newDist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (holes != null) {
|
||||||
|
for (final GeoPolygon hole : holes) {
|
||||||
|
double holeDistance = hole.computeOutsideDistance(distanceStyle, x, y, z);
|
||||||
|
if (holeDistance != 0.0 && holeDistance < minimumDistance) {
|
||||||
|
minimumDistance = holeDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return minimumDistance;
|
return minimumDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,8 @@ public class GeoPolygonFactory {
|
||||||
* @param pointList is a list of the GeoPoints to build an arbitrary polygon out of. If points go
|
* @param pointList is a list of the GeoPoints to build an arbitrary polygon out of. If points go
|
||||||
* clockwise from a given pole, then that pole should be within the polygon. If points go
|
* clockwise from a given pole, then that pole should be within the polygon. If points go
|
||||||
* counter-clockwise, then that pole should be outside the polygon.
|
* counter-clockwise, then that pole should be outside the polygon.
|
||||||
* @param holes is a list of polygons representing "holes" in the outside polygon. Null == none.
|
* @param holes is a list of polygons representing "holes" in the outside polygon. Holes describe the area outside
|
||||||
|
* each hole as being "in set". Null == none.
|
||||||
* @return a GeoPolygon corresponding to what was specified, or null if a valid polygon cannot be generated
|
* @return a GeoPolygon corresponding to what was specified, or null if a valid polygon cannot be generated
|
||||||
* from this input.
|
* from this input.
|
||||||
*/
|
*/
|
||||||
|
@ -73,7 +74,8 @@ public class GeoPolygonFactory {
|
||||||
* @param pointList is a list of the GeoPoints to build an arbitrary polygon out of. If points go
|
* @param pointList is a list of the GeoPoints to build an arbitrary polygon out of. If points go
|
||||||
* clockwise from a given pole, then that pole should be within the polygon. If points go
|
* clockwise from a given pole, then that pole should be within the polygon. If points go
|
||||||
* counter-clockwise, then that pole should be outside the polygon.
|
* counter-clockwise, then that pole should be outside the polygon.
|
||||||
* @param holes is a list of polygons representing "holes" in the outside polygon. Null == none.
|
* @param holes is a list of polygons representing "holes" in the outside polygon. Holes describe the area outside
|
||||||
|
* each hole as being "in set". Null == none.
|
||||||
* @param leniencyValue is the maximum distance (in units) that a point can be from the plane and still be considered as
|
* @param leniencyValue is the maximum distance (in units) that a point can be from the plane and still be considered as
|
||||||
* belonging to the plane. Any value greater than zero may cause some of the provided points that are in fact outside
|
* belonging to the plane. Any value greater than zero may cause some of the provided points that are in fact outside
|
||||||
* the strict definition of co-planarity, but are within this distance, to be discarded for the purposes of creating a
|
* the strict definition of co-planarity, but are within this distance, to be discarded for the purposes of creating a
|
||||||
|
|
Loading…
Reference in New Issue