/**
* 使用方法:
* 1.根據(jù)經(jīng)緯度,獲取'MBR'數(shù)據(jù)
* @param float $lat 緯度
* @param float $lon 經(jīng)度
* @param float $distance 距離(單位公里 如5就是5公里)
* @return array 'MBR'數(shù)據(jù)
* 使用實例:
* $gpsdis = (new Getmbr)->Main($lat,$lon,$distance)
*
* 2.根據(jù)經(jīng)緯度捡偏,計算2個點之間的距離翔试。
* @param float $lat 緯度1
* @param float $lon 經(jīng)度1
* @param float $lat 緯度2
* @param float $lon 經(jīng)度2
* @return float 距離(公里锯仪、千米)
* 使用實例:
* $distance = (new Getmbr)->Distance($lat1, $lon1, $lat2, $lon2)
*
* 說明:
* 這個根據(jù)一個經(jīng)緯度坐標(biāo)、距離然后求另外一個經(jīng)緯度坐標(biāo)的作用佩谷,
* 主要就是確定一個最小外包矩形(Minimum bounding rectangle,簡稱MBR)于微。
* 例如暂衡,我要找一個坐標(biāo)點(lat,lon)的5公里范圍內(nèi)的所有商戶信息、景點信息等浊服。
* 這個MBR就是一個最大的范圍统屈,
* 這個矩形是包含5公里范圍內(nèi)所有這些有效信息的一個最小矩形摆马。
* 利用公式,求出四個方向0度鸿吆、90度囤采、180度、270度方向上的四個坐標(biāo)點就可以得到這個MBR惩淳。
*
* 如果有一個應(yīng)用蕉毯,表里存有100萬的數(shù)據(jù),數(shù)據(jù)包含一個lat思犁、lon的經(jīng)緯度信息代虾。
* 就可以先根據(jù)輸入的經(jīng)緯度和距離得到一個MBR,然后通過類似
SELECT Id
FROM IdInfoTable
WHERE latitude >= minLat AND latitude < maxLat
AND longitude >= minLon AND longitude < maxLon
*
*/
namespace app\index\controller;
class Getmbr {
//最大緯度值
? ? public $MaxLatitude;
? ? //最小緯度值
? ? public $MinLatitude;
? ? public $MaxLongitude;
? ? public $MinLongitude;
? ? public $Ea = 6378137;? ? //? 赤道半徑
? ? public $Eb = 6356725;? ? //? 極半徑
? ? const EARTH_RADIUS = 6371.0;//km 地球半徑 平均值激蹲,千米
/**
* 獲取'MBR'數(shù)據(jù)
* @param float $lat 緯度
* @param float $lon 經(jīng)度
* @param float $distance 距離(單位公里 如5就是5公里)
* @return array 'MBR'數(shù)據(jù)
* */
? ? public function Main($lat,$lon,$distance)
{
$this->GetMBR($lat, $lon, $distance);
? ? ? ? //返回'MBR'數(shù)據(jù)
? ? ? ? return [
'MaxLatitude'=>$this->MaxLatitude,
? ? ? ? ? ? 'MinLatitude'=>$this->MinLatitude,
? ? ? ? ? ? 'MaxLongitude'=>$this->MaxLongitude,
? ? ? ? ? ? 'MinLongitude'=>$this->MinLongitude
];
? ? }
private function GetMBR($centorlatitude, $centorLogitude, $distance)
{
//以下為核心代碼
? ? ? ? $range? = 180 / pi()* $distance / 6372.797; //里面的 $distance 就代表搜索 $distance 之內(nèi)棉磨,單位km
? ? ? ? $lngR? = $range / cos($centorlatitude * pi()/ 180);
? ? ? ? $this->MaxLatitude= $centorlatitude + $range; //最大緯度
? ? ? ? $this->MinLatitude= $centorlatitude - $range; //最小緯度
? ? ? ? $this->MaxLongitude= $centorLogitude + $lngR; //最大經(jīng)度
? ? ? ? $this->MinLongitude= $centorLogitude - $lngR; //最小經(jīng)度
//得出這四個值以后,就可以根據(jù)你數(shù)據(jù)庫里存的經(jīng)緯度信息查找記錄了~
? ? }
/**
* 將角度換算為弧度学辱。
* @param float $degrees 角度
* @return float 弧度
* */
? ? private function ConvertDegreesToRadians($degrees)
{
return $degrees * M_PI / 180;
? ? }
/**
* 根據(jù)經(jīng)緯度乘瓤,計算2個點之間的距離。
* @param float $lat 緯度1
* @param float $lon 經(jīng)度1
* @param float $lat 緯度2
* @param float $lon 經(jīng)度2
* @return float 距離(公里策泣、千米)
* */
? ? public function Distance($lat1, $lon1, $lat2, $lon2){
//用haversine公式計算球面兩點間的距離衙傀。
//經(jīng)緯度轉(zhuǎn)換成弧度
? ? ? ? $lat1 = $this->ConvertDegreesToRadians($lat1);
? ? ? ? $lon1 = $this->ConvertDegreesToRadians($lon1);
? ? ? ? $lat2 = $this->ConvertDegreesToRadians($lat2);
? ? ? ? $lon2 = $this->ConvertDegreesToRadians($lon2);
? ? ? ? //差值
? ? ? ? $vLon = abs($lon1 - $lon2);
? ? ? ? $vLat = abs($lat1 - $lat2);
? ? ? ? //h is the great circle distance in radians, great circle就是一個球體上的切面,它的圓心即是球心的一個周長最大的圓萨咕。
? ? ? ? $h = $this->HaverSin($vLat)+ cos($lat1)* cos($lat2)* $this->HaverSin($vLon);
? ? ? ? $distance = 2 * self::EARTH_RADIUS * asin(sqrt($h));
? ? ? ? return $distance;
? ? }
private function HaverSin($theta)
{
$v = sin($theta / 2);
? ? ? ? return $v * $v;
? ? }
}