坐标系-距离
2022-01-11 08:31 / 浏览量:1362

坐标系:在一些地点可能需要坐标来满足一些功能,如地图查询、导航、距离远近,一般网站我们可以采用腾讯地图、百度地图、高德地图提供JS API来实现坐标获取,建议至少保留小数点后6及位以上,以此为基础,介绍以下几种可能用到的方法。

1.计算两点间距离

//@desc 根据两点间的经纬度计算距离
//@param float lat1 地点1纬度值
//@param float lng1 地点1经度值
//@param float lat2 地点2纬度值
//@param float lng2 地点2经度值
//@param int precision 距离精度
// 单位:m
function getDistance($lat1, $lng1, $lat2, $lng2, $precision = 0){ 
 $earthRadius = 6367000; //approximate radius of earth in meters 
 //Convert these degrees to radians 
 //to work with the formula 
 $lat1 = ($lat1 * pi()) / 180; 
 $lng1 = ($lng1 * pi()) / 180; 
 $lat2 = ($lat2 * pi()) / 180; 
 $lng2 = ($lng2 * pi()) / 180; 
 //Using the 
 //Haversine formula 
 //http://en.wikipedia.org/wiki/Haversine_formula 
 //calculate the distance 
 $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, $precision);
}

2.距离格式转换

//@desc 距离转换
//@param float size 距离米
//@param int digits 精度
//@param int en 返回英文单位
//1000比例距离单位数
function size2mb($size, $digits = 2, $en = 0){  
 //digits,要保留几位小数  
 $unit = array('米', '公里', '千公里', '百万公里', '太米', '拍米', '艾米', '泽米', '尧米'); //单位数组,是必须1000进制依次的哦。  
 $en_unit = array('m', 'km', 'Mm', 'Gm', 'Tm', 'Pm', 'Em', 'Zm', 'Ym');  
 $base = 1000; //对数的基数  
 $i = floor(log($size, $base)); //字节数对1000取对数,值向下取整。  
 return ($size > 0 ? round($size / pow($base, $i), $digits) : 0) . ($en ? $en_unit[$i] : $unit[$i]);
}

3.返回坐标点一定距离的四角坐标

/** 
* 计算某个经纬度的周围某段距离,正方形中心点至四个点的距离为distance 
* @param  lng float 经度 
* @param  lat float 纬度 
* @param  distance float 该点所在圆的半径,该圆与此正方形内切,默认值为1千米 
* @param  radius 地球半径 平均6371km 
* @return array 正方形的四个点的经纬度坐标 
*/
function returnSquarePoint($lat, $lng, $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)  
 );
}

4.数据库距离运算

这里是在laravel中操作

// 坐标点范围
public function scopeSquarePoint(Builder $query, $lat, $lng, $distance = 1, $radius = 6371){    
 $point = returnSquarePoint($lat, $lng, $distance, $radius);    
  $conditions = [ 
         ['latitude', '>', $point['right-bottom']['lat']], 
                ['latitude', 'where($conditions);         
}
/*
** Get the distance SelectRawSql.
** @returnsql
*/
protected function distanceSelectRawSql($latitude, $longitude){    
 return 'ACOS(SIN((' . $latitude . ' * 3.1415) / 180 ) *SIN((latitude * 3.1415) / 180 ) +COS((' . $latitude . ' * 3.1415) / 180 ) * COS((latitude * 3.1415) / 180 ) *COS((' . $longitude . '* 3.1415) / 180 - (longitude * 3.1415) / 180 ) ) * 6367 as distance';
}

实际调用

$results = Model::where('status',3)      
// 指定搜索范围(空间数量多的话最好开启,增加查询速度)      
->squarePoint($latitude , $longitude)
->selectRaw('*,'.$this->distanceSelectRawSql($latitude,$longitude))->orderBy('distance', 'asc')->limit(20)->get();