diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java index 67f624f3194..94783882c46 100755 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java @@ -164,32 +164,44 @@ public class GeoPolygonFactory { return null; } - //First approximation to find a point - final GeoPoint centerOfMass = getCenterOfMass(planetModel, filteredPointList); - final Boolean isCenterOfMassInside = isInsidePolygon(centerOfMass, filteredPointList); - if (isCenterOfMassInside != null) { - return generateGeoPolygon(planetModel, filteredPointList, holes, centerOfMass, isCenterOfMassInside); - } - - //System.err.println("points="+pointList); - // Create a random number generator. Effectively this furnishes us with a repeatable sequence - // of points to use for poles. - final Random generator = new Random(1234); - for (int counter = 0; counter < 1000000; counter++) { - //counter++; - // Pick the next random pole - final GeoPoint pole = pickPole(generator, planetModel, filteredPointList); - // Is it inside or outside? - final Boolean isPoleInside = isInsidePolygon(pole, filteredPointList); - if (isPoleInside != null) { - // Legal pole - //System.out.println("Took "+counter+" iterations to find pole"); - //System.out.println("Pole = "+pole+"; isInside="+isPoleInside+"; pointList = "+pointList); - return generateGeoPolygon(planetModel, filteredPointList, holes, pole, isPoleInside); + try { + //First approximation to find a point + final GeoPoint centerOfMass = getCenterOfMass(planetModel, filteredPointList); + final Boolean isCenterOfMassInside = isInsidePolygon(centerOfMass, filteredPointList); + if (isCenterOfMassInside != null) { + return generateGeoPolygon(planetModel, filteredPointList, holes, centerOfMass, isCenterOfMassInside); } - // If pole choice was illegal, try another one + + //System.err.println("points="+pointList); + // Create a random number generator. Effectively this furnishes us with a repeatable sequence + // of points to use for poles. + final Random generator = new Random(1234); + for (int counter = 0; counter < 1000000; counter++) { + //counter++; + // Pick the next random pole + final GeoPoint pole = pickPole(generator, planetModel, filteredPointList); + // Is it inside or outside? + final Boolean isPoleInside = isInsidePolygon(pole, filteredPointList); + if (isPoleInside != null) { + // Legal pole + //System.out.println("Took "+counter+" iterations to find pole"); + //System.out.println("Pole = "+pole+"; isInside="+isPoleInside+"; pointList = "+pointList); + return generateGeoPolygon(planetModel, filteredPointList, holes, pole, isPoleInside); + } + // If pole choice was illegal, try another one + } + throw new IllegalArgumentException("cannot find a point that is inside the polygon "+filteredPointList); + } catch (TileException e) { + // Couldn't tile the polygon; use GeoComplexPolygon instead, if we can. + if (holes != null && holes.size() > 0) { + // We currently cannot get the list of points that went into making a hole back out, so don't allow this case. + // In order to support it, we really need to change the API contract, which is a bigger deal. + throw new IllegalArgumentException(e.getMessage()); + } + final List description = new ArrayList<>(1); + description.add(new PolygonDescription(pointList)); + return makeLargeGeoPolygon(planetModel, description); } - throw new IllegalArgumentException("cannot find a point that is inside the polygon "+filteredPointList); } /** Generate a point at the center of mass of a list of points. @@ -372,7 +384,7 @@ public class GeoPolygonFactory { final List filteredPointList, final List holes, final GeoPoint testPoint, - final boolean testPointInside) { + final boolean testPointInside) throws TileException { // We will be trying twice to find the right GeoPolygon, using alternate siding choices for the first polygon // side. While this looks like it might be 2x as expensive as it could be, there's really no other choice I can // find. @@ -750,7 +762,7 @@ public class GeoPolygonFactory { final int endPointIndex, final SidedPlane startingEdge, final List holes, - final GeoPoint testPoint) { + final GeoPoint testPoint) throws TileException { // It could be the case that we need a concave polygon. So we need to try and look for that case // as part of the general code for constructing complex polygons. @@ -1003,7 +1015,7 @@ public class GeoPolygonFactory { if (foundBadEdge) { // Unaddressed bad edge - throw new IllegalArgumentException("Could not tile polygon; found a pathological coplanarity that couldn't be addressed"); + throw new TileException("Could not tile polygon; found a pathological coplanarity that couldn't be addressed"); } // No violations found: we know it's a legal concave polygon. @@ -1686,4 +1698,11 @@ public class GeoPolygonFactory { public boolean value = false; } + /** Exception we throw when we can't tile a polygon due to numerical precision issues. + */ + private static class TileException extends Exception { + public TileException(final String msg) { + super(msg); + } + } } 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 a780bad350e..fdc9c6d946a 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 @@ -22,7 +22,6 @@ import java.util.BitSet; import java.util.Collections; import org.junit.Test; -import org.junit.Ignore; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -623,7 +622,7 @@ shape: } @Test - public void testPolygonFactoryCase3() { + public void testPolygonFactoryCase3() throws Exception { /* This one failed to be detected as convex: @@ -1102,7 +1101,6 @@ shape: } @Test - @Ignore public void testCoplanarityTileConvex() throws Exception { // This test has been disabled because it is possible that the polygon specified actually intersects itself. //POLYGON((24.39398 65.77519,24.3941 65.77498,24.394024 65.77497,24.393976 65.77495,24.393963 65.77493,24.394068 65.774925,24.394156 65.77495,24.394201 65.77495,24.394234 65.77496,24.394266 65.77498,24.394318 65.77498,24.39434 65.774956,24.394377 65.77495,24.394451 65.77494,24.394476 65.77495,24.394457 65.77498,24.39398 65.77519))" @@ -1123,12 +1121,11 @@ shape: points.add(new GeoPoint(PlanetModel.SPHERE, Geo3DUtil.fromDegrees(65.77494), Geo3DUtil.fromDegrees(24.394451))); points.add(new GeoPoint(PlanetModel.SPHERE, Geo3DUtil.fromDegrees(65.77495), Geo3DUtil.fromDegrees(24.394476))); points.add(new GeoPoint(PlanetModel.SPHERE, Geo3DUtil.fromDegrees(65.77498), Geo3DUtil.fromDegrees(24.394457))); - GeoCompositePolygon polygon = (GeoCompositePolygon)GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points); + GeoPolygon polygon = GeoPolygonFactory.makeGeoPolygon(PlanetModel.SPHERE, points); assertTrue(polygon != null); } @Test - @Ignore public void testCoplanarityConcave() throws Exception { //POLYGON((-52.18851 64.53777,-52.18853 64.53828,-52.18675 64.53829,-52.18676 64.53855,-52.18736 64.53855,-52.18737 64.53881,-52.18677 64.53881,-52.18683 64.54009,-52.18919 64.53981,-52.18916 64.53905,-52.19093 64.53878,-52.19148 64.53775,-52.18851 64.53777)) List points = new ArrayList<>();