1. 程式人生 > >根據自動定位獲取範圍內最近的資訊

根據自動定位獲取範圍內最近的資訊

以前的一個專案,需求是根據當前使用者上傳的經緯度座標,在資料庫幾十萬萬條資料中查詢出符合“周圍3公里範圍內”條件的座標點。

  所以,我首先想到的是,對每條資料去進行遍歷,跟資料庫中的每個點進行距離計算,當距離小於3公里時候,認為匹配成功。經測試,這樣做確實能得到結果,但是效率極其低下,因為每條資料都得去和資料庫中的幾十萬條資料進行比對,其耗費的時間可想而知。對於這種情況,是使用者所無法忍受的。

  後來利用正方形的四個點,去和使用者上傳的經緯度進行比較。由此,問題轉向了,如何計算正方形四個點經緯度的問題!

  無意中看到一個的帖子,裡面使用python實現了計算四個點經緯度的方法。

  其實現原理也是很相似的,先計算出當前點周圍的正方形的四個點,然後使用經緯度直接去資料庫匹配資料

假設已知點的經緯度分別為lng , lat

先實現經度範圍的查詢,在haversin公式中令φ1 = φ2,可得:


**
     * 計算某個經緯度的周圍某段距離的正方形的四個點
     *
     * @param
     *            radius 地球半徑 平均6371km
     * @param
     *            lng float 經度
     * @param
     *            lat float 緯度
     * @param
     *            distance float 該點所在圓的半徑,該圓與此正方形內切,預設值為1千米
     * @return array 正方形的四個點的經緯度座標
     */
    public function returnSquarePoint($lng, $lat, $distance = 1, $radius = 6371)
    {
        $dlng = 2 * asin(sin($distance / (2 * $radius)) / cos(deg2rad($lat)));
        $dlng = rad2deg($dlng);

        $dlat = $distance / $radius;
        $dlat = rad2deg($dlat);

        return array(
            'left-top' => array(
                'lat' => $lat + $dlat,
                'lng' => $lng - $dlng
            ),
            'right-top' => array(
                'lat' => $lat + $dlat,
                'lng' => $lng + $dlng
            ),
            'left-bottom' => array(
                'lat' => $lat - $dlat,
                'lng' => $lng - $dlng
            ),
            'right-bottom' => array(
                'lat' => $lat - $dlat,
                'lng' => $lng + $dlng
            )
        );
    }

在lat和lng上建立一個聯合索引後,使用此項查詢,執行效率飛漲。

上面可以取出範圍內的資料資訊,如果單獨需要最近的資訊的話:獲取兩點之間的距離

/** 其中一個經緯度是自動定位獲取的經緯度 */
function getDistanceBetweenPointsNew( $latitude1 , $longitude1 , $latitude2 , $longitude2 ) 
{
  $theta = $longitude1 - $longitude2;

  $miles = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));

  $miles = acos($miles);

  $miles = rad2deg($miles);

  $miles = $miles * 60 * 1.1515;
  $feet = $miles * 5280;
  $yards = $feet / 3;
  $kilometers = $miles * 1.609344;
  $meters = $kilometers * 1000;

  return compact('miles','feet','yards','kilometers','meters'); 
}

$point1 = array('lat' => 40.770623, 'long' => -73.964367);

$point2 = array('lat' => 40.758224, 'long' => -73.917404);

$distance = getDistanceBetweenPointsNew($point1['lat'], $point1['long'], $point2['lat'], $point2['long']);

foreach ($distance as $unit => $value) 
{
  echo $unit.': '.number_format($value,4).'<br />';
}

/** 正常情況只需要根據公里引數對比即可 */