随着移动终端的普及,很多应用都具有LBS功能,如查找附近的餐馆、酒店等应用。

一、球面距离

简单的做法,一般保存了目标位置的经纬度;根据用户提供的经纬度,通过球面距离公式进行计算。公式如下:

  S=2*asin(sqrt(pow(sin((lat1-lat2)/2),2)+cos(lat1)*cos(lat2)*pow(sin((lng1-lng2)/2),2)))*R

二、Geohash

  其实还有一种做法,就是要提到的GeoHash。GeoHash将一个经纬度转换成一个可以排序比较的字符串编码。GeoHash表示的并不是一个点,而是一个矩形区域。使用者可以发布地址编码,既能表明自己位于某地址附近,又不至于暴露自己的精确坐标,有助于隐私保护。

    GeoHash编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。 这个特性可以用于附近地点搜索。Geohash比直接用经纬度的高效很多。
        编码方式:首先,将纬度范围(-90, 90)平分成两个区间(-90,0)、(0, 90),如果目标纬度位于前一个区间,则编码为0,否则编码为1。然后,再将(0, 90)分成 (0, 45), (45, 90)两个区间,如果目标纬度位于前一个区间,则编码为0,否则编码为1。以此类推,直到精度符合要求为止。

  为什么需要将经纬度两串编码交叉组合成一串编码?如图所示,我们将二进制编码的结果填写到空间中,当将空间划分为四块时候,编码的顺序分别是左下角00,左上角01,右下脚10,右上角11,也就 是类似于Z的曲线,当我们递归的将各个块分解成更小的子块时,编码的顺序是自相似的(分形),每一个子快也形成Z曲线,这种类型的曲线被称为Peano空间填充曲线。这种类型的空间填充曲线的优点是将二维空间转换成一维曲线(事实上是分形维),对大部分而言,编码相似的距离也相近,但Peano空间填充曲线最大的缺点就是突变性,有些编码相邻但距离却相差很远,比如0111与1000,编码是相邻的,但距离相差很大。

 

 

  除Peano空间填充曲线外,还有很多空间填充曲线,如图所示,其中效果公认较好是Hilbert空间填充曲线,相较于Peano曲线而 言,Hilbert曲线没有较大的突变。为什么GeoHash不选择Hilbert空间填充曲线呢?可能是Peano曲线思路以及计算上比较简单吧,事实 上,Peano曲线就是一种四叉树线性编码方式。

 

 

三、使用注意点

1)由于GeoHash是将区域划分为一个个规则矩形,并对每个矩形进行编码,这样在查询附近POI信息时会导致以下问题,比如红色的点是我们的位 置,绿色的两个点分别是附近的两个餐馆,但是在查询的时候会发现距离较远餐馆的GeoHash编码与我们一样(因为在同一个GeoHash区域块上),而 较近餐馆的GeoHash编码与我们不一致。这个问题往往产生在边界处。

 

 

  解决的思路很简单,我们查询时,除了使用定位点的GeoHash编码进行匹配外,还使用周围8个区域的GeoHash编码,这样可以避免这个问题。

2)我们已经知道现有的GeoHash算法使用的是Peano空间填充曲线,这种曲线会产生突变,造成了编码虽然相似但距离可能相差很大的问题,因此在查询附近餐馆时候,首先筛选GeoHash编码相似的POI点,然后进行实际距离计算。

posted on 2016-07-07 21:44  成都笨笨  阅读(1200)  评论(0编辑  收藏  举报