You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by rm...@apache.org on 2016/03/28 17:46:31 UTC

lucene-solr:master: factor out polygon/box generation into GeoTestUtil. removes lots of leniency and unnecessary quantization! may cause failures!!!!

Repository: lucene-solr
Updated Branches:
  refs/heads/master 010f02216 -> 956e4363f


factor out polygon/box generation into GeoTestUtil. removes lots of leniency and unnecessary quantization! may cause failures!!!!


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

Branch: refs/heads/master
Commit: 956e4363f10718096c3c522fb3798c8b389ab953
Parents: 010f022
Author: Robert Muir <rm...@apache.org>
Authored: Mon Mar 28 11:48:14 2016 -0400
Committer: Robert Muir <rm...@apache.org>
Committed: Mon Mar 28 11:48:14 2016 -0400

----------------------------------------------------------------------
 .../spatial/util/BaseGeoPointTestCase.java      | 165 +++---------------
 .../apache/lucene/spatial/util/GeoTestUtil.java | 167 ++++++++++++++++++-
 2 files changed, 192 insertions(+), 140 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/956e4363/lucene/spatial/src/test/org/apache/lucene/spatial/util/BaseGeoPointTestCase.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/test/org/apache/lucene/spatial/util/BaseGeoPointTestCase.java b/lucene/spatial/src/test/org/apache/lucene/spatial/util/BaseGeoPointTestCase.java
index c0633eb..e25266a 100644
--- a/lucene/spatial/src/test/org/apache/lucene/spatial/util/BaseGeoPointTestCase.java
+++ b/lucene/spatial/src/test/org/apache/lucene/spatial/util/BaseGeoPointTestCase.java
@@ -19,13 +19,11 @@ package org.apache.lucene.spatial.util;
 import java.io.IOException;
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.lucene.analysis.MockAnalyzer;
 import org.apache.lucene.codecs.FilterCodec;
@@ -438,7 +436,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
 
     int iters = atLeast(25);
     for (int iter=0;iter<iters;iter++) {
-      GeoRect rect = randomRect(small, small == false);
+      GeoRect rect = randomRect(small);
 
       if (VERBOSE) {
         System.out.println("\nTEST: iter=" + iter + " rect=" + rect);
@@ -609,67 +607,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
     return quantizeLon(result);
   }
   
-  /** Returns {polyLats, polyLons} double[] array */
-  private double[][] surpriseMePolygon() {
-    // repeat until we get a poly that doesn't cross dateline:
-    newPoly:
-    while (true) {
-      //System.out.println("\nPOLY ITER");
-      double centerLat = randomLat(false);
-      double centerLon = randomLon(false);
-
-      double radius = 0.1 + 20 * random().nextDouble();
-      double radiusDelta = random().nextDouble();
-
-      ArrayList<Double> lats = new ArrayList<>();
-      ArrayList<Double> lons = new ArrayList<>();
-      double angle = 0.0;
-      while (true) {
-        angle += random().nextDouble()*40.0;
-        //System.out.println("  angle " + angle);
-        if (angle > 360) {
-          break;
-        }
-        double len = radius * (1.0 - radiusDelta + radiusDelta * random().nextDouble());
-        //System.out.println("    len=" + len);
-        double lat = centerLat + len * Math.cos(Math.toRadians(angle));
-        double lon = centerLon + len * Math.sin(Math.toRadians(angle));
-        if (lon <= GeoUtils.MIN_LON_INCL || lon >= GeoUtils.MAX_LON_INCL) {
-          // cannot cross dateline: try again!
-          continue newPoly;
-        }
-        if (lat > 90) {
-          // cross the north pole
-          lat = 180 - lat;
-          lon = 180 - lon;
-        } else if (lat < -90) {
-          // cross the south pole
-          lat = -180 - lat;
-          lon = 180 - lon;
-        }
-        if (lon <= GeoUtils.MIN_LON_INCL || lon >= GeoUtils.MAX_LON_INCL) {
-          // cannot cross dateline: try again!
-          continue newPoly;
-        }
-        lats.add(lat);
-        lons.add(lon);
-
-        //System.out.println("    lat=" + lats.get(lats.size()-1) + " lon=" + lons.get(lons.size()-1));
-      }
-
-      // close it
-      lats.add(lats.get(0));
-      lons.add(lons.get(0));
 
-      double[] latsArray = new double[lats.size()];
-      double[] lonsArray = new double[lons.size()];
-      for(int i=0;i<lats.size();i++) {
-        latsArray[i] = lats.get(i);
-        lonsArray[i] = lons.get(i);
-      }
-      return new double[][] {latsArray, lonsArray};
-    }
-  }
 
   /** Override this to quantize randomly generated lat, so the test won't fail due to quantization errors, which are 1) annoying to debug,
    *  and 2) should never affect "real" usage terribly. */
@@ -683,25 +621,12 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
     return lon;
   }
 
