This page presents a variety of calculations for latitude/longitude points, with the formulæ and code fragments for implementing them.
Adapted from http://www.movabletype.co.uk/scripts/latlong.htmlEnter the coordinates into the text boxes to try out the calculations. A variety of formats are accepted, principally:



All these formulæ are for calculations on the basis of a spherical earth (ignoring ellipsoidal effects) – which is accurate enough^{*} for most purposes… [In fact, the earth is very slightly ellipsoidal; using a spherical model gives errors typically up to 0.3% – see notes for further details].
This uses the "haversine" formula to calculate the greatcircle distance between two points – that is, the shortest distance over the earth’s surface – giving an "asthecrowflies" distance between the points (ignoring any hills they fly over, of course!).
Haversine formula: 
a = sin²(Δφ/2) + cos φ_{1} ⋅ cos φ_{2} ⋅ sin²(Δλ/2) c = 2 ⋅ atan2( √a, √(1−a) ) d = R ⋅ c 
where:  φ is latitude, λ is longitude, R is earth’s radius (mean radius = 6,371km); note that angles need to be in radians to pass to trig functions! 
JavaScript:  var R = 6378; // km var φ1 = lat1.toRadians(); var φ2 = lat2.toRadians(); var Δφ = (lat2lat1).toRadians(); var Δλ = (lon2lon1).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(1a)); var d = R * c; 
Note in these scripts, I generally use lat/lon for latitude/longitude in degrees, and φ/λ for latitude/longitude in radians – having found that mixing degrees & radians is often the easiest route to headscratching bugs...
The haversine formula^{1} "remains particularly wellconditioned for numerical computation even at small distances" – unlike calculations based on the spherical law of cosines. The "versed sine" is 1−cosθ, and the "halfversedsine" is (1−cosθ)/2 = sin²(θ/2) as used above. Once widely used by navigators, it was described by Roger Sinnott in Sky & Telescope magazine in 1984 (“Virtues of the Haversine”): Sinnott explained that the angular separation between Mizar and Alcor in Ursa Major – 0°11′49.69″ – could be accurately calculated on a TRS80 using the haversine.
For the curious, c is the angular distance in radians, and a is the square of half the chord length between the points. A (remarkably marginal) performance improvement can be obtained, of course, by factoring out the terms which get squared.
In fact, JavaScript (and most modern computers & languages) use "IEEE 754" 64bit floatingpoint numbers, which provide 15 significant figures of precision. By my estimate, with this precision, the simple spherical law of cosines formula (cos c = cos a cos b + sin a sin b cos C) gives wellconditioned results down to distances as small as a few metres on the Earth’s surface. (Note that the geodetic form of the law of cosines is rearranged from the canonical one so that the latitude can be used directly, rather than the colatitude).
This makes the simpler law of cosines a reasonable 1line alternative to the haversine formula for many purposes. The choice may be driven by coding context, available trig functions (in different languages), etc – and, for very small distances an equirectangualar approximation may be more suitable.
Law of cosines:  d = acos( sin φ_{1} ⋅ sin φ_{2} + cos φ_{1} ⋅ cos φ_{2} ⋅ cos Δλ ) ⋅ R 
JavaScript:  var φ1 = lat1.toRadians(), φ2 = lat2.toRadians(), Δλ = (lon2lon1).toRadians(), R = 6371; // gives d in km var d = Math.acos( Math.sin(φ1)*Math.sin(φ2) + Math.cos(φ1)*Math.cos(φ2) * Math.cos(Δλ) ) * R; 
Excel:  =ACOS(SIN(lat1)*SIN(lat2)+COS(lat1)*COS(lat2)*COS(lon2lon1))*6371 
(or with lat/lon in degrees):  =ACOS(SIN(lat1*PI()/360)*SIN(lat2*PI()/360)+COS(lat1*PI()/360)*COS(lat2*PI()/360)*COS(lon2*PI()/360lon1*PI()/360))*6371 
If performance is an issue and accuracy less important, for small distances Pythagoras’ theorem can be used on an equirectangular projection:^{*}
Formula  x = Δλ ⋅ cos φ_{m} y = Δφ d = R ⋅ √x² + y² 
JavaScript:  var x = (λ2λ1) * Math.cos((φ1+φ2)/2); var y = (φ2φ1); var d = Math.sqrt(x*x + y*y) * R; 
This uses just one trig and one sqrt function – as against halfadozen trig functions for cos law, and 7 trigs + 2 sqrts for haversine. Accuracy is somewhat complex: along meridians there are no errors, otherwise they depend on distance, bearing, and latitude, but are small enough for many purposes^{*} (and often trivial compared with the spherical approximation itself).
Alternatively, the polar coordinate flatEarth formula can be used: using the colatitudes θ_{1} = π/2−φ_{1} and θ_{2} = π/2−φ_{2}, then d = R ⋅ √θ_{1}² + θ_{2}² − 2 ⋅ θ_{1} ⋅ θ_{2} ⋅ cos Δλ. I’ve not compared accuracy.
In general, your current heading will vary as you follow a great circle path (orthodrome); the final heading will differ from the initial heading by varying degrees according to distance and latitude (if you were to go from say 35°N,45°E (≈ Baghdad) to 35°N,135°E (≈ Osaka), you would start on a heading of 60° and end up on a heading of 120°!).
This formula is for the initial bearing (sometimes referred to as forward azimuth) which if followed in a straight line along a greatcircle arc will take you from the start point to the end point:^{1}
Formula:  θ = atan2( sin Δλ ⋅ cos φ_{2} , cos φ_{1} ⋅ sin φ_{2} − sin φ_{1} ⋅ cos φ_{2} ⋅ cos Δλ ) 
JavaScript:  var y = Math.sin(λ2λ1) * Math.cos(φ2); var x = Math.cos(φ1)*Math.sin(φ2)  Math.sin(φ1)*Math.cos(φ2)*Math.cos(λ2λ1); var brng = Math.atan2(y, x).toDegrees(); 
Excel: (lat/lon in radians) 
=ATAN2(COS(lat1)*SIN(lat2)SIN(lat1)*COS(lat2)*COS(lon2lon1), SIN(lon2lon1)*COS(lat2)) *note that Excel reverses the arguments to ATAN2 – see notes below 
Since atan2 returns values in the range π ... +π (that is, 180° ... +180°), to normalise the result to a compass bearing (in the range 0° ... 360°, with −ve values transformed into the range 180° ... 360°), convert to degrees and then use (θ+360) % 360, where % is modulo.
For final bearing, simply take the initial bearing from the end point to the start point and reverse it (using θ = (θ+180) % 360).
This is the halfway point along a great circle path between the two points.^{1}
Formula:  B_{x} = cos φ_{2} ⋅ cos Δλ B_{y} = cos φ_{2} ⋅ sin Δλ φ_{m} = atan2( sin φ_{1} + sin φ_{2}, √(cos φ_{1} + B_{x})² + B_{y}² ) λ_{m} = λ_{1} + atan2(B_{y}, cos(φ_{1})+B_{x}) 
JavaScript:  var Bx = Math.cos(φ2) * Math.cos(λ2λ1); var By = Math.cos(φ2) * Math.sin(λ2λ1); var φ3 = Math.atan2(Math.sin(φ1) + Math.sin(φ2), Math.sqrt( (Math.cos(φ1)+Bx)*(Math.cos(φ1)+Bx) + By*By ) ); var λ3 = λ1 + Math.atan2(By, Math.cos(φ1) + Bx); 
Just as the initial bearing may vary from the final bearing, the midpoint may not be located halfway between latitudes/longitudes; the midpoint between 35°N,45°E and 35°N,135°E is around 45°N,90°E.
Destination point given distance and bearing from start pointGiven a start point, initial bearing, and distance, this will calculate the destination point and final bearing travelling along a (shortest distance) great circle arc. 
Formula:  φ_{2} = asin( sin φ_{1} ⋅ cos δ + cos φ_{1} ⋅ sin δ ⋅ cos θ ) 
λ_{2} = λ_{1} + atan2( sin θ ⋅ sin δ ⋅ cos φ_{1}, cos δ − sin φ_{1} ⋅ sin φ_{2} )  
where  φ is latitude, λ is longitude, θ is the bearing (in radians, clockwise from north), δ is the angular distance (in radians) d/R; d being the distance travelled, R the earth’s radius 
JavaScript:  var φ2 = Math.asin( Math.sin(φ1)*Math.cos(d/R) + Math.cos(φ1)*Math.sin(d/R)*Math.cos(brng) ); var λ2 = λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1), Math.cos(d/R)Math.sin(φ1)*Math.sin(φ2)); 
Excel: (lat/lon in radians) 
lat2: =ASIN(SIN(lat1)*COS(d/R) + COS(lat1)*SIN(d/R)*COS(brng)) lon2: =lon1 + ATAN2(COS(d/R)SIN(lat1)*SIN(lat2), SIN(brng)*SIN(d/R)*COS(lat1)) * Remember that Excel reverses the arguments to ATAN2 – see notes below 
For final bearing, simply take the initial bearing from the end point to the start point and reverse it (using θ = (θ+180) % 360).
Intersection of two paths given start points and bearingsThis is a rather more complex calculation than most others on this page, but I've been asked for it a number of times. This comes from Ed William’s aviation formulary. See below for the JavaScript. 
Formula: 
δ_{12} = 2⋅asin( √(sin²(Δφ/2) + cos φ_{1} ⋅ cos φ_{2} ⋅ sin²(Δλ/2)) ) if sin(λ_{2}−λ_{1}) > 0 α_{1} = (θ_{1} − θ_{12} + π) % 2π − π α_{1} = α_{1} α_{3} = acos( −cos α_{1} ⋅ cos α_{2} + sin α_{1} ⋅ sin α_{2} ⋅ cos δ_{12} ) 
where  φ_{1}, λ_{1}, θ_{1} : 1st point & bearing % = mod,   = abs 
note –  if sin α_{1} = 0 and sin α_{2} = 0: infinite solutions if sin α_{1} ⋅ sin α_{2} < 0: ambiguous solution this formulation is not always wellconditioned for meridional or equatorial lines 
This is a lot simpler using vectors rather than spherical trigonometry: see latlongvectors.html.
Here’s a new one: I’ve sometimes been asked about distance of a point from a greatcircle path (sometimes called cross track error).
Formula:  d_{xt} = asin( sin(δ_{13}) ⋅ sin(θ_{13}−θ_{12}) ) ⋅ R 
where  δ_{13} is (angular) distance from start point to third point θ_{13} is (initial) bearing from start point to third point θ_{12} is (initial) bearing from start point to end point R is the earth’s radius 
JavaScript:  var dXt = Math.asin(Math.sin(d13/R)*Math.sin(θ13θ12)) * R; 
Here, the greatcircle path is identified by a start point and an end point – depending on what initial data you’re working from, you can use the formulæ above to obtain the relevant distance and bearings. The sign of d_{xt} tells you which side of the path the third point is on.
The alongtrack distance, from the start point to the closest point on the path to the third point, is
Formula:  d_{at} = acos( cos(δ_{13}) / cos(δ_{xt}) ) ⋅ R 
where  δ_{13} is (angular) distance from start point to third point δ_{xt} is (angular) crosstrack distance R is the earth’s radius 
JavaScript:  var dAt = Math.acos(Math.cos(d13/R)/Math.cos(dXt/R)) * R; 
And: "Clairaut’s formula" will give you the maximum latitude of a great circle path, given a bearing θ and latitude φ on the great circle:
Formula:  φ_{max} = acos(  sin θ ⋅ cos φ  ) 
JavaScript:  var φMax = Math.acos(Math.abs(Math.sin(θ)*Math.cos(φ))); 
A "rhumb line" (or loxodrome) is a path of constant bearing, which crosses all meridians at the same angle.
Sailors used to (and sometimes still) navigate along rhumb lines since it is easier to follow a constant compass bearing than to be continually adjusting the bearing, as is needed to follow a great circle. Rhumb lines are straight lines on a Mercator Projection map (also helpful for navigation).
Rhumb lines are generally longer than greatcircle (orthodrome) routes. For instance, London to New York is 4% longer along a rhumb line than along a great circle – important for aviation fuel, but not particularly to sailing vessels. New York to Beijing – close to the most extreme example possible (though not sailable!) – is 30% longer along a rhumb line.
Key to calculations of rhumb lines is the inverse Gudermannian function¹, which gives the height on a Mercator projection map of a given latitude: ln(tanφ + secφ) or ln( tan(π/4+φ/2) ). This of course tends to infinity at the poles (in keeping with the Mercator projection). For obsessives, there is even an ellipsoidal version, the "isometric latitude": ln( tan(π/4+φ/2) / [ (1−e⋅sinφ) / (1+e⋅sinφ) ]^{e/2}).
The formulæ to derive Mercator projection easting and northing coordinates from spherical latitude and longitude are then¹
E = R ⋅ λ  
N = R ⋅ ln( tan(π/4 + φ/2) ) 
The following formulæ are from Ed Williams’ aviation formulary.¹
Since a rhumb line is a straight line on a Mercator projection, the distance between two points along a rhumb line is the length of that line (by Pythagoras); but the distortion of the projection needs to be compensated for.
On a constant latitude course (travelling eastwest), this compensation is simply cosφ; in the general case, it is Δφ/Δψ where Δψ = ln( tan(π/4 + φ_{2}/2) / tan(π/4 + φ_{1}/2) ) (the "projected" latitude difference)
Formula:  Δψ = ln( tan(π/4 + φ_{2}/2) / tan(π/4 + φ_{1}/2) )  ("projected" latitude difference) 
q = Δφ/Δψ (or cosφ for EW line)  
d = √(Δφ² + q²⋅Δλ²) ⋅ R  (Pythagoras)  
where  φ is latitude, λ is longitude, Δλ is taking shortest route (<180º), R is the earth’s radius, ln is natural log  
JavaScript:  var Δψ = Math.log(Math.tan(Math.PI/4+φ2/2)/Math.tan(Math.PI/4+φ1/2)); var q = Math.abs(Δψ) > 10e12 ? Δφ/Δψ : Math.cos(φ1); // EW course becomes illconditioned with 0/0 // if dLon over 180° take shorter rhumb across antimeridian: if (Math.abs(Δλ) > Math.PI) Δλ = Δλ>0 ? (2*Math.PIΔλ) : (2*Math.PI+Δλ); var dist = Math.sqrt(Δφ*Δφ + q*q*Δλ*Δλ) * R; 
A rhumb line is a straight line on a Mercator projection, with an angle on the projection equal to the compass bearing.
Formula:  Δψ = ln( tan(π/4 + φ_{2}/2) / tan(π/4 + φ_{1}/2) )  ("projected" latitude difference) 
θ = atan2(Δλ, Δψ)  
where  φ is latitude, λ is longitude, Δλ is taking shortest route (<180º), R is the earth’s radius, ln is natural log  
JavaScript:  var Δψ = Math.log(Math.tan(Math.PI/4+φ2/2)/Math.tan(Math.PI/4+φ1/2)); var q = Math.abs(Δψ) > 10e12 ? Δφ/Δψ : Math.cos(φ1); // EW course becomes illconditioned with 0/0 // if dLon over 180° take shorter rhumb across antimeridian: if (Math.abs(Δλ) > Math.PI) Δλ = Δλ>0 ? (2*Math.PIΔλ) : (2*Math.PI+Δλ); var brng = Math.atan2(Δλ, Δψ).toDegrees(); 
Given a start point and a distance d along constant bearing θ, this will calculate the destination point. If you maintain a constant bearing along a rhumb line, you will gradually spiral in towards one of the poles.
Formula:  δ = d/R  (angular distance) 
Δψ = ln( tan(π/4 + φ_{2}/2) / tan(π/4 + φ_{1}/2) )  ("projected" latitude difference)  
q = Δφ/Δψ (or cosφ for EW line)  
Δλ = δ ⋅ sin θ / q  
φ_{2} = φ_{1} + δ ⋅ cos θ  
λ_{2} = λ_{1} + Δλ  
where  φ is latitude, λ is longitude, Δλ is taking shortest route (<180°), ln is natural log and % is modulo, R is the earth’s radius  
JavaScript:  var Δφ = δ*Math.cos(θ); var φ2 = φ1 + Δλ; var Δψ = Math.log(Math.tan(φ2/2+Math.PI/4)/Math.tan(φ1/2+Math.PI/4)); var q = Δψ > 10e12 ? Δφ / Δψ : Math.cos(φ1); // EW course becomes illconditioned with 0/0 var Δλ = δ*Math.sin(θ)/q; // check for some daft bugger going past the pole, normalise latitude if so if (Math.abs(φ2) > Math.PI/2) φ2 = φ2>0 ? Math.PIφ2 : Math.PIφ2; λ2 = (λ1+dLon+Math.PI)%(2*Math.PI)  Math.PI; 
This formula for calculating the "loxodromic midpoint", the point halfway along a rhumb line between two points, is due to Robert Hill and Clive Tooth^{1} (thx Axel!).
Formula:  φ_{m} = (φ_{1}+φ_{2}) / 2  
f_{1} = tan(π/4 + φ_{1}/2)  
f_{2} = tan(π/4 + φ_{2}/2)  
f_{m} = tan(π/4+φ_{m}/2)  
λ_{m} = [ (λ_{2}−λ_{1}) ⋅ ln(f_{m}) + λ_{1} ⋅ ln(f_{2}) − λ_{2} ⋅ ln(f_{1}) ] / ln(f_{2}/f_{1})  
where  φ is latitude, λ is longitude, ln is natural log  
JavaScript:  if (Math.abs(λ2λ1) > Math.PI) λ1 += 2*Math.PI; // crossing antimeridian var φ3 = (φ1+φ2)/2; var f1 = Math.tan(Math.PI/4 + φ1/2); var f2 = Math.tan(Math.PI/4 + φ2/2); var f3 = Math.tan(Math.PI/4 + φ3/2); var λ3 = ( (λ2λ1)*Math.log(f3) + λ1*Math.log(f2)  λ2*Math.log(f1) ) / Math.log(f2/f1); if (!isFinite(λ3)) λ3 = (λ1+λ2)/2; // parallel of latitude λ3 = (λ3+3*Math.PI) % (2*Math.PI)  Math.PI; // normalise to 180..+180º 
Using these scripts in web pages would be something like the following:
<script src="latlon.js">/* Latitude/Longitude formulae */</script> <script src="geo.js">/* Geodesy representation conversions */</script> ... <form> Lat1: <input type="text" name="lat1" id="lat1"> Lon1: <input type="text" name="lon1" id="lon1"> Lat2: <input type="text" name="lat2" id="lat2"> Lon2: <input type="text" name="lon2" id="lon2"> <button onClick="var p1 = new LatLon(Geo.parseDMS(f.lat1.value), Geo.parseDMS(f.lon1.value)); var p2 = new LatLon(Geo.parseDMS(f.lat2.value), Geo.parseDMS(f.lon2.value)); alert(p1.distanceTo(p2));">Calculate distance</button> </form>
If you use jQuery, the code can be separated from the HTML:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script src="latlon.js">/* Latitude/Longitude formulae */</script> <script src="geo.js">/* Geodesy representation conversions */</script> <script> $(document).ready(function() { $('#calcdist').click(function() { var p1 = new LatLon(Geo.parseDMS($('#lat1').val()), Geo.parseDMS($('#lon1').val())); var p2 = new LatLon(Geo.parseDMS($('#lat2').val()), Geo.parseDMS($('#lon2').val())); $('#resultdistance').html(p1.distanceTo(p2)); }); }); </script> ... <form> Lat1: <input type="text" name="lat1" id="lat1"> Lon1: <input type="text" name="lon1" id="lon1"> Lat2: <input type="text" name="lat2" id="lat2"> Lon2: <input type="text" name="lon2" id="lon2"> <button id="calcdist">Calculate distance</button> <output id="resultdistance"></output> km </form>
No, I’ve not included decimal minutes: a decimal system is easy, a sexagesimal system has merits, but mixing the two is a complete sow’s ear. Switch off the option on your GPS!
Notes:
See below for the source code of the JavaScript implementation, also available on GitHub. These functions should be simple to translate into other languages if required.
Update January 2010: I have revised the scripts to be structured as methods of
a LatLon object. Of course, JavaScript is a prototypebased
rather than classbased language,
so this is only nominally a class, but isolating code into a separate namespace is good JavaScript
practice, and this approach may also make it clearer to implement these functions in other languages.
If you’re not familiar with JavaScript syntax, LatLon.prototype.distanceTo = function(point)
{ ... }
, for instance, defines a "distanceTo
" method of the LatLon
object
(/class) which takes a LatLon
object as a parameter (and returns a number). The
Geo namespace acts as a static class for geodesy formatting / parsing / conversion functions.
I have extended (polluted, if you like) the base JavaScript object prototypes with trim(), toRadians()
toDegrees(), and toPrecisionFixed() methods. I’ve adopted JSDoc format for the descriptions.
I have also created a page illustrating the use of the spherical law of cosines for selecting points from a database within a specified bounding circle – the example is based on MySQL+PDO, but should be extensible to other DBMS platforms.
Several people have asked about example Excel spreadsheets, so I have implemented the distance & bearing and the destination point formulæ as spreadsheets, in a form which breaks down the all stages involved to illustrate the operation.
I offer these formulæ & scripts for free use and adaptation as my contribution to the opensource infosphere from which I have received so much. You are welcome to reuse these scripts [under a simple attribution license, without any warranty express or implied] provided solely that you retain my copyright notice and a reference to this page.
If you would like to show your appreciation and support continued development of these scripts, I would most gratefully accept donations.
If you need any advice or development work done, I am available for consultancy.
If you have any queries or find any problems, contact me at ku.oc.epytelbavom@oegstpircs.
© 20022014 Chris Veness