Created
March 7, 2016 19:14
-
-
Save jtribble/ae95f491e2da9d2c0d44 to your computer and use it in GitHub Desktop.
Compute the distance between two points using the Haversine formula. See: https://en.wikipedia.org/wiki/Haversine_formula
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Compute the distance between two points using the Haversine formula | |
// | |
// See: https://en.wikipedia.org/wiki/Haversine_formula | |
// | |
// Example: geoCoordDistance( | |
// {lat: '48° 12′ 30″ N', lng: '16° 22′ 23″ E'}, | |
// {lat: '23° 33′ 0″ S', lng: '46° 38′ 0″ W'} | |
// ) => 10130 | |
// | |
;(function(global) { | |
'use strict'; | |
/** | |
* Polyfill for Number.prototype.toRadians | |
*/ | |
if (typeof Number.prototype.toRadians === 'undefined') { | |
Number.prototype.toRadians = function() { | |
return this * Math.PI / 180; | |
} | |
} | |
/** | |
* @var {object} - Regex codes for °, ′, and ″ | |
*/ | |
const symbols = { | |
degrees: unescape('%B0'), // ° | |
minutes: unescape('%u2032'), // ′ | |
seconds: unescape('%u2033') // ″ | |
}; | |
/** | |
* @var {number} - Earth's radius, in kilometers | |
*/ | |
const earthRadius = 6371; | |
/** | |
* Convert lat/lng from DMS to decimal degrees format | |
* | |
* @param {number} degrees - The degree information | |
* @param {number} minutes - The minute information | |
* @param {number} seconds - The second information | |
* @param {string} cardinalDir - N, S, E, W | |
* @return {number} - Decimal format | |
*/ | |
const dmsToDecDeg = (degrees, minutes, seconds, cardinalDir) => { | |
const decDeg = degrees + (minutes / 60) + (seconds / 3600); | |
return (~['N', 'E'].indexOf(cardinalDir)) ? decDeg : -decDeg; | |
}; | |
/** | |
* Convert geo coordinate string (e.g. 48° 12′ 30″ N) to a geo coord shaped object | |
* | |
* @param {string} str - The lat/lng string | |
* @return {number} - The value in radians | |
*/ | |
const coordStrToObj = str => { | |
const degPieces = str.split(symbols.degrees).map(s => s.trim()); | |
const minPieces = degPieces[1].split(symbols.minutes).map(s => s.trim()); | |
const secPieces = minPieces[1].split(symbols.seconds).map(s => s.trim()); | |
const degrees = Number(degPieces[0]); | |
const minutes = Number(minPieces[0]); | |
const seconds = Number(secPieces[0]); | |
const cardinalDir = secPieces[1]; | |
const decimalDegrees = dmsToDecDeg(degrees, minutes, seconds, cardinalDir); | |
const decimalRadians = decimalDegrees.toRadians(); | |
return { | |
decimalDegrees, | |
decimalRadians, | |
degrees, | |
minutes, | |
seconds, | |
cardinalDir | |
}; | |
}; | |
/** | |
* Given lat and lng string (e.g. 48° 12′ 30″ N), return distance between them in kilometers | |
* | |
* @param {object} one - The first point | |
* @param {string} one.lat - The first point's latitude string | |
* @param {string} one.lng - The first point's longitude string | |
* @param {object} two - The second point | |
* @param {string} two.lat - The second point's latitude string | |
* @param {string} two.lng - The second point's longitude string | |
* @return {number} - The distance in kilometers | |
*/ | |
const geoCoordDistance = (one, two) => { | |
const ptOne = { | |
lat: coordStrToObj(one.lat), | |
lng: coordStrToObj(one.lng) | |
}; | |
const ptTwo = { | |
lat: coordStrToObj(two.lat), | |
lng: coordStrToObj(two.lng) | |
}; | |
const latDelta = (ptTwo.lat.decimalDegrees - ptOne.lat.decimalDegrees).toRadians(); | |
const lngDelta = (ptTwo.lng.decimalDegrees - ptOne.lng.decimalDegrees).toRadians(); | |
const a = ( | |
Math.pow(Math.sin(latDelta / 2), 2) + | |
Math.cos(ptOne.lat.decimalRadians) * Math.cos(ptTwo.lat.decimalRadians) * | |
Math.pow(Math.sin(lngDelta / 2), 2) | |
); | |
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); | |
const d = earthRadius * c; | |
// return the distance | |
return d; | |
}; | |
// export function to global object | |
global.geoCoordDistance = geoCoordDistance; | |
})(window); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment