GeoHash 函数没有返回正确的结果

GeoHash Function not returning correct result

我正在尝试编写一个 geohashing 函数,它采用 latitude/longitude 对和 returns 它的 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");
    }
}

我得到 101001000100000011011010100011 转换为 kh0dl3 base32,我期待 11000001000000011110101110110 转换为 c20fbm。

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

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

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");
    }
}

无论您从何处获得预期的字符串,该来源都在撒谎。首先,您预期的 String 只有 29 个字符长,这意味着缺少 1 个字符。此外,前两位需要为 01,因为经度为负而纬度为正。

但是您的代码中仍然存在错误:如果我正确理解了 geohash 的组成,您正在切换附加到 hash 的经度和纬度位(第二个和第三个 [= geoHash(float, float, float, float, float, float, String) 方法中处理 lnglat).

的 12=] 子句

更新

经进一步调查,您得到意外结果的另一个原因似乎是,显然,base32 和 base2 之间存在不止一种可能的转换。我尝试了一些我能找到的在线 decoders/encoders,他们都给了我你在问题中提到的结果。然而,在阅读维基百科页面Geohash后,似乎用于将 geohashes 从 base2 编码为 base32 的算法不同。

例如,让我们检查一下您实际获得的 geohash(因此没有关于缺失数字的歧义)。您声称的方法 returns 101001000100000011011010100011 转换为 kh0dl3。没错,当我输入here时,我也得到了这个结果。但是让我们仔细看看。前 5 个字符是 10100,或者,转换为十进制表示法,12(base2 字符串中的 5 个字符对应 base32 字符串中的一个字符,因此我们需要一次取 5 个字符)。在我刚刚链接到的页面中输入 10100 会产生 Kkh0dl3 的第一个字符,正如预期的那样。但是,根据维基百科 Geohash 页面中的 table,12 不会转换为 k,而是 d。很明显,geohashes 的 base32-base2-conversion 算法与您用来获得预期结果的算法不同。

当然 return 不是您期望的结果。维基百科页面字面上说你可以从所有数字的 base32 解码 geohash, 除了 a, i, l, o.