blob: a692798170d207148178d6862bf59c408a6b1c8a [file] [log] [blame]
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 fb024b6..e2625b5 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
@@ -33,6 +33,8 @@ public class GeoConvexPolygon extends GeoBasePolygon {
protected final List<GeoPoint> points;
/** A bitset describing, for each edge, whether it is internal or not */
protected final BitSet isInternalEdges;
+ /** The list of holes. If a point is in the hole, it is *not* in the polygon */
+ protected final List<GeoPolygon> holes;
/** A list of edges */
protected SidedPlane[] edges = null;
@@ -44,7 +46,7 @@ public class GeoConvexPolygon extends GeoBasePolygon {
protected double fullDistance = 0.0;
/** Set to true when the polygon is complete */
protected boolean isDone = false;
-
+
/**
* Create a convex polygon from a list of points. The first point must be on the
* external edge.
@@ -52,8 +54,20 @@ public class GeoConvexPolygon extends GeoBasePolygon {
*@param pointList is the list of points to create the polygon from.
*/
public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList) {
+ this(planetModel, pointList, null);
+ }
+
+ /**
+ * Create a convex polygon from a list of points. The first point must be on the
+ * external edge.
+ *@param planetModel is the planet model.
+ *@param pointList is the list of points to create the polygon from.
+ *@param holes is the list of GeoPolygon objects that describe holes in the complex polygon. Null == no holes.
+ */
+ public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final List<GeoPolygon> holes) {
super(planetModel);
this.points = pointList;
+ this.holes = holes;
this.isInternalEdges = new BitSet();
done(false);
}
@@ -66,10 +80,30 @@ public class GeoConvexPolygon extends GeoBasePolygon {
*@param internalEdgeFlags is a bitset describing whether each edge is internal or not.
*@param returnEdgeInternal is true when the final return edge is an internal one.
*/
- public GeoConvexPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final BitSet internalEdgeFlags,
- final boolean returnEdgeInternal) {
+ public GeoConvexPolygon(final PlanetModel planetModel,
+ final List<GeoPoint> pointList,
+ final BitSet internalEdgeFlags,
+ final boolean returnEdgeInternal) {
+ this(planetModel, pointList, null, internalEdgeFlags, returnEdgeInternal);
+ }
+
+ /**
+ * Create a convex polygon from a list of points, keeping track of which boundaries
+ * are internal. This is used when creating a polygon as a building block for another shape.
+ *@param planetModel is the planet model.
+ *@param pointList is the set of points to create the polygon from.
+ *@param holes is the list of GeoPolygon objects that describe holes in the complex polygon. Null == no holes.
+ *@param internalEdgeFlags is a bitset describing whether each edge is internal or not.
+ *@param returnEdgeInternal is true when the final return edge is an internal one.
+ */
+ public GeoConvexPolygon(final PlanetModel planetModel,
+ final List<GeoPoint> pointList,
+ final List<GeoPolygon> holes,
+ final BitSet internalEdgeFlags,
+ final boolean returnEdgeInternal) {
super(planetModel);
this.points = pointList;
+ this.holes = holes;
this.isInternalEdges = internalEdgeFlags;
done(returnEdgeInternal);
}
@@ -81,9 +115,27 @@ public class GeoConvexPolygon extends GeoBasePolygon {
*@param startLatitude is the latitude of the first point.
*@param startLongitude is the longitude of the first point.
*/
- public GeoConvexPolygon(final PlanetModel planetModel, final double startLatitude, final double startLongitude) {
+ public GeoConvexPolygon(final PlanetModel planetModel,
+ final double startLatitude,
+ final double startLongitude) {
+ this(planetModel, startLatitude, startLongitude, null);
+ }
+
+ /**
+ * Create a convex polygon, with a starting latitude and longitude.
+ * Accepts only values in the following ranges: lat: {@code -PI/2 -> PI/2}, lon: {@code -PI -> PI}
+ *@param planetModel is the planet model.
+ *@param startLatitude is the latitude of the first point.
+ *@param startLongitude is the longitude of the first point.
+ *@param holes is the list of GeoPolygon objects that describe holes in the complex polygon. Null == no holes.
+ */
+ public GeoConvexPolygon(final PlanetModel planetModel,
+ final double startLatitude,
+ final double startLongitude,
+ final List<GeoPolygon> holes) {
super(planetModel);
points = new ArrayList<>();
+ this.holes = holes;
isInternalEdges = new BitSet();
points.add(new GeoPoint(planetModel, startLatitude, startLongitude));
}
@@ -138,12 +190,6 @@ public class GeoConvexPolygon extends GeoBasePolygon {
edges[i] = sp;
notableEdgePoints[i] = new GeoPoint[]{start, end};
}
- createCenterPoint();
- }
-
- /** Compute a reasonable center point.
- */
- protected void createCenterPoint() {
// In order to naively confirm that the polygon is convex, I would need to
// check every edge, and verify that every point (other than the edge endpoints)
// is within the edge's sided plane. This is an order n^2 operation. That's still
@@ -157,6 +203,7 @@ public class GeoConvexPolygon extends GeoBasePolygon {
}
}
}
+ // Pick an edge point arbitrarily
edgePoints = new GeoPoint[]{points.get(0)};
}
@@ -176,6 +223,13 @@ public class GeoConvexPolygon extends GeoBasePolygon {
if (!edge.isWithin(x, y, z))
return false;
}
+ if (holes != null) {
+ for (final GeoPolygon polygon : holes) {
+ if (polygon.isWithin(x, y, z)) {
+ return false;
+ }
+ }
+ }
return true;
}
@@ -207,6 +261,14 @@ public class GeoConvexPolygon extends GeoBasePolygon {
}
}
}
+ if (holes != null) {
+ // Each hole needs to be looked at for intersection too, since a shape can be entirely within the hole
+ for (final GeoPolygon hole : holes) {
+ if (hole.intersects(p, notablePoints, bounds)) {
+ return true;
+ }
+ }
+ }
//System.err.println(" no intersection");
return false;
}
@@ -270,6 +332,14 @@ public class GeoConvexPolygon extends GeoBasePolygon {
return false;
if (!other.isInternalEdges.equals(isInternalEdges))
return false;
+ if (other.holes != null || holes != null) {
+ if (other.holes == null || holes == null) {
+ return false;
+ }
+ if (!other.holes.equals(holes)) {
+ return false;
+ }
+ }
return (other.points.equals(points));
}
@@ -277,12 +347,15 @@ public class GeoConvexPolygon extends GeoBasePolygon {
public int hashCode() {
int result = super.hashCode();
result = 31 * result + points.hashCode();
+ if (holes != null) {
+ result = 31 * result + holes.hashCode();
+ }
return result;
}
@Override
public String toString() {
- return "GeoConvexPolygon: {planetmodel=" + planetModel + ", points=" + points + "}";
+ return "GeoConvexPolygon: {planetmodel=" + planetModel + ", points=" + points + ((holes== null)?"":", holes=" + holes) + "}";
}
}
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 8ee4290..cfcd1ac 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
@@ -37,13 +37,32 @@ public class GeoPolygonFactory {
* its neighbors determines inside/outside for the entire polygon.
* @return a GeoPolygon corresponding to what was specified.
*/
- public static GeoPolygon makeGeoPolygon(final PlanetModel planetModel, final List<GeoPoint> pointList, final int convexPointIndex) {
+ public static GeoPolygon makeGeoPolygon(final PlanetModel planetModel,
+ final List<GeoPoint> pointList,
+ final int convexPointIndex) {
+ return makeGeoPolygon(planetModel, pointList, convexPointIndex, null);
+ }
+
+ /**
+ * Create a GeoMembershipShape of the right kind given the specified bounds.
+ *
+ * @param pointList is a list of the GeoPoints to build an arbitrary polygon out of.
+ * @param convexPointIndex is the index of a single convex point whose conformation with
+ * its neighbors determines inside/outside for the entire polygon.
+ * @param holes is a list of polygons representing "holes" in the outside polygon. Null == none.
+ * @return a GeoPolygon corresponding to what was specified.
+ */
+ public static GeoPolygon makeGeoPolygon(final PlanetModel planetModel,
+ final List<GeoPoint> pointList,
+ final int convexPointIndex,
+ final List<GeoPolygon> holes) {
// The basic operation uses a set of points, two points determining one particular edge, and a sided plane
// describing membership.
return buildPolygonShape(planetModel, pointList, convexPointIndex, getLegalIndex(convexPointIndex + 1, pointList.size()),
new SidedPlane(pointList.get(getLegalIndex(convexPointIndex - 1, pointList.size())),
pointList.get(convexPointIndex), pointList.get(getLegalIndex(convexPointIndex + 1, pointList.size()))),
- false);
+ false,
+ holes);
}
/** Build a GeoMembershipShape given points, starting edge, and whether starting edge is internal or not.
@@ -52,9 +71,17 @@ public class GeoPolygonFactory {
* @param endPointIndex is another of the points constituting the starting edge.
* @param startingEdge is the plane describing the starting edge.
* @param isInternalEdge is true if the specified edge is an internal one.
+ * @param holes is the list of holes in the polygon, or null if none.
* @return a GeoMembershipShape corresponding to what was specified.
*/
- public static GeoPolygon buildPolygonShape(final PlanetModel planetModel, final List<GeoPoint> pointsList, final int startPointIndex, final int endPointIndex, final SidedPlane startingEdge, final boolean isInternalEdge) {
+ public static GeoPolygon buildPolygonShape(
+ final PlanetModel planetModel,
+ final List<GeoPoint> pointsList,
+ final int startPointIndex,
+ final int endPointIndex,
+ final SidedPlane startingEdge,
+ final boolean isInternalEdge,
+ final List<GeoPolygon> holes) {
// Algorithm as follows:
// Start with sided edge. Go through all points in some order. For each new point, determine if the point is within all edges considered so far.
// If not, put it into a list of points for recursion. If it is within, add new edge and keep going.
@@ -119,7 +146,7 @@ public class GeoPolygonFactory {
}
// We want the other side for the recursion
SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
- rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true));
+ rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true, holes));
recursionList.clear();
}
currentList.add(newPoint);
@@ -147,11 +174,11 @@ public class GeoPolygonFactory {
SidedPlane newBoundary = new SidedPlane(currentList.get(currentList.size() - 2), currentList.get(0), currentList.get(currentList.size() - 1));
// We want the other side for the recursion
SidedPlane otherSideNewBoundary = new SidedPlane(newBoundary);
- rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true));
+ rval.addShape(buildPolygonShape(planetModel, recursionList, recursionList.size() - 2, recursionList.size() - 1, otherSideNewBoundary, true, holes));
recursionList.clear();
}
// Now, add in the current shape.
- rval.addShape(new GeoConvexPolygon(planetModel, currentList, internalEdgeList, returnEdgeInternalBoundary));
+ rval.addShape(new GeoConvexPolygon(planetModel, currentList, holes, internalEdgeList, returnEdgeInternalBoundary));
//System.out.println("Done creating polygon");
return rval;
}