一种基于经纬度的地理位置编码方案

阮一峰的新闻周刊介绍了高德的位置口令,高德本月推出了一个新功能,可以位需要提供准确位置的用户生成一个 6 位编码,其他人直接搜索这个编码就能找到那个位置,而不需要知道这个位置的名称。
文章后面说:要是国家出台统一算法就好了,为每个地点生成一个固定不变的位置码,用处就大了。

我想,这倒没有必要,为所有位置提供编码的方案不就是经纬度么?
经纬度在日常表达方面确实会有一些障碍,读起来不大方便,而且我不确定有多少人知道经纬度,虽然这是初中就学了的。
我设计了一个 8 位编码方案(BASE32,只包含数字和大写英文字母):

经纬度 1 度大约偏差 111 公里,精确到小数点后 3 位小数,可以控制偏差在 100 米范围内,对于日常使用是可以接受的。

总共 360,000 x 180,000 = 648 亿个点。
二进制 36 位可以表达(687 亿),也就是 5 Bytes。
BASE32 8 位足够可以表达了(10995 亿)(7 位只有 343 亿,差一点)。

百度地图开放平台上用坐标拾取器获取两个坐标用来测试,结果如下:

  • 华中科技大学的毛泽东像位置是 (114.420025,30.514723),精度控制到小数点后三位,换算过来就是 BRLMVBKC
  • 美国自由女神像位置是 (-74.044500, 40.689225),精度控制到小数点后三位,换算过来就是 ARYMQF7B

Base32 字母出现的频率较多,为了减少英文字母的使用,我改成十六进制的表达方式,只多了一位而已,可以接受。测试结果如下:

  • 华中科技大学的毛泽东像位置 (114.420025,30.514723) 换算过来就是 0C56CA8542
  • 美国自由女神像位置 (-74.044500, 40.689225) 换算过来就是 0470C817E1

Python 代码示例:

# woody geo codec

import base64

# encode = base64.b32encode
# decode = base64.b32decode
encode = base64.b16encode
decode = base64.b16decode

def wgc_encode(lat:float, lon:float) -> str:
    lat_num = int((lat + 180) * 1000)
    lon_num = int((lon + 90) * 1000)
    num = lat_num * 180000 + lon_num
    return encode(num.to_bytes(5, byteorder="big")).decode()

def wgc_decode(code:str) -> tuple[float, float]:
    num = int.from_bytes(decode(code))
    lat_num = num // 180000
    lon_num = num % 180000
    print(lat_num, lon_num)
    lat = (lat_num - 180000) / 1000
    lon = (lon_num - 90000) / 1000
    return lat, lon

for lat, lon in ((114.420025, 30.514723), (-74.044500, 40.689225)):
    print((lat, lon))
    code = wgc_encode(lat, lon)
    print(code)
    print(wgc_decode(code))
如果你有魔法,你可以看到一个评论框~