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);
+ }
+ }
+ }
+ }
+
+
}