转载:http://tech.idv2.com/2011/06/17/location-search/
附近地点搜索,顾名思义,就是搜索用户附近有哪些地点。随着GPS和带有GPS功能的移动设备的普及, 附近地点搜索也变得炙手可热。不过在网上却很少有这方面的讨论。本文的方法并不算最好, 但足以应付一般的应用了。
本文中,数据库采用MySQL,语言采用python。理论上别的数据库和语言也没问题, 但我们要在经纬度上设置两个索引,所以如果你的数据库不支持索引,或者不支持在一个查询中使用两个索引, 那就只能想别的办法了。
球面最短距离公式
球面上任意两点之间的距离计算公式可以参考维基百科上的下述文章,这里就不再赘述了。
值得一提的是,维基百科推荐使用Haversine公式,理由是Great-circle distance公式用到了大量余弦函数, 而两点间距离很短时(比如地球表面上相距几百米的两点),余弦函数会得出0.999…的结果, 会导致较大的舍入误差。而Haversine公式采用了正弦函数,即使距离很小,也能保持足够的有效数字。 以前采用三角函数表计算时的确会有这个问题,但经过实际验证,采用计算机来计算时,两个公式的区别不大。 稳妥起见,这里还是采用Haversine公式。
其中
- R为地球半径,可取平均值 6371km;
- φ1, φ2 表示两点的纬度;
- Δλ 表示两点经度的差值。
距离计算函数
下面就是计算球面间两点(lat0, lng)-(lat1, lng1)之间距离的函数。
from math import sin, asin, cos, radians, fabs, sqrt
EARTH_RADIUS=6371 # 地球平均半径,6371km
def hav(theta):
s = sin(theta / 2)
return s * s
def get_distance_hav(lat0, lng0, lat1, lng1):
"用haversine公式计算球面两点间的距离。"
# 经纬度转换成弧度
lat0 = radians(lat0)
lat1 = radians(lat1)
lng0 = radians(lng0)
lng1 = radians(lng1)
dlng = fabs(lng0 - lng1)
dlat = fabs(lat0 - lat1)
h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng)
distance = 2 * EARTH_RADIUS * asin(sqrt(h))
return distance
范围搜索算法
在庞大的地理数据库中搜索地点,索引是很重要的。但是,我们的需求是搜索附近地点, 例如,坐标(39.91, 116.37)附近500米内有什么地点?搜索条件是地点坐标与当前坐标之间的距离, 显然是无法应用索引的。
那么换个思路:首先算出“给定坐标附近500米”这个范围的坐标范围。 虽然它是个圆,但我们可以先求出该圆的外接正方形,然后拿正方形的经纬度范围去搜索数据库。
如图,红色部分为要求的搜索范围,绿色部分为实际搜索范围。
先来求东西两侧的的范围边界。在haversin公式中令φ1 = φ2,可得
写成python代码就是
dlng = 2 * asin(sin(distance / (2 * EARTH_RADIUS)) / cos(lat))
dlng = degrees(dlng) # 弧度转换成角度
然后求南北两侧的范围边界,在haversin公式中令 Δλ = 0,可得
写成python代码就是
dlat = distance / EARTH_RADIUS
dlng = degrees(dlat) # 弧度转换成角度
这样,根据当前点坐标,我们可以得出搜索范围为
left-top : (lat + dlat, lng - dlng)
right-top : (lat + dlat, lng + dlng)
left-bottom : (lat - dlat, lng - dlng)
right-bottom: (lat - dlat, lng + dlng)
然后利用这个范围构造SQL语句,即可实现范围查询:
SELECT * FROM place WHERE lat > lat1 AND lat < lat2 AND lng > lng1 AND lng < lng2;
在lat
和lng
列上建立索引,能从一定程度上提高范围查询的效率。
不过,这样查询到的地点是正方形范围内的地点,一些结果与当前点的距离可能会超出给定的距离。 如果要求严格,可以遍历结果并计算与当前点之间的距离,并过滤掉不符合要求的结果。
总结
附近地点搜索条件是距离,而数据库中一般只保存地点的经纬度,因此无法直接查询。 本文将距离转化成经纬度范围,利用经纬度上的索引,提高查询效率。
相关推荐
Geocoding经纬度批量查询工具可以经纬度批量查询,地址反查经纬,批量生成地图,批量导出各种查询结果,可以自由设置地图规格;让你省时,省力,方便快捷Geocoding经纬度批量查询工
GPSspg xGeocoding 工具,大批量地址经纬度解析转换工具。地址与经纬度相互解析 地址解析经纬度,商户名解析经纬度,经纬度解析地址,甚至可以将经纬度再次反解析出地址以便对比。大批量自动化。 各大地图经纬度相互...
经纬度批量查询工具经纬度批量查询工具经纬度批量查询工具经纬度批量查询工具
行政编码:取 民政部网站 2020年10月最新数据 经纬度:取 百度API geocoding V3
另外根据地址获取经纬度可以利用百度提供的 “Geocoding API”,可以直接百度:“ 百度Geocoding ”,参考地址:http://developer.baidu.com/map/index.php?title=webapi/guide/webservice-geocoding
rev_geocoding.0
实现步骤 1、 查询接口 网站上这种类型的接口还不少,笔者直接找了百度地图的接口做,接口文档,调用的API是Geocoding API中的地理编码服务 请求示例:对北京市百度大厦进行地理编码查询 ...这里面需要一个ak参数,...
根据百度Geocoding API获取,还有其他很多的数据可以获取到,可自行改动
中间经历了一些波折,刚开始直接使用网上代码debug半天都不行,才发现要随时跟进官方改动,使用别人的API一定要看说明书啊! 首先需要从百度地图平台上注册一个AK(在这之前要注册百度的开发者身份,免费),进入其...
Laravel开发-google-geocoding 用于Laravel的谷歌地理编码API集成
python根据百度地图api将地址转成经纬度
rev_geocoding.idx
当前的实现包括: - :warning: MapQuest :warning: MapQuest - - API返回纬度/经度坐标和规范化的地址信息。 这可用于执行地址验证,用户输入地址的实时映射,距离计算等。 请参阅最新。 :warning: 有关...
使用Google表格可以对地址进行地理编码,从地址到纬度/经度,反之亦然。 试纸 在上尝试使用包含示例地址数据的脚本。 您可以输入自己的地址数据,并在下面的行中对其进行地理编码。 您必须先登录Google帐户,然后...
* 根据地理坐标获取国家、省份、城市,及周边数据类(利用百度Geocoding API实现) * 百度密钥获取方法:http://lbsyun.baidu.com/apiconsole/key?application=key(需要先注册百度开发者账号) * Func: * Public ...
尽管名字很长,但它是一个很小的Ruby库,可以通过Google Geocoding API或MelissaData快速标准化邮政地址。 因此,如果您有在线商店,并且需要验证送货地址,则可以考虑使用此库。 那不是什么 这不是对地址或位置...
该系统使用ChatGPT开发,旨在帮助用户快速找到附近的公共厕所。系统使用Python编写的代码,可通过输入当前位置信息,分析附近的公共厕所位置和距离,并为用户提供最佳路线。 ChatGPT是使用的开发工具,旨在帮助用户...
地理编码器 GoLang软件包,提供了一种使用Google Geocoding API的简便方法。 通过以下链接查看有关Google Geocoding API的更多信息: : 您可以使用go get: go get github.com/kelvins/geocoder用法用法示例: ...
百度Geocoding API与Route Matrix API调用代码(Java源码).rar Java代码后台调用Route Matrix API v1.0;Route Matrix API v2.0;Geocoding API