透過經緯度計算距離獲取附近商家

Get_old發表於2024-02-20

實際開發中,常常需要獲取使用者附近的商家,思路是

  • 獲取使用者位置(經緯度資訊)
  • 在資料庫中查詢在距離範圍內的商家

注: 本文章內計算距離所使用地球半徑統一為 6378.138 km

public function mpa_list($latitude,$longitude,$distance)
    {
        // $latitude = 34.306465;
        // $longitude = 109.050952;
        // $distance = 5;
        //1.計算最大最小經緯度範圍
        $range  = 180 / pi() * $distance / 6378.138; //搜尋 N km 之內
        $lngR   = $range / cos($latitude * pi() / 180);
        $maxLat = $latitude + $range; //最大緯度
        $minLat = $latitude - $range; //最小緯度
        $maxLng = $longitude + $lngR; //最大經度
        $minLng = $longitude - $lngR; //最小經度
        //2.查詢經緯度符合條件的商家
        $list = Village::select("id","title","longitude","latitude")
                ->whereBetween('latitude', [$minLat, $maxLat])
                ->whereBetween('longitude', [$minLng, $maxLng])
                ->where('status', 1)
                ->get();
        //3.計算距離
        foreach ($list as &$item){
            $item['distance'] = $this->getDistanceBy2Point([$longitude, $latitude], [$item['longitude'], $item['latitude']]);
        }
        if($list){
            $list = $list->toArray();
        }
        //4.排序
        $list = $this->arraySort($list, 'distance');

        return $list;
    }

二維陣列排序方法

// 二維陣列排序方法
    public static function arraySort($arr, $field, $sort = SORT_ASC){
        $key = array_column($arr, $field);
        array_multisort($key, $sort, $arr);
        return $arr;
    }

根據經緯度計算兩點距離

    /**
     * 根據起點座標和終點座標測距離
     * @param  [array]   $from     [起點座標(經緯度),例如:array(118.012951,36.810024)]
     * @param  [array]   $to     [終點座標(經緯度)]
     * @param  [bool]    $km        是否以公里為單位 false:米 true:公里(千米)
     * @param  [int]     $decimal   精度 保留小數位數
     * @return [string]  距離數值
     */
    public static function getDistanceBy2Point($from, $to, $km = true, $decimal = 2){
        sort($from);
        sort($to);
        $EARTH_RADIUS = 6378.138; // 地球半徑係數
        $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 > 1000){
            return round($distance / 1000, 2) . 'km';
        }
        return round($distance, $decimal) . 'm';
    }

實際測試:我這邊的測試資料比較少,我就用了50公里範圍之內的。因為我的資料庫裡面只新增了連個測試商家,大家將就看一下,理解了就行了。

​編輯

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章