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;
} }
@ -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