Geohash icon indicating copy to clipboard operation
Geohash copied to clipboard

你这个解释叼。网上一堆解释,还各种图片,花里胡哨看不懂

Open largezhou opened this issue 6 years ago • 0 comments

你这个前面的 栗子 + 原理 两段,我就给整明白了,,,谢谢~

很快我就用 PHP 代码实现一下,当然 base32 那里是照抄你的,

算出的结果一样,

public function testGeoHash()
{
    dump($this->geoHash(116.402843, 39.999375)); // 鸟巢
    dump($this->geoHash(116.3967, 39.99932)); // 水立方
    dump($this->geoHash(116.40382, 39.918118)); // 故宫
}

public function geoHash(float $lon, float $lat): string
{
    $lonBin = $this->geoToBin($lon, -180.0, 180.0);
    $latBin = $this->geoToBin($lat, -90.0, 90.0);

    $bin = $this->geoMerge($lonBin, $latBin);

    $hash = $this->base32($bin);

    return $hash;
}

protected function geoToBin(float $val, float $min, float $max): string
{
    $res = '';
    for ($i = 0; $i < 20; $i++) {
        $middle = ($max + $min) / 2;
        if ($val <= $middle) {
            $res .= '0';
            $max = $middle;
        } else {
            $res .= '1';
            $min = $middle;
        }
    }

    return $res;
}

protected function geoMerge(string $lonBin, string $latBin): string
{
    $res = '';
    for ($i = 0; $i < 20; $i++) {
        $res .= $lonBin[$i].$latBin[$i];
    }

    return $res;
}

protected function base32(string $str): string
{
    $base32Alphabet = '0123456789bcdefghjkmnpqrstuvwxyz';

    $len = strlen($str);
    $step = (int) ($len / 8); // 转成 8 位的 base32 编码

    $res = '';

    for ($i = 0; $i < $len; $i += $step) {
        $subStr = substr($str, $i, $step);
        $subLen = strlen($subStr);

        $index = 0;
        for ($j = 0; $j < $subLen; $j++) {
            $index += ($subStr[$j] === '0')
                ? 0
                : (1 << ($subLen - 1 - $j));
        }

        $res .= $base32Alphabet[$index];
    }

    return $res;
}

largezhou avatar Feb 24 '20 09:02 largezhou