Measuring the distance between two coordinates in PHP Measuring the distance between two coordinates in PHP php php

Measuring the distance between two coordinates in PHP


Not long ago I wrote an example of the haversine formula, and published it on my website:

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

➽ Note that you get the distance back in the same unit as you pass in with the parameter $earthRadius. The default value is 6371000 meters so the result will be in [m] too. To get the result in miles, you could e.g. pass 3959 miles as $earthRadius and the result would be in [mi]. In my opinion it is a good habit to stick with the SI units, if there is no particular reason to do otherwise.

Edit:

As TreyA correctly pointed out, the Haversine formula has weaknesses with antipodal points because of rounding errors (though it is stable for small distances). To get around them, you could use the Vincenty formula instead.

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


I found this code which is giving me reliable results.

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

results :

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


It's just addition to @martinstoeckli and @Janith Chinthana answers. For those who curious about which algorithm is fastest i wrote the performance test. Best performance result shows optimized function from 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;}

Here is test results:

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%