Fix north pole overflow error in GeoHashUtils.bbox() (#32891)

Fixes an overflow error in  GeoHashUtils.bbox() calculation of a
bounding box for geohashes with maximum precision located next to the
north pole.
This commit is contained in:
Igor Motov 2018-08-21 14:59:37 -04:00 committed by GitHub
parent fcf8cadd9a
commit 3973bb4028
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 6 deletions

View File

@ -25,6 +25,8 @@ import org.apache.lucene.util.BitUtil;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import static org.apache.lucene.geo.GeoUtils.MAX_LAT_INCL;
/** /**
* Utilities for converting to/from the GeoHash standard * Utilities for converting to/from the GeoHash standard
* *
@ -48,6 +50,8 @@ public class GeoHashUtils {
private static final double LAT_SCALE = (0x1L<<BITS)/180.0D; private static final double LAT_SCALE = (0x1L<<BITS)/180.0D;
private static final double LON_SCALE = (0x1L<<BITS)/360.0D; private static final double LON_SCALE = (0x1L<<BITS)/360.0D;
private static final short MORTON_OFFSET = (BITS<<1) - (PRECISION*5); private static final short MORTON_OFFSET = (BITS<<1) - (PRECISION*5);
/** Bit encoded representation of the latitude of north pole */
private static final long MAX_LAT_BITS = (0x1L << (PRECISION * 5 / 2)) - 1;
// No instance: // No instance:
private GeoHashUtils() { private GeoHashUtils() {
@ -218,12 +222,19 @@ public class GeoHashUtils {
long ghLong = longEncode(geohash, len); long ghLong = longEncode(geohash, len);
// shift away the level // shift away the level
ghLong >>>= 4; ghLong >>>= 4;
// deinterleave and add 1 to lat and lon to get topRight // deinterleave
long lat = BitUtil.deinterleave(ghLong >>> 1) + 1; long lon = BitUtil.deinterleave(ghLong >>> 1);
long lon = BitUtil.deinterleave(ghLong) + 1; long lat = BitUtil.deinterleave(ghLong);
GeoPoint topRight = GeoPoint.fromGeohash(BitUtil.interleave((int)lon, (int)lat) << 4 | len); if (lat < MAX_LAT_BITS) {
// add 1 to lat and lon to get topRight
GeoPoint topRight = GeoPoint.fromGeohash(BitUtil.interleave((int)(lat + 1), (int)(lon + 1)) << 4 | len);
return new Rectangle(bottomLeft.lat(), topRight.lat(), bottomLeft.lon(), topRight.lon()); return new Rectangle(bottomLeft.lat(), topRight.lat(), bottomLeft.lon(), topRight.lon());
} else {
// We cannot go north of north pole, so just using 90 degrees instead of calculating it using
// add 1 to lon to get lon of topRight, we are going to use 90 for lat
GeoPoint topRight = GeoPoint.fromGeohash(BitUtil.interleave((int)lat, (int)(lon + 1)) << 4 | len);
return new Rectangle(bottomLeft.lat(), MAX_LAT_INCL, bottomLeft.lon(), topRight.lon());
}
} }
/** /**

View File

@ -98,6 +98,11 @@ public class GeoHashTests extends ESTestCase {
} }
} }
public void testNorthPoleBoundingBox() {
Rectangle bbox = GeoHashUtils.bbox("zzbxfpgzupbx"); // Bounding box with maximum precision touching north pole
assertEquals(90.0, bbox.maxLat, 0.0000001); // Should be 90 degrees
}
public void testInvalidGeohashes() { public void testInvalidGeohashes() {
IllegalArgumentException ex; IllegalArgumentException ex;