PHP高级学习地理地图定位算法详解
本文给出了一个PHP高级学习中Geo地图定位算法的实例。分享给大家参考,如下:
前言
在日常开发中,我们经常需要找到一个物体的位置,或者找到附近的范围等。我们自然想到的方法是利用各种提供服务的地图网站的API,基于API,利用经纬度实现定位,找到附近范围等。但是由于缺乏对原理的理解,在距离比较或者控制精度方面,我们不知道如何利用这些经纬度值来实现距离变换和比较。在本章中,我们将讨论基于地理的定位算法的原理。
概念
纬线:纬线是垂直于地轴的线,东西方向环绕地球,所有纬度都是平行的。其中,赤道为最长纬度,纬度为0度,纬度值为角度值,从赤道分为北纬和南纬,两者均为0-90度;子午线:地球上的垂直线,是连接南北两极并与纬度线垂直相交的半圆。子午线为0,分为西经和东经,两者均为0-180,子午线也是一个角度值;经纬度与米的换算:经纬度为0.00001度,约为1米。这可以在GPS测量距离时实现。只要GPS精确到小数点后五位,都在10米以内;为了便于理解,地球被认为是一个基于经纬线的坐标系。经度范围从-180到180,纬度范围从-90到90。地球上的任何一点都可以由经纬度唯一确定。在实际应用中,如果用两个维度来确定一个点,计算量会很大,因为一个维度决定一个平面。如果二维平面上的所有点都用一个数字来表示,也就是把经度和纬度转换成一个字符串,就可以用一维坐标来表示,大大减少了计算量。这就是现在广泛使用的geoHash。GeoHash:Geohash是一个公共域地理编码系统,它将地理位置编码成一系列字母和数字。Geohash提供了任意精度等属性,以及从代码末尾逐渐删除字符以减小其大小(并逐渐失去精度)的可能性。由于准确性逐渐下降,附近的地方经常(但不总是)出现类似的前缀。共享前缀越长,两地距离越近。
原理
可以将地球上的一个点表示为一串字母,相似地方的字母前缀越多越常见。这可以使位置搜索在开发中变得容易。它的原理是基于上面提到的geoHash值。让我们详细解释一下geoHash值是如何计算的:
GeoHash二进制码按经纬度计算(算法用经纬度值解释:(116.389550,39.928167))。首先计算纬度二进制:2.1区间[-90,90],并将其划分为[-90,0],[0,90],称为左右区间,可以确定为39 . 39990 . 99999999909 2.2然后将区间[0,90]划分为[0,45]和[45,90],我们可以确定39.928167属于左区间[0,45],并且2.3递归上述过程39.928167始终属于某个区间[a,b]。随着每次迭代,区间[a,b]总是不断缩小,越来越近;2.4这样,序列1011100011的纬度二进制码将与算法一起生成。
同样的,地球经度以二进制计算,区间为[-180,180],116.389550的经度可以编码。计算结果1101001011;
集团编码:通过以上计算,纬度生成的编码为10111 00011,经度生成的编码为11010 01011。偶数放在经度,奇数放在纬度,两个字符串编码组合生成一个新的字符串:11100 11101 00100 01111。32个字母0-9和b-z(不包括a、I、l和o)用于base32编码。首先将11100 11101 00100 01111转换为十进制,对应28、29、4、15,十进制对应的代码为wx4g。Geohash实际上将整个地图或者某个划分区域划分一次。由于它采用base32编码方式,即Geohash中的每个字母或数字(如wx4g0e中的W)由5位(2 ^ 5=32,base32)组成,可以有32种不同的组合(0~31),所以我们可以将整个地图区域划分为32个区域第一次划分地图如下图所示(每个区域中的数字对应区域对应的代码):
经过多次分解,我们可以得到更准确的位置划分。例如,上面计算的wx4g可以精确到一个城市:
从上图可以看出,相邻城区的geoHash值共有前缀比较多,我们可以用共有前缀来判断附近的相邻位置。当然,准确的范围也是根据经纬度和哈希值的范围来确定的。如下表所示,geo精确到8位数的公共前缀,可以表示附近20米左右的范围:
在PHP中的实现与应用
在了解了geo的定位算法原理后,我们可以在PHP开发过程中使用这个定位函数。目前,位置定位和搜索功能有很多解决方案。基于PHP,我从自己的实践中推荐了几个:使用现成的地图API实现地理定位、搜索范围、计算距离等功能,比如国内的百度、高德,可以使用很多免费的API;如果你需要一个更大更精确的范围,你可以使用谷歌的地理api。缺点是每天的请求数量是有限制的。如果是企业级应用,需要为增加请求数量的权限付费。查看链接:https://developers . Google.com/maps/documentation/geocode/start通过NoSQL存储组件实现定位操作和存储:由于我们经常需要将定位数据计算后落地,所以业内有很多存储组件提供直接的计算和存储解决方案,比如MongoDB,适合在国内云平台上直接使用。对于AWS平台,dynamodb也作为NoSQL存储组件提供。这些存储组件可以直接导入经纬度,自动转换为geoHash进行登陆存储,还提供了直接计算距离和搜索范围数据返回的功能。Redis可用于本地部署服务器:Redis 3.2版本后,提供了geo操作、搜索和登陆功能,可以结合新版php-redis扩展实现GEO的方法。参考链接:http://www.redis.cn/commands.html,用PHP在redis上实现geo操作,请参考上面GitHub提供的方法描述:https://github.com/phpredis/phpredis. Redis实际封装了计算经纬度参数的方法,转换成geohash值作为Zset的Score存储在Zset中,所以也可以作为普通的Zset来操作。在实际应用中,我们经常把商品和人作为价值值,把地理哈希值作为分值,这样就可以在一定的分值范围内搜索到人或物。例如,在一定半径内搜索值:$ redis-georadius ($ key,$经度,$纬度,$半径,$单位[,array $ options]);用PHP计算原生geoHash:这个方法比较复杂,就是根据geoHash原理,用PHP语言实现这个算法,距离和搜索半径也是用PHP计算的。这相当于创造了一个新的轮子。当然,如果业务复杂度较高,那么PHP需要支持GeoHash算法,或者自己打包Geo类。在这里,我推荐一个在GitHub上比较完整的PHP-GEO支持:https://github.com/geocoder-php/Geocoder,或者如果你只需要计算GeoHash值,可以使用一个在互联网上广泛转发的计算Hash值的PHP方法:private $ coding=' 0123456789 bcdefghjkmnpqrstuvwxyz ';/***通过经度和纬度计算geoHash * @ param $ lat * @ param $ long * @返回字符串*/公共函数calcGeoHash($lat,$ long){ $ plat=$ this-precision($ lat);$ latbits=1;$ err=45而($ err $ plat){ $ latbits;$ err/=2;} $ plong=$ this-precision($ long);$ long bits=1;$ err=90而($ err $ plong){ $ long bits;$ err/=2;}$bits=max($latbits,$ long bits);$ longbits=$ bits$ latbits=$ bits$ add long=1;while (($longbits $latbits)%5!=0){ $ long bits=$ addlong;$latbits=!$ addlong$addlong=!$ addlong}$blat=$this-binEncode($lat,-90,90,$ latbits);$blong=$this-binEncode($long,-180,180,$ long bits);$ binary=$ uselong=1;while(strlen($ blat)strlen($ blong)){ if($ uselong){ $ binary=$ binary . substr($ blong,0,1);$blong=substr($blong,1);} else { $ binary=$ binary . substr($ blat,0,1);$blat=substr($blat,1);}$uselong=!$ uselong} $ hash=for($ I=0;$ is tren($二进制);$i=5){$n=bindec(substr($binary,$i,5));$hash=$hash。$ this-编码[$ n];}返回$ hash}/* * * @ param $ number * @ return float | int */private function precision($ number){ $ precision=0;$pt=strpos($number,'.');if ($pt!==false){ $ precision=-(strlen($ number)-$ pt-1);}返回功率(10,$ precision)/2;}/* * * @ param $ number * @ param $min * @ param $max * @ param $ bit count * @ return string */private函数binEncode($number,$ min,$ max,$ bit count){ if($ bit count==0)return“”;$ mid=($ min $ max)/2;if ($number$mid)返回“1”。$this-binEncode($number,$mid,$max,$ bit count-1);elsereturn“0”。$this-binEncode($number,$min,$mid,$ bit count-1);}
总结
GeoHash算法是将二维坐标转换为一位字符串的算法,可以通过不同字符串的公共前缀来判断彼此之间的距离。它经常在日常业务中使用。文中还介绍了不同的实现方式,具体实现方案要以实际业务需求为准。如果是高精度或企业级的大规模应用,可以先考虑MongoDB或其他提供Geo功能的存储组件。如果是轻量级的,可以使用第三方区域API或者redis做geo的简单应用。如果业务需求复杂度不高,不建议直接用PHP编写。毕竟效率会比较低,而且这也不是业务关注的重点,所以没有必要再造车轮。
更多对PHP相关内容感兴趣的读者可以查看本网站专题:《php面向对象程序设计入门教程》、《PHP数组(Array)操作技巧大全》、《PHP基本语法入门教程》、《PHP运算与运算符用法总结》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》、《php常见数据库操作技巧汇总》、0103010
希望本文对PHP编程有所帮助。
版权声明:PHP高级学习地理地图定位算法详解是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。