-  protected GeoRect randomRect(boolean small, boolean canCrossDateLine) {
-    double lat0 = randomLat(small);
-    double lat1 = randomLat(small);
-    double lon0 = randomLon(small);
-    double lon1 = randomLon(small);
-
-    if (lat1 < lat0) {
-      double x = lat0;
-      lat0 = lat1;
-      lat1 = x;
-    }
-
-    if (canCrossDateLine == false && lon1 < lon0) {
-      double x = lon0;
-      lon0 = lon1;
-      lon1 = x;
+  protected GeoRect randomRect(boolean small) {
+    if (small) {
+      return GeoTestUtil.nextBoxNear(originLat, originLon);
+    } else {
+      return GeoTestUtil.nextBox();
     }
-
-    return new GeoRect(lat0, lat1, lon0, lon1);
   }
 
   protected void initIndexWriterConfig(String field, IndexWriterConfig iwc) {
@@ -726,17 +651,6 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
         || GeoRelationUtils.pointInRectPrecise(pointLat, pointLon, rect.minLat, rect.maxLat, rect.minLon, 180.0);
     }
   }
-  
-  static final boolean polygonContainsPoint(double polyLats[], double polyLons[], double pointLat, double pointLon) {
-    return GeoRelationUtils.pointInPolygon(polyLats, polyLons, pointLat, pointLon);
-  }
-
-  static final boolean circleContainsPoint(double centerLat, double centerLon, double radiusMeters, double pointLat, double pointLon) {
-    double distanceMeters = SloppyMath.haversinMeters(centerLat, centerLon, pointLat, pointLon);
-    boolean result = distanceMeters <= radiusMeters;
-    //System.out.println("  shouldMatch?  centerLon=" + centerLon + " centerLat=" + centerLat + " pointLon=" + pointLon + " pointLat=" + pointLat + " result=" + result + " distanceMeters=" + (distanceKM * 1000));
-    return result;
-  }
 
   private void verify(boolean small, double[] lats, double[] lons) throws Exception {
     verifyRandomRectangles(small, lats, lons);
@@ -800,8 +714,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
         System.out.println("\nTEST: iter=" + iter + " s=" + s);
       }
       
-      // Rect: don't allow dateline crossing when testing small:
-      GeoRect rect = randomRect(small, small == false);
+      GeoRect rect = randomRect(small);
 
       Query query = newRectQuery(FIELD_NAME, rect.minLat, rect.maxLat, rect.minLon, rect.maxLon);
 
@@ -981,7 +894,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
         } else if (Double.isNaN(lats[id])) {
           expected = false;
         } else {
-          expected = circleContainsPoint(centerLat, centerLon, radiusMeters, lats[id], lons[id]);
+          expected = SloppyMath.haversinMeters(centerLat, centerLon, lats[id], lons[id]) <= radiusMeters;
         }
 
         if (hits.get(docID) != expected) {
@@ -1073,49 +986,16 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
         System.out.println("\nTEST: iter=" + iter + " s=" + s);
       }
 
