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 375ec6088e4..05e58ee5734 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 @@ -46,8 +46,6 @@ class GeoConcavePolygon extends GeoBasePolygon { protected GeoPoint[][] notableEdgePoints = null; /** A point which is on the boundary of the polygon */ protected GeoPoint[] edgePoints = null; - /** Tracking the maximum distance we go at any one time, so to be sure it's legal */ - protected double fullDistance = 0.0; /** Set to true when the polygon is complete */ protected boolean isDone = false; /** A bounds object for each sided plane */ @@ -189,10 +187,21 @@ class GeoConcavePolygon extends GeoBasePolygon { for (int i = 0; i < points.size(); i++) { final GeoPoint start = points.get(i); final GeoPoint end = points.get(legalIndex(i + 1)); - final double distance = start.arcDistance(end); - if (distance > fullDistance) - fullDistance = distance; - final GeoPoint check = points.get(legalIndex(i + 2)); + // We have to find the next point that is not on the plane between start and end. + // If there is no such point, it's an error. + final Plane planeToFind = new Plane(start, end); + int endPointIndex = -1; + for (int j = 0; j < points.size(); j++) { + final int index = legalIndex(j + i + 2); + if (!planeToFind.evaluateIsZero(points.get(index))) { + endPointIndex = index; + break; + } + } + if (endPointIndex == -1) { + throw new IllegalArgumentException("Polygon points are all coplanar"); + } + final GeoPoint check = points.get(endPointIndex); // Here note the flip of the sense of the sided plane!! final SidedPlane sp = new SidedPlane(check, false, start, end); //System.out.println("Created edge "+sp+" using start="+start+" end="+end+" check="+check); 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 0a48eeb3a37..d1e009178f3 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 @@ -44,8 +44,6 @@ class GeoConvexPolygon extends GeoBasePolygon { protected GeoPoint[][] notableEdgePoints = null; /** A point which is on the boundary of the polygon */ protected GeoPoint[] edgePoints = null; - /** Tracking the maximum distance we go at any one time, so to be sure it's legal */ - protected double fullDistance = 0.0; /** Set to true when the polygon is complete */ protected boolean isDone = false; /** A bounds object for each sided plane */ @@ -185,10 +183,21 @@ class GeoConvexPolygon extends GeoBasePolygon { for (int i = 0; i < points.size(); i++) { final GeoPoint start = points.get(i); final GeoPoint end = points.get(legalIndex(i + 1)); - final double distance = start.arcDistance(end); - if (distance > fullDistance) - fullDistance = distance; - final GeoPoint check = points.get(legalIndex(i + 2)); + // We have to find the next point that is not on the plane between start and end. + // If there is no such point, it's an error. + final Plane planeToFind = new Plane(start, end); + int endPointIndex = -1; + for (int j = 0; j < points.size(); j++) { + final int index = legalIndex(j + i + 2); + if (!planeToFind.evaluateIsZero(points.get(index))) { + endPointIndex = index; + break; + } + } + if (endPointIndex == -1) { + throw new IllegalArgumentException("Polygon points are all coplanar"); + } + final GeoPoint check = points.get(endPointIndex); final SidedPlane sp = new SidedPlane(check, start, end); //System.out.println("Created edge "+sp+" using start="+start+" end="+end+" check="+check); edges[i] = sp; 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 144c4a53009..67804a2accf 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 @@ -714,12 +714,17 @@ public class GeoPolygonFactory { // the start point of the first edge and the end point of the last edge. If the first edge start point is the same as the last edge end point, // it's a degenerate case and we want to just clean out the edge buffer entirely. - final List points = new ArrayList(includedEdges.size()); - final BitSet internalEdges = new BitSet(includedEdges.size()-1); + final List points = new ArrayList(includedEdges.size()+1); + final BitSet internalEdges = new BitSet(includedEdges.size()); final boolean returnIsInternal; if (firstEdge.startPoint == lastEdge.endPoint) { // Degenerate case!! There is no return edge -- or rather, we already have it. + if (includedEdges.size() < 3) { + // This means we found a degenerate cycle of edges. If we emit a polygon at this point it + // has no contents, so we've clearly done something wrong, but not sure what. + throw new IllegalArgumentException("polygon was illegal (degenerate illegal two-edge cyclical polygon encountered in processing)"); + } Edge edge = firstEdge; points.add(edge.startPoint); int i = 0; @@ -945,8 +950,39 @@ public class GeoPolygonFactory { // Get the next point final GeoPoint newPoint = pointList.get(endIndex); // Build the new edge - final boolean isNewPointWithin = currentEdge.plane.isWithin(newPoint); - final SidedPlane newPlane = new SidedPlane(currentEdge.startPoint, isNewPointWithin, pointList.get(startIndex), newPoint); + // We have to be sure that the point we use as a check does not lie on the plane. + // In order to meet that goal, we need to go hunting for a point that meets the criteria. If we don't + // find one, we've got a linear "polygon" that we cannot use. + + // We need to know the sidedness of the new plane. The point we're going to be presenting to it has + // a certain relationship with the sided plane we already have for the current edge. If the current edge + // is colinear with the new edge, then we want to maintain the same relationship. If the new edge + // is not colinear, then we can use the new point's relationship with the current edge as our guide. + + final boolean isNewPointWithin; + final GeoPoint pointToPresent; + if (currentEdge.plane.evaluateIsZero(newPoint)) { + // The new point is colinear with the current edge. We'll have to look for the first point that isn't. + int checkPointIndex = -1; + final Plane checkPlane = new Plane(pointList.get(startIndex), newPoint); + for (int i = 0; i < pointList.size(); i++) { + final int index = getLegalIndex(startIndex - 1 - i, pointList.size()); + if (!checkPlane.evaluateIsZero(pointList.get(index))) { + checkPointIndex = index; + break; + } + } + if (checkPointIndex == -1) { + throw new IllegalArgumentException("polygon is illegal (linear)"); + } + pointToPresent = pointList.get(checkPointIndex); + isNewPointWithin = currentEdge.plane.isWithin(pointToPresent); + } else { + isNewPointWithin = currentEdge.plane.isWithin(newPoint); + pointToPresent = currentEdge.startPoint; + } + + final SidedPlane newPlane = new SidedPlane(pointToPresent, isNewPointWithin, pointList.get(startIndex), newPoint); /* System.out.println("For next plane, the following points are in/out:"); for (final GeoPoint p: pointList) {