You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mi...@apache.org on 2015/09/11 16:58:21 UTC

svn commit: r1702490 - in /lucene/dev/branches/lucene6780/lucene/sandbox/src: java/org/apache/lucene/search/ java/org/apache/lucene/util/ test/org/apache/lucene/search/ test/org/apache/lucene/util/

Author: mikemccand
Date: Fri Sep 11 14:58:20 2015
New Revision: 1702490

URL: http://svn.apache.org/r1702490
Log:
LUCENE-6780: add randomized test; remove more annots; add some nocommits; rename some radius -> radiusMeters

Modified:
    lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/search/GeoBoundingBox.java
    lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/util/GeoDistanceUtils.java
    lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/util/GeoUtils.java
    lucene/dev/branches/lucene6780/lucene/sandbox/src/test/org/apache/lucene/search/TestGeoPointQuery.java
    lucene/dev/branches/lucene6780/lucene/sandbox/src/test/org/apache/lucene/util/TestGeoUtils.java

Modified: lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/search/GeoBoundingBox.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/search/GeoBoundingBox.java?rev=1702490&r1=1702489&r2=1702490&view=diff
==============================================================================
--- lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/search/GeoBoundingBox.java (original)
+++ lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/search/GeoBoundingBox.java Fri Sep 11 14:58:20 2015
@@ -19,6 +19,8 @@ package org.apache.lucene.search;
 
 import org.apache.lucene.util.GeoUtils;
 
+// nocommit rename to GeoRect?  It's not just a bounding box ... it's any rect ...
+
 /** NOTE: package private; just used so {@link GeoPointInPolygonQuery} can communicate its bounding box to {@link GeoPointInBBoxQuery}. */
 class GeoBoundingBox {
   public final double minLon;
@@ -44,4 +46,9 @@ class GeoBoundingBox {
     this.minLat = minLat;
     this.maxLat = maxLat;
   }
+
+  @Override
+  public String toString() {
+    return "GeoBoundingBox(lon=" + minLon + " TO " + maxLon + ", lat=" + minLat + " TO " + maxLat + ")";
+  }
 }

Modified: lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/util/GeoDistanceUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/util/GeoDistanceUtils.java?rev=1702490&r1=1702489&r2=1702490&view=diff
==============================================================================
--- lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/util/GeoDistanceUtils.java (original)
+++ lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/util/GeoDistanceUtils.java Fri Sep 11 14:58:20 2015
@@ -110,8 +110,9 @@ public class GeoDistanceUtils {
   }
 
   /**
-   *  Finds the closest point to a rectangle (defined by rMinX, rMinY, rMaxX, rMaxY) from the given (lon, lat) point
-   *  the result is provided in closestPt
+   *  Finds the closest point within a rectangle (defined by rMinX, rMinY, rMaxX, rMaxY) to the given (lon, lat) point
+   *  the result is provided in closestPt.  When the point is outside the rectangle, the closest point is on an edge
+   *  or corner of the rectangle; else, the closest point is the point itself.
    */
   public static void closestPointOnBBox(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
                                         final double lon, final double lat, double[] closestPt) {

Modified: lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/util/GeoUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/util/GeoUtils.java?rev=1702490&r1=1702489&r2=1702490&view=diff
==============================================================================
--- lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/util/GeoUtils.java (original)
+++ lucene/dev/branches/lucene6780/lucene/sandbox/src/java/org/apache/lucene/util/GeoUtils.java Fri Sep 11 14:58:20 2015
@@ -246,11 +246,11 @@ public final class GeoUtils {
    *
    * @param lon longitudinal center of circle (in degrees)
    * @param lat latitudinal center of circle (in degrees)
-   * @param radius distance radius of circle (in meters)
+   * @param radiusMeters distance radius of circle (in meters)
    * @return a list of lon/lat points representing the circle
    */
   @SuppressWarnings({"unchecked","rawtypes"})
-  public static ArrayList<double[]> circleToPoly(final double lon, final double lat, final double radius) {
+  public static ArrayList<double[]> circleToPoly(final double lon, final double lat, final double radiusMeters) {
     double angle;
     // a little under-sampling (to limit the number of polygonal points): using archimedes estimation of pi
     final int sides = 25;
@@ -262,7 +262,7 @@ public final class GeoUtils {
     final int sidesLen = sides-1;
     for (int i=0; i<sidesLen; ++i) {
       angle = (i*360/sides);
-      pt = GeoProjectionUtils.pointFromLonLatBearing(lon, lat, angle, radius, pt);
+      pt = GeoProjectionUtils.pointFromLonLatBearing(lon, lat, angle, radiusMeters, pt);
       lons[i] = pt[0];
       lats[i] = pt[1];
     }
@@ -289,40 +289,40 @@ public final class GeoUtils {
   }
 
   private static boolean rectAnyCornersOutsideCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
-                                                     final double centerLon, final double centerLat, final double radius) {
-    return (SloppyMath.haversin(centerLat, centerLon, rMinY, rMinX)*1000.0 > radius
-        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMinX)*1000.0 > radius
-        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMaxX)*1000.0 > radius
-        || SloppyMath.haversin(centerLat, centerLon, rMinY, rMaxX)*1000.0 > radius);
+                                                     final double centerLon, final double centerLat, final double radiusMeters) {
+    return (SloppyMath.haversin(centerLat, centerLon, rMinY, rMinX)*1000.0 > radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMinX)*1000.0 > radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMaxX)*1000.0 > radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMinY, rMaxX)*1000.0 > radiusMeters);
   }
 
   private static boolean rectAnyCornersInCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
