1143

How do I calculate the distance between two points specified by latitude and longitude?

For clarification, I'd like the distance in kilometers; the points use the WGS84 system and I'd like to understand the relative accuracies of the approaches available.

Zero
  • 74,117
  • 18
  • 147
  • 154
Robin Minto
  • 15,027
  • 4
  • 37
  • 40
  • For better accuracy - see https://stackoverflow.com/questions/1420045/how-to-find-distance-from-the-latitude-and-longitude-of-two-locations/1422562#1422562 – Lior Kogan Jul 21 '17 at 07:54
  • 4
    Note that you cannot apply a Haversine formula on an ellipsoid of revolution like WGS 84. You can only apply this method on a sphere with a radius. – Mike T Jul 23 '18 at 02:05
  • 8
    Most of the answers here are using simple spherical trigonometry, so the results are rather crude compared to the WGS84 ellipsoid distances used in the GPS system. Some of the answers do refer to Vincenty's formula for ellipsoids, but that algorithm was designed for use on 1960s' era desk calculators and it has stability & accuracy issues; we have better hardware and software now. Please see [GeographicLib](https://geographiclib.sourceforge.io/) for a high quality library with implementations in various languages. – PM 2Ring Aug 03 '18 at 13:26
  • @MikeT - true though many of the answers here seem useful *over small distances*: If you take lat/long from WGS 84, and apply Haversine *as if those were* points on a sphere, don't you get answers whose errors are only due to the earth's flattening factor, so perhaps within 1% of a more accurate formula? With the caveat that these are small distances, say within a single town. – ToolmakerSteve Nov 25 '18 at 15:27
  • 1
    For these plateforms: Mono/.NET 4.5/.NET Core/Windows Phone 8.x/Universal Windows Platform/Xamarin iOS/Xamarin Android see https://stackoverflow.com/a/54296314/2736742 – A. Morel Jan 21 '19 at 20:02

49 Answers49

1364

This link might be helpful to you, as it details the use of the Haversine formula to calculate the distance.

Excerpt:

This script [in Javascript] calculates great-circle distances between the two points – that is, the shortest distance over the earth’s surface – using the ‘Haversine’ formula.

function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
  var R = 6371; // Radius of the earth in km
  var dLat = deg2rad(lat2-lat1);  // deg2rad below
  var dLon = deg2rad(lon2-lon1); 
  var a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * 
    Math.sin(dLon/2) * Math.sin(dLon/2)
    ; 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  var d = R * c; // Distance in km
  return d;
}

function deg2rad(deg) {
  return deg * (Math.PI/180)
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • 59
    Does this calculation/method account for the Earth being a spheroid (not a perfect sphere)? The original question asked for distance on between points on a WGS84 globe. Not sure how much error creeps in by using a perfect sphere, but I suspect it can be quite a lot depending on where the points are on the globe, thus the distinction is worth bearing in mind. – redcalx Nov 08 '11 at 08:33
  • 18
    The Haversine formula doesn't account for the Earth being a spheroid, so you'll get some error introduced due to that fact. It can't be guaranteed correct to better than 0.5%. That may or may not be an acceptable level of error though. – Brandon Dec 28 '11 at 16:20
  • 2
    Wrapped the logic into a function, so it should be usable in JS out of the box, actually using this in NodeJS now... – Tracker1 Dec 13 '12 at 00:55
  • 29
    Is there any reason to use `Math.atan2(Math.sqrt(a), Math.sqrt(1-a))` instead of `Math.asin(Math.sqrt(h))`, which would be the direct implementation of the formula that the Wikipedia article uses? Is it more efficient and/or more numerically stable? – musiphil Dec 20 '12 at 03:47
  • 3
    Here is implementation of the same code in PHP, https://gist.github.com/gajus/5487925. – Gajus Apr 30 '13 at 10:40
  • 1
    @UsmanMutawakil Works perfectly fine with lat/long obtained from Google Maps API. – Pascal Jul 01 '13 at 17:51
  • @Pascal I used it to calculate the distance from Milford MA to Boston, using Longitude and Latitude for each. I then compared that to the results in google maps. What did you do to come to your conclusion? – Usman Mutawakil Jul 02 '13 at 07:25
  • 1
    @UsmanMutawakil Using 42.139722, -71.516667 for Milford and 42.358056, -71.063611 for Boston I get a distance of 44.497 km or 27.65 miles. Pretty much what I get in Google Maps with the distance tool. – Pascal Jul 02 '13 at 14:29
  • @Pascal I just entered that into Google and it's says 38 miles. Try googling "distance from 42.139722, -71.516667 to 42.358056, -71.063611." I live in Milford. It is not 27 miles from Boston. 38 Miles definitely sounds right. This algorithm is definitely off. Try a known distance from your current location to another known distance. I bet it's off by 25% of the actual. – Usman Mutawakil Jul 03 '13 at 03:39
  • 18
    @UsmanMutawakil Well, the 38 miles you get is distance on the road. This algorithm calculates a straight line distance on the earth's surface. Google Maps has a distance tool (bottom left, "Labs") that does the same, use that to compare. – Pascal Jul 03 '13 at 17:35
  • 2
    All such measurements are at best approximations. We can ignore the errors inherent in great circle distance computation due to the absence of spheroid ablation. When you are measuring points less than a few hundred kilometres apart the errors are small. When the distances are large enough for significant error, the errors are swamped in practical applications by other factors such as traffic conditions or water and air currents. – Peter Wone Jul 10 '13 at 07:12
  • Why don't we use the absolute value, like `abs(dLat)`, in case it has the negative value due to `lat2 < lat1`? – Triet Doan Mar 05 '14 at 16:40
  • 4
    @Forte_201092: Because that is not necessary - as `(sin(x))²` equals `(sin(-x))²` – Jean Hominal May 30 '14 at 09:16
  • 4
    This formula seems fine for larger distances, but what if we're trying to measure relatively small distances (<3 miles)? I ran a couple tests with this formula and got anywhere between 30-50% error. For example, using var testCoords1 = { 'lat': 40.7483126, 'long': -73.3314238 }; var testCoords2 = { 'lat': 40.7385402, 'long': -73.3205462 }; it's showing about 1.65 miles (using "Measure Distance" on GMaps) but the function returns 0.88 miles (I converted km to mi in the function). – giwook Nov 19 '15 at 00:21
  • 1
    @giwook, "Measure Distance" takes you down Fairvew and Deer Park. The formula is more like the length of the hypotenuse that would complete that triangle. – JonSG Jul 03 '16 at 18:16
  • it's worth noting that this method ignores ( ellipsoidal effects ) , however its accurate enough for most use cases !! – Ahmed Eid Jan 10 '17 at 23:55
  • Why sin and cos are called twice? Btw, atan2 avoids a rounding problem. About precision... You can easily compare results of your own computations using 2 different radiuses of the Earth. If the difference will be unacceptable, go for an ellipsoid formula, but it's much more complex. – Brian Cannard Jan 16 '18 at 18:37
  • the Haversine formula is not for WGS94 ellipsoid but for spherical coordinates – JeanClaudeDaudin Mar 25 '18 at 14:15
  • 1
    Here is a simplified version for the maniacs like me out there who get triggered by unnecessary variables https://gist.github.com/manix/7ce097c73728e07178af74cb4c62a341 – php_nub_qq Sep 13 '18 at 11:47
  • 4
    Please can someone explain what is `a` and `c` in the code? – Kumar Abhirup Dec 15 '19 at 07:32
  • 2
    What about if I want to calculate the distance between 2 points described by latitude, longitude and height? – Alan Evangelista Dec 18 '19 at 23:41
  • @KumarAbhirup: Given that `distance = radius * c`, `c` seems to be the [chord](https://en.wikipedia.org/wiki/Chord_(geometry)) of a circle. Yes, for sufficient curvature (= long enough distance between points), the chord is essentially underground as it represents the straight line distance between two points. – Flater Aug 10 '21 at 12:45
  • I believe the deg2rad method should be written as "return deg * Math.PI / 180", just removing the parenthesis. This allows the compiler to perform the multiplication first then divide, which will preserve precision. In general, if you are not going to overflow, you should multiply first. This nuance may not be as big an issue with today's hardware. – user3481644 Sep 27 '21 at 13:38
  • I did a short benchmark on @musiphil's question with Kotlin on the JVM with JHM. The `atan2` variant was 3-4 times faster than `asin`. But please do not count on my benchmark and do your own for your language. – debuglevel Nov 14 '21 at 12:17
  • Any license on this code? I'm guessing it comes from somewhere and just wanted attribution correct. – Espen Klem Sep 20 '22 at 04:18
  • 1
    @EspenKlem since this is a straightforward implementation of a formula from public domain, I don't think that the author of code could claim it as their copyright and apply a license. There's too little to be copyrighted (naming, etc). I suggest linking this post or the original formula somewhere for colleagues. (Of course, this is not a legal advice.) – Roman Boiko Dec 19 '22 at 17:42
495

I needed to calculate a lot of distances between the points for my project, so I went ahead and tried to optimize the code, I have found here. On average in different browsers my new implementation runs 2 times faster than the most upvoted answer.

function distance(lat1, lon1, lat2, lon2) {
  const r = 6371; // km
  const p = Math.PI / 180;

  const a = 0.5 - Math.cos((lat2 - lat1) * p) / 2
                + Math.cos(lat1 * p) * Math.cos(lat2 * p) *
                  (1 - Math.cos((lon2 - lon1) * p)) / 2;

  return 2 * r * Math.asin(Math.sqrt(a));
}

You can play with my jsPerf and see the results here.

Recently I needed to do the same in python, so here is a python implementation:

from math import cos, asin, sqrt, pi

def distance(lat1, lon1, lat2, lon2):
    r = 6371 # km
    p = pi / 180

    a = 0.5 - cos((lat2-lat1)*p)/2 + cos(lat1*p) * cos(lat2*p) * (1-cos((lon2-lon1)*p))/2
    return 2 * r * asin(sqrt(a))

And for the sake of completeness: Haversine on Wikipedia.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
78

Here is a C# Implementation:

static class DistanceAlgorithm
{
    const double PIx = 3.141592653589793;
    const double RADIUS = 6378.16;

    /// <summary>
    /// Convert degrees to Radians
    /// </summary>
    /// <param name="x">Degrees</param>
    /// <returns>The equivalent in radians</returns>
    public static double Radians(double x)
    {
        return x * PIx / 180;
    }

    /// <summary>
    /// Calculate the distance between two places.
    /// </summary>
    /// <param name="lon1"></param>
    /// <param name="lat1"></param>
    /// <param name="lon2"></param>
    /// <param name="lat2"></param>
    /// <returns></returns>
    public static double DistanceBetweenPlaces(
        double lon1,
        double lat1,
        double lon2,
        double lat2)
    {
        double dlon = Radians(lon2 - lon1);
        double dlat = Radians(lat2 - lat1);

        double a = (Math.Sin(dlat / 2) * Math.Sin(dlat / 2)) + Math.Cos(Radians(lat1)) * Math.Cos(Radians(lat2)) * (Math.Sin(dlon / 2) * Math.Sin(dlon / 2));
        double angle = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
        return angle * RADIUS;
    }

}
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
jaircazarin-old-account
  • 2,875
  • 3
  • 20
  • 17
  • 15
    You are using the equatorial radius, but you should be using the mean radius, which is 6371 km – Philippe Leybaert Jul 10 '09 at 12:18
  • 7
    Shouldn't this be `double dlon = Radians(lon2 - lon1);` and `double dlat = Radians(lat2 - lat1);` – Chris Marisic Jan 15 '10 at 15:40
  • I agree with Chris Marisic. I used the original code and the calculations were wrong. I added the call to convert the deltas to radians and it works properly now. I submitted an edit and am waiting for it to be peer reviewed. – Bryan Bedard Dec 04 '11 at 04:53
  • I submitted another edit because lat1 & lat2 also need to be converted to radians. I also revised the formula for the assignment to a to match the formula and code found here: http://www.movable-type.co.uk/scripts/latlong.html – Bryan Bedard Dec 04 '11 at 06:48
  • does the `RADIUS` value need to be 6371 as in the other answers? – Chris Hayes Jan 23 '19 at 18:02
  • @jaircazarin-old-account what exactly does this function return ? kilometers, miles? –  Jan 18 '20 at 19:32
  • @user12360120 The result is in the same units as the radius. So if radius is about 6371 km, then kilometers. If it's more like 3958 (miles), then result is also in miles. If it's 1 (radius of a sphere), then the result will be in radiuses of that sphere. :-) – Roman Boiko Dec 27 '22 at 23:11
72

Here is a java implementation of the 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));
}

Note that here we are rounding the answer to the nearest km.

Nav
  • 19,885
  • 27
  • 92
  • 135
whostolebenfrog
  • 955
  • 6
  • 8
  • 2
    If we wanted to calculate the distance between between two points in meters, what would be the more accurate way? To use `6371000` as the radius of the earth? (avg. radius of earth is 6371000 meters) or convert kilometers to meters from your function? – Micro Dec 12 '16 at 18:29
  • if you want miles, multiple the result by `0.621371` – lasec0203 Sep 09 '19 at 05:20
43

This is a simple PHP function that will give a very reasonable approximation (under +/-1% error margin).

<?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 said before; the earth is NOT a sphere. It is like an old, old baseball that Mark McGwire decided to practice with - it is full of dents and bumps. The simpler calculations (like this) treat it like a sphere.

Different methods may be more or less precise according to where you are on this irregular ovoid AND how far apart your points are (the closer they are the smaller the absolute error margin). The more precise your expectation, the more complex the math.

For more info: wikipedia geographic distance

AbraCadaver
  • 78,200
  • 7
  • 66
  • 87
tony gil
  • 9,424
  • 6
  • 76
  • 100
  • 4
    This works perfectly! I just added $distance_miles = $km * 0.621371; and that's all I needed for approximate distance in miles! Thanks Tony. –  Aug 08 '14 at 05:17
43

Thanks very much for all this. I used the following code in my Objective-C iPhone app:

const double PIx = 3.141592653589793;
const double RADIO = 6371; // Mean radius of Earth in Km

double convertToRadians(double val) {

   return val * PIx / 180;
}

-(double)kilometresBetweenPlace1:(CLLocationCoordinate2D) place1 andPlace2:(CLLocationCoordinate2D) place2 {

        double dlon = convertToRadians(place2.longitude - place1.longitude);
        double dlat = convertToRadians(place2.latitude - place1.latitude);

        double a = ( pow(sin(dlat / 2), 2) + cos(convertToRadians(place1.latitude))) * cos(convertToRadians(place2.latitude)) * pow(sin(dlon / 2), 2);
        double angle = 2 * asin(sqrt(a));

        return angle * RADIO;
}

Latitude and Longitude are in decimal. I didn't use min() for the asin() call as the distances that I'm using are so small that they don't require it.

It gave incorrect answers until I passed in the values in Radians - now it's pretty much the same as the values obtained from Apple's Map app :-)

Extra update:

If you are using iOS4 or later then Apple provide some methods to do this so the same functionality would be achieved with:

-(double)kilometresBetweenPlace1:(CLLocationCoordinate2D) place1 andPlace2:(CLLocationCoordinate2D) place2 {

    MKMapPoint  start, finish;


    start = MKMapPointForCoordinate(place1);
    finish = MKMapPointForCoordinate(place2);

    return MKMetersBetweenMapPoints(start, finish) / 1000;
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Stephen Watson
  • 1,700
  • 16
  • 17
  • 2
    iOS SDK has its own implementation: https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocation_Class/#//apple_ref/occ/instm/CLLocation/distanceFromLocation: – tuler Mar 27 '16 at 12:15
  • I think the parenthesis around `pow(sin(dlat / 2), 2) + cos(convertToRadians(place1.latitude))` is incorrect. Remove those, and the result matches what I get when I use other implementations on this page, or implement the Haversine formula from [Wikipedia](https://en.wikipedia.org/wiki/Great-circle_distance) from scratch. – zanedp Jan 17 '19 at 19:33
  • Using the coordinates (40.7127837, -74.0059413) for NYC and (34.052234, -118.243685) for LA, with the `()` around that sum, I get 3869.75. Without them, I get 3935.75, which is pretty much what a web search turns up. – zanedp Jan 17 '19 at 19:39
32

In the other answers an implementation in is missing.

Calculating the distance between two point is quite straightforward with the distm function from the geosphere package:

distm(p1, p2, fun = distHaversine)

where:

p1 = longitude/latitude for point(s)
p2 = longitude/latitude for point(s)
# type of distance calculation
fun = distCosine / distHaversine / distVincentySphere / distVincentyEllipsoid 

As the earth is not perfectly spherical, the Vincenty formula for ellipsoids is probably the best way to calculate distances. Thus in the geosphere package you use then:

distm(p1, p2, fun = distVincentyEllipsoid)

Off course you don't necessarily have to use geosphere package, you can also calculate the distance in base R with a function:

hav.dist <- function(long1, lat1, long2, lat2) {
  R <- 6371
  diff.long <- (long2 - long1)
  diff.lat <- (lat2 - lat1)
  a <- sin(diff.lat/2)^2 + cos(lat1) * cos(lat2) * sin(diff.long/2)^2
  b <- 2 * asin(pmin(1, sqrt(a))) 
  d = R * b
  return(d)
}
Jaap
  • 81,064
  • 34
  • 182
  • 193
  • To make sure I am clear on what you said: The code you give at end of post: Is that an implementation of Vincenty formula? As far as you know, it should give same answer as calling Vincenty in geosphere? [I don't have geosphere or other library; just looking for some code to include in a cross-platform app. I would of course verify some test cases against a known good calculator.] – ToolmakerSteve Nov 25 '18 at 15:16
  • 1
    @ToolmakerSteve the function at the end of my answer is an implementation of the Haversine method – Jaap Nov 25 '18 at 15:23
  • Hi @Jaap could I ask what is the unit of measurement for the formula? Is it in metres? – Jackson Dec 04 '19 at 01:53
  • 1
    @Jaap I liked the explanation of 'Vincenty formula for ellipsoids' which I tested to be very accurate. @Jackson `distm(p1, p2, fun = distVincentyEllipsoid)` gives output in metres which you have to divide with 1000 to get values in kilometres. – Tiny_hopper Nov 25 '20 at 05:28
32

I post here my working example.

List all points in table having distance between a designated point (we use a random point - lat:45.20327, long:23.7806) less than 50 KM, with latitude & longitude, in MySQL (the table fields are coord_lat and coord_long):

List all having DISTANCE<50, in Kilometres (considered Earth radius 6371 KM):

SELECT denumire, (6371 * acos( cos( radians(45.20327) ) * cos( radians( coord_lat ) ) * cos( radians( 23.7806 ) - radians(coord_long) ) + sin( radians(45.20327) ) * sin( radians(coord_lat) ) )) AS distanta 
FROM obiective 
WHERE coord_lat<>'' 
    AND coord_long<>'' 
HAVING distanta<50 
ORDER BY distanta desc

The above example was tested in MySQL 5.0.95 and 5.5.16 (Linux).

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
conualfy
  • 657
  • 2
  • 9
  • 17
  • I think a good approach might be pre filtering the results using an aproximation, so the heavy formula is applied only for some cases. Specially usefull if you have other conditions. I'm using this for the initial aprox: http://stackoverflow.com/questions/1253499/simple-calculations-for-working-with-lat-lon-km-distance – Pato May 19 '17 at 20:57
13

The haversine is definitely a good formula for probably most cases, other answers already include it so I am not going to take the space. But it is important to note that no matter what formula is used (yes not just one). Because of the huge range of accuracy possible as well as the computation time required. The choice of formula requires a bit more thought than a simple no brainer answer.

This posting from a person at nasa, is the best one I found at discussing the options

http://www.cs.nyu.edu/visual/home/proj/tiger/gisfaq.html

For example, if you are just sorting rows by distance in a 100 miles radius. The flat earth formula will be much faster than the haversine.

HalfPi = 1.5707963;
R = 3956; /* the radius gives you the measurement unit*/

a = HalfPi - latoriginrad;
b = HalfPi - latdestrad;
u = a * a + b * b;
v = - 2 * a * b * cos(longdestrad - longoriginrad);
c = sqrt(abs(u + v));
return R * c;

Notice there is just one cosine and one square root. Vs 9 of them on the Haversine formula.

Arturo Hernandez
  • 2,749
  • 3
  • 28
  • 36
  • 2
    It's a nice possibility. Just be aware that the recommended maximum distance in the discussion is *12* miles, not *100*, and that even so, errors might creep up to 30 meters (100 ft), depending on the globe's position. – Eric Wu Aug 12 '19 at 17:00
10

There is some errors in the code provided, I've fixed it below.

All the above answers assumes the earth is a sphere. However, a more accurate approximation would be that of an oblate spheroid.

a= 6378.137#equitorial radius in km
b= 6356.752#polar radius in km

def Distance(lat1, lons1, lat2, lons2):
    lat1=math.radians(lat1)
    lons1=math.radians(lons1)
    R1=(((((a**2)*math.cos(lat1))**2)+(((b**2)*math.sin(lat1))**2))/((a*math.cos(lat1))**2+(b*math.sin(lat1))**2))**0.5 #radius of earth at lat1
    x1=R1*math.cos(lat1)*math.cos(lons1)
    y1=R1*math.cos(lat1)*math.sin(lons1)
    z1=R1*math.sin(lat1)

    lat2=math.radians(lat2)
    lons2=math.radians(lons2)
    R2=(((((a**2)*math.cos(lat2))**2)+(((b**2)*math.sin(lat2))**2))/((a*math.cos(lat2))**2+(b*math.sin(lat2))**2))**0.5 #radius of earth at lat2
    x2=R2*math.cos(lat2)*math.cos(lons2)
    y2=R2*math.cos(lat2)*math.sin(lons2)
    z2=R2*math.sin(lat2)
    
    return ((x1-x2)**2+(y1-y2)**2+(z1-z2)**2)**0.5
Community
  • 1
  • 1
9

pip install haversine

Python implementation

Origin is the center of the contiguous United States.

from haversine import haversine, Unit
origin = (39.50, 98.35)
paris = (48.8567, 2.3508)
haversine(origin, paris, unit=Unit.MILES)

To get the answer in kilometers simply set unit=Unit.KILOMETERS (that's the default).

Uri
  • 2,992
  • 8
  • 43
  • 86
invoketheshell
  • 3,819
  • 2
  • 20
  • 35
  • 4
    You're importing a non-standard package that does all the work. I don't know if that's all that useful. – Teepeemm Dec 01 '15 at 01:23
  • The package is in the PyPI, Python Package Index, as a python 3 package along with numpy and scikit-learn. Not sure why one is apposed to packages. They tend to be quite useful. As open source, one could also examine the methods contained. I think many would find this package useful so I will leave the post despite the downvote. Cheers. :) – invoketheshell Jun 30 '16 at 16:55
  • It looks useful, but I would like to include the exact pip command to install this package. – Uri Aug 02 '21 at 05:26
9

There could be a simpler solution, and more correct: The perimeter of earth is 40,000Km at the equator, about 37,000 on Greenwich (or any longitude) cycle. Thus:

pythagoras = function (lat1, lon1, lat2, lon2) {
   function sqr(x) {return x * x;}
   function cosDeg(x) {return Math.cos(x * Math.PI / 180.0);}

   var earthCyclePerimeter = 40000000.0 * cosDeg((lat1 + lat2) / 2.0);
   var dx = (lon1 - lon2) * earthCyclePerimeter / 360.0;
   var dy = 37000000.0 * (lat1 - lat2) / 360.0;

   return Math.sqrt(sqr(dx) + sqr(dy));
};

I agree that it should be fine-tuned as, I myself said that it's an ellipsoid, so the radius to be multiplied by the cosine varies. But it's a bit more accurate. Compared with Google Maps and it did reduce the error significantly.

Meymann
  • 2,520
  • 2
  • 28
  • 22
  • Is this function return distance in km? – Wikki Oct 15 '16 at 17:34
  • It is, just because the equator and the longitude cycles are in Km. For miles, just divide 40000 and 37000 by 1.6. Feeling geeky, you can convert it to Ris, multiplyung by about 7 or to parasang, dividing by 2.2 ;-) – Meymann Oct 17 '16 at 04:46
  • This seems to be the best answer offered here. I wish to use it but I just wonder whether there is a way to verify the correctness of this algorithm. I tested f(50,5,58,3). It gives 832km, whereas https://www.movable-type.co.uk/scripts/latlong.html using the 'haversine' formula gives 899km. Is there such a big difference? – Chong Lip Phang Apr 19 '18 at 07:44
  • Moreover, I think the value returned by the above code is in m, and not km. – Chong Lip Phang Apr 19 '18 at 07:45
  • @ChongLipPhang - CAUTION: Pythagorean theorem is only reasonable approximation *for small areas*, as this theorem assumes the earth is flat. As an extreme case, start on the equator, and move 90 degrees east and 90 degrees north. The end result of course is the north pole, and is the same as moving 0 degrees east and 90 degrees north; so doing sqrt(sqr(dx) + sqr(dy)) will be wildly off in the first case. ~ sqrt(10km sqr + 10km sqr) ~= 14.4 km vs correct distance ~ 10km. – ToolmakerSteve Nov 24 '18 at 16:39
  • .. actually I didn't run the formula; I see it uses average of the two latitudes. But the point remains: the formula has no way to correctly conclude that a motion from equator of (dlat=90 degrees, dlong=90 degrees) is the same as (dlat=90 degrees, dlong=0 degrees), so at least one of those cases must be very far off in the formula. – ToolmakerSteve Nov 24 '18 at 16:47
  • Near the poles, its better to use "Polar Coordinate Flat Earth Formula" as approximation. See that section in [Computing Distances](https://cs.nyu.edu/visual/home/proj/tiger/gisfaq.html). Discussed in this [SO post](https://stackoverflow.com/a/19772119/199364). Away from the poles, that formula also works well; however it doesn't adjust for slight flattening of Earth ellipsoid, – ToolmakerSteve Nov 24 '18 at 22:02
  • 2
    This formula has an inaccurate number in it. circumference through poles is 6356.752 NASA * 2 Pi = 39940.651 km. Not 37000. So gives low answers for changes in latitude, as Chong saw. Replace "37000000.0" with "39940651.0". With this correction, my guess is accuracy to 1 part in 100, over distances up to one degree. (Not verified.) – ToolmakerSteve Nov 25 '18 at 15:12
8

I don't like adding yet another answer, but the Google maps API v.3 has spherical geometry (and more). After converting your WGS84 to decimal degrees you can do this:

<script src="http://maps.google.com/maps/api/js?sensor=false&libraries=geometry" type="text/javascript"></script>  

distance = google.maps.geometry.spherical.computeDistanceBetween(
    new google.maps.LatLng(fromLat, fromLng), 
    new google.maps.LatLng(toLat, toLng));

No word about how accurate Google's calculations are or even what model is used (though it does say "spherical" rather than "geoid". By the way, the "straight line" distance will obviously be different from the distance if one travels on the surface of the earth which is what everyone seems to be presuming.

8

As pointed out, an accurate calculation should take into account that the earth is not a perfect sphere. Here are some comparisons of the various algorithms offered here:

geoDistance(50,5,58,3)
Haversine: 899 km
Maymenn: 833 km
Keerthana: 897 km
google.maps.geometry.spherical.computeDistanceBetween(): 900 km

geoDistance(50,5,-58,-3)
Haversine: 12030 km
Maymenn: 11135 km
Keerthana: 10310 km
google.maps.geometry.spherical.computeDistanceBetween(): 12044 km

geoDistance(.05,.005,.058,.003)
Haversine: 0.9169 km
Maymenn: 0.851723 km
Keerthana: 0.917964 km
google.maps.geometry.spherical.computeDistanceBetween(): 0.917964 km

geoDistance(.05,80,.058,80.3)
Haversine: 33.37 km
Maymenn: 33.34 km
Keerthana: 33.40767 km
google.maps.geometry.spherical.computeDistanceBetween(): 33.40770 km

Over small distances, Keerthana's algorithm does seem to coincide with that of Google Maps. Google Maps does not seem to follow any simple algorithm, suggesting that it may be the most accurate method here.

Anyway, here is a Javascript implementation of Keerthana's algorithm:

function geoDistance(lat1, lng1, lat2, lng2){
    const a = 6378.137; // equitorial radius in km
    const b = 6356.752; // polar radius in km

    var sq = x => (x*x);
    var sqr = x => Math.sqrt(x);
    var cos = x => Math.cos(x);
    var sin = x => Math.sin(x);
    var radius = lat => sqr((sq(a*a*cos(lat))+sq(b*b*sin(lat)))/(sq(a*cos(lat))+sq(b*sin(lat))));

    lat1 = lat1 * Math.PI / 180;
    lng1 = lng1 * Math.PI / 180;
    lat2 = lat2 * Math.PI / 180;
    lng2 = lng2 * Math.PI / 180;

    var R1 = radius(lat1);
    var x1 = R1*cos(lat1)*cos(lng1);
    var y1 = R1*cos(lat1)*sin(lng1);
    var z1 = R1*sin(lat1);

    var R2 = radius(lat2);
    var x2 = R2*cos(lat2)*cos(lng2);
    var y2 = R2*cos(lat2)*sin(lng2);
    var z2 = R2*sin(lat2);

    return sqr(sq(x1-x2)+sq(y1-y2)+sq(z1-z2));
}
Chong Lip Phang
  • 8,755
  • 5
  • 65
  • 100
7

You can use the build in CLLocationDistance to calculate this:

CLLocation *location1 = [[CLLocation alloc] initWithLatitude:latitude1 longitude:longitude1];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:latitude2 longitude:longitude2];
[self distanceInMetersFromLocation:location1 toLocation:location2]

- (int)distanceInMetersFromLocation:(CLLocation*)location1 toLocation:(CLLocation*)location2 {
    CLLocationDistance distanceInMeters = [location1 distanceFromLocation:location2];
    return distanceInMeters;
}

In your case if you want kilometers just divide by 1000.

Andre Cytryn
  • 2,506
  • 4
  • 28
  • 43
6

Here is a typescript implementation of the Haversine formula

static getDistanceFromLatLonInKm(lat1: number, lon1: number, lat2: number, lon2: number): number {
    var deg2Rad = deg => {
        return deg * Math.PI / 180;
    }

    var r = 6371; // Radius of the earth in km
    var dLat = deg2Rad(lat2 - lat1);   
    var dLon = deg2Rad(lon2 - lon1);
    var a =
        Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(deg2Rad(lat1)) * Math.cos(deg2Rad(lat2)) *
        Math.sin(dLon / 2) * Math.sin(dLon / 2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    var d = r * c; // Distance in km
    return d;
}
Sel
  • 1,934
  • 1
  • 22
  • 13
6

Here is the SQL Implementation to calculate the distance in km,

SELECT UserId, ( 3959 * acos( cos( radians( your latitude here ) ) * cos( radians(latitude) ) * 
cos( radians(longitude) - radians( your longitude here ) ) + sin( radians( your latitude here ) ) * 
sin( radians(latitude) ) ) ) AS distance FROM user HAVING
distance < 5  ORDER BY distance LIMIT 0 , 5;

For further details in the implementation by programming langugage, you can just go through the php script given here

Kiran Maniya
  • 8,453
  • 9
  • 58
  • 81
5

This script [in PHP] calculates distances between the two points.

public static function getDistanceOfTwoPoints($source, $dest, $unit='K') {
        $lat1 = $source[0];
        $lon1 = $source[1];
        $lat2 = $dest[0];
        $lon2 = $dest[1];

        $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 == "M")
        {
            return ($miles * 1.609344 * 1000);
        }
        else if ($unit == "N") {
            return ($miles * 0.8684);
        } 
        else {
            return $miles;
        }
    }
5

Java implementation in according to Haversine formula

double calculateDistance(double latPoint1, double lngPoint1, 
                         double latPoint2, double lngPoint2) {
    if(latPoint1 == latPoint2 && lngPoint1 == lngPoint2) {
        return 0d;
    }

    final double EARTH_RADIUS = 6371.0; //km value;

    //converting to radians
    latPoint1 = Math.toRadians(latPoint1);
    lngPoint1 = Math.toRadians(lngPoint1);
    latPoint2 = Math.toRadians(latPoint2);
    lngPoint2 = Math.toRadians(lngPoint2);

    double distance = Math.pow(Math.sin((latPoint2 - latPoint1) / 2.0), 2) 
            + Math.cos(latPoint1) * Math.cos(latPoint2)
            * Math.pow(Math.sin((lngPoint2 - lngPoint1) / 2.0), 2);
    distance = 2.0 * EARTH_RADIUS * Math.asin(Math.sqrt(distance));

    return distance; //km value
}
ak-j
  • 650
  • 7
  • 12
4

here is an example in postgres sql (in km, for miles version, replace 1.609344 by 0.8684 version)

CREATE OR REPLACE FUNCTION public.geodistance(alat float, alng float, blat  

float, blng  float)
  RETURNS float AS
$BODY$
DECLARE
    v_distance float;
BEGIN

    v_distance = asin( sqrt(
            sin(radians(blat-alat)/2)^2 
                + (
                    (sin(radians(blng-alng)/2)^2) *
                    cos(radians(alat)) *
                    cos(radians(blat))
                )
          )
        ) * cast('7926.3352' as float) * cast('1.609344' as float) ;


    RETURN v_distance;
END 
$BODY$
language plpgsql VOLATILE SECURITY DEFINER;
alter function geodistance(alat float, alng float, blat float, blng float)
owner to postgres;
fla
  • 143
  • 4
4

I made a custom function in R to calculate haversine distance(km) between two spatial points using functions available in R base package.

custom_hav_dist <- function(lat1, lon1, lat2, lon2) {
R <- 6371
Radian_factor <- 0.0174533
lat_1 <- (90-lat1)*Radian_factor
lat_2 <- (90-lat2)*Radian_factor
diff_long <-(lon1-lon2)*Radian_factor

distance_in_km <- 6371*acos((cos(lat_1)*cos(lat_2))+ 
                 (sin(lat_1)*sin(lat_2)*cos(diff_long)))
rm(lat1, lon1, lat2, lon2)
return(distance_in_km)
}

Sample output

custom_hav_dist(50.31,19.08,54.14,19.39)
[1] 426.3987

PS: To calculate distances in miles, substitute R in function (6371) with 3958.756 (and for nautical miles, use 3440.065).

sourav karwa
  • 101
  • 1
  • 3
  • how to calculate the speed? – LeMarque Dec 28 '21 at 04:50
  • The code is about calculating the distance between two geostationary-spatial points. Didn't get the idea why speed calculation is required here ?? – sourav karwa Dec 29 '21 at 05:38
  • Actually, if the timestamps are given, we can calculate the speed, as distance is calculated using the formula. but if there are one minute interval time stamps and we wanted to learn about the speed of (any vehicle moving) at every 5 minute interval, I was wondering how to do that? – LeMarque Dec 29 '21 at 06:41
  • You can further add in the code to calculate speed but in my use case, it wasn't necessary hence didn't calculate speed. Would love to hear what's your approach with that – sourav karwa Dec 30 '21 at 22:15
3

To calculate the distance between two points on a sphere you need to do the Great Circle calculation.

There are a number of C/C++ libraries to help with map projection at MapTools if you need to reproject your distances to a flat surface. To do this you will need the projection string of the various coordinate systems.

You may also find MapWindow a useful tool to visualise the points. Also as its open source its a useful guide to how to use the proj.dll library, which appears to be the core open source projection library.

3

Here is my java implementation for calculation distance via decimal degrees after some search. I used mean radius of world (from wikipedia) in km. İf you want result miles then use world radius in miles.

public static double distanceLatLong2(double lat1, double lng1, double lat2, double lng2) 
{
  double earthRadius = 6371.0d; // KM: use mile here if you want mile result

  double dLat = toRadian(lat2 - lat1);
  double dLng = toRadian(lng2 - lng1);

  double a = Math.pow(Math.sin(dLat/2), 2)  + 
          Math.cos(toRadian(lat1)) * Math.cos(toRadian(lat2)) * 
          Math.pow(Math.sin(dLng/2), 2);

  double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

  return earthRadius * c; // returns result kilometers
}

public static double toRadian(double degrees) 
{
  return (degrees * Math.PI) / 180.0d;
}
3
function getDistanceFromLatLonInKm(position1, position2) {
    "use strict";
    var deg2rad = function (deg) { return deg * (Math.PI / 180); },
        R = 6371,
        dLat = deg2rad(position2.lat - position1.lat),
        dLng = deg2rad(position2.lng - position1.lng),
        a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
            + Math.cos(deg2rad(position1.lat))
            * Math.cos(deg2rad(position2.lat))
            * Math.sin(dLng / 2) * Math.sin(dLng / 2),
        c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return R * c;
}

console.log(getDistanceFromLatLonInKm(
    {lat: 48.7931459, lng: 1.9483572},
    {lat: 48.827167, lng: 2.2459745}
));
Raphael C
  • 2,296
  • 1
  • 22
  • 22
3

Here's the accepted answer implementation ported to Java in case anyone needs it.

package com.project529.garage.util;


/**
 * Mean radius.
 */
private static double EARTH_RADIUS = 6371;

/**
 * Returns the distance between two sets of latitudes and longitudes in meters.
 * <p/>
 * Based from the following JavaScript SO answer:
 * http://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula,
 * which is based on https://en.wikipedia.org/wiki/Haversine_formula (error rate: ~0.55%).
 */
public double getDistanceBetween(double lat1, double lon1, double lat2, double lon2) {
    double dLat = toRadians(lat2 - lat1);
    double dLon = toRadians(lon2 - lon1);

    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
            Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
                    Math.sin(dLon / 2) * Math.sin(dLon / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double d = EARTH_RADIUS * c;

    return d;
}

public double toRadians(double degrees) {
    return degrees * (Math.PI / 180);
}
Eduardo Naveda
  • 1,880
  • 3
  • 15
  • 30
3

For those looking for an Excel formula based on WGS-84 & GRS-80 standards:

=ACOS(COS(RADIANS(90-Lat1))*COS(RADIANS(90-Lat2))+SIN(RADIANS(90-Lat1))*SIN(RADIANS(90-Lat2))*COS(RADIANS(Long1-Long2)))*6371

Source

Korayem
  • 12,108
  • 5
  • 69
  • 56
  • 1
    In ƛ format: =LAMBDA(lat₁,lng₁,lat₂,lng₂, LET(R, 6371, ΔLat, RADIANS(lat₂ - lat₁), ΔLng, RADIANS(lng₂ - lng₁), a, SIN(ΔLat / 2)^2 + COS(RADIANS(lat₁)) * COS(RADIANS(lat₂)) * SIN(ΔLng / 2)^2, c, 2 * ATAN2(SQRT(1 - a), SQRT(a)), d, R * c * 0.621371, d)) – CalvinDale Jul 25 '22 at 18:46
2

there is a good example in here to calculate distance with PHP http://www.geodatasource.com/developers/php :

 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;
     }
 }
ayalcinkaya
  • 3,303
  • 29
  • 25
2

Here is the implementation VB.NET, this implementation will give you the result in KM or Miles based on an 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
Taiseer Joudeh
  • 8,953
  • 1
  • 41
  • 45
2

I condensed the computation down by simplifying the formula.

Here it is 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
Kache
  • 15,647
  • 12
  • 51
  • 79
2
function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2,units) {
  var R = 6371; // Radius of the earth in km
  var dLat = deg2rad(lat2-lat1);  // deg2rad below
  var dLon = deg2rad(lon2-lon1); 
  var a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * 
    Math.sin(dLon/2) * Math.sin(dLon/2)
    ; 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  var d = R * c; 
  var miles = d / 1.609344; 

if ( units == 'km' ) {  
return d; 
 } else {
return miles;
}}

Chuck's solution, valid for miles also.

MPaulo
  • 1,491
  • 14
  • 19
2

In Mysql use the following function pass the parameters as using POINT(LONG,LAT)

CREATE FUNCTION `distance`(a POINT, b POINT)
 RETURNS double
    DETERMINISTIC
BEGIN

RETURN

GLength( LineString(( PointFromWKB(a)), (PointFromWKB(b)))) * 100000; -- To Make the distance in meters

END;
shanavascet
  • 589
  • 1
  • 4
  • 18
2

Here's another converted to Ruby code:

include Math
#Note: from/to = [lat, long]

def get_distance_in_km(from, to)
  radians = lambda { |deg| deg * Math.PI / 180 }
  radius = 6371 # Radius of the earth in kilometer
  dLat = radians[to[0]-from[0]]
  dLon = radians[to[1]-from[1]]

  cosines_product = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(radians[from[0]]) * Math.cos(radians[to[1]]) * Math.sin(dLon/2) * Math.sin(dLon/2)

  c = 2 * Math.atan2(Math.sqrt(cosines_product), Math.sqrt(1-cosines_product)) 
  return radius * c # Distance in kilometer
end
aldrien.h
  • 3,437
  • 2
  • 30
  • 52
2

One of the main challenges to calculating distances - especially large ones - is accounting for the curvature of the Earth. If only the Earth were flat, calculating the distance between two points would be as simple as for that of a straight line! The Haversine formula includes a constant (it's the R variable below) that represents the radius of the Earth. Depending on whether you are measuring in miles or kilometers, it would equal 3956 mi or 6367 km respectively.

The basic formula is:

dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
c = 2 * atan2( sqrt(a), sqrt(1-a) )
distance = R * c (where R is the radius of the Earth)
 
R = 6367 km OR 3956 mi
     lat1, lon1: The Latitude and Longitude of point 1 (in decimal degrees)
     lat2, lon2: The Latitude and Longitude of point 2 (in decimal degrees)
     unit: The unit of measurement in which to calculate the results where:
     'M' is statute miles (default)
     'K' is kilometers
     'N' is nautical miles

Sample

function distance(lat1, lon1, lat2, lon2, unit) {
    try {
        var radlat1 = Math.PI * lat1 / 180
        var radlat2 = Math.PI * lat2 / 180
        var theta = lon1 - lon2
        var radtheta = Math.PI * theta / 180
        var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
        dist = Math.acos(dist)
        dist = dist * 180 / Math.PI
        dist = dist * 60 * 1.1515
        if (unit == "K") {
            dist = dist * 1.609344
        }
        if (unit == "N") {
            dist = dist * 0.8684
        }
        return dist
    } catch (err) {
        console.log(err);
    }
}
Ramprasath Selvam
  • 3,868
  • 3
  • 25
  • 41
  • While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Suraj Rao Apr 01 '19 at 13:33
2

As this is the most popular discussion of the topic I'll add my experience from late 2019-early 2020 here. To add to the existing answers - my focus was to find an accurate AND fast (i.e. vectorized) solution.

Let's start with what is mostly used by answers here - the Haversine approach. It is trivial to vectorize, see example in python below:

def haversine(lat1, lon1, lat2, lon2):
    """
    Calculate the great circle distance between two points
    on the earth (specified in decimal degrees)

    All args must be of equal length.
    Distances are in meters.
    
    Ref:
    https://stackoverflow.com/questions/29545704/fast-haversine-approximation-python-pandas
    https://ipython.readthedocs.io/en/stable/interactive/magics.html
    """
    Radius = 6.371e6
    lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])

    dlon = lon2 - lon1
    dlat = lat2 - lat1

    a = np.sin(dlat/2.0)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2.0)**2

    c = 2 * np.arcsin(np.sqrt(a))
    s12 = Radius * c
    
    # initial azimuth in degrees
    y = np.sin(lon2-lon1) * np.cos(lat2)
    x = np.cos(lat1)*np.sin(lat2) - np.sin(lat1)*np.cos(lat2)*np.cos(dlon)
    azi1 = np.arctan2(y, x)*180./math.pi

    return {'s12':s12, 'azi1': azi1}

Accuracy-wise, it is least accurate. Wikipedia states 0.5% of relative deviation on average without any sources. My experiments show less of a deviation. Below is the comparison ran on 100,000 random points vs my library, which should be accurate to millimeter levels:

np.random.seed(42)
lats1 = np.random.uniform(-90,90,100000)
lons1 = np.random.uniform(-180,180,100000)
lats2 = np.random.uniform(-90,90,100000)
lons2 = np.random.uniform(-180,180,100000)
r1 = inverse(lats1, lons1, lats2, lons2)
r2 = haversine(lats1, lons1, lats2, lons2)
print("Max absolute error: {:4.2f}m".format(np.max(r1['s12']-r2['s12'])))
print("Mean absolute error: {:4.2f}m".format(np.mean(r1['s12']-r2['s12'])))
print("Max relative error: {:4.2f}%".format(np.max((r2['s12']/r1['s12']-1)*100)))
print("Mean relative error: {:4.2f}%".format(np.mean((r2['s12']/r1['s12']-1)*100)))

Output:

Max absolute error: 26671.47m
Mean absolute error: -2499.84m
Max relative error: 0.55%
Mean relative error: -0.02%

So on average 2.5km deviation on 100,000 random pairs of coordinates, which may be good for majority of cases.

Next option is Vincenty's formulae which is accurate up to millimeters, depending on convergence criteria and can be vectorized as well. It does have the issue with convergence near antipodal points. You can make it converge at those points by relaxing convergence criteria, but accuracy drops to 0.25% and more. Outside of antipodal points Vincenty will provide results close to Geographiclib within relative error of less than 1.e-6 on average.

