• geohash学习


    geohash编解码

    import (
    	"github.com/mmcloughlin/geohash"
    )
    
    func Test_Demo(t *testing.T) {
    	// 编码经纬度到 geohash 字符串
    	lat, lon := 40.7128, -74.0060       // 纽约市的位置
    	geoHash := geohash.Encode(lat, lon) // geohash 字符串
    	fmt.Println(geoHash)                // dr5regw3ppyz
    
    	// 解码 geohash 字符串到经纬度坐标
    	lat, lon = geohash.Decode("dr5regw3ppyz")
    	fmt.Printf("lat: %.4f, lon: %.4f", lat, lon)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    mmcloughlin开发的geohash

    func ConvertIntToString(hash uint64, chars uint) string
    将整数 geohash 转换为具有 chars 字符的等效字符串 geohash
    精度:5chars
    The provided integer geohash is interpreted to have 5
    chars bits of precision.

    func ConvertStringToInt(hash string) (uint64, uint)
    将字符串 geohash 转换为等效的整数 geohash
    返回整数哈希值及其精度

    func Decode(hash string) (lat, lng float64)
    将字符串 geohash 解码为 (lat, lng) 坐标

    func DecodeCenter(hash string) (lat, lng float64)
    将字符串 geohash 解码到边界框的中心点

    func DecodeInt(hash uint64) (lat, lng float64)
    将提供的 64 位整数 geohash 解码为 (lat, lng) 坐标

    func DecodeIntWithPrecision(hash uint64, bits uint) (lat, lng float64)
    将提供的整数 geohash 解码为 (lat, lng) 点的精度位。

    func Encode(lat, lng float64) string
    函数编码
    将(lat、lng)编码为具有标准 12 个字符精度的字符串 geohash

    func EncodeInt(lat, lng float64) uint64
    将 (lat, lng) 编码为 64 位整数 geohash

    func EncodeIntWithPrecision(lat, lng float64, bits uint) uint64
    将 (lat, lng) 编码为具有指定位数的整数

    func EncodeWithPrecision(lat, lng float64, chars uint) string
    将 (lat, lng) 编码为具有指定精度字符数(最多 12)的字符串 geohash

    func Neighbor(hash string, direction Direction) string
    返回一个 geohash 字符串,该字符串对应于所提供方向上所提供的 geohash 的邻居

    func NeighborInt(hash uint64, direction Direction) uint64
    返回一个 uint64,它对应于所提供的散列在所提供的方向上以 64 位精度的邻居

    func NeighborIntWithPrecision(hash uint64, bits uint, direction Direction) uint64
    返回一个 uint64s,它对应于给定精度的指定方向上所提供的哈希的邻居

    func Neighbors(hash string) []string
    返回与所提供的 geohash 邻居相对应的 geohash 字符串切片

    func NeighborsInt(hash uint64) []uint64
    返回一个 uint64 切片,对应于所提供的哈希的 64 位精度的邻居

    func NeighborsIntWithPrecision(hash uint64, bits uint) []uint64
    返回 uint64 的切片,该切片对应于给定精度下提供的哈希的邻居

    func Validate(hash string) error
    验证字符串 geohash

    type Box struct {
    	MinLat float64
    	MaxLat float64
    	MinLng float64
    	MaxLng float64
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    表示纬度/经度空间中的矩形

    func BoundingBox(hash string) Box
    返回由给定字符串 geohash 编码的区域

    func BoundingBoxInt(hash uint64) Box
    返回由给定 64 位整数 geohash 编码的区域

    func BoundingBoxIntWithPrecision(hash uint64, bits uint) Box
    返回由具有指定精度的整数 geohash 编码的区域

    func (b Box) Center() (lat, lng float64)
    返回盒子的中心

    func (b Box) Contains(lat, lng float64) bool
    决定 (lat, lng) 是否包含在框中

    func (b Box) Round() (lat, lng float64)
    返回框内的一个点,努力舍入到最小精度

    type Direction int
    表示纬度/经度空间中的方向

    const (
    	North Direction = iota // 0
    	NorthEast
    	East
    	SouthEast
    	South
    	SouthWest
    	West
    	NorthWest
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    基本方向和基本方向,从正北开始,顺时针旋转一圈

    Geohash算法

    利用分层的网格系统来表示地球上的给定区域
    在每个网格中,Geohash单元格将地球表面的区域划分为更小的子区域
    每个 Geohash 单元格都可以映射到一个不同的 Geohash 字符串

    由于 Geohash 单元格始终是正方形的,因此每个 Geohash 单元格的实际外观是类似于矩形的。
    geohash.DecodeCenter 函数使用该矩形,以确定 Geohash 编码本身所代表的地理区域的标准矩形外接盒子,并返回该盒子的中心点经纬度坐标作为解码结果。

    Geohash 字符串本身并不包含与其对应的矩形精确的边界坐标,因此在使用 geohash.DecodeCenter 函数时,应该了解解码结果可能与实际位置略有偏差的事实。

    示例

    纬度 lat:39.9257460000,经度 lng:116.5998310000
    纬度二进制计算

    范围负区间正区间取值
    (-90, 90)(-90,0](0, 90)1
    (0, 90)(0,45](45,90)0
    (0, 45)(0,22.5)[22.5,45)1
    (22.5,45)(22.5,33.75)[33.75,45)1
    1
    0
    0
    0
    1

    纬度落于区间使用1和0进行标识,最后可以组成一个二进制数字101110001100011;同理,经度二进制计算 110100101100010。

    最后,奇数位放纬度,偶数位放经度:
    1 1 0 1 0 0 1 0 1 1 0 0 0 1 0
1 0 1 1 1 0 0 0 1 1 0 0 0 1 1

    得到30位的字节数组:
    11100 11101 00100 01111 00000 01101

    每五位二进制转为一个十进制:

    t1 := 0b11100
    t2 := 0b11101
    t3 := 0b00100
    t4 := 0b01111
    t5 := 0b00000
    t6 := 0b01101
    fmt.Println(t1, t2, t3, t4, t5, t6) // 28 29 4 15 0 13
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    对应base32编码 wx4g0e

    原理

    将整个地图或者某个分割所得的区域进行进一步划分,由于采用的是base32编码方式,这样可以将整个地图区域分为32个区域,通过00000 ~ 11111来标识这32个区域。
    第一次对地图划分后的情况如下图所示(每个区域中的编号对应于该区域所对应的编码)
    在这里插入图片描述
    在这里插入图片描述
    Geohash的0、1串序列是经度0、1序列和纬度0、1序列中的数字交替进行排列,偶数位对应的序列为经度序列(从0位开始),奇数位对应的序列为纬度序列。

    在这里插入图片描述

    在进行第一次划分时,Geohash0、1序列中的前5个bits(11100),那么这5bits中有3bits是表示经度,2bits表示纬度。

    将经度划分成8个区段(2^3 = 8)
    将纬度划分为4个区段(2^2 = 4)
    形成了32个区域(对应Base32)
    
    • 1
    • 2
    • 3

    缺点

    将每一个区域画成一块块矩形块,每个矩形块使用一个字符串表示,当需要查询附近的点时,通过自己的坐标计算出一个字符串,根据这个字符串定位到所在的矩形块,然后返回这个矩形块中的点。
    例如 wx4e就包含wx4e0e,也就是说wx4e0e在wx4e范围内。
    在这里插入图片描述
    通行做法:不仅获取当前所在的矩形区域,还获取周围8个矩形块中的点(已经知道自己的经纬度,只需要用自己的经纬度减去最小划分单位的经纬度)。
    在这里插入图片描述
    通过上面这张图,就能很容易的计算出周围8个点的经纬度。有了经纬度就能定位到周围8个矩形块。这样就能获取包括自己所在矩形块的9个矩形块中的所有的点。
    最后分别计算这些点和自己的距离(由于范围很小,点的数量就也很少,计算量就很少)过滤掉不满足条件的点。

    redis中的geohash

    存储地理位置信息,并对存储的信息进行操作。

    geoadd:添加地理位置的坐标。
    geopos:获取地理位置的坐标。
    geodist:计算两个位置之间的距离。
    georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
    georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
    geohash:返回一个或多个位置对象的 geohash 值。

    geoadd
    存储指定的地理空间位置,将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定 key
    GEOADD key longitude latitude member [longitude latitude member …]

    geopos
    从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil
    GEOPOS key member [member …]

    geodist
    返回两个给定位置之间的距离
    GEODIST key member1 member2 [m|km|ft|mi]

    • member1 member2 为两个地理位置
    • 最后一个距离单位参数说明:
      m米,默认单位 / km千米 / mi英里 / ft英尺。

    georadius、georadiusbymember
    以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

    georadiusbymember 和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 georadiusbymember 的中心点是由给定的位置元素决定的, 而不是使用经度和纬度来决定中心点。
    GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
    GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
    WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
    WITHCOORD: 将位置元素的经度和纬度也一并返回。
    WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
    COUNT 限定返回的记录数。
    ASC: 查找结果根据距离从近到远排序。
    DESC: 查找结果根据从远到近排序。

    geohash
    Redis GEO 使用 geohash 来保存地理位置的坐标。
    geohash 用于获取一个或多个位置元素的 geohash 值。

    geohash 语法格式如下:
    GEOHASH key member [member …]

    参考文档

    https://zhuanlan.zhihu.com/p/35940647

    附录

    geohash编码

    在这里插入图片描述
    在这里插入图片描述

    Base32

    将数字 0~9 ,加上26个字母(去除a,i,l,o 四个)进行组合而成的32个字符编码形式
    在这里插入图片描述

  • 相关阅读:
    Express:JSONP 接口
    杭州亚运会虚实短视频《功成》,给数字人三维动画宣传片制作有何启发?
    stack和queue的使用和模拟实现
    shiro-第二篇-整合springboot
    史上最全Java面试题,Java面试必备
    从实现到原理,聊聊Java中的SPI动态扩展
    uniapp中使用render.js进行openers、arcgis等地图操作
    服务器怎么买,腾讯云服务器购买三种流程介绍
    LNMP搭建
    我的创作二周年纪念日
  • 原文地址:https://blog.csdn.net/wangkai6666/article/details/132768451