-      // TODO: poly query can't handle dateline crossing yet:
-      final GeoRect bbox = randomRect(small, false);
-
       // Polygon
-      final double[] polyLats;
-      final double[] polyLons;
-      // TODO: factor this out, maybe if we add Polygon class?
-      switch (random().nextInt(3)) {
-      case 0:
-        // box
-        polyLats = new double[5];
-        polyLons = new double[5];
-        polyLats[0] = bbox.minLat;
-        polyLons[0] = bbox.minLon;
-        polyLats[1] = bbox.maxLat;
-        polyLons[1] = bbox.minLon;
-        polyLats[2] = bbox.maxLat;
-        polyLons[2] = bbox.maxLon;
-        polyLats[3] = bbox.minLat;
-        polyLons[3] = bbox.maxLon;
-        polyLats[4] = bbox.minLat;
-        polyLons[4] = bbox.minLon;
-        break;
-      case 1:
-        // right triangle
-        polyLats = new double[4];
-        polyLons = new double[4];
-        polyLats[0] = bbox.minLat;
-        polyLons[0] = bbox.minLon;
-        polyLats[1] = bbox.maxLat;
-        polyLons[1] = bbox.minLon;
-        polyLats[2] = bbox.maxLat;
-        polyLons[2] = bbox.maxLon;
-        polyLats[3] = bbox.minLat;
-        polyLons[3] = bbox.minLon;
-        break;
-      default:
-        // surprise me!
-        double[][] res = surpriseMePolygon();
-        polyLats = res[0];
-        polyLons = res[1];
-        break;
+      final double[][] polygon;
+      if (small) {
+        polygon = GeoTestUtil.nextPolygonNear(originLat, originLon);
+      } else {
+        polygon = GeoTestUtil.nextPolygon();
       }
+      
+      final double[] polyLats = polygon[0];
+      final double[] polyLons = polygon[1];
       Query query = newPolygonQuery(FIELD_NAME, polyLats, polyLons);
 
       if (VERBOSE) {
@@ -1153,7 +1033,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
         } else if (Double.isNaN(lats[id])) {
           expected = false;
         } else {
-          expected = polygonContainsPoint(polyLats, polyLons, lats[id], lons[id]);
+          expected = GeoRelationUtils.pointInPolygon(polyLats, polyLons, lats[id], lons[id]);
         }
 
         if (hits.get(docID) != expected) {
@@ -1186,7 +1066,14 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
   }
 
   public void testRectBoundariesAreInclusive() throws Exception {
-    GeoRect rect = randomRect(random().nextBoolean(), false);
+    GeoRect rect;
+    // TODO: why this dateline leniency???
+    while (true) {
+      rect = randomRect(random().nextBoolean());
+      if (rect.crossesDateline() == false) {
+        break;
+      }
+    }
     Directory dir = newDirectory();
     IndexWriterConfig iwc = newIndexWriterConfig();
     RandomIndexWriter w = new RandomIndexWriter(random(), dir, iwc);
@@ -1319,7 +1206,7 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase {
   public void testEquals() throws Exception {   
     Query q1, q2;
 
-    GeoRect rect = randomRect(false, true);
+    GeoRect rect = randomRect(false);
 
     q1 = newRectQuery("field", rect.minLat, rect.maxLat, rect.minLon, rect.maxLon);
     q2 = newRectQuery("field", rect.minLat, rect.maxLat, rect.minLon, rect.maxLon);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/956e4363/lucene/spatial/src/test/org/apache/lucene/spatial/util/GeoTestUtil.java
----------------------------------------------------------------------
diff --git a/lucene/spatial/src/test/org/apache/lucene/spatial/util/GeoTestUtil.java b/lucene/spatial/src/test/org/apache/lucene/spatial/util/GeoTestUtil.java
index f28e623..0059888 100644
--- a/lucene/spatial/src/test/org/apache/lucene/spatial/util/GeoTestUtil.java
+++ b/lucene/spatial/src/test/org/apache/lucene/spatial/util/GeoTestUtil.java
@@ -16,6 +16,7 @@
  */
 package org.apache.lucene.spatial.util;
 
+import java.util.ArrayList;
 import java.util.Random;
 
 import com.carrotsearch.randomizedtesting.RandomizedContext;
@@ -27,7 +28,6 @@ public class GeoTestUtil {
   public static double nextLatitude() {
     return -90 + 180.0 * random().nextDouble();
   }
-
   
   /** returns next pseudorandom longitude (anywhere) */
   public static double nextLongitude() {
@@ -68,6 +68,171 @@ public class GeoTestUtil {
     return normalizeLongitude(randomRangeMaybeSlightlyOutside(minLongitude, maxLongitude));
   }
   
+  /** returns next pseudorandom box: can cross the 180th meridian */
+  public static GeoRect nextBox() {
+    return nextBoxInternal(nextLatitude(), nextLatitude(), nextLongitude(), nextLongitude(), true);
+  }
+  
+  /** returns next pseudorandom box, can cross the 180th meridian, kinda close to {@code otherLatitude} and {@code otherLongitude} */
+  public static GeoRect nextBoxNear(double otherLatitude, double otherLongitude) {
+    GeoUtils.checkLongitude(otherLongitude);
+    GeoUtils.checkLongitude(otherLongitude);
+    return nextBoxInternal(nextLatitudeNear(otherLatitude), nextLatitudeNear(otherLatitude), 
+                           nextLongitudeNear(otherLongitude), nextLongitudeNear(otherLongitude), true);
+  }
+  
+  /** returns next pseudorandom polygon */
+  public static double[][] nextPolygon() {
+    if (random().nextBoolean()) {
+      return surpriseMePolygon(null, null);
+    }
+
+    GeoRect box = nextBoxInternal(nextLatitude(), nextLatitude(), nextLongitude(), nextLongitude(), false);
+    if (random().nextBoolean()) {
+      // box
+      return boxPolygon(box);
+    } else {
+      // triangle
+      return trianglePolygon(box);
+    }
+  }
+  
+  /** returns next pseudorandom polygon, kinda close to {@code otherLatitude} and {@code otherLongitude} */
+  public static double[][] nextPolygonNear(double otherLatitude, double otherLongitude) {
+    if (random().nextBoolean()) {
+      return surpriseMePolygon(otherLatitude, otherLongitude);
+    }
+
+    GeoRect box = nextBoxInternal(nextLatitudeNear(otherLatitude), nextLatitudeNear(otherLatitude), 
+                                  nextLongitudeNear(otherLongitude), nextLongitudeNear(otherLongitude), false);
+    if (random().nextBoolean()) {
+      // box
+      return boxPolygon(box);
+    } else {
+      // triangle
+      return trianglePolygon(box);
+    }
+  }
+
+  private static GeoRect nextBoxInternal(double lat0, double lat1, double lon0, double lon1, boolean canCrossDateLine) {
+    if (lat1 < lat0) {
+      double x = lat0;
+      lat0 = lat1;
+      lat1 = x;
+    }
+
+    if (canCrossDateLine == false && lon1 < lon0) {
+      double x = lon0;
+      lon0 = lon1;
+      lon1 = x;
+    }
+
+    return new GeoRect(lat0, lat1, lon0, lon1);
+  }
+  
+  private static double[][] boxPolygon(GeoRect box) {
+    assert box.crossesDateline() == false;
+    final double[] polyLats = new double[5];
+    final double[] polyLons = new double[5];
+    polyLats[0] = box.minLat;
+    polyLons[0] = box.minLon;
+    polyLats[1] = box.maxLat;
+    polyLons[1] = box.minLon;
+    polyLats[2] = box.maxLat;
+    polyLons[2] = box.maxLon;
+    polyLats[3] = box.minLat;
+    polyLons[3] = box.maxLon;
+    polyLats[4] = box.minLat;
+    polyLons[4] = box.minLon;
+    return new double[][] { polyLats, polyLons };
+  }
+  
+  private static double[][] trianglePolygon(GeoRect box) {
+    assert box.crossesDateline() == false;
+    final double[] polyLats = new double[4];
+    final double[] polyLons = new double[4];
+    polyLats[0] = box.minLat;
+    polyLons[0] = box.minLon;
+    polyLats[1] = box.maxLat;
+    polyLons[1] = box.minLon;
+    polyLats[2] = box.maxLat;
+    polyLons[2] = box.maxLon;
+    polyLats[3] = box.minLat;
+    polyLons[3] = box.minLon;
+    return new double[][] { polyLats, polyLons };
+  }
+  
+  /** Returns {polyLats, polyLons} double[] array */
+  private static double[][] surpriseMePolygon(Double otherLatitude, Double otherLongitude) {
+    // repeat until we get a poly that doesn't cross dateline:
+    newPoly:
+    while (true) {
+      //System.out.println("\nPOLY ITER");
+      final double centerLat;
+      final double centerLon;
+      if (otherLatitude == null) {
+        centerLat = nextLatitude();
+        centerLon = nextLongitude();
+      } else {
+        GeoUtils.checkLatitude(otherLatitude);
+        GeoUtils.checkLongitude(otherLongitude);
+        centerLat = nextLatitudeNear(otherLatitude);
+        centerLon = nextLongitudeNear(otherLongitude);
+      }
+
+      double radius = 0.1 + 20 * random().nextDouble();
+      double radiusDelta = random().nextDouble();
+
+      ArrayList<Double> lats = new ArrayList<>();
+      ArrayList<Double> lons = new ArrayList<>();
+      double angle = 0.0;
+      while (true) {
+        angle += random().nextDouble()*40.0;
+        //System.out.println("  angle " + angle);
+        if (angle > 360) {
+          break;
+        }
+        double len = radius * (1.0 - radiusDelta + radiusDelta * random().nextDouble());
+        //System.out.println("    len=" + len);
+        double lat = centerLat + len * Math.cos(Math.toRadians(angle));
+        double lon = centerLon + len * Math.sin(Math.toRadians(angle));
+        if (lon <= GeoUtils.MIN_LON_INCL || lon >= GeoUtils.MAX_LON_INCL) {
+          // cannot cross dateline: try again!
+          continue newPoly;
+        }
+        if (lat > 90) {
+          // cross the north pole
+          lat = 180 - lat;
+          lon = 180 - lon;
+        } else if (lat < -90) {
+          // cross the south pole
+          lat = -180 - lat;
+          lon = 180 - lon;
+        }
+        if (lon <= GeoUtils.MIN_LON_INCL || lon >= GeoUtils.MAX_LON_INCL) {
+          // cannot cross dateline: try again!
+          continue newPoly;
+        }
+        lats.add(lat);
+        lons.add(lon);
+
+        //System.out.println("    lat=" + lats.get(lats.size()-1) + " lon=" + lons.get(lons.size()-1));
+      }
+
+      // close it
+      lats.add(lats.get(0));
+      lons.add(lons.get(0));
+
+      double[] latsArray = new double[lats.size()];
+      double[] lonsArray = new double[lons.size()];
+      for(int i=0;i<lats.size();i++) {
+        latsArray[i] = lats.get(i);
+        lonsArray[i] = lons.get(i);
+      }
+      return new double[][] {latsArray, lonsArray};
+    }
+  }
+  
   /** Returns random double min to max or up to 1% outside of that range */
   private static double randomRangeMaybeSlightlyOutside(double min, double max) {
     return min + (random().nextDouble() + (0.5 - random().nextDouble()) * .02) * (max - min);