在PHP中测量两个坐标之间的距离

您好,我有需要计算两点之间的距离拉特和长。

我想避免任何外部API调用。

我试图在PHP中实现Haversine公式:

这里是代码:

class CoordDistance { public $lat_a = 0; public $lon_a = 0; public $lat_b = 0; public $lon_b = 0; public $measure_unit = 'kilometers'; public $measure_state = false; public $measure = 0; public $error = ''; public function DistAB() { $delta_lat = $this->lat_b - $this->lat_a ; $delta_lon = $this->lon_b - $this->lon_a ; $earth_radius = 6372.795477598; $alpha = $delta_lat/2; $beta = $delta_lon/2; $a = sin(deg2rad($alpha)) * sin(deg2rad($alpha)) + cos(deg2rad($this->lat_a)) * cos(deg2rad($this->lat_b)) * sin(deg2rad($beta)) * sin(deg2rad($beta)) ; $c = asin(min(1, sqrt($a))); $distance = 2*$earth_radius * $c; $distance = round($distance, 4); $this->measure = $distance; } } 

用一些有公共距离的给定点进行testing我没有得到可靠的结果。

我不明白原始公式或实施中是否有错误

不久之前,我写了一个半夏配方的例子,并在我的网站上发表:

 /** * Calculates the great-circle distance between two points, with * the Haversine formula. * @param float $latitudeFrom Latitude of start point in [deg decimal] * @param float $longitudeFrom Longitude of start point in [deg decimal] * @param float $latitudeTo Latitude of target point in [deg decimal] * @param float $longitudeTo Longitude of target point in [deg decimal] * @param float $earthRadius Mean earth radius in [m] * @return float Distance between points in [m] (same as earthRadius) */ function haversineGreatCircleDistance( $latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000) { // convert from degrees to radians $latFrom = deg2rad($latitudeFrom); $lonFrom = deg2rad($longitudeFrom); $latTo = deg2rad($latitudeTo); $lonTo = deg2rad($longitudeTo); $latDelta = $latTo - $latFrom; $lonDelta = $lonTo - $lonFrom; $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) + cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2))); return $angle * $earthRadius; } 

➽请注意,当您使用参数$earthRadius传入时,您将返回距离相同的单位。 默认值是6371000米,结果也是[m]。 要获得英里的结果,你可以例如通过3959英里作为$earthRadius ,结果将在[英里]。 在我看来,坚持国际单位是一个好习惯,如果没有其他的理由。

编辑:

TreyA正确地指出,由于四舍五入误差(尽pipe对于小距离它稳定的),Haversine公式具有反对点的弱点。 为了解决这个问题,你可以使用Vincenty公式 。

 /** * Calculates the great-circle distance between two points, with * the Vincenty formula. * @param float $latitudeFrom Latitude of start point in [deg decimal] * @param float $longitudeFrom Longitude of start point in [deg decimal] * @param float $latitudeTo Latitude of target point in [deg decimal] * @param float $longitudeTo Longitude of target point in [deg decimal] * @param float $earthRadius Mean earth radius in [m] * @return float Distance between points in [m] (same as earthRadius) */ public static function vincentyGreatCircleDistance( $latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000) { // convert from degrees to radians $latFrom = deg2rad($latitudeFrom); $lonFrom = deg2rad($longitudeFrom); $latTo = deg2rad($latitudeTo); $lonTo = deg2rad($longitudeTo); $lonDelta = $lonTo - $lonFrom; $a = pow(cos($latTo) * sin($lonDelta), 2) + pow(cos($latFrom) * sin($latTo) - sin($latFrom) * cos($latTo) * cos($lonDelta), 2); $b = sin($latFrom) * sin($latTo) + cos($latFrom) * cos($latTo) * cos($lonDelta); $angle = atan2(sqrt($a), $b); return $angle * $earthRadius; } 

我发现这个代码给了我可靠的结果。

 function distance($lat1, $lon1, $lat2, $lon2, $unit) { $theta = $lon1 - $lon2; $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta)); $dist = acos($dist); $dist = rad2deg($dist); $miles = $dist * 60 * 1.1515; $unit = strtoupper($unit); if ($unit == "K") { return ($miles * 1.609344); } else if ($unit == "N") { return ($miles * 0.8684); } else { return $miles; } } 

结果:

 echo distance(32.9697, -96.80322, 29.46786, -98.53506, "M") . " Miles<br>"; echo distance(32.9697, -96.80322, 29.46786, -98.53506, "K") . " Kilometers<br>"; echo distance(32.9697, -96.80322, 29.46786, -98.53506, "N") . " Nautical Miles<br>"; 

