LUCENE-7159: improve testing of polygon tree methods

This commit is contained in:
Robert Muir 2016-04-03 14:07:56 -04:00
parent 741a1e4eed
commit bb2e01c3d9
2 changed files with 121 additions and 0 deletions

View File

@ -145,4 +145,112 @@ public class TestPolygon extends LuceneTestCase {
}
}
}
/** If polygon.contains(box) returns true, then any point in that box should return true as well */
public void testContainsRandom() throws Exception {
for (int i = 0; i < 1000; i++) {
Polygon polygon = nextPolygon();
for (int j = 0; j < 100; j++) {
Rectangle rectangle = GeoTestUtil.nextSimpleBox();
// allowed to conservatively return false
if (polygon.contains(rectangle.minLat, rectangle.maxLat, rectangle.minLon, rectangle.maxLon)) {
for (int k = 0; k < 1000; k++) {
// this tests in our range but sometimes outside! so we have to double-check its really in other box
double latitude = nextLatitudeAround(rectangle.minLat, rectangle.maxLat);
double longitude = nextLongitudeAround(rectangle.minLon, rectangle.maxLon);
// check for sure its in our box
if (latitude >= rectangle.minLat && latitude <= rectangle.maxLat && longitude >= rectangle.minLon && longitude <= rectangle.maxLon) {
assertTrue(polygon.contains(latitude, longitude));
}
}
}
}
}
}
/** If polygon.contains(box) returns true, then any point in that box should return true as well */
// different from testContainsRandom in that its not a purely random test. we iterate the vertices of the polygon
// and generate boxes near each one of those to try to be more efficient.
public void testContainsEdgeCases() throws Exception {
for (int i = 0; i < 1000; i++) {
Polygon polygon = nextPolygon();
double polyLats[] = polygon.getPolyLats();
double polyLons[] = polygon.getPolyLons();
for (int vertex = 0; vertex < polyLats.length; vertex++) {
for (int j = 0; j < 10; j++) {
Rectangle rectangle = GeoTestUtil.nextSimpleBoxNear(polyLats[vertex], polyLons[vertex]);
// allowed to conservatively return false
if (polygon.contains(rectangle.minLat, rectangle.maxLat, rectangle.minLon, rectangle.maxLon)) {
for (int k = 0; k < 100; k++) {
// this tests in our range but sometimes outside! so we have to double-check its really in other box
double latitude = nextLatitudeAround(rectangle.minLat, rectangle.maxLat);
double longitude = nextLongitudeAround(rectangle.minLon, rectangle.maxLon);
// check for sure its in our box
if (latitude >= rectangle.minLat && latitude <= rectangle.maxLat && longitude >= rectangle.minLon && longitude <= rectangle.maxLon) {
assertTrue(polygon.contains(latitude, longitude));
}
}
}
}
}
}
}
/** If polygon.intersects(box) returns false, then any point in that box should return false as well */
public void testIntersectRandom() {
for (int i = 0; i < 100; i++) {
Polygon polygon = nextPolygon();
for (int j = 0; j < 100; j++) {
Rectangle rectangle = GeoTestUtil.nextSimpleBox();
// allowed to conservatively return true.
if (polygon.contains(rectangle.minLat, rectangle.maxLat, rectangle.minLon, rectangle.maxLon) == false &&
polygon.crosses(rectangle.minLat, rectangle.maxLat, rectangle.minLon, rectangle.maxLon) == false) {
for (int k = 0; k < 1000; k++) {
// this tests in our range but sometimes outside! so we have to double-check its really in other box
double latitude = nextLatitudeAround(rectangle.minLat, rectangle.maxLat);
double longitude = nextLongitudeAround(rectangle.minLon, rectangle.maxLon);
// check for sure its in our box
if (latitude >= rectangle.minLat && latitude <= rectangle.maxLat && longitude >= rectangle.minLon && longitude <= rectangle.maxLon) {
assertFalse(polygon.contains(latitude, longitude));
}
}
}
}
}
}
/** If polygon.intersects(box) returns false, then any point in that box should return false as well */
// different from testIntersectsRandom in that its not a purely random test. we iterate the vertices of the polygon
// and generate boxes near each one of those to try to be more efficient.
public void testIntersectEdgeCases() {
for (int i = 0; i < 100; i++) {
Polygon polygon = nextPolygon();
double polyLats[] = polygon.getPolyLats();
double polyLons[] = polygon.getPolyLons();
for (int vertex = 0; vertex < polyLats.length; vertex++) {
for (int j = 0; j < 10; j++) {
Rectangle rectangle = GeoTestUtil.nextSimpleBoxNear(polyLats[vertex], polyLons[vertex]);
// allowed to conservatively return true.
if (polygon.contains(rectangle.minLat, rectangle.maxLat, rectangle.minLon, rectangle.maxLon) == false &&
polygon.crosses(rectangle.minLat, rectangle.maxLat, rectangle.minLon, rectangle.maxLon) == false) {
for (int k = 0; k < 100; k++) {
// this tests in our range but sometimes outside! so we have to double-check its really in other box
double latitude = nextLatitudeAround(rectangle.minLat, rectangle.maxLat);
double longitude = nextLongitudeAround(rectangle.minLon, rectangle.maxLon);
// check for sure its in our box
if (latitude >= rectangle.minLat && latitude <= rectangle.maxLat && longitude >= rectangle.minLon && longitude <= rectangle.maxLon) {
assertFalse(polygon.contains(latitude, longitude));
}
}
}
}
}
}
}
}

View File

@ -75,6 +75,11 @@ public class GeoTestUtil {
public static Rectangle nextBox() {
return nextBoxInternal(nextLatitude(), nextLatitude(), nextLongitude(), nextLongitude(), true);
}
/** returns next pseudorandom box: will not cross the 180th meridian */
public static Rectangle nextSimpleBox() {
return nextBoxInternal(nextLatitude(), nextLatitude(), nextLongitude(), nextLongitude(), false);
}
/** returns next pseudorandom box, can cross the 180th meridian, kinda close to {@code otherLatitude} and {@code otherLongitude} */
public static Rectangle nextBoxNear(double otherLatitude, double otherLongitude) {
@ -83,6 +88,14 @@ public class GeoTestUtil {
return nextBoxInternal(nextLatitudeNear(otherLatitude), nextLatitudeNear(otherLatitude),
nextLongitudeNear(otherLongitude), nextLongitudeNear(otherLongitude), true);
}
/** returns next pseudorandom box, will not cross the 180th meridian, kinda close to {@code otherLatitude} and {@code otherLongitude} */
public static Rectangle nextSimpleBoxNear(double otherLatitude, double otherLongitude) {
GeoUtils.checkLongitude(otherLongitude);
GeoUtils.checkLongitude(otherLongitude);
return nextBoxInternal(nextLatitudeNear(otherLatitude), nextLatitudeNear(otherLatitude),
nextLongitudeNear(otherLongitude), nextLongitudeNear(otherLongitude), false);
}
/** returns next pseudorandom polygon */
public static Polygon nextPolygon() {