From 44df5b60266549e410b7691ebf49583d7370c0e3 Mon Sep 17 00:00:00 2001 From: Karl Wright Date: Sat, 20 Aug 2016 07:35:38 -0400 Subject: [PATCH] LUCENE-7412: Make sure no combined edge of a polygon extends for more than 180 degrees. --- .../spatial3d/geom/GeoConcavePolygon.java | 16 ++++++++++- .../spatial3d/geom/GeoConvexPolygon.java | 16 ++++++++++- .../lucene/spatial3d/geom/GeoPolygonTest.java | 27 ++++++++++++++++--- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConcavePolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConcavePolygon.java index a133b3e77db..1abc06c30f4 100644 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConcavePolygon.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConcavePolygon.java @@ -237,7 +237,21 @@ class GeoConcavePolygon extends GeoBasePolygon { while (invertedEdges[legalIndex(bound2Index)].isNumericallyIdentical(invertedEdge)) { bound2Index--; } - eitherBounds.put(edge, new EitherBound(invertedEdges[legalIndex(bound1Index)], invertedEdges[legalIndex(bound2Index)])); + bound1Index = legalIndex(bound1Index); + bound2Index = legalIndex(bound2Index); + // Also confirm that all interior points are within the bounds + int startingIndex = bound2Index; + while (true) { + startingIndex = legalIndex(startingIndex+1); + if (startingIndex == bound1Index) { + break; + } + final GeoPoint interiorPoint = points.get(startingIndex); + if (!invertedEdges[bound1Index].isWithin(interiorPoint) || !invertedEdges[bound2Index].isWithin(interiorPoint)) { + throw new IllegalArgumentException("Concave polygon has a side that is more than 180 degrees"); + } + } + eitherBounds.put(edge, new EitherBound(invertedEdges[bound1Index], invertedEdges[bound2Index])); // For intersections, we look at the point at the intersection between the previous edge and this one. We need to locate the // Intersection bounds needs to look even further forwards/backwards if (otherInvertedEdge != null) { diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.java index 860eb2655ec..dbf8f9fb84b 100755 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoConvexPolygon.java @@ -230,7 +230,21 @@ class GeoConvexPolygon extends GeoBasePolygon { while (edges[legalIndex(bound2Index)].isNumericallyIdentical(edge)) { bound2Index--; } - eitherBounds.put(edge, new EitherBound(edges[legalIndex(bound1Index)], edges[legalIndex(bound2Index)])); + bound1Index = legalIndex(bound1Index); + bound2Index = legalIndex(bound2Index); + // Also confirm that all interior points are within the bounds + int startingIndex = bound2Index; + while (true) { + startingIndex = legalIndex(startingIndex+1); + if (startingIndex == bound1Index) { + break; + } + final GeoPoint interiorPoint = points.get(startingIndex); + if (!edges[bound1Index].isWithin(interiorPoint) || !edges[bound2Index].isWithin(interiorPoint)) { + throw new IllegalArgumentException("Convex polygon has a side that is more than 180 degrees"); + } + } + eitherBounds.put(edge, new EitherBound(edges[bound1Index], edges[bound2Index])); // For intersections, we look at the point at the intersection between the previous edge and this one. We need to locate the // Intersection bounds needs to look even further forwards/backwards if (otherEdge != null) { diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java index a5a02070c73..67450608bb0 100755 --- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java +++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/geom/GeoPolygonTest.java @@ -692,7 +692,7 @@ shape: polyList.add(p5); GeoPolygon p = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, polyList); - System.out.println("p = "+p); + //System.out.println("p = "+p); XYZBounds bounds = new XYZBounds(); p.getBounds(bounds); @@ -733,8 +733,8 @@ shape: final GeoPoint point = new GeoPoint(PlanetModel.WGS84, -0.41518838180529244, 3.141592653589793); final GeoPoint encodedPoint = new GeoPoint(-0.9155623168963972, 2.3309121299774915E-10, -0.40359240449795253); - System.out.println("point = "+point); - System.out.println("encodedPoint = "+encodedPoint); + //System.out.println("point = "+point); + //System.out.println("encodedPoint = "+encodedPoint); assertTrue(p.isWithin(point)); assertTrue(solid.isWithin(point)); @@ -906,5 +906,26 @@ shape: assertTrue(solid.isWithin(checkPoint)); } + + @Test + public void testPolygonFailureCase1() { + final List poly2List = new ArrayList<>(); + poly2List.add(new GeoPoint(PlanetModel.WGS84, -0.6370451769779303, 2.5318373679431616)); + poly2List.add(new GeoPoint(PlanetModel.WGS84, 1.5707963267948966, -3.141592653589793)); + poly2List.add(new GeoPoint(PlanetModel.WGS84, -1.0850383189690824, 2.4457272005608357E-47)); + poly2List.add(new GeoPoint(PlanetModel.WGS84, -0.5703530503197992, -3.141592653589793)); + final BitSet poly2Bitset = new BitSet(); + poly2Bitset.set(1); + + boolean result; + try { + final GeoConvexPolygon poly2 = new GeoConvexPolygon(PlanetModel.WGS84, poly2List); + result = true; + } catch (IllegalArgumentException e) { + result = false; + } + + assertTrue(!result); + } }