这只是@martinstoeckli和@Janith Chinthana的答案。 对于那些对哪种algorithm是最快的我感到好奇,我写了性能testing 。 最佳性能结果显示来自codexworld.com的优化function:

 /** * Optimized algorithm from http://www.codexworld.com * * @param float $latitudeFrom * @param float $longitudeFrom * @param float $latitudeTo * @param float $longitudeTo * * @return float [km] */ function codexworldGetDistanceOpt($latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo) { $rad = M_PI / 180; //Calculate distance from latitude and longitude $theta = $longitudeFrom - $longitudeTo; $dist = sin($latitudeFrom * $rad) * sin($latitudeTo * $rad) + cos($latitudeFrom * $rad) * cos($latitudeTo * $rad) * cos($theta * $rad); return acos($dist) / $rad * 60 * 1.852; } 

这里是testing结果:

 Test name Repeats Result Performance codexworld-opt 10000 0.084952 sec +0.00% codexworld 10000 0.104127 sec -22.57% custom 10000 0.107419 sec -26.45% custom2 10000 0.111576 sec -31.34% custom1 10000 0.136691 sec -60.90% vincenty 10000 0.165881 sec -95.26% 

这里用于计算两个纬度和经度之间的距离的简单和完美的代码。 下面的代码已经从这里find – http://www.codexworld.com/distance-between-two-addresses-google-maps-api-php/

 $latitudeFrom = '22.574864'; $longitudeFrom = '88.437915'; $latitudeTo = '22.568662'; $longitudeTo = '88.431918'; //Calculate distance from latitude and longitude $theta = $longitudeFrom - $longitudeTo; $dist = sin(deg2rad($latitudeFrom)) * sin(deg2rad($latitudeTo)) + cos(deg2rad($latitudeFrom)) * cos(deg2rad($latitudeTo)) * cos(deg2rad($theta)); $dist = acos($dist); $dist = rad2deg($dist); $miles = $dist * 60 * 1.1515; $distance = ($miles * 1.609344).' km'; 

对于那些喜欢更短,更快(不调用deg2rad())的人。

 function circle_distance($lat1, $lon1, $lat2, $lon2) { $rad = M_PI / 180; return acos(sin($lat2*$rad) * sin($lat1*$rad) + cos($lat2*$rad) * cos($lat1*$rad) * cos($lon2*$rad - $lon1*$rad)) * 6371;// Kilometers } 

对于确切的值这样做:

 public function DistAB() { $delta_lat = $this->lat_b - $this->lat_a ; $delta_lon = $this->lon_b - $this->lon_a ; $a = pow(sin($delta_lat/2), 2); $a += cos(deg2rad($this->lat_a9)) * cos(deg2rad($this->lat_b9)) * pow(sin(deg2rad($delta_lon/29)), 2); $c = 2 * atan2(sqrt($a), sqrt(1-$a)); $distance = 2 * $earth_radius * $c; $distance = round($distance, 4); $this->measure = $distance; } 

嗯,我认为应该这样做…

编辑:

对于公式和至lessJS实现尝试: http : //www.movable-type.co.uk/scripts/latlong.html

敢于我…我忘了减去圆圈函数中的所有值…

试试这给出了令人敬畏的结果

 function getDistance($point1_lat, $point1_long, $point2_lat, $point2_long, $unit = 'km', $decimals = 2) { // Calculate the distance in degrees $degrees = rad2deg(acos((sin(deg2rad($point1_lat))*sin(deg2rad($point2_lat))) + (cos(deg2rad($point1_lat))*cos(deg2rad($point2_lat))*cos(deg2rad($point1_long-$point2_long))))); // Convert the distance in degrees to the chosen unit (kilometres, miles or nautical miles) switch($unit) { case 'km': $distance = $degrees * 111.13384; // 1 degree = 111.13384 km, based on the average diameter of the Earth (12,735 km) break; case 'mi': $distance = $degrees * 69.05482; // 1 degree = 69.05482 miles, based on the average diameter of the Earth (7,913.1 miles) break; case 'nmi': $distance = $degrees * 59.97662; // 1 degree = 59.97662 nautic miles, based on the average diameter of the Earth (6,876.3 nautical miles) } return round($distance, $decimals); } 

由于这里写的大圆距离理论,乘数在每个坐标上都改变了:

http://en.wikipedia.org/wiki/Great-circle_distance

你可以使用这里描述的公式计算最接近的值:

http://en.wikipedia.org/wiki/Great-circle_distance#Worked_example

关键是将每个度 – 分秒值转换为所有度值:

 N 36°7.2', W 86°40.2' N = (+) , W = (-), S = (-), E = (+) referencing the Greenwich meridian and Equator parallel (phi) 36.12° = 36° + 7.2'/60' (lambda) -86.67° = 86° + 40.2'/60' 

你好这里代码获取距离和时间使用两个不同的经纬度

 $url ="https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=16.538048,80.613266&destinations=23.0225,72.5714"; $ch = curl_init(); // Disable SSL verification curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Will return the response, if false it print the response curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Set the url curl_setopt($ch, CURLOPT_URL,$url); // Execute $result=curl_exec($ch); // Closing curl_close($ch); $result_array=json_decode($result); print_r($result_array); 

您可以检查示例下面的链接获取时间之间的两个不同的位置使用纬度和经度在PHP中