根据业务,往往需要搜索一个范围内,所有商铺或者人或者什么的需求,当然,前提是所有将要搜索的数据肯定是在自己的数据库中,并且记录了坐标。
比如,根据图1,搜O点周边500米范围内的所有目标。
一般获取两点之间的距离,要通过一个球面距离计算方法,并且这个方法加到数据库的搜索SQL中:
$distance = ",ROUND(6378.138 * 2 * ASIN(
SQRT(
POW(SIN((" . $sql['addr_lat'] . " * PI() / 180 - addr_lat * PI() / 180) / 2), 2) +
COS(" . $sql['addr_lat'] . " * PI() / 180) * COS(addr_lat * PI() / 180) *
POW(SIN((" . $sql['addr_lng'] . " * PI() / 180 - addr_lng * PI() / 180) / 2), 2)
)
) * 1000) AS distance";
当我们对数据表中所有的数据,进行球面距离计算搜索的时候,无疑是一个巨大的计算量,而我们现在就是要想办法,缩小这个搜索范围,以减少搜索量和计算量。
思路:
图1我们从O点,向外扩张500米,画了一个圆圈(图1红色)。然后以这个圆圈的直径为边长,画了一个正方形(图1绿色)
当我们能够确定A点和B点坐标的时候,我们就可以在数据表的所有数据中,搜索A点和B点经纬度之间的数据。这大大的减少了搜索所有数据的成本:
where (经度 between 1111 and 22222) and (维度 between 2222 and 3333)
那么如何确定A点和B点的坐标呢?
如果我们知道,1经度,对应的是多少米,1维度,对应的是多少米,是不是就很容易知道两点的坐标了?
知识点:
地球上的纬度以赤道为界,向南向北各划分出90个纬度,全球总共划分为180个纬度。每1°经度地表面的实地长度大约就是111千米。
纬线的长度不相等,赤道是最长的纬线圈,从赤道向两极纬线长度减小。每一条纬线都划分为360个经度,因此每1°经度地表面的实地距离不相等。在赤道处1°经度地表面的实地距离最大,由赤道向两极缩小。
在纬线上,经度每差1度,实际距离为111×cosθ千米。(其中θ表示该纬线的纬度.在不同纬线上,经度每差1度的实际距离是不相等的)。
知识点结束
由此可以知道,1维度,对应的是111米的距离,但是1经度对应多少米?因为地球是个“球”,所以地点不同,1经度对应的距离也不同。但是可以根据公式计算出来:经度每差1度,实际距离为111×cosθ千米
这样是不是就可以知道从O点扩散500米以后,A点和B点坐标???
因为我们数据表中保存的坐标,一般都是百度地图、高德地图、腾讯地图等等服务商返回的坐标,这个坐标,并不和现实的物理坐标相同。所以计算出来的1经纬度对应的距离并不正确。
坐标距离计算公式:
function getDistance($lng1,$lat1,$lng2,$lat2){
$earthRadius =6367000;
$lat1 = ($lat1 * pi() ) / 180;
$lng1 = ($lng1 * pi() ) / 180;
$lat2 = ($lat2 * pi() ) / 180;
$lng2 = ($lng2 * pi() ) / 180;
$calcLongitude = $lng2 - $lng1;
$calcLatitude = $lat2 - $lat1;
$stepOne = pow(sin($calcLatitude / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($calcLongitude / 2), 2);
$stepTwo = 2 * asin(min(1, sqrt($stepOne)));
$calculatedDistance = ($earthRadius * $stepTwo);
return round($calculatedDistance/1000); //单位米
}
通过上面的方法,我们可以计算出两个坐标之间的距离:
$lng1 = 116.527113;
$lat1 = 39.936773;
$lng2 = 117.527113;
$lat2 = 39.936773;
比如上面的数据,通过设置两个相差值为1的经纬度,可以得出,当前位置1经纬度之间的距离。这样就满足了我们要获得A点和B点坐标的需求。
然后可以通过SQL来对A点B点之间的范围进行查找。
完工!