Geographiclib, mentioned here, is really the current golden standard. It has several implementations and fairly fast, especially if you are using C++ version.

Now, if you are planning to use Python for anything above 10k points I'd suggest to consider my vectorized implementation. I created a geovectorslib library with vectorized Vincenty routine for my own needs, which uses Geographiclib as fallback for near antipodal points. Below is the comparison vs Geographiclib for 100k points. As you can see it provides up to 20x improvement for inverse and 100x for direct methods for 100k points and the gap will grow with number of points. Accuracy-wise it will be within 1.e-5 rtol of Georgraphiclib.

Direct method for 100,000 points
94.9 ms ± 25 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
9.79 s ± 1.4 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

Inverse method for 100,000 points
1.5 s ± 504 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
24.2 s ± 3.91 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
Oleg Medvedyev
  • 1,574
  • 14
  • 16
2

You can calculate it by using Haversine formula which is:

a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
c = 2 ⋅ atan2( √a, √(1−a) )
d = R ⋅ c

An example to calculate distance between two points is given below

Suppose i have to calculate distance between New Delhi to London, so how can i use this formula :

New delhi co-ordinates= 28.7041° N, 77.1025° E
London co-ordinates= 51.5074° N, 0.1278° W

var R = 6371e3; // metres
var φ1 = 28.7041.toRadians();
var φ2 = 51.5074.toRadians();
var Δφ = (51.5074-28.7041).toRadians();
var Δλ = (0.1278-77.1025).toRadians();

var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
        Math.cos(φ1) * Math.cos(φ2) *
        Math.sin(Δλ/2) * Math.sin(Δλ/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

var d = R * c; // metres
d = d/1000; // km
WapShivam
  • 964
  • 12
  • 20
2

If you want the driving distance/route (posting it here because this is the first result for the distance between two points on google but for most people the driving distance is more useful), you can use Google Maps Distance Matrix Service:

getDrivingDistanceBetweenTwoLatLong(origin, destination) {

 return new Observable(subscriber => {
  let service = new google.maps.DistanceMatrixService();
  service.getDistanceMatrix(
    {
      origins: [new google.maps.LatLng(origin.lat, origin.long)],
      destinations: [new google.maps.LatLng(destination.lat, destination.long)],
      travelMode: 'DRIVING'
    }, (response, status) => {
      if (status !== google.maps.DistanceMatrixStatus.OK) {
        console.log('Error:', status);
        subscriber.error({error: status, status: status});
      } else {
        console.log(response);
        try {
          let valueInMeters = response.rows[0].elements[0].distance.value;
          let valueInKms = valueInMeters / 1000;
          subscriber.next(valueInKms);
          subscriber.complete();
        }
       catch(error) {
        subscriber.error({error: error, status: status});
       }
      }
    });
});
}
Renato Probst
  • 5,914
  • 2
  • 42
  • 45
2

You could use a module like geolib too:

How to install:

$ npm install geolib

How to use:

import { getDistance } from 'geolib'

const distance = getDistance(
    { latitude: 51.5103, longitude: 7.49347 },
    { latitude: "51° 31' N", longitude: "7° 28' E" }
)

console.log(distance)

Documentation: https://www.npmjs.com/package/geolib

Arthur Ronconi
  • 2,290
  • 25
  • 25
1

Had an issue with math.deg in LUA... if anyone knows a fix please clean up this code!

In the meantime here's an implementation of the Haversine in LUA (use this with Redis!)

function calcDist(lat1, lon1, lat2, lon2)
    lat1= lat1*0.0174532925
    lat2= lat2*0.0174532925
    lon1= lon1*0.0174532925
    lon2= lon2*0.0174532925

    dlon = lon2-lon1
    dlat = lat2-lat1

    a = math.pow(math.sin(dlat/2),2) + math.cos(lat1) * math.cos(lat2) * math.pow(math.sin(dlon/2),2)
    c = 2 * math.asin(math.sqrt(a))
    dist = 6371 * c      -- multiply by 0.621371 to convert to miles
    return dist
end

cheers!

Eric Walsh
  • 3,035
  • 1
  • 16
  • 21
1

FSharp version, using miles:

let radialDistanceHaversine location1 location2 : float = 
                let degreeToRadian degrees = degrees * System.Math.PI / 180.0
                let earthRadius = 3959.0
                let deltaLat = location2.Latitude - location1.Latitude |> degreeToRadian
                let deltaLong = location2.Longitude - location1.Longitude |> degreeToRadian
                let a =
                    (deltaLat / 2.0 |> sin) ** 2.0
                    + (location1.Latitude |> degreeToRadian |> cos)
                    * (location2.Latitude |> degreeToRadian |> cos)
                    * (deltaLong / 2.0 |> sin) ** 2.0
                atan2 (a |> sqrt) (1.0 - a |> sqrt)
                * 2.0
                * earthRadius
Ryan
  • 2,109
  • 1
  • 15
  • 19
1

Dart lang:

import 'dart:math' show cos, sqrt, asin;

double calculateDistance(LatLng l1, LatLng l2) {
  const p = 0.017453292519943295;
  final a = 0.5 -
      cos((l2.latitude - l1.latitude) * p) / 2 +
      cos(l1.latitude * p) *
          cos(l2.latitude * p) *
          (1 - cos((l2.longitude - l1.longitude) * p)) /
          2;
  return 12742 * asin(sqrt(a));
}
Oleg Khalidov
  • 5,108
  • 1
  • 28
  • 29
1

The functions needed for an accurate calculation of distance between lat-long points are complex, and the pitfalls are many. I would not recomend haversine or other spherical solutions due to the big inaccuracies (the earth is not a perfect sphere). The vincenty formula is better, but will in some cases throw errors, even when coded correctly.

Instead of coding the functions yourself I suggest using geopy which have implemented the very accurate geographiclib for distance calculations (paper from author).

#pip install geopy
from geopy.distance import geodesic
NY = [40.71278,-74.00594]
Beijing = [39.90421,116.40739]
print("WGS84: ",geodesic(NY, Beijing).km) #WGS84 is Standard
print("Intl24: ",geodesic(NY, Beijing, ellipsoid='Intl 1924').km) #geopy includes different ellipsoids
print("Custom ellipsoid: ",geodesic(NY, Beijing, ellipsoid=(6377., 6356., 1 / 297.)).km) #custom ellipsoid

#supported ellipsoids:
#model             major (km)   minor (km)     flattening
#'WGS-84':        (6378.137,    6356.7523142,  1 / 298.257223563)
#'GRS-80':        (6378.137,    6356.7523141,  1 / 298.257222101)
#'Airy (1830)':   (6377.563396, 6356.256909,   1 / 299.3249646)
#'Intl 1924':     (6378.388,    6356.911946,   1 / 297.0)
#'Clarke (1880)': (6378.249145, 6356.51486955, 1 / 293.465)
#'GRS-67':        (6378.1600,   6356.774719,   1 / 298.25)

The only drawback with this library is that it doesn't support vectorized calculations. For vectorized calculations you can use the new geovectorslib.

#pip install geovectorslib
from geovectorslib import inverse
print(inverse(lats1,lons1,lats2,lons2)['s12'])

lats and lons are numpy arrays. Geovectorslib is very accurate and extremly fast! I haven't found a solution for changing ellipsoids though. The WGS84 ellipsoid is used as standard, which is the best choice for most uses.

Kristian K
  • 491
  • 5
  • 11
1

If you are using python; pip install geopy

from geopy.distance import geodesic


origin = (30.172705, 31.526725)  # (latitude, longitude) don't confuse
destination = (30.288281, 31.732326)

print(geodesic(origin, destination).meters)  # 23576.805481751613
print(geodesic(origin, destination).kilometers)  # 23.576805481751613
print(geodesic(origin, destination).miles)  # 14.64994773134371
Irfan wani
  • 4,084
  • 2
  • 19
  • 34
1

Here is the Erlang implementation

lat_lng({Lat1, Lon1}=_Point1, {Lat2, Lon2}=_Point2) ->
  P = math:pi() / 180,
  R = 6371, % Radius of Earth in KM
  A = 0.5 - math:cos((Lat2 - Lat1) * P) / 2 +
    math:cos(Lat1 * P) * math:cos(Lat2 * P) * (1 - math:cos((Lon2 - Lon1) * P))/2,
  R * 2 * math:asin(math:sqrt(A)).
Aaron Lelevier
  • 19,850
  • 11
  • 76
  • 111
0

Here's a simple javascript function that may be useful from this link.. somehow related but we're using google earth javascript plugin instead of maps

function getApproximateDistanceUnits(point1, point2) {

    var xs = 0;
    var ys = 0;

    xs = point2.getX() - point1.getX();
    xs = xs * xs;

    ys = point2.getY() - point1.getY();
    ys = ys * ys;

    return Math.sqrt(xs + ys);
}

The units tho are not in distance but in terms of a ratio relative to your coordinates. There are other computations related you can substitute for the getApproximateDistanceUnits function link here

Then I use this function to see if a latitude longitude is within the radius

function isMapPlacemarkInRadius(point1, point2, radi) {
    if (point1 && point2) {
        return getApproximateDistanceUnits(point1, point2) <= radi;
    } else {
        return 0;
    }
}

point may be defined as

 $$.getPoint = function(lati, longi) {
        var location = {
            x: 0,
            y: 0,
            getX: function() { return location.x; },
            getY: function() { return location.y; }
        };
        location.x = lati;
        location.y = longi;

        return location;
    };

then you can do your thing to see if a point is within a region with a radius say:

 //put it on the map if within the range of a specified radi assuming 100,000,000 units
        var iconpoint = Map.getPoint(pp.latitude, pp.longitude);
        var centerpoint = Map.getPoint(Settings.CenterLatitude, Settings.CenterLongitude);

        //approx ~200 units to show only half of the globe from the default center radius
        if (isMapPlacemarkInRadius(centerpoint, iconpoint, 120)) {
            addPlacemark(pp.latitude, pp.longitude, pp.name);
        }
        else {
            otherSidePlacemarks.push({
                latitude: pp.latitude,
                longitude: pp.longitude,
                name: pp.name
            });

        }
bherto39
  • 1,516
  • 3
  • 14
  • 29
0
//JAVA
    public Double getDistanceBetweenTwoPoints(Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
    final int RADIUS_EARTH = 6371;

    double dLat = getRad(latitude2 - latitude1);
    double dLong = getRad(longitude2 - longitude1);

    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(getRad(latitude1)) * Math.cos(getRad(latitude2)) * Math.sin(dLong / 2) * Math.sin(dLong / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return (RADIUS_EARTH * c) * 1000;
    }

    private Double getRad(Double x) {
    return x * Math.PI / 180;
    }
Victor Powell
  • 1,828
  • 1
  • 12
  • 8
borchvm
  • 3,533
  • 16
  • 44
  • 45
0

I've created this small Javascript LatLng object, might be useful for somebody.

var latLng1 = new LatLng(5, 3);
var latLng2 = new LatLng(6, 7);
var distance = latLng1.distanceTo(latLng2); 

Code:

/**
 * latLng point
 * @param {Number} lat
 * @param {Number} lng
 * @returns {LatLng}
 * @constructor
 */
function LatLng(lat,lng) {
    this.lat = parseFloat(lat);
    this.lng = parseFloat(lng);

    this.__cache = {};
}

LatLng.prototype = {
    toString: function() {
        return [this.lat, this.lng].join(",");
    },

    /**
     * calculate distance in km to another latLng, with caching
     * @param {LatLng} latLng
     * @returns {Number} distance in km
     */
    distanceTo: function(latLng) {
        var cacheKey = latLng.toString();
        if(cacheKey in this.__cache) {
            return this.__cache[cacheKey];
        }

        // the fastest way to calculate the distance, according to this jsperf test;
        // http://jsperf.com/haversine-salvador/8
        // http://stackoverflow.com/questions/27928
        var deg2rad = 0.017453292519943295; // === Math.PI / 180
        var lat1 = this.lat * deg2rad;
        var lng1 = this.lng * deg2rad;
        var lat2 = latLng.lat * deg2rad;
        var lng2 = latLng.lng * deg2rad;
        var a = (
            (1 - Math.cos(lat2 - lat1)) +
            (1 - Math.cos(lng2 - lng1)) * Math.cos(lat1) * Math.cos(lat2)
            ) / 2;
        var distance = 12742 * Math.asin(Math.sqrt(a)); // Diameter of the earth in km (2 * 6371)

        // cache the distance
        this.__cache[cacheKey] = distance;

        return distance;
    }
};
Jorik
  • 641
  • 5
  • 6
0
function distance($lat1, $lon1, $lat2, $lon2) { 
    $pi80 = M_PI / 180; 
    $lat1 *= $pi80; $lon1 *= $pi80; $lat2 *= $pi80; $lon2 *= $pi80; 
    $dlat = $lat2 - $lat1; 
    $dlon = $lon2 - $lon1; 
    $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlon / 2) * sin($dlon / 2);  
    $km = 6372.797 * 2 * atan2(sqrt($a), sqrt(1 - $a)); 
    return $km; 
}
Anurag
  • 83
  • 1
  • 11
0

Here's a Scala implementation:

  def calculateHaversineDistance(lat1: Double, lon1: Double, lat2: Double, lon2: Double): Double = {
    val long2 = lon2 * math.Pi / 180
    val lat2 = lat2 * math.Pi / 180
    val long1 = lon1 * math.Pi / 180
    val lat1 = lat1 * math.Pi / 180

    val dlon = long2 - long1
    val dlat = lat2 - lat1
    val a = math.pow(math.sin(dlat / 2), 2) + math.cos(lat1) * math.cos(lat2) * math.pow(math.sin(dlon / 2), 2)
    val c = 2 * math.atan2(Math.sqrt(a), math.sqrt(1 - a))
    val haversineDistance = 3961 * c // 3961 = radius of earth in miles
    haversineDistance
  }
Remis Haroon - رامز
  • 3,304
  • 4
  • 34
  • 62
0

To calculate the distance between two points specified by latitude and longitude, you can use the Haversine formula or Vincenty's formulae. Both formulas take into account the curvature of the Earth and provide reasonably accurate results. Here's a brief explanation of each method:

Haversine Formula: The Haversine formula calculates the great-circle distance between two points on a sphere (in this case, the Earth) assuming a perfect sphere. It is simpler and faster than Vincenty's formulae but may have slightly lower accuracy, especially for longer distances.

The Haversine formula is as follows:

a = sin²(Δlat/2) + cos(lat1) * cos(lat2) * sin²(Δlon/2)
c = 2 * atan2(√a, √(1-a))
d = R * c

Where:

Δlat is the difference in latitude between the two points.
Δlon is the difference in longitude between the two points.
lat1 and lat2 are the latitudes of the two points.
R is the radius of the Earth (mean radius: 6,371 km).

You can find direct implementation at Haversine Implementations

Vincenty's Formulae: Vincenty's formulae are more complex but provide higher accuracy for calculating the distance between two points on an ellipsoidal model of the Earth. They take into account the Earth's shape and provide accurate results for any pair of points on the globe.

There are two variations of Vincenty's formulae: the direct formula, which calculates the distance between points, and the inverse formula, which calculates the initial bearing, final bearing, and distance between points.

To use Vincenty's formulae, you'll need to implement the specific equations in your chosen programming language.

Direct Formula: The direct formula calculates the destination point (latitude and longitude) given a starting point, initial bearing, and distance. It is useful when you know the starting point, the desired distance, and the initial bearing towards the destination.

The formula is as follows:

α1 = atan2((1 - f) * tan(lat1), cos(α0))
sinσ1 = (cos(U2) * sin(α1))^2 + (cos(U1) * sin(U2) - sin(U1) * cos(U2) * cos(α1))^2
sinσ = sqrt(sinσ1)
cosσ = sin(U1) * sin(U2) + cos(U1) * cos(U2) * cos(α1)
σ = atan2(sinσ, cosσ)
sinα = cos(U1) * cos(U2) * sin(α1) / sinσ
cos2αm = 1 - sinα^2
C = (f / 16) * cos2αm * (4 + f * (4 - 3 * cos2αm))
λ = L + (1 - C) * f * sinα * (σ + C * sinσ * (cos(2 * σ) + C * cosσ * (-1 + 2 * cos(2 * σ)^2)))
Δ = L2 - λ
L = λ

Where:

lat1, lon1: Starting point latitude and longitude in radians.
α0: Initial bearing in radians.
U1 = atan((1 - f) * tan(lat1))
U2 = atan((1 - f) * tan(lat2)), where lat2 is calculated iteratively using the formula above.
f = (a - b) / a, where a and b are the equatorial and polar radii of the Earth, respectively.

Inverse Formula: The inverse formula calculates the distance, initial bearing, and final bearing between two points on the Earth's surface. It is useful when you know the latitude and longitude of both points.

The formula is as follows:

L = lon2 - lon1
λ = L
λʹ = 2π + atan2(y, x)
σ = atan2(yʹ, xʹ)
C = (f / 16) * cos^2αm * (4 + f * (4 - 3 * cos^2αm))
λ = L + (1 - C) * f * sinα * (σ + C * sinσ * (cos(2 * σ) + C * cosσ * (-1 + 2 * cos(2 * σ)^2)))

Where:

lat1, lon1: Latitude and longitude of the first point in radians.
lat2, lon2: Latitude and longitude of the second point in radians.
L = lon2 - lon1
U1 = atan((1 - f) * tan(lat1))
U2 = atan((1 - f) * tan(lat2))
sinα = cos(U2) * sin(L)
cosα = sqrt(1 - sinα^2)
cos^2αm = cosα^2 * cosσ^2
x = σ - sinα * sinσ
y = λʹ - sinα * sinσ
xʹ = cos(U1) * sin(U2) - sin(U1) * cos(U2) * cos(L)
yʹ = cos(U2) * sin(L)
Sarvesh Mishra
  • 2,014
  • 15
  • 30