php获取到距离并进行排序

255 阅读1分钟

一、sql根据经纬度

DB::select("SELECT *, ACOS(
           COS(RADIANS('$latitude')) *
           COS(RADIANS(latitude)) *
           COS(RADIANS(longitude) - RADIANS('$longitude')) +
           SIN(RADIANS('$latitude')) *
           SIN(RADIANS(latitude))
       ) * 6378 as distance FROM 表 ORDER BY distance ASC limit 10");
   
   

二、使用 redis-Geo

public function test(){
    $arr = Request::instance()->post();

    $latitude = $arr['latitude'];
    $longitude = $arr['longitude'];

    $redis = $this->redis;

 try {
        $param_a = array('areaCache');
        $ret = call_user_func_array(array($redis, 'EXISTS'), $param_a);
        if($ret){
            $param = array('georadius', 'areaCache', $longitude, $latitude, 55000, 'm', 'WITHDIST', 'WITHCOORD','ASC');
            $nearbyList = call_user_func_array(array($redis, 'rawCommand'), $param);
            //半径50000、单位m/km可选、距离显示、排序规则
            return getjson('1', '查找到排序:', $nearbyList);
        }else{
            return getjson('1', '没有查询到:','异常!' );
    }

    } catch (Exception $e){

    }
 }
 
 注:方法:call_user_func_array( callable $callback , array $param_arr )
 把第一个参数作为回调函数(callback)调用,把参数数组作(param_arr)为回调函数的的参数传入。
 

或者获取腾讯位置服务 WebService API | 腾讯位置服务

public function address(){
        try {
            //获取经纬度
            $lat = request()->get('lat');
            $lng = request()->get('lng');
            //调用第三方获取周边信息
            $message = file_get_contents("https://apis.map.qq.com/ws/place/v1/search?keyword=学校&boundary=nearby($lat,$lng,1000)&key=BR5BZ-2XUES-O5HOT-62FWR-LFWZJ-ARFLN");
            $message=json_decode($message,true)['data'];
            //周边景点存入redis
            foreach ($message as $v){
                Redis::rawCommand('geoadd','address',$v['location']['lng'],$v['location']['lat'],$v['title']);
            }
            //计算两点排序
            $data = Redis::rawCommand('GEORADIUS','address',$lng,$lat,'1000','km','withdist','asc');
            if (!$data){
                return json_encode(['code'=>200,'msg'=>'排序成功','data'=>$data]);
            }
            return json_encode(['code'=>200,'msg'=>'排序成功','data'=>$data]);
        }catch (\Exception $exception){
            return json_encode(['code'=>2001,$exception->getMessage(),'data'=>'']);
        }
    }

 

三、调用地图API接口

/**
 * 根据起点坐标和终点坐标测距离[http://lbs.qq.com/webservice_v1/guide-distance.html]
 * @param  [array]   $from [起点坐标(经纬度),例如:array(118.012951,36.810024)]
 * @param  [array]   $to [终点坐标(经纬度)]
 * @return [string]  距离数值
 */
function get_distance($from,$to){
    sort($from);
    sort($to);
    $from = implode(",", $from);
    $to = implode(",", $to);
    $curl = 'http://apis.map.qq.com/ws/distance/v1/?mode=driving&from='.$from.'&to='.$to.'&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77';
    $content = request($curl);
    $result = json_decode($content,true);
    return $result['result']['elements']['distance'];
}

四、数学计算

    /**
     * 根据起点坐标和终点坐标测距离
     * @param  [array]   $from     [起点坐标(经纬度),例如:array(118.012951,36.810024)]
     * @param  [array]   $to     [终点坐标(经纬度)]
     * @param  [bool]    $km        是否以公里为单位 false:米 true:公里(千米)
     * @param  [int]     $decimal   精度 保留小数位数
     * @return [string]  距离数值
     */
    function get_distance($from,$to,$km=true,$decimal=2){
        sort($from);
        sort($to);
        $EARTH_RADIUS = 6370.996; // 地球半径系数

        $distance = $EARTH_RADIUS*2*asin(sqrt(pow(sin( ($from[0]*pi()/180-$to[0]*pi()/180)/2),2)+cos($from[0]*pi()/180)*cos($to[0]*pi()/180)* pow(sin( ($from[1]*pi()/180-$to[1]*pi()/180)/2),2)))*1000;

        if($km){
            $distance = $distance / 1000;
        }

        return round($distance, $decimal);
    }