Geohash
Geohash copied to clipboard
你这个解释叼。网上一堆解释,还各种图片,花里胡哨看不懂
你这个前面的 栗子 + 原理 两段,我就给整明白了,,,谢谢~
很快我就用 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;
}