Skip to content

Instantly share code, notes, and snippets.

@harini-ua
Last active July 12, 2020 13:45
Show Gist options
  • Save harini-ua/6908bc92d9b42080e940bf622455eb50 to your computer and use it in GitHub Desktop.
Save harini-ua/6908bc92d9b42080e940bf622455eb50 to your computer and use it in GitHub Desktop.
Calculated distance between two GPS locations. Using the Haversin formula. [MySQL, PHP, JAVA, JavaScript, Python, Node.js]

Haversine distance

This code can to calculate the distance between two points using latitude and longitude.

Usage in PHP

<?php

use HaversineFormula\Distance;

$inKilometers = Distance::toKilometers(30.261699, -97.738967, 29.869229, -97.959595);
$inMiles      = Distance::toMiles(30.261699, -97.738967, 29.869229, -97.959595);

Usage in MySQL

/*
 * @param lat1  (double)   latitude of origin
 * @param lon1  (double)   longitude of origin
 * @param lat2  (double)   latitude of destination
 * @param lon2  (double)   longitude of destination
 * @param unit  (enum)     MILE, MI for miles or KILOMETER, KM for kilometers
 * @return      (double)   Distance between the two points in the units specified.
 */
FUNCTION DISTANCE( lat1 DOUBLE, lon1 DOUBLE, lat2 DOUBLE, lon2 DOUBLE, unit ENUM( 'MILE', 'KILOMETER', 'MI', 'KM' ) )

Calculate the distance between San Francisco, CA and New York, NY in miles

mysql> SELECT DISTANCE( 37.7756, -122.4193, 40.71448, -74.00598, 'MI' );
2565.80921930121

Find the two closest cities (in our table) to Paris, France

mysql> SELECT city, country FROM cities ORDER BY DISTANCE( 48.856638, 2.352241, cities.lat, cities.lon, 'KM' ) ASC LIMIT 2;
Geneva       Switzerland
Barcelona    Spain

Usage in JAVA

double distance = HaversineFormula.distance(51.5112139, -0.119824, 48.8567, 2.3508, 'M');
 
NumberFormat df = DecimalFormat.getInstance();
df.setMaximumFractionDigits(3);
df.setRoundingMode(RoundingMode.CEILING);
System.out.println(df.format(distance) + " Miles\n"); //displays 213.471 Miles

Usage in Python

haversine([-0.116773, 51.510357], [-77.009003, 38.889931])

Usage in JavaScript

var haversine = require('haversine-distance')

var a = { lat: 37.8136, lng: 144.9631 }
var b = { lat: 33.8650, lon: 151.2094 }

// 714504.18 (in meters)
console.log(haversine(a, b))

Usage in Node.js

  • options.unit - Unit of measurement applied to result (default km, available km, mile, meter, nmi)
  • options.threshold - If passed, will result in library returning boolean value of whether or not the start and end points are within that supplied threshold. (default null)
  • options.format - The format of start and end coordinate arguments. See table below for available values. (default null)
const haversine = require('haversine')

const start = {
  latitude: 30.849635,
  longitude: -83.24559
}

const end = {
  latitude: 27.950575,
  longitude: -82.457178
}

