How to calculate the distance between two points specified by longitude and latitude?
For clarity, I want the distance in kilometers; these points use the WGS84 system, and I want to know the relative accuracy of the available methods.
#1st floor
This is a simple PHP function that gives a very reasonable approximation (error range is + / - 1%).
<?php function distance($lat1, $lon1, $lat2, $lon2) { $pi80 = M_PI / 180; $lat1 *= $pi80; $lon1 *= $pi80; $lat2 *= $pi80; $lon2 *= $pi80; $r = 6372.797; // mean radius of Earth in km $dlat = $lat2 - $lat1; $dlon = $lon2 - $lon1; $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlon / 2) * sin($dlon / 2); $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); $km = $r * $c; //echo '<br/>'.$km; return $km; } ?>
As mentioned before; the earth is not a sphere. Like the old baseball Mark McGwire decided to practice, it was full of dents and bumps. A simpler calculation (like this) treats it as a sphere.
Depending on your position on this irregular egg and the distance between points (the closer the distance, the smaller the absolute error range), different methods may be more or less accurate. The more accurate your expectations are, the more complex the mathematics will be.
For more information: Wikipedia geographic distance
#2nd floor
This is the Java implementation of Haversine formula.
public final static double AVERAGE_RADIUS_OF_EARTH_KM = 6371; public int calculateDistanceInKilometer(double userLat, double userLng, double venueLat, double venueLng) { double latDistance = Math.toRadians(userLat - venueLat); double lngDistance = Math.toRadians(userLng - venueLng); double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) + Math.cos(Math.toRadians(userLat)) * Math.cos(Math.toRadians(venueLat)) * Math.sin(lngDistance / 2) * Math.sin(lngDistance / 2); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return (int) (Math.round(AVERAGE_RADIUS_OF_EARTH_KM * c)); }
Please note that here we round the answer to the nearest kilometer.
#3rd floor
Here is a good example to use PHP http://www.geodatasource.com/developers/php Calculated distance:
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; } }
#4th floor
This is an implementation of VB.NET that will provide you with the results of KM or Miles based on the Enum value you pass.
Public Enum DistanceType Miles KiloMeters End Enum Public Structure Position Public Latitude As Double Public Longitude As Double End Structure Public Class Haversine Public Function Distance(Pos1 As Position, Pos2 As Position, DistType As DistanceType) As Double Dim R As Double = If((DistType = DistanceType.Miles), 3960, 6371) Dim dLat As Double = Me.toRadian(Pos2.Latitude - Pos1.Latitude) Dim dLon As Double = Me.toRadian(Pos2.Longitude - Pos1.Longitude) Dim a As Double = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(Me.toRadian(Pos1.Latitude)) * Math.Cos(Me.toRadian(Pos2.Latitude)) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2) Dim c As Double = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a))) Dim result As Double = R * c Return result End Function Private Function toRadian(val As Double) As Double Return (Math.PI / 180) * val End Function End Class
#5th floor
I simplify the calculation by simplifying the formula.
In Ruby:
include Math earth_radius_mi = 3959 radians = lambda { |deg| deg * PI / 180 } coord_radians = lambda { |c| { :lat => radians[c[:lat]], :lng => radians[c[:lng]] } } # from/to = { :lat => (latitude_in_degrees), :lng => (longitude_in_degrees) } def haversine_distance(from, to) from, to = coord_radians[from], coord_radians[to] cosines_product = cos(to[:lat]) * cos(from[:lat]) * cos(from[:lng] - to[:lng]) sines_product = sin(to[:lat]) * sin(from[:lat]) return earth_radius_mi * acos(cosines_product + sines_product) end