GeoHash函数未返回正确的结果

时间:2017-07-30 16:54:18

标签: java geohashing

我正在尝试编写一个geohashing函数,它接受纬度/经度对并返回其base2(geohash一旦转换为base32)字符串。但是,这给了我不正确的结果。这有什么问题?

public static void main(String[] args) {
    float latitude = 45.512794f;
    float longitude = -122.679565f;
    System.out.println(geoHash(latitude, longitude));
}

private static String geoHash(float lat, float lng) {
    float lowLat = -90.0f;
    float highLat = 90.0f;
    float lowLng = -180.0f;
    float highLng = 180.0f;
    return geoHash(lowLng, highLng, lowLat, highLat, lat, lng, "");
}

private static String geoHash(float lowLng, float highLng, float lowLat, float highLat, float lat, float lng, String hash) {
    if (hash.length() == 30)
        return hash;

    float midLat = (lowLat + highLat) / 2;
    float midLng = (lowLng + highLng) / 2;
    if (lng <= midLng && lat <= midLat) {
        return geoHash(lowLng, midLng, lowLat, midLat, lat, lng, hash + "00");
    } else if (lng > midLng && lat <= midLat) {
        return geoHash(midLng, highLng, lowLat, midLat, lat, lng, hash + "01");
    } else if (lng <= midLng && lat > midLat) {
        return geoHash(lowLng, midLng, midLat, highLat, lat, lng, hash + "10");
    } else {
        return geoHash(midLng, highLng, midLat, highLat, lat, lng, hash + "11");
    }
}

我正在转换为kh0dl3 base32的101001000100000011011010100011,我期待转换为c20fbm的11000001000000011110101110110。

我不明白的是前两对比特在我从我的函数(1010)获得的结果中是相同的,这意味着它在同一象限中击中了两次。在实际转换的geohash中,我在网上发现它们是两个不同的象限(1100)。

编辑:进一步调试,并在选择的答案的帮助下,我发现我正在正确解码基数32(我使用的是4位,而不是5位)。我也应该使用在https://en.wikipedia.org/wiki/Geohash找到的表格。我的代码中也有错误,修复如下:

private static String geoHash(float lowLng, float highLng, float lowLat, float highLat, float lat, float lng, String hash) {
    if (hash.length() == 30)
        return hash;

    float midLng = (lowLng + highLng) / 2.0f;
    float midLat = (lowLat + highLat) / 2.0f;
    if (lng <= midLng && lat <= midLat) {
        return geoHash(lowLng, midLng, lowLat, midLat, lat, lng, hash + "00");
    } else if (lng <= midLng && lat > midLat) {
        return geoHash(lowLng, midLng, midLat, highLat, lat, lng, hash + "01");
    } else if (lng > midLng && lat <= midLat) {
        return geoHash(midLng, highLng, lowLat, midLat, lat, lng, hash + "10");
    } else {
        return geoHash(midLng, highLng, midLat, highLat, lat, lng, hash + "11");
    }
}

2 个答案:

答案 0 :(得分:0)

无论你从哪里得到你期望的字符串,该来源就是撒谎。首先,您期望的String只有29个字符长,这意味着缺少1个字符。此外,前两位需要为01,因为经度为负,但纬度为正。

但是你的代码中仍然存在一个错误:如果我正确理解了geohash的构成,那么你要切换附加到hash的经度和纬度位(第二个和第三个{{1}您处理ifgeoHash(float, float, float, float, float, float, String)的{​​{1}}方法中的}子句。

更新

经过进一步调查,看起来你得到意想不到的结果的另一个原因是,显然,base32和base2之间有多个可能的转换。我尝试了一些我能找到的在线解码器/编码器,他们都给了我在你的问题中提到的结果。但是,在阅读维基百科页面Geohash后,似乎用于编码从base2到base32的地理位置的算法是不同的。

例如,让我们检查你实际得到的geohash(所以没有关于缺失数字的歧义)。您的方法会返回lng,您声明会将其转换为lat。是的,当我输入here时,我也得到了这个结果。但是让我们看一下。前5个字符是101001000100000011011010100011,或者转换为十进制表示法kh0dl3(base2字符串中的5个字符对应于base32字符串中的一个字符,因此我们需要一次取5个字符)。在我刚刚关联的页面中输入10100会产生12 10100的第一个字符,正如预期的那样。但是,根据Wikipedia Geohash页面中的表格,K不会转换为kh0dl3,而是转换为12。显然,geohashes的base32-base2-conversion算法与你用来获得预期结果的算法不同。

答案 1 :(得分:-1)

当然,它不会返回您期望的结果。 Wikipedia页面从字面上说,您可以从base32解码除a,i,l,o 以外的所有数字上的geohash。