LUCENE-6859: GeoPointInPolygonQuery would occasionally fail with incorrect ranges

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1711014 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Knize 2015-10-28 13:54:36 +00:00
parent 60017e0ce3
commit 77f7614a46
3 changed files with 41 additions and 46 deletions

View File

@ -56,7 +56,7 @@ public final class GeoPointInPolygonQuery extends GeoPointInBBoxQueryImpl {
* that fall within or on the boundary of the polygon defined by the input parameters. * that fall within or on the boundary of the polygon defined by the input parameters.
*/ */
public GeoPointInPolygonQuery(final String field, final double[] polyLons, final double[] polyLats) { public GeoPointInPolygonQuery(final String field, final double[] polyLons, final double[] polyLats) {
this(field, computeBBox(polyLons, polyLats), polyLons, polyLats); this(field, GeoUtils.polyToBBox(polyLons, polyLats), polyLons, polyLats);
} }
/** Common constructor, used only internally. */ /** Common constructor, used only internally. */
@ -75,16 +75,8 @@ public final class GeoPointInPolygonQuery extends GeoPointInBBoxQueryImpl {
throw new IllegalArgumentException("first and last points of the polygon must be the same (it must close itself): polyLons[0]=" + polyLons[0] + " polyLons[" + (polyLons.length-1) + "]=" + polyLons[polyLons.length-1]); throw new IllegalArgumentException("first and last points of the polygon must be the same (it must close itself): polyLons[0]=" + polyLons[0] + " polyLons[" + (polyLons.length-1) + "]=" + polyLons[polyLons.length-1]);
} }
// convert polygon vertices to coordinates within tolerance this.x = polyLons;
this.x = toleranceConversion(polyLons); this.y = polyLats;
this.y = toleranceConversion(polyLats);
}
private double[] toleranceConversion(double[] vals) {
for (int i=0; i<vals.length; ++i) {
vals[i] = ((int)(vals[i]/GeoUtils.TOLERANCE))*GeoUtils.TOLERANCE;
}
return vals;
} }
@Override @SuppressWarnings("unchecked") @Override @SuppressWarnings("unchecked")
@ -167,7 +159,8 @@ public final class GeoPointInPolygonQuery extends GeoPointInBBoxQueryImpl {
@Override @Override
protected boolean cellIntersectsShape(final double minLon, final double minLat, final double maxLon, final double maxLat) { protected boolean cellIntersectsShape(final double minLon, final double minLat, final double maxLon, final double maxLat) {
return cellWithin(minLon, minLat, maxLon, maxLat) || cellCrosses(minLon, minLat, maxLon, maxLat); return cellContains(minLon, minLat, maxLon, maxLat) || cellWithin(minLon, minLat, maxLon, maxLat)
|| cellCrosses(minLon, minLat, maxLon, maxLat);
} }
/** /**
@ -183,32 +176,6 @@ public final class GeoPointInPolygonQuery extends GeoPointInBBoxQueryImpl {
} }
} }
private static GeoRect computeBBox(double[] polyLons, double[] polyLats) {
if (polyLons.length != polyLats.length) {
throw new IllegalArgumentException("polyLons and polyLats must be equal length");
}
double minLon = Double.POSITIVE_INFINITY;
double maxLon = Double.NEGATIVE_INFINITY;
double minLat = Double.POSITIVE_INFINITY;
double maxLat = Double.NEGATIVE_INFINITY;
for (int i=0;i<polyLats.length;i++) {
if (GeoUtils.isValidLon(polyLons[i]) == false) {
throw new IllegalArgumentException("invalid polyLons[" + i + "]=" + polyLons[i]);
}
if (GeoUtils.isValidLat(polyLats[i]) == false) {
throw new IllegalArgumentException("invalid polyLats[" + i + "]=" + polyLats[i]);
}
minLon = Math.min(polyLons[i], minLon);
maxLon = Math.max(polyLons[i], maxLon);
minLat = Math.min(polyLats[i], minLat);
maxLat = Math.max(polyLats[i], maxLat);
}
return new GeoRect(minLon, maxLon, minLat, maxLat);
}
/** /**
* API utility method for returning the array of longitudinal values for this GeoPolygon * API utility method for returning the array of longitudinal values for this GeoPolygon
* The returned array is not a copy so do not change it! * The returned array is not a copy so do not change it!

View File

@ -62,6 +62,7 @@ abstract class GeoPointTermsEnum extends FilteredTermsEnum {
DETAIL_LEVEL = (short)(((GeoUtils.BITS<<1)-computeMaxShift())/2); DETAIL_LEVEL = (short)(((GeoUtils.BITS<<1)-computeMaxShift())/2);
computeRange(0L, (short) (((GeoUtils.BITS) << 1) - 1)); computeRange(0L, (short) (((GeoUtils.BITS) << 1) - 1));
assert rangeBounds.isEmpty() == false;
Collections.sort(rangeBounds); Collections.sort(rangeBounds);
} }

View File

@ -46,31 +46,31 @@ public final class GeoUtils {
private GeoUtils() { private GeoUtils() {
} }
public static Long mortonHash(final double lon, final double lat) { public static final Long mortonHash(final double lon, final double lat) {
return BitUtil.interleave(scaleLon(lon), scaleLat(lat)); return BitUtil.interleave(scaleLon(lon), scaleLat(lat));
} }
public static double mortonUnhashLon(final long hash) { public static final double mortonUnhashLon(final long hash) {
return unscaleLon(BitUtil.deinterleave(hash)); return unscaleLon(BitUtil.deinterleave(hash));
} }
public static double mortonUnhashLat(final long hash) { public static final double mortonUnhashLat(final long hash) {
return unscaleLat(BitUtil.deinterleave(hash >>> 1)); return unscaleLat(BitUtil.deinterleave(hash >>> 1));
} }
private static long scaleLon(final double val) { private static final long scaleLon(final double val) {
return (long) ((val-MIN_LON_INCL) * LON_SCALE); return (long) ((val-MIN_LON_INCL) * LON_SCALE);
} }
private static long scaleLat(final double val) { private static final long scaleLat(final double val) {
return (long) ((val-MIN_LAT_INCL) * LAT_SCALE); return (long) ((val-MIN_LAT_INCL) * LAT_SCALE);
} }
private static double unscaleLon(final long val) { private static final double unscaleLon(final long val) {
return (val / LON_SCALE) + MIN_LON_INCL; return (val / LON_SCALE) + MIN_LON_INCL;
} }
private static double unscaleLat(final long val) { private static final double unscaleLat(final long val) {
return (val / LAT_SCALE) + MIN_LAT_INCL; return (val / LAT_SCALE) + MIN_LAT_INCL;
} }
@ -182,7 +182,7 @@ public final class GeoUtils {
*/ */
public static boolean rectContains(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY, public static boolean rectContains(final double aMinX, final double aMinY, final double aMaxX, final double aMaxY,
final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) { final double bMinX, final double bMinY, final double bMaxX, final double bMaxY) {
return !(bMinX < aMinX || bMinY < aMinY || bMaxX > aMaxX || bMaxY > aMaxY); return !(bMinX < aMinX || bMinY < aMinY || bMaxX > aMaxX || bMaxY > aMaxY);
} }
/** /**
@ -366,6 +366,33 @@ public final class GeoUtils {
StrictMath.toDegrees(minLat), StrictMath.toDegrees(maxLat)); StrictMath.toDegrees(minLat), StrictMath.toDegrees(maxLat));
} }
public static GeoRect polyToBBox(double[] polyLons, double[] polyLats) {
if (polyLons.length != polyLats.length) {
throw new IllegalArgumentException("polyLons and polyLats must be equal length");
}
double minLon = Double.POSITIVE_INFINITY;
double maxLon = Double.NEGATIVE_INFINITY;
double minLat = Double.POSITIVE_INFINITY;
double maxLat = Double.NEGATIVE_INFINITY;
for (int i=0;i<polyLats.length;i++) {
if (GeoUtils.isValidLon(polyLons[i]) == false) {
throw new IllegalArgumentException("invalid polyLons[" + i + "]=" + polyLons[i]);
}
if (GeoUtils.isValidLat(polyLats[i]) == false) {
throw new IllegalArgumentException("invalid polyLats[" + i + "]=" + polyLats[i]);
}
minLon = Math.min(polyLons[i], minLon);
maxLon = Math.max(polyLons[i], maxLon);
minLat = Math.min(polyLats[i], minLat);
maxLat = Math.max(polyLats[i], maxLat);
}
return new GeoRect(GeoUtils.unscaleLon(GeoUtils.scaleLon(minLon)), GeoUtils.unscaleLon(GeoUtils.scaleLon(maxLon)),
GeoUtils.unscaleLat(GeoUtils.scaleLat(minLat)), GeoUtils.unscaleLat(GeoUtils.scaleLat(maxLat)));
}
/* /*
/** /**
* Computes whether or a 3dimensional line segment intersects or crosses a sphere * Computes whether or a 3dimensional line segment intersects or crosses a sphere