Функция GeoHash не возвращает правильный результат

Я пытаюсь написать функцию геохеширования, которая принимает пару широта/долгота и возвращает строку base2 (геохэш, преобразованный в 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), что означает, что он дважды попадает в один и тот же квадрант. В фактическом конвертированном геохэше, который я нашел в Интернете, это два разных квадранта (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");
    }
}

person jLangley011    schedule 30.07.2017    source источник
comment
Вы пытались отладить свой код? Могу ли я предложить вам использовать некоторые существующие библиотеки (скажем, github.com/davidmoten/geo)?   -  person    schedule 30.07.2017


Ответы (2)


Где бы вы ни получили ожидаемую строку, этот источник лгал. Во-первых, ваша ожидаемая строка имеет длину всего 29 символов, что означает отсутствие 1 символа. Кроме того, первые два бита должны быть равны 01, потому что долгота отрицательна, а широта положительна.

Но в вашем коде все еще есть ошибка: если я правильно понимаю состав геохэша, вы переключаете биты для долготы и широты, которые вы добавляете к hash (второе и третье предложение if в методе geoHash(float, float, float, float, float, float, String), где вы обрабатываете lng и lat).

Обновлять

После дальнейшего изучения кажется, что еще одна причина, по которой вы получаете неожиданные результаты, заключается в том, что, по-видимому, существует более одного возможного преобразования между base32 и base2. Я попробовал несколько онлайн-декодеров/кодировщиков, которые смог найти, и все они дали мне результаты, о которых вы упомянули в своем вопросе. Однако, прочитав страницу Википедии Geohash, кажется, что алгоритм, используемый для кодирования геохэшей из base2 для base32 отличается.

Например, давайте рассмотрим геохэш, который вы фактически получили (чтобы не было двусмысленности в отношении пропущенных цифр). Ваш метод возвращает 101001000100000011011010100011, который, как вы утверждаете, преобразуется в kh0dl3. Правда, когда я ввожу его здесь, Я также получаю этот результат. Но давайте посмотрим немного ближе. Первые 5 символов — это 10100, или, преобразованные в десятичную запись, 12 (5 символов из строки base2 соответствуют одному символу в строке base32, следовательно, нам нужно взять сразу 5 символов). Ввод 10100 на страницу, на которую я только что ссылался, дает K, первый символ kh0dl3, как и ожидалось. Однако, согласно таблице на странице Wikipedia Geohash, 12 переводится не в k, а в d. Таким образом, очевидно, что алгоритм преобразования base32-base2 для геохешей отличается от того, который вы использовали для получения ожидаемого результата.

person Stingy    schedule 30.07.2017

Конечно, он не возвращает ожидаемого результата. На странице в Википедии буквально сказано, что вы можете декодировать геохеш из base32 для всех цифр, кроме a, i, l, o.

person kopisusuanget    schedule 24.05.2019