1.前言
我叫外卖,10公里外的商户我相信他是不会送餐的。
我叫桶装水,3公里估计人家都嫌远。
这类对距离敏感的业务,也就是传说的o2o业务,都需要在一定的距离范围内开展工作。
2.涉及的问题
这类距离敏感型业务,涉及4个最基本的问题。
1、如何获取当前用户位置坐标
2、如何计算两个坐标点之间的直线距离
3、如何从全体商户集合中筛选出符合距离要求的一批商户
4、如何根据远近进行排序
3.解决问题的思路
一、或取当前用户坐标位置
这个客户端基本都提供现成的api,我们以微信小程序为例,通过调用wx.getLocation可以得到当前用户的经度坐标longitude,与纬度坐标latitude
//微信小程序
wx.getLocation({
type: 'wgs84',
success: function(res) {
var latitude = res.latitude
var longitude = res.longitude
var speed = res.speed
var accuracy = res.accuracy
}
})
二、计算两点间直线距离
计算两点间距离,这个有固定的数学公式,示例代码如下,获得距离米数。(这个其实应该属于排序环节)
//计算距离(米)
$distance = getDistance(40.035076141357,116.3627243042,40.035076142357,116.3927243142);
var_dump($distance);
//计算公式
function getDistance($lat1, $lng1, $lat2, $lng2)
{
$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);
}
三、筛选附近的商户
1、首先要给数据库商户表家里索引,经度与纬度联合索引
2、依据当前点,范围反向计算出最大、最小经纬度
3、使用范围查询
//根据当前坐标,范围计算最大最小坐标点
function getAround($latitude,$longitude,$raidus)
{
$PI = 3.14159265;
$degree = (24901*1609)/360.0;
$dpmLat = 1/$degree;
$radiusLat = $dpmLat*$raidus;
$minLat = $latitude - $radiusLat;
$maxLat = $latitude + $radiusLat;
$mpdLng = $degree*cos($latitude * ($PI/180));
$dpmLng = 1 / $mpdLng;
$radiusLng = $dpmLng*$raidus;
$minLng = $longitude - $radiusLng;
$maxLng = $longitude + $radiusLng;
return array (minLat=>$minLat, maxLat=>$maxLat, minLng=>$minLng, maxLng=>$maxLng);
}
//范围查询
SELECT * FROM 商户表 WHERE (latitude BETWEEN minLat AND maxLat) and (longitude BETWEEN minLng and maxLng);
四、进行远近排序
对于整数数组我们可以方便的使用各类排序算法,但当数组元素是对象时,就平添了实现上的麻烦。
$shops = 已查询出的商户集合;//这是一个对象数组
$myspace = array('lat'=>40.035076141357,'lng'=>116.3627243042);
//计算各点与当前点的距离
for($i=0;$i<count($shops);$i++){
$d = getDistance($myspace['lat'],$myspace['lng'],$shops[$i]['lat'],$shops[$i]['lng']);
$shops[$i]['distance'] = $d;
}
//排序,一般而言周边商户数据量都比较小,这里用冒泡排序算法实现
bublleSort($shops);
//$shops已经按距离从近到远排序
function swap(&$arr,$i,$j){
if($arr[$i]['distance']>$arr[$j]['distance']){
$temp = $arr[$i];
$arr[$i] = $arr[$j];
$arr[$j] = $temp;
}
}
function bubbleSort(&$arr){
for($i=0;$i<count($arr)-1;$i++){
for($j=$i+1;$j<count($arr);$j++){
swap($arr,$i,$j);
}
}
}