Skip to content

Commit c49775f

Browse files
committed
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.
1 parent e00b535 commit c49775f

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

server/src/main/java/org/elasticsearch/common/geo/GeoHashUtils.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import java.util.ArrayList;
2626
import java.util.Collection;
2727

28+
import static org.apache.lucene.geo.GeoUtils.MAX_LAT_INCL;
29+
2830
/**
2931
* Utilities for converting to/from the GeoHash standard
3032
*
@@ -48,6 +50,8 @@ public class GeoHashUtils {
4850
private static final double LAT_SCALE = (0x1L<<BITS)/180.0D;
4951
private static final double LON_SCALE = (0x1L<<BITS)/360.0D;
5052
private static final short MORTON_OFFSET = (BITS<<1) - (PRECISION*5);
53+
/** Bit encoded representation of the latitude of north pole */
54+
private static final long MAX_LAT_BITS = (0x1L << (PRECISION * 5 / 2)) - 1;
5155

5256
// No instance:
5357
private GeoHashUtils() {
@@ -218,12 +222,19 @@ public static Rectangle bbox(final String geohash) {
218222
long ghLong = longEncode(geohash, len);
219223
// shift away the level
220224
ghLong >>>= 4;
221-
// deinterleave and add 1 to lat and lon to get topRight
222-
long lat = BitUtil.deinterleave(ghLong >>> 1) + 1;
223-
long lon = BitUtil.deinterleave(ghLong) + 1;
224-
GeoPoint topRight = GeoPoint.fromGeohash(BitUtil.interleave((int)lon, (int)lat) << 4 | len);
225-
226-
return new Rectangle(bottomLeft.lat(), topRight.lat(), bottomLeft.lon(), topRight.lon());
225+
// deinterleave
226+
long lon = BitUtil.deinterleave(ghLong >>> 1);
227+
long lat = BitUtil.deinterleave(ghLong);
228+
if (lat < MAX_LAT_BITS) {
229+
// add 1 to lat and lon to get topRight
230+
GeoPoint topRight = GeoPoint.fromGeohash(BitUtil.interleave((int)(lat + 1), (int)(lon + 1)) << 4 | len);
231+
return new Rectangle(bottomLeft.lat(), topRight.lat(), bottomLeft.lon(), topRight.lon());
232+
} else {
233+
// We cannot go north of north pole, so just using 90 degrees instead of calculating it using
234+
// add 1 to lon to get lon of topRight, we are going to use 90 for lat
235+
GeoPoint topRight = GeoPoint.fromGeohash(BitUtil.interleave((int)lat, (int)(lon + 1)) << 4 | len);
236+
return new Rectangle(bottomLeft.lat(), MAX_LAT_INCL, bottomLeft.lon(), topRight.lon());
237+
}
227238
}
228239

229240
/**

server/src/test/java/org/elasticsearch/common/geo/GeoHashTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ public void testLongGeohashes() {
9898
}
9999
}
100100

101+
public void testNorthPoleBoundingBox() {
102+
Rectangle bbox = GeoHashUtils.bbox("zzbxfpgzupbx"); // Bounding box with maximum precision touching north pole
103+
assertEquals(90.0, bbox.maxLat, 0.0000001); // Should be 90 degrees
104+
}
105+
101106
public void testInvalidGeohashes() {
102107
IllegalArgumentException ex;
103108

0 commit comments

Comments
 (0)