转载: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经纬度批量查询工具”,它是一款高效且易用的软件,旨在帮助用户快速处理大量的经纬度查询任务,实现地址反查以及批量生成地图等功能。本文将深入探讨这款工具的主要特性和应用...
GPSspg xGeocoding 工具,大批量地址经纬度解析转换工具。地址与经纬度相互解析 地址解析经纬度,商户名解析经纬度,经纬度解析地址,甚至可以将经纬度再次反解析出地址以便对比。大批量自动化。 各大地图经纬度相互...
经纬度批量查询工具是一款专为IT专业人士和地理爱好者设计的应用,它允许用户高效地查询大量经纬度坐标对应的位置信息。这款工具在地理信息系统(GIS)领域有着广泛的应用,例如在地图数据处理、导航系统开发、遥感...
1. **GeoCoding**:这是将地理坐标(经纬度)转换为人类可读地址(如街道、城市、国家等)的过程。这个项目可能依赖于第三方的GeoCoding服务,如Google Maps API或OpenStreetMap Nominatim API。它们提供RESTful接口...
下面我们将详细探讨如何在C#环境中利用高德地图API实现经纬度解析成中文地址。 首先,我们需要了解高德地图API的基本概念。高德地图API是一组接口,允许开发者在其应用程序中嵌入地图、搜索、导航等功能。反地理...
4. **优化性能**:描述中提到,这个实现大约能处理4万随机经纬度/秒,但为了提高效率,可以考虑使用空间索引结构,如R树或者四叉树,来减少查询时的比较次数。 5. **异常处理与错误检测**:在实际应用中,需要考虑...
实现这个功能,我们首先需要一个地理编码(Geocoding)服务,它可以将经纬度坐标转换为具体的地址。在Java中,可以使用Google Maps Geocoding API或其他第三方API,如高德地图API、百度地图API等。这些API提供了...
在提供的代码中,我们可以看到使用了百度地图API来实现根据地址获取经纬度的功能。这段代码使用JavaScript编写,并且依赖于百度地图API的JavaScript库。当用户在输入框中输入一个地址并点击“查询”按钮时,`...
接下来,根据经纬度获取地址,我们同样可以使用上述API的逆向地理编码(Reverse Geocoding)功能。只需将请求中的`address`参数替换为`latlng`,并传入经纬度坐标: ```csharp public async Task<string> ...
在iOS中,我们可以使用Core Location框架来获取设备的实时经纬度坐标。Core Location提供了CLLocationManager类,通过它我们可以监听并获取到用户的当前位置信息。 接下来,获取城市区号的过程通常需要一个地理编码...
在Google Maps API中,我们可以使用Geocoding API来实现这一功能。这个API能够根据提供的经纬度返回详细的地理位置信息,包括街道地址、城市、国家等。 描述中提到的“使用代码,只需填入经纬度即可获取地理位置...
Google Maps API是一个强大的工具,它提供了多种接口供开发者调用,其中包括Geocoding API,用于将人类可读的地址转换为经纬度坐标,反之亦然。这个过程称为地理编码。批量获取经纬度意味着我们需要处理大量的地址,...
在Java编程中,根据两点的经纬度来计算距离是一项常见的任务,特别是在地理信息系统(GIS)或者定位服务相关的应用中。这个任务通常涉及到地球表面的距离计算,因为经纬度是地球坐标系统的一部分。以下是一些相关的...
本项目专注于批量获取地址的经纬度,使用了Java编程语言,结合谷歌地图API来实现这一功能。下面将详细阐述相关知识点。 1. **Java编程基础**: Java是一种广泛使用的面向对象的编程语言,具有跨平台性、高效性和...
"天地图搜索及获取经纬度工具"是一款专为初学者设计的应用程序,它结合了天地图服务,使得用户能够方便地进行地理位置搜索,并且能够获取到相应的经纬度坐标。这个工具对于那些正在学习地理信息系统(GIS)、Web开发...
在这个场景下,我们将探讨如何使用百度和Google的API来实现批量的经纬度到地址的转换。 首先,让我们了解一下经纬度。在地球表面,我们用经度和纬度来精确定位位置。经度是从本初子午线(通过英国格林尼治的线)...
总之,通过百度Geocoding API或其他类似服务,我们可以轻松地根据经纬度坐标获取城市名,从而在各种应用场景中实现精准的位置服务。同时,IP-CITY文件为批量处理IP地理位置提供了另一种解决方案。理解和运用这些工具...
本示例主要关注如何在C# WinForm应用中实现百度地图经纬度到腾讯地图经纬度的转换,这对于那些需要在不同地图服务之间进行路径规划或者位置信息处理的开发者来说尤其重要。 首先,我们需要理解经纬度系统。经纬度是...
逆地理编码(Reverse Geocoding)是相对于地理编码(Geocoding)的,后者是将经纬度转换为地址信息。百度地图API提供了逆地理编码接口,允许开发者通过输入地址字符串来获取对应的经纬度坐标。 要使用百度地图API...
有了经纬度后,我们可以通过Geocoding服务将它们转换为人类可读的地址。Android提供了`Geocoder`类来实现这个功能,但需要注意的是,这个服务并非所有设备或区域都支持: ```java public String getAddress(double ...