You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by kw...@apache.org on 2016/04/05 06:54:36 UTC

lucene-solr:branch_6x: LUCENE-7173: Bring polygon API into compliance with 2D version.

Repository: lucene-solr
Updated Branches:
  refs/heads/branch_6x b37da2b87 -> 1a33e75c2


LUCENE-7173: Bring polygon API into compliance with 2D version.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/1a33e75c
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/1a33e75c
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/1a33e75c

Branch: refs/heads/branch_6x
Commit: 1a33e75c2934b1cb7427d5b4e214f8589ee0139b
Parents: b37da2b
Author: Karl Wright <Da...@gmail.com>
Authored: Mon Apr 4 18:56:59 2016 -0400
Committer: Karl Wright <Da...@gmail.com>
Committed: Tue Apr 5 00:52:03 2016 -0400

----------------------------------------------------------------------
 .../org/apache/lucene/spatial3d/Geo3DPoint.java | 122 ++++++++++---------
 1 file changed, 62 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/1a33e75c/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
----------------------------------------------------------------------
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
index f0f2020..944ce39 100644
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/Geo3DPoint.java
@@ -22,6 +22,8 @@ import java.util.ArrayList;
 import org.apache.lucene.document.Field;
 import org.apache.lucene.document.FieldType;
 import org.apache.lucene.index.PointValues;
+import org.apache.lucene.geo.Polygon;
+import org.apache.lucene.geo.GeoUtils;
 import org.apache.lucene.spatial3d.geom.Vector;
 import org.apache.lucene.spatial3d.geom.GeoPoint;
 import org.apache.lucene.spatial3d.geom.GeoShape;
@@ -30,6 +32,8 @@ import org.apache.lucene.spatial3d.geom.GeoCircleFactory;
 import org.apache.lucene.spatial3d.geom.GeoBBoxFactory;
 import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
 import org.apache.lucene.spatial3d.geom.GeoPath;
+import org.apache.lucene.spatial3d.geom.GeoCompositePolygon;
+import org.apache.lucene.spatial3d.geom.GeoPolygon;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.NumericUtils;
@@ -64,8 +68,8 @@ public final class Geo3DPoint extends Field {
    */
   public Geo3DPoint(String name, double latitude, double longitude) {
     super(name, TYPE);
-    checkLatitude(latitude);
-    checkLongitude(longitude);
+    GeoUtils.checkLatitude(latitude);
+    GeoUtils.checkLongitude(longitude);
     // Translate latitude/longitude to x,y,z:
     final GeoPoint point = new GeoPoint(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude));
     fillFieldsData(point.x, point.y, point.z);
@@ -94,8 +98,8 @@ public final class Geo3DPoint extends Field {
    * @throws IllegalArgumentException if {@code field} is null, location has invalid coordinates, or radius is invalid.
    */
   public static Query newDistanceQuery(final String field, final double latitude, final double longitude, final double radiusMeters) {
-    checkLatitude(latitude);
-    checkLongitude(longitude);
+    GeoUtils.checkLatitude(latitude);
+    GeoUtils.checkLongitude(longitude);
     final GeoShape shape = GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude), fromMeters(radiusMeters));
     return newShapeQuery(field, shape);
   }
