firebase / geofire-android

GeoFire for Android apps
Apache License 2.0
133 stars 36 forks source link

Geohash algorithm is incorrect #24

Open mrd5591 opened 2 years ago

mrd5591 commented 2 years ago

In method queryForGeohash in GeoHashQuery.java, we see this code:

String hash = geohash.getGeoHashString(); int precision = (int)Math.ceil((double)bits/Base32Utils.BITS_PER_BASE32_CHAR); if (hash.length() < precision) { return new GeoHashQuery(hash, hash+"~"); }

AND

if (endValue > 31) { endHash = base + "~"; }

If the length of the geohash is less than the precision or endValue is greater than 31, add on a tilde to the geohash. But, we run into problems with this when we filter out duplicates in the method queriesAtLocation. When we join duplicate queries, we use the compareTo string method to determine if one query is a prefix to another, but ~ is "less than" letters and numbers when comparing strings so this results in not getting a completely accurate boundary box to find all matching geohashes.

Ex:

center = new GeoLocation(40.45448960350406, -79.99045468343982); radiusInMeters = 8046.72;

bounds = GeoHashUtils.getGeoHashQueryBounds(center, radiusInMeters);

We would expect to get

[ [ 'dppn0', 'dppnh' ], [ 'dppnh', 'dppn~' ], [ 'dppj0', 'dppjh' ], [ 'dppjh', 'dppj~' ] ]

as our result. In fact, I verified this using geofire-common library in Javascript. However in this implementation, we get:

[ [ 'dppn0', 'dppnh' ], [ 'dppj0', 'dppjh' ] ]