Calculate distance between two latitude-longitude points? (Haversine formula)
Asked Answered
P

49

1160

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.

Portaltoportal answered 26/8, 2008 at 12:50 Comment(6)
For better accuracy - see #1420545Titanium
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.Hackman
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 for a high quality library with implementations in various languages.Keelboat
@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.Comforter
For these plateforms: Mono/.NET 4.5/.NET Core/Windows Phone 8.x/Universal Windows Platform/Xamarin iOS/Xamarin Android see https://mcmap.net/q/46813/-calculating-distance-between-two-latitude-and-longitude-geocoordinatesComposite
See also this great Python answer: Fast Haversine Approximation (Python/Pandas)Trimly
O
1381

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)
}
Outsize answered 26/8, 2008 at 12:55 Comment(26)
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.Mere
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.Mezzorelievo
Wrapped the logic into a function, so it should be usable in JS out of the box, actually using this in NodeJS now...Nephritis
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?Rosiorosita
Here is implementation of the same code in PHP, gist.github.com/gajus/5487925.Antimonyl
@UsmanMutawakil Works perfectly fine with lat/long obtained from Google Maps API.Huey
@Huey 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?Handicapper
@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.Huey
@Huey 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.Handicapper
@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.Huey
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.Garfish
Why don't we use the absolute value, like abs(dLat), in case it has the negative value due to lat2 < lat1?Erastianism
@Forte_201092: Because that is not necessary - as (sin(x))² equals (sin(-x))²Swivel
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).Lyse
@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.Gaslight
it's worth noting that this method ignores ( ellipsoidal effects ) , however its accurate enough for most use cases !!Corallite
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.Nona
the Haversine formula is not for WGS94 ellipsoid but for spherical coordinatesOlindaolinde
Here is a simplified version for the maniacs like me out there who get triggered by unnecessary variables gist.github.com/manix/7ce097c73728e07178af74cb4c62a341Wayzgoose
Please can someone explain what is a and c in the code?Ineradicable
What about if I want to calculate the distance between 2 points described by latitude, longitude and height?Ruelu
@KumarAbhirup: Given that distance = radius * c, c seems to be the chord 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.Oarfish
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.Gerita
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.Elainaelaine
Any license on this code? I'm guessing it comes from somewhere and just wanted attribution correct.Morra
@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.)Leena
B
506

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.

Burroughs answered 7/2, 2014 at 8:52 Comment(15)
The js one above seems to be 40 miles wrong when I convert it from km to milesGesso
@Gesso and have have you calculated that it is wrong? What did you compare it to?Burroughs
I compared it to google maps. It seemed to be 40miles less in comparison to google maps for london to birminghamGesso
@Gesso and how does google calculate the distance?Burroughs
I'm just letting you know that they calculated it differently. Because it was 40 miles difference in comparison to the above calculation. And I'm guessing Google is most likely to be correctGesso
@Gesso and there is highly likely that google calculates distance if you will be taking some roads and not a straight line.Burroughs
Google calculates driving distance, this calculates "as the crow flies"Celestaceleste
@BenGuild it does the same thing, but it does it faster. So yes, it is betterBurroughs
@SalvadorDali you can replace all var by constLynching
@Lynching and will it improve speed? Most probably no, but I will end up with a lot of 'your stuff doesn't work' for people who copypaste it in old browsersBurroughs
@SalvadorDali Thanks for this distance code. It just saved me... literally days of head-scratching. The Python implementation is short and concise. Cheers!Drupe
Is it only me or I can't figure out how to convert distance from km to miles and visa versa .. :(Betrothal
@KhalilKhalaf most probably it is just you. Multiplying a number by another number is not that hard. I will even help you with a number: 0.6213Burroughs
here lat long is in radians? and it gives result in km?Salicylate
I compared your program's results with various other programs that convert lat/lon to kilometers, and found they are all VERY close. So yours wins!Schoolmaster
S
79

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

}
Sangraal answered 19/10, 2008 at 1:30 Comment(7)
You are using the equatorial radius, but you should be using the mean radius, which is 6371 kmCreepy
Shouldn't this be double dlon = Radians(lon2 - lon1); and double dlat = Radians(lat2 - lat1);Israelitish
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.Goshawk
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: movable-type.co.uk/scripts/latlong.htmlGoshawk
does the RADIUS value need to be 6371 as in the other answers?Idolatrize
@Sangraal what exactly does this function return ? kilometers, miles?Commandant
@Commandant 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. :-)Leena
E
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.

Eldrida answered 26/9, 2012 at 11:0 Comment(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?Shufu
if you want miles, multiple the result by 0.621371Nike
P
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;
}
Preoccupied answered 7/12, 2010 at 13:56 Comment(3)
iOS SDK has its own implementation: developer.apple.com/library/ios/documentation/CoreLocation/…:Latticework
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 from scratch.Unavailing
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.Unavailing
M
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

Memoried answered 24/6, 2012 at 14:11 Comment(1)
This works perfectly! I just added $distance_miles = $km * 0.621371; and that's all I needed for approximate distance in miles! Thanks Tony.Flatfoot
H
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).