-                                                final double centerLon, final double centerLat, final double radius) {
-    return (SloppyMath.haversin(centerLat, centerLon, rMinY, rMinX)*1000.0 <= radius
-        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMinX)*1000.0 <= radius
-        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMaxX)*1000.0 <= radius
-        || SloppyMath.haversin(centerLat, centerLon, rMinY, rMaxX)*1000.0 <= radius);
+                                                final double centerLon, final double centerLat, final double radiusMeters) {
+    return (SloppyMath.haversin(centerLat, centerLon, rMinY, rMinX)*1000.0 <= radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMinX)*1000.0 <= radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMaxY, rMaxX)*1000.0 <= radiusMeters
+        || SloppyMath.haversin(centerLat, centerLon, rMinY, rMaxX)*1000.0 <= radiusMeters);
   }
 
   public static boolean rectWithinCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
-                                         final double centerLon, final double centerLat, final double radius) {
-    return !(rectAnyCornersOutsideCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radius));
+                                         final double centerLon, final double centerLat, final double radiusMeters) {
+    return !(rectAnyCornersOutsideCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters));
   }
 
   /**
    * Computes whether a rectangle crosses a circle
    */
   public static boolean rectCrossesCircle(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
-                                          final double centerLon, final double centerLat, final double radius) {
-    return rectAnyCornersInCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radius)
-        || isClosestPointOnRectWithinRange(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radius);
+                                          final double centerLon, final double centerLat, final double radiusMeters) {
+    return rectAnyCornersInCircle(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters)
+        || isClosestPointOnRectWithinRange(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, radiusMeters);
   }
 
-  public static boolean isClosestPointOnRectWithinRange(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
-                                                        final double centerLon, final double centerLat, final double radius) {
+  private static boolean isClosestPointOnRectWithinRange(final double rMinX, final double rMinY, final double rMaxX, final double rMaxY,
+                                                         final double centerLon, final double centerLat, final double radiusMeters) {
     double[] closestPt = {0, 0};
     GeoDistanceUtils.closestPointOnBBox(rMinX, rMinY, rMaxX, rMaxY, centerLon, centerLat, closestPt);
-    return SloppyMath.haversin(centerLat, centerLon, closestPt[1], closestPt[0])*1000.0 <= radius;
+    return SloppyMath.haversin(centerLat, centerLon, closestPt[1], closestPt[0])*1000.0 <= radiusMeters;
   }
 
   /**
@@ -337,12 +337,13 @@ public final class GeoUtils {
    * @param centerLon longitudinal location of center search point (in degrees)
    * @param centerLat latitudinal location of center search point (in degrees)
    * @param centerAlt altitude of the center point (in meters)
-   * @param radius search sphere radius (in meters)
+   * @param radiusMeters search sphere radius (in meters)
    * @return whether the provided line segment is a secant of the
    */
+  // nocommit can/should we remove this?
   private static boolean lineCrossesSphere(double lon1, double lat1, double alt1, double lon2,
                                            double lat2, double alt2, double centerLon, double centerLat,
-                                           double centerAlt, double radius) {
+                                           double centerAlt, double radiusMeters) {
     // convert to cartesian 3d (in meters)
     double[] ecf1 = GeoProjectionUtils.llaToECF(lon1, lat1, alt1, null);
     double[] ecf2 = GeoProjectionUtils.llaToECF(lon2, lat2, alt2, null);
@@ -357,7 +358,7 @@ public final class GeoUtils {
 
     final double a = dX*dX + dY*dY + dZ*dZ;
     final double b = 2 * (fX*dX + fY*dY + fZ*dZ);
-    final double c = (fX*fX + fY*fY + fZ*fZ) - (radius*radius);
+    final double c = (fX*fX + fY*fY + fZ*fZ) - (radiusMeters*radiusMeters);
 
     double discrim = (b*b)-(4*a*c);
     if (discrim < 0) {

Modified: lucene/dev/branches/lucene6780/lucene/sandbox/src/test/org/apache/lucene/search/TestGeoPointQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6780/lucene/sandbox/src/test/org/apache/lucene/search/TestGeoPointQuery.java?rev=1702490&r1=1702489&r2=1702490&view=diff
==============================================================================
--- lucene/dev/branches/lucene6780/lucene/sandbox/src/test/org/apache/lucene/search/TestGeoPointQuery.java (original)
+++ lucene/dev/branches/lucene6780/lucene/sandbox/src/test/org/apache/lucene/search/TestGeoPointQuery.java Fri Sep 11 14:58:20 2015
@@ -146,18 +146,15 @@ public class TestGeoPointQuery extends L
     return searcher.search(q, limit);
   }
 
-  @Test
   public void testRectCrossesCircle() throws Exception {
     assertTrue(GeoUtils.rectCrossesCircle(-180, -90, 180, 0.0, 0.667, 0.0, 88000.0));
   }
 
-  @Test
   public void testBBoxQuery() throws Exception {
     TopDocs td = bboxQuery(-96.7772, 32.778650, -96.77690000, 32.778950, 5);
     assertEquals("GeoBoundingBoxQuery failed", 4, td.totalHits);
   }
 
-  @Test
   public void testPolyQuery() throws Exception {
     TopDocs td = polygonQuery(new double[]{-96.7682647, -96.8280029, -96.6288757, -96.4929199,
             -96.6041564, -96.7449188, -96.76826477, -96.7682647},
@@ -166,7 +163,6 @@ public class TestGeoPointQuery extends L
     assertEquals("GeoPolygonQuery failed", 2, td.totalHits);
   }
 
-  @Test
   public void testPacManPolyQuery() throws Exception {
     // pacman
     double[] px = {0, 10, 10, 0, -8, -10, -8, 0, 10, 10, 0};
@@ -190,25 +186,21 @@ public class TestGeoPointQuery extends L
     assertTrue(GeoUtils.rectWithinPoly(-5, 0, -2, 5, px, py, xMin, yMin, xMax, yMax));
   }
 
-  @Test
   public void testBBoxCrossDateline() throws Exception {
     TopDocs td = bboxQuery(179.0, -45.0, -179.0, -44.0, 20);
     assertEquals("BBoxCrossDateline query failed", 2, td.totalHits);
   }
 
-  @Test
   public void testWholeMap() throws Exception {
     TopDocs td = bboxQuery(-179.9, -89.9, 179.9, 89.9, 20);
     assertEquals("testWholeMap failed", 24, td.totalHits);
   }
 
-  @Test
   public void smallTest() throws Exception {
     TopDocs td = geoDistanceQuery(-73.998776, 40.720611, 1, 20);
     assertEquals("smallTest failed", 2, td.totalHits);
   }
 
-  @Test
   public void testInvalidBBox() throws Exception {
     try {
       bboxQuery(179.0, -92.0, 181.0, -91.0, 20);
@@ -218,13 +210,11 @@ public class TestGeoPointQuery extends L
     throw new Exception("GeoBoundingBox should not accept invalid lat/lon");
   }
 
-  @Test
   public void testGeoDistanceQuery() throws Exception {
     TopDocs td = geoDistanceQuery(-96.4538113027811, 32.94823588839368, 6000, 20);
     assertEquals("GeoDistanceQuery failed", 2, td.totalHits);
   }
 
-  @Test
   public void testMultiValuedQuery() throws Exception {
     TopDocs td = bboxQuery(-96.4538113027811, 32.7559529921407, -96.7706036567688, 32.7756745755423, 20);
     // 3 single valued docs + 2 multi-valued docs
@@ -239,13 +229,11 @@ public class TestGeoPointQuery extends L
     assertEquals("GeoDistanceQuery failed",18, td.totalHits);
   }
 
-  @Test
   public void testGeoDistanceQueryCrossDateline() throws Exception {
     TopDocs td = geoDistanceQuery(-179.9538113027811, 32.94823588839368, 120000, 20);
     assertEquals("GeoDistanceQuery failed", 3, td.totalHits);
   }
 
-  @Test
   public void testInvalidGeoDistanceQuery() throws Exception {
     try {
       geoDistanceQuery(181.0, 92.0, 120000, 20);
@@ -264,7 +252,6 @@ public class TestGeoPointQuery extends L
     doTestRandom(10000);
   }
 
-  @Test
   public void testMortonEncoding() throws Exception {
     long hash = GeoUtils.mortonHash(180, 90);
     assertEquals(180.0, GeoUtils.mortonUnhashLon(hash), 0);
@@ -453,6 +440,8 @@ public class TestGeoPointQuery extends L
                 double centerLat = bbox.minLat + ((bbox.maxLat - bbox.minLat)/2.0);
                 double centerLon = bbox.minLon + ((bbox.maxLon - bbox.minLon)/2.0);
 
+                // nocommit just make a random point and radius?
+
                 // radius (in meters) as a function of the random generated bbox
                 final double radius = SloppyMath.haversin(centerLon, centerLat, centerLon, bbox.minLat)*1000.0;
 
@@ -627,7 +616,7 @@ public class TestGeoPointQuery extends L
          || (tMaxLon - tLon) == 0 || (tMaxLat - tLat) == 0);
   }
 
-  private static GeoBoundingBox randomBBox() {
+  public static GeoBoundingBox randomBBox() {
     double lat0 = randomLat();
     double lat1 = randomLat();
     double lon0 = randomLon();

Modified: lucene/dev/branches/lucene6780/lucene/sandbox/src/test/org/apache/lucene/util/TestGeoUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene6780/lucene/sandbox/src/test/org/apache/lucene/util/TestGeoUtils.java?rev=1702490&r1=1702489&r2=1702490&view=diff
==============================================================================
--- lucene/dev/branches/lucene6780/lucene/sandbox/src/test/org/apache/lucene/util/TestGeoUtils.java (original)
+++ lucene/dev/branches/lucene6780/lucene/sandbox/src/test/org/apache/lucene/util/TestGeoUtils.java Fri Sep 11 14:58:20 2015
@@ -21,6 +21,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
+import org.apache.lucene.search.TestGeoPointQuery;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -210,7 +211,6 @@ public class TestGeoUtils extends Lucene
   public static double randomLatFullRange() {
     return (180d * random().nextDouble()) - 90d;
   }
-
   public static double randomLonFullRange() {
     return (360d * random().nextDouble()) - 180d;
   }
@@ -222,4 +222,74 @@ public class TestGeoUtils extends Lucene
   public static double randomLon() {
     return GeoUtils.normalizeLon(originLon + lonRange * (random().nextDouble() - 0.5));
   }
+
+  // nocommit test other APIs, e.g. bbox around a circle
+  public void testRandomRectsAndCircles() throws Exception {
+    int iters = atLeast(1000);
+    int iter = 0;
+
+    while (iter < iters) {
+
+      // Random rect:
+      double minLat = randomLat();
+      double maxLat = randomLat();
+      double minLon = randomLon();
+      double maxLon = randomLon();
+
+      if (maxLat < minLat) {
+        double x = minLat;
+        minLat = maxLat;
+        maxLat = x;
+      }
+
+      if (maxLon < minLon) {
+        // nocommit but what about testing crossing the dateline?
+        double x = minLon;
+        minLon = maxLon;
+        maxLon = x;
+      }
+
+      double centerLat = randomLat();
+      double centerLon = randomLon();
+      double radiusMeters = 10000000*random().nextDouble();
+
+      boolean expected;
+      if (GeoUtils.rectCrossesCircle(minLon, minLat, maxLon, maxLon, centerLon, centerLat, radiusMeters) == false) {
+        // Rect and circle are disjoint
+        expected = false;
+      } else if (GeoUtils.rectWithinCircle(minLon, minLat, maxLon, maxLon, centerLon, centerLat, radiusMeters)) {
+        // Rect fully contained inside circle
+        expected = true;
+      } else {
+        // TODO: would be nice to somehow test this case too
+        continue;
+      }
+
+      if (VERBOSE) {
+        System.out.println("\nTEST: iter=" + iter + " rect: lon=" + minLon + " TO " + maxLon + ", lat=" + minLat + " TO " + maxLat + "; circle: lon=" + centerLon + " lat=" + centerLat + " radiusMeters=" + radiusMeters);
+        if (expected) {
+          System.out.println("  circle fully contains rect");
+        } else {
+          System.out.println("  circle and rect are disjoint");
+        }
+      }
+
+      iter++;
+
+      // Randomly pick points inside the rect and check distance to the center:
+      int iters2 = atLeast(1000);
+      for(int iter2=0;iter2<iters2;iter2++) {
+        double lon = minLon + random().nextDouble() * (maxLon - minLon);
+        double lat = minLat + random().nextDouble() * (maxLat - minLat);
+        double distanceMeters = SloppyMath.haversin(centerLat, centerLon, lat, lon)*1000.0;
+        boolean actual = distanceMeters < radiusMeters;
+        if (expected != actual) {
+          System.out.println("  lon=" + lon + " lat=" + lat + " distanceMeters=" + distanceMeters);
+          assertEquals(expected, actual);
+        }
+      }
+    }
+  }
+
+
 }