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

嗨,我需要计算两点之间的距离,有经纬度和经纬度。

我希望避免任何对外部 API 的调用。

我尝试用 PHP 实现这个半正矢公式:

密码如下:

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;


}
}

用一些有公共距离的给定点进行测试,我得不到一个可靠的结果。

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

219025 次浏览

对于精确的数值,它是这样的:

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;
}

我觉得这样应该可以了。

编辑:

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

我敢说... 我忘了去除圆函数中的所有值..。

乘数在每个坐标处都会改变,因为大圆距离理论写在这里:

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'

不久前,我写了一个半正矢公式的例子,并发表在我的网站上:

/**
* 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传递,结果将以[ mi ]为单位。在我看来,如果没有特别的原因,坚持使用 SI 单位是一个好习惯。

编辑:

正如 TreyA 正确指出的那样,由于舍入误差(尽管它在短距离内稳定 ) ,半正矢公式在使用 对足点时存在弱点。为了绕过它们,你可以使用 文森特配方代替。

/**
* 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>";

对于那些喜欢更短和更快(不调用 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
}

这里是计算经纬度间距离的简单而完美的代码。从这里找到了以下代码 -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';

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

$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 中的经纬度获取两个不同位置之间的时间

试试这个会有很棒的效果

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);
}

这只是对 @ martinstoeckli@ Janith Chinthana答案的补充。对于那些想知道哪种算法最快的人,我写了 性能测试。最佳性能结果显示 Codexworld.com的优化功能:

/**
* 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.853;
}

以下是测试结果:

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%

这是一个老问题了,但是对于那些对 PHP 代码感兴趣并且返回与 Google Maps 相同结果的人来说,下面的代码可以完成这项工作:

/**
* Computes the distance between two coordinates.
*
* Implementation based on reverse engineering of
* <code>google.maps.geometry.spherical.computeDistanceBetween()</code>.
*
* @param float $lat1 Latitude from the first point.
* @param float $lng1 Longitude from the first point.
* @param float $lat2 Latitude from the second point.
* @param float $lng2 Longitude from the second point.
* @param float $radius (optional) Radius in meters.
*
* @return float Distance in meters.
*/
function computeDistance($lat1, $lng1, $lat2, $lng2, $radius = 6378137)
{
static $x = M_PI / 180;
$lat1 *= $x; $lng1 *= $x;
$lat2 *= $x; $lng2 *= $x;
$distance = 2 * asin(sqrt(pow(sin(($lat1 - $lat2) / 2), 2) + cos($lat1) * cos($lat2) * pow(sin(($lng1 - $lng2) / 2), 2)));


return $distance * $radius;
}

我用不同的坐标测试过,效果很好。

我认为它应该比一些替代品更快。但没有测试。

提示: 谷歌地图使用6378137作为地球半径。所以使用它与其他算法可能也有效。

尝试这个函数来计算经纬度点之间的距离

function calculateDistanceBetweenTwoPoints($latitudeOne='', $longitudeOne='', $latitudeTwo='', $longitudeTwo='',$distanceUnit ='',$round=false,$decimalPoints='')
{
if (empty($decimalPoints))
{
$decimalPoints = '3';
}
if (empty($distanceUnit)) {
$distanceUnit = 'KM';
}
$distanceUnit = strtolower($distanceUnit);
$pointDifference = $longitudeOne - $longitudeTwo;
$toSin = (sin(deg2rad($latitudeOne)) * sin(deg2rad($latitudeTwo))) + (cos(deg2rad($latitudeOne)) * cos(deg2rad($latitudeTwo)) * cos(deg2rad($pointDifference)));
$toAcos = acos($toSin);
$toRad2Deg = rad2deg($toAcos);


$toMiles  =  $toRad2Deg * 60 * 1.1515;
$toKilometers = $toMiles * 1.609344;
$toNauticalMiles = $toMiles * 0.8684;
$toMeters = $toKilometers * 1000;
$toFeets = $toMiles * 5280;
$toYards = $toFeets / 3;




switch (strtoupper($distanceUnit))
{
case 'ML'://miles
$toMiles  = ($round == true ? round($toMiles) : round($toMiles, $decimalPoints));
return $toMiles;
break;
case 'KM'://Kilometers
$toKilometers  = ($round == true ? round($toKilometers) : round($toKilometers, $decimalPoints));
return $toKilometers;
break;
case 'MT'://Meters
$toMeters  = ($round == true ? round($toMeters) : round($toMeters, $decimalPoints));
return $toMeters;
break;
case 'FT'://feets
$toFeets  = ($round == true ? round($toFeets) : round($toFeets, $decimalPoints));
return $toFeets;
break;
case 'YD'://yards
$toYards  = ($round == true ? round($toYards) : round($toYards, $decimalPoints));
return $toYards;
break;
case 'NM'://Nautical miles
$toNauticalMiles  = ($round == true ? round($toNauticalMiles) : round($toNauticalMiles, $decimalPoints));
return $toNauticalMiles;
break;
}




}

然后使用这个函数作为

echo calculateDistanceBetweenTwoPoints('11.657740','77.766270','11.074820','77.002160','ML',true,5);

希望能有帮助

最简单的方法之一是:

$my_latitude = "";
$my_longitude = "";
$her_latitude = "";
$her_longitude = "";


$distance = round((((acos(sin(($my_latitude*pi()/180)) * sin(($her_latitude*pi()/180))+cos(($my_latitude*pi()/180)) * cos(($her_latitude*pi()/180)) * cos((($my_longitude- $her_longitude)*pi()/180))))*180/pi())*60*1.1515*1.609344), 2);
echo $distance;

它将四舍五入到2个小数点。

您可以尝试使用库 地理数学

composer require rkondratuk/geo-math-php:^1

例如:

<?php


use PhpGeoMath\Model\Polar3dPoint;


$polarPoint1 = new Polar3dPoint(
40.758742779050706, -73.97855507715238, Polar3dPoint::EARTH_RADIUS_IN_METERS
);


$polarPoint2 = new Polar3dPoint(
40.74843388072615, -73.98566565776102, Polar3dPoint::EARTH_RADIUS_IN_METERS
);


$geoDistance = $polarPoint2->calcGeoDistanceToPoint($polarPoint1);