Halvaard answered 12/3, 2012 at 23:37 Comment(1)
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: #1253999Demaggio
R
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
  p <- pi/180
  diff.long <- (long2 - long1) * p
  diff.lat <- (lat2 - lat1) * p
  a <- sin(diff.lat/2)^2 + cos(lat1 * p) * cos(lat2 * p) * sin(diff.long/2)^2
  b <- 2 * asin(pmin(1, sqrt(a))) 
  d = R * b
  return(d)
}
Radium answered 15/4, 2014 at 21:59 Comment(6)
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.]Comforter
@Comforter the function at the end of my answer is an implementation of the Haversine methodRadium
Hi @Radium could I ask what is the unit of measurement for the formula? Is it in metres?Boarder
@Radium I liked the explanation of 'Vincenty formula for ellipsoids' which I tested to be very accurate. @Boarder distm(p1, p2, fun = distVincentyEllipsoid) gives output in metres which you have to divide with 1000 to get values in kilometres.Labret
The base R implementation above is incorrect, as it does not convert longitude and latitude to radians.Punish
@Punish Strange nobody saw this in all those years. Changed the answer so that the base R implementation is now correct. Thx for letting me know!Radium
T
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.

Teniers answered 4/11, 2013 at 16:20 Comment(1)
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.Feoff
B
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
Bluestocking answered 16/6, 2016 at 22:25 Comment(1)
Could you add sources to your formulae?Belayneh
O
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).

Olivero answered 14/7, 2015 at 5:52 Comment(3)
You're importing a non-standard package that does all the work. I don't know if that's all that useful.Simons
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. :)Olivero
It looks useful, but I would like to include the exact pip command to install this package.Randy
K
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.

Kimmel answered 10/2, 2016 at 7:26 Comment(8)
Is this function return distance in km?Pollen
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 ;-)Kimmel
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 movable-type.co.uk/scripts/latlong.html using the 'haversine' formula gives 899km. Is there such a big difference?Aubade
Moreover, I think the value returned by the above code is in m, and not km.Aubade
@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.Comforter
.. 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.Comforter
Near the poles, its better to use "Polar Coordinate Flat Earth Formula" as approximation. See that section in Computing Distances. Discussed in this SO post. Away from the poles, that formula also works well; however it doesn't adjust for slight flattening of Earth ellipsoid,Comforter
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.)Comforter
C
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.

Cipher answered 20/7, 2014 at 0:10 Comment(1)
distance is in meters. alternatively one can use computeLength()Bordelaise
A
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));
}
Aubade answered 19/4, 2018 at 8:42 Comment(0)
W
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.

Warship answered 26/6, 2013 at 8:43 Comment(0)
B
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;
}
Burkhard answered 12/12, 2015 at 15:59 Comment(0)
P
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

Poyssick answered 9/10, 2018 at 10:14 Comment(0)
M
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;
        }
    }
Mcabee answered 21/2, 2017 at 7:4 Comment(0)
K
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
}
Kreis answered 30/1, 2019 at 20:10 Comment(0)
C
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;
Cotemporary answered 21/12, 2016 at 7:34 Comment(0)
B
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).

Ballyhoo answered 5/10, 2020 at 18:12 Comment(4)
how to calculate the speed?Selfcontained
The code is about calculating the distance between two geostationary-spatial points. Didn't get the idea why speed calculation is required here ??Ballyhoo
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?Selfcontained
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 thatBallyhoo
F
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.

Freezedrying answered 19/10, 2008 at 1:30 Comment(0)
B
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;
}
Balcom answered 12/2, 2014 at 20:52 Comment(0)
E
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}
));
Ethno answered 29/4, 2015 at 14:22 Comment(1)
You have got a typo, second cos should be of pos2Jabez
W
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:
 * https://mcmap.net/q/45581/-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);
}
Winters answered 12/10, 2015 at 20:59 Comment(0)
A
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

Apostle answered 10/2, 2020 at 22:7 Comment(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))Encaenia
F
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;
     }
 }
Flashcube answered 15/1, 2013 at 1:48 Comment(0)
F
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
Furl answered 2/4, 2013 at 8:35 Comment(1)
Upon calculating "a", did you wrote Math.Sin( dLat ..) twice by mistake?Celebes
A
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
Albertson answered 13/6, 2013 at 2:16 Comment(0)
B
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.

Birl answered 8/11, 2013 at 6:34 Comment(0)
A
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;
Alexisaley answered 28/5, 2014 at 8:59 Comment(0)
F
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
Fachan answered 16/10, 2017 at 13:21 Comment(0)
W
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);
    }
}
Wofford answered 1/4, 2019 at 12:39 Comment(1)
While this code may solve the question, including an explanation 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.Blastogenesis
S
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://mcmap.net/q/46814/-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)
Stapleton answered 9/1, 2020 at 2:47 Comment(0)
E
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
Esker answered 10/1, 2020 at 13:27 Comment(0)
H
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});
       }
      }
    });
});
}
Harbor answered 2/12, 2020 at 13:38 Comment(0)
S
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

Sculpsit answered 30/8, 2021 at 13:50 Comment(0)
S
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!

Sawicki answered 30/11, 2014 at 20:56 Comment(1)
Don't forget to declare variables (dlon,dlat,a,c,dist) as local to not pollute the global space.Unexpected
H
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
Highlander answered 14/6, 2018 at 22:20 Comment(0)
S
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));
}
Sanborne answered 8/1, 2020 at 13:30 Comment(0)
O
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.

Ora answered 1/6, 2020 at 18:54 Comment(0)
S
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
Stedt answered 5/11, 2020 at 12:8 Comment(0)
I
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)).
Innkeeper answered 2/5, 2021 at 15:18 Comment(0)
A
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
            });

        }
Angrist answered 17/10, 2012 at 9:12 Comment(0)
T
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;
    }
Teador answered 5/6, 2014 at 10:46 Comment(0)
F
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;
    }
};
Foetor answered 12/8, 2014 at 14:7 Comment(0)
S
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; 
}
Spun answered 7/4, 2021 at 21:9 Comment(0)
E
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
  }
Encroachment answered 30/12, 2021 at 13:2 Comment(0)
M
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)
Mersey answered 4/7, 2023 at 18:13 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.