@@ -113,10 +117,10 @@ public final class Geo3DPoint extends Field {
    * @throws IllegalArgumentException if {@code field} is null, or the box has invalid coordinates.
    */
   public static Query newBoxQuery(final String field, final double minLatitude, final double maxLatitude, final double minLongitude, final double maxLongitude) {
-    checkLatitude(minLatitude);
-    checkLongitude(minLongitude);
-    checkLatitude(maxLatitude);
-    checkLongitude(maxLongitude);
+    GeoUtils.checkLatitude(minLatitude);
+    GeoUtils.checkLongitude(minLongitude);
+    GeoUtils.checkLatitude(maxLatitude);
+    GeoUtils.checkLongitude(maxLongitude);
     final GeoShape shape = GeoBBoxFactory.makeGeoBBox(PlanetModel.WGS84, 
       fromDegrees(maxLatitude), fromDegrees(minLatitude), fromDegrees(minLongitude), fromDegrees(maxLongitude));
     return newShapeQuery(field, shape);
@@ -125,36 +129,28 @@ public final class Geo3DPoint extends Field {
   /** 
    * Create a query for matching a polygon.
    * <p>
-   * The supplied {@code polyLatitudes}/{@code polyLongitudes} must be clockwise or counter-clockwise.
+   * The supplied {@code polygons} must be clockwise on the outside level, counterclockwise on the next level in, etc.
    * @param field field name. must not be null.
-   * @param polyLatitudes latitude values for points of the polygon: must be within standard +/-90 coordinate bounds.
-   * @param polyLongitudes longitude values for points of the polygon: must be within standard +/-180 coordinate bounds.
+   * @param polygons is the list of polygons to use to construct the query; must be at least one.
    * @return query matching points within this polygon
    */
-  public static Query newPolygonQuery(final String field, final double[] polyLatitudes, final double[] polyLongitudes) {
-    if (polyLatitudes.length != polyLongitudes.length) {
-      throw new IllegalArgumentException("same number of latitudes and longitudes required");
-    }
-    if (polyLatitudes.length < 4) {
-      throw new IllegalArgumentException("need three or more points");
-    }
-    if (polyLatitudes[0] != polyLatitudes[polyLatitudes.length-1] || polyLongitudes[0] != polyLongitudes[polyLongitudes.length-1]) {
-      throw new IllegalArgumentException("last point must equal first point");
+  public static Query newPolygonQuery(final String field, final Polygon... polygons) {
+    if (polygons.length < 1) {
+      throw new IllegalArgumentException("need at least one polygon");
     }
-    
-    final List<GeoPoint> polyPoints = new ArrayList<>(polyLatitudes.length-1);
-    for (int i = 0; i < polyLatitudes.length-1; i++) {
-      final double latitude = polyLatitudes[i];
-      final double longitude = polyLongitudes[i];
-      checkLatitude(latitude);
-      checkLongitude(longitude);
-      polyPoints.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude)));
+    final GeoShape shape;
+    if (polygons.length == 1) {
+      shape = fromPolygon(polygons[0], false);
+    } else {
+      final GeoCompositePolygon poly = new GeoCompositePolygon();
+      for (final Polygon p : polygons) {
+        poly.addShape(fromPolygon(p, false));
+      }
+      shape = poly;
     }
-    // We use the polygon constructor that looks at point order.
-    final GeoShape shape = GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, polyPoints, null);
     return newShapeQuery(field, shape);
   }
-  
+
   /** 
    * Create a query for matching a path.
    * <p>
@@ -172,14 +168,47 @@ public final class Geo3DPoint extends Field {
     for (int i = 0; i < pathLatitudes.length; i++) {
       final double latitude = pathLatitudes[i];
       final double longitude = pathLongitudes[i];
-      checkLatitude(latitude);
-      checkLongitude(longitude);
+      GeoUtils.checkLatitude(latitude);
+      GeoUtils.checkLongitude(longitude);
       points[i] = new GeoPoint(PlanetModel.WGS84, fromDegrees(latitude), fromDegrees(longitude));
     }
     final GeoShape shape = new GeoPath(PlanetModel.WGS84, fromMeters(pathWidthMeters), points);
     return newShapeQuery(field, shape);
   }
   
+  /**
+    * Convert a Polygon object into a GeoPolygon.
+    * This method uses
+    * @param polygon is the Polygon object.
+    * @param reverseMe is true if the order of the points should be reversed.
+    * @return the GeoPolygon.
+    */
+  protected static GeoPolygon fromPolygon(final Polygon polygon, final boolean reverseMe) {
+    // First, assemble the "holes".  The geo3d convention is to use the same polygon sense on the inner ring as the
+    // outer ring, so we process these recursively with reverseMe flipped.
+    final Polygon[] theHoles = polygon.getHoles();
+    final List<GeoPolygon> holeList = new ArrayList<>(theHoles.length);
+    for (final Polygon hole : theHoles) {
+      holeList.add(fromPolygon(hole, !reverseMe));
+    }
+    // Now do the polygon itself
+    final double[] polyLats = polygon.getPolyLats();
+    final double[] polyLons = polygon.getPolyLons();
+    
+    // I presume the arguments have already been checked
+    final List<GeoPoint> points = new ArrayList<>(polyLats.length-1);
+    // We skip the last point anyway because the API requires it to be repeated, and geo3d doesn't repeat it.
+    for (int i = 0; i < polyLats.length - 1; i++) {
+      if (reverseMe) {
+        points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[i]), fromDegrees(polyLons[i])));
+      } else {
+        final int index = polyLats.length - 2 - i;
+        points.add(new GeoPoint(PlanetModel.WGS84, fromDegrees(polyLats[index]), fromDegrees(polyLons[index])));
+      }
+    }
+    return GeoPolygonFactory.makeGeoPolygon(PlanetModel.WGS84, points, holeList);
+  }
+  
   /** 
    * Creates a new Geo3DPoint field with the specified x,y,z.
    *
@@ -235,31 +264,4 @@ public final class Geo3DPoint extends Field {
     return result.toString();
   }
 
-  // TODO LUCENE-7152: share this with GeoUtils.java from spatial module
-
-  /** Minimum longitude value. */
-  private static final double MIN_LON_INCL = -180.0D;
-
-  /** Maximum longitude value. */
-  private static final double MAX_LON_INCL = 180.0D;
-
-  /** Minimum latitude value. */
-  private static final double MIN_LAT_INCL = -90.0D;
-
-  /** Maximum latitude value. */
-  private static final double MAX_LAT_INCL = 90.0D;
-
-  /** validates latitude value is within standard +/-90 coordinate bounds */
-  private static void checkLatitude(double latitude) {
-    if (Double.isNaN(latitude) || latitude < MIN_LAT_INCL || latitude > MAX_LAT_INCL) {
-      throw new IllegalArgumentException("invalid latitude " +  latitude + "; must be between " + MIN_LAT_INCL + " and " + MAX_LAT_INCL);
-    }
-  }
-
-  /** validates longitude value is within standard +/-180 coordinate bounds */
-  private static void checkLongitude(double longitude) {
-    if (Double.isNaN(longitude) || longitude < MIN_LON_INCL || longitude > MAX_LON_INCL) {
-      throw new IllegalArgumentException("invalid longitude " +  longitude + "; must be between " + MIN_LON_INCL + " and " + MAX_LON_INCL);
-    }
-  }
 }