2

I am trying to write a geohashing function that takes a latitude/longitude pair and returns its base2 (geohash once converted to base32) string. However, this is giving me incorrect results. What is wrong with it?

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

I am geting 101001000100000011011010100011 which converts to kh0dl3 base32, and I am expecting 11000001000000011110101110110 which converts to c20fbm.

what i don't understand is the first two pairs of bits are the same in the result that I get from my function (1010), meaning it hit the same quadrant twice. In the actual converted geohash I found online they are two different quadrants (1100).

Edit: Upon further debugging, and with the selected answer's help, I found that I was decoding the base 32 incorrectly (I was using 4 bits, instead of 5). I also should have used the table found at https://en.wikipedia.org/wiki/Geohash. There is also an error in my code, fixed below:

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

2 回答 2

0

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

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

更新

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

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

于 2017-07-30T17:50:45.670 回答
-1

当然,它不会返回您期望的结果。维基百科页面字面意思是,您可以在所有数字上从 base32 解码 geohash,除了 a, i, l, o

于 2019-05-24T09:00:08.280 回答