LUCENE-8257: All edges have a backing plane, so edge membership doesn't bleed through to the opposite side of the world.

This commit is contained in:
Karl Wright 2018-04-17 02:45:44 -04:00
parent 72ee0f64d4
commit 4ee92c22a4
2 changed files with 34 additions and 5 deletions

View File

@ -590,6 +590,8 @@ class GeoComplexPolygon extends GeoBasePolygon {
}
}
private final static double[] halfProportions = new double[]{0.5};
/**
* An instance of this class describes a single edge, and includes what is necessary to reliably determine intersection
* in the context of the even/odd algorithm used.
@ -600,6 +602,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
public final GeoPoint[] notablePoints;
public final SidedPlane startPlane;
public final SidedPlane endPlane;
public final SidedPlane backingPlane;
public final Plane plane;
public final XYZBounds planeBounds;
public Edge previous = null;
@ -612,13 +615,19 @@ class GeoComplexPolygon extends GeoBasePolygon {
this.plane = new Plane(startPoint, endPoint);
this.startPlane = new SidedPlane(endPoint, plane, startPoint);
this.endPlane = new SidedPlane(startPoint, plane, endPoint);
final GeoPoint interpolationPoint = plane.interpolate(startPoint, endPoint, halfProportions)[0];
this.backingPlane = new SidedPlane(interpolationPoint, interpolationPoint, 0.0);
this.planeBounds = new XYZBounds();
this.planeBounds.addPoint(startPoint);
this.planeBounds.addPoint(endPoint);
this.planeBounds.addPlane(pm, this.plane, this.startPlane, this.endPlane);
this.planeBounds.addPlane(pm, this.plane, this.startPlane, this.endPlane, this.backingPlane);
//System.err.println("Recording edge "+this+" from "+startPoint+" to "+endPoint+"; bounds = "+planeBounds);
}
public boolean isWithin(final double thePointX, final double thePointY, final double thePointZ) {
return plane.evaluateIsZero(thePointX, thePointY, thePointZ) && startPlane.isWithin(thePointX, thePointY, thePointZ) && endPlane.isWithin(thePointX, thePointY, thePointZ) && backingPlane.isWithin(thePointX, thePointY, thePointZ);
}
// Hashcode and equals are system default!!
}
@ -945,7 +954,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
@Override
public boolean matches(final Edge edge) {
// Early exit if the point is on the edge.
if (edge.plane.evaluateIsZero(thePointX, thePointY, thePointZ) && edge.startPlane.isWithin(thePointX, thePointY, thePointZ) && edge.endPlane.isWithin(thePointX, thePointY, thePointZ)) {
if (edge.isWithin(thePointX, thePointY, thePointZ)) {
return false;
}
@ -1041,7 +1050,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
@Override
public boolean matches(final Edge edge) {
// Early exit if the point is on the edge.
if (edge.plane.evaluateIsZero(thePointX, thePointY, thePointZ) && edge.startPlane.isWithin(thePointX, thePointY, thePointZ) && edge.endPlane.isWithin(thePointX, thePointY, thePointZ)) {
if (edge.isWithin(thePointX, thePointY, thePointZ)) {
return false;
}
@ -1289,7 +1298,7 @@ class GeoComplexPolygon extends GeoBasePolygon {
@Override
public boolean matches(final Edge edge) {
// Early exit if the point is on the edge, in which case we accidentally discovered the answer.
if (edge.plane.evaluateIsZero(thePointX, thePointY, thePointZ) && edge.startPlane.isWithin(thePointX, thePointY, thePointZ) && edge.endPlane.isWithin(thePointX, thePointY, thePointZ)) {
if (edge.isWithin(thePointX, thePointY, thePointZ)) {
return false;
}

View File

@ -1586,5 +1586,25 @@ shape:
final GeoPoint point = new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(1.98E-321), Geo3DUtil.fromDegrees(0.005183505059185348));
assertTrue(polygon.isWithin(point) == largePolygon.isWithin(point));
}
@Test
public void testLUCENE8257() {
//POLYGON((12.9610296281349 -8.35317290232106,15.448601008878832 -3.990004427754539,22.375905319231205 0.2308875600810982,-13.473550791109867 30.10483127471788,-17.854443360411242 33.07441476406424,-3.928621142543736E-11 4.688559453373203E-11,0.0 -5.546974900361278E-104,12.9610296281349 -8.35317290232106))
final List<GeoPoint> points = new ArrayList<>();
points.add(new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(-8.35317290232106), Geo3DUtil.fromDegrees(12.9610296281349)));
points.add(new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(-3.990004427754539), Geo3DUtil.fromDegrees(15.448601008878832)));
points.add(new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(0.2308875600810982), Geo3DUtil.fromDegrees(22.375905319231205)));
points.add(new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(30.10483127471788), Geo3DUtil.fromDegrees(-13.473550791109867)));
points.add(new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(33.07441476406424), Geo3DUtil.fromDegrees(-17.854443360411242)));
points.add(new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(4.688559453373203E-11), Geo3DUtil.fromDegrees(-3.928621142543736E-11)));
points.add(new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(-5.546974900361278E-104), Geo3DUtil.fromDegrees(0.0)));
final GeoPolygonFactory.PolygonDescription description = new GeoPolygonFactory.PolygonDescription(points);
final GeoPolygon polygon = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, description);
final GeoPolygon largePolygon = GeoPolygonFactory.makeLargeGeoPolygon(PlanetModel.WGS84, Collections.singletonList(description));
//POINT(-179.99999999999997 -9.638811778842766E-12)
final GeoPoint point = new GeoPoint(PlanetModel.WGS84, Geo3DUtil.fromDegrees(-9.638811778842766E-12), Geo3DUtil.fromDegrees(-179.99999999999997));
assertTrue(polygon.isWithin(point) == largePolygon.isWithin(point));
}
}