console.log(haversine(start, end))
console.log(haversine(start, end, {unit: 'mile'}))
console.log(haversine(start, end, {unit: 'meter'}))
console.log(haversine(start, end, {threshold: 1}))
console.log(haversine(start, end, {threshold: 1, unit: 'mile'}))
console.log(haversine(start, end, {threshold: 1, unit: 'meter'}))
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class HaversineFormula {
public static double distance(double lat1, double lon1, double lat2, double lon2, char unit) {
double theta = lon1 - lon2;
double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2))
+ Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
dist = Math.acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
if (unit == 'K') {
dist = dist * 1.609344;
} else if (unit == 'N') {
dist = dist * 0.8684;
}
return dist;
}
// This function converts decimal degrees to radians
private static double deg2rad(double deg) {
return (deg * Math.PI / 180.0);
}
// This function converts radians to decimal degrees
private static double rad2deg(double rad) {
return (rad * 180 / Math.PI);
}
public static void main(String[] args) {
//place test code here
}
}
<?php
namespace HaversineFormula;
const EARTH_RADIUS = 6371;
const KILOMETER_TO_MILE = 0.621371192;
class Distance
{
/**
* @param float $fromLat
* @param float $fromLon
* @param float $toLat
* @param float $toLon
*
* @return float
*/
private static function calculate($fromLat, $fromLon, $toLat, $toLon)
{
$dLat = deg2rad($toLat - $fromLat);
$dLon = deg2rad($toLon - $fromLon);
$a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($fromLat)) * cos(deg2rad($toLat)) * sin($dLon/2) * sin($dLon/2);
$c = 2 * asin(sqrt($a));
$d = self::EARTH_RADIUS * $c;
return round($d);
}
/**
* @param float $fromLat
* @param float $fromLon
* @param float $toLat
* @param float $toLon
*
* @return float
*/
public static function toKilometers($fromLat, $fromLon, $toLat, $toLon)
{
return self::calculate($fromLat, $fromLon, $toLat, $toLon);
}
/**
* @param float $fromLat
* @param float $fromLon
* @param float $toLat
* @param float $toLon
*
* @return float
*/
public static function toMiles($fromLat, $fromLon, $toLat, $toLon)
{
$distance = self::calculate($fromLat, $fromLon, $toLat, $toLon);
return round($distance * self::KILOMETER_TO_MILE);
}
}
def haversine(coord1: object, coord2: object):
import math
# Coordinates in decimal degrees (e.g. 2.89078, 12.79797)
lon1, lat1 = coord1
lon2, lat2 = coord2
R = 6371000 # radius of Earth in meters
phi_1 = math.radians(lat1)
phi_2 = math.radians(lat2)
delta_phi = math.radians(lat2 - lat1)
delta_lambda = math.radians(lon2 - lon1)
a = math.sin(delta_phi / 2.0) ** 2 + math.cos(phi_1) * math.cos(phi_2) * math.sin(delta_lambda / 2.0) ** 2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
meters = R * c # output distance in meters
km = meters / 1000.0 # output distance in kilometers
meters = round(meters, 3)
km = round(km, 3)
return km
/*
* Calculates the straight line distance between two GPS coordinates
*
* @author Jason Kruse <jason@jasonkruse.com> or @mnisjk
* @copyright 2014
* @license BSD (see LICENSE)
*
* @param lat1 (double) latitude of origin
* @param lon1 (double) longitude of origin
* @param lat2 (double) latitude of destination
* @param lon2 (double) longitude of destination
* @param unit (enum) MILE, MI for miles or KILOMETER, KM for kilometers
* @return (double) Distance between the two points in the units specified.
*
* This function is very helpful for ordering a list of results by nearst first with:
*
* ORDER BY DISTANCE( userInput.lat, userInput.lon, locations.lat, locations.lon ) ASC;
*/
DROP FUNCTION IF EXISTS DISTANCE;
DELIMITER $$
CREATE FUNCTION DISTANCE( lat1 DOUBLE, lon1 DOUBLE, lat2 DOUBLE, lon2 DOUBLE, unit ENUM( 'MILE', 'KILOMETER', 'MI', 'KM' ) )
RETURNS DOUBLE
BEGIN
DECLARE dist DOUBLE;
DECLARE latDist DOUBLE;
DECLARE lonDist DOUBLE;
DECLARE a,c,r DOUBLE;
# earth's radius
IF unit = 'MILE' OR unit = 'MI' THEN SET r = 3959;
ELSE SET r = 6371;
END IF;
# Haversine formula <http://en.wikipedia.org/wiki/Haversine_formula>
SET latDist = RADIANS( lat2 - lat1 );
SET lonDist = RADIANS( lon2 - lon1 );
SET a = POW( SIN( latDist/2 ), 2 ) + COS( RADIANS( lat1 ) ) * COS( RADIANS( lat2 ) ) * POW( SIN( lonDist / 2 ), 2 );
SET c = 2 * ATAN2( SQRT( a ), SQRT( 1 - a ) );
SET dist = r * c;
RETURN dist;
END$$
DELIMITER ;
var haversine = (function () {
var RADII = {
km: 6371,
mile: 3960,
meter: 6371000,
nmi: 3440
}
// convert to radians
var toRad = function (num) {
return num * Math.PI / 180
}
// convert coordinates to standard format based on the passed format option
var convertCoordinates = function (format, coordinates) {
switch (format) {
case '[lat,lon]':
return { latitude: coordinates[0], longitude: coordinates[1] }
case '[lon,lat]':
return { latitude: coordinates[1], longitude: coordinates[0] }
case '{lon,lat}':
return { latitude: coordinates.lat, longitude: coordinates.lon }
case 'geojson':
return { latitude: coordinates.geometry.coordinates[1], longitude: coordinates.geometry.coordinates[0] }
default:
return coordinates
}
}
return function haversine (startCoordinates, endCoordinates, options) {
options = options || {}
var R = options.unit in RADII
? RADII[options.unit]
: RADII.km
var start = convertCoordinates(options.format, startCoordinates)
var end = convertCoordinates(options.format, endCoordinates)
var dLat = toRad(end.latitude - start.latitude)
var dLon = toRad(end.longitude - start.longitude)
var lat1 = toRad(start.latitude)
var lat2 = toRad(end.latitude)
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2)
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
if (options.threshold) {
return options.threshold > (R * c)
}
return R * c
}
})()
if (typeof module !== 'undefined' && module.exports) {
module.exports = haversine
}
var atan2 = Math.atan2
var cos = Math.cos
var sin = Math.sin
var sqrt = Math.sqrt
var PI = Math.PI
// (mean) radius of Earth (meters)
var R = 6378137
function squared (x) { return x * x }
function toRad (x) { return x * PI / 180.0 }
module.exports = function haversineDistance (a, b) {
var aLat = a.latitude || a.lat
var bLat = b.latitude || b.lat
var aLng = a.longitude || a.lng || a.lon
var bLng = b.longitude || b.lng || b.lon
var dLat = toRad(bLat - aLat)
var dLon = toRad(bLng - aLng)
var f = squared(sin(dLat / 2.0)) + cos(toRad(aLat)) * cos(toRad(bLat)) * squared(sin(dLon / 2.0))
var c = 2 * atan2(sqrt(f), sqrt(1 - f))
return R * c
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment