2008-08-26 17 views
654

Как рассчитать расстояние между двумя точками, заданными широтой и долготой?Рассчитать расстояние между двумя точками долготы широты? (Формула Хаверсина)

Для уточнения, я хотел бы расстояние в километрах; точки используют систему WGS84, и я хотел бы понять относительную точность доступных подходов.

ответ

827

Этот link может быть вам полезен, так как он детализирует и использует Haversine formula для расчета расстояния.

Выдержки:

Этот сценарий [в Javascript] вычисляет большой круг расстояния между двумя точками - то есть, кратчайшее расстояние по поверхности Земли - по формуле «гаверсинуса».

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) 
} 
+27

Учитывает ли этот расчет/метод, что Земля является сфероидом (а не идеальной сферой)? Первоначальный вопрос задал расстояние между точками на глобусе WGS84. Не уверен, насколько ошибка ползет, используя идеальную сферу, но я подозреваю, что это может быть довольно много в зависимости от того, где точки находятся на земном шаре, поэтому различие стоит иметь в виду. – redcalx 2011-11-08 08:33:38

+10

Формула Хаверсина не учитывает, что Земля является сфероидом, поэтому из-за этого вы получите некоторую ошибку. Не может быть гарантировано правильное значение более 0,5%. Тем не менее, это может быть или не быть приемлемым уровнем ошибки. – Brandon 2011-12-28 16:20:25

+2

Обернул логику в функцию, поэтому ее можно использовать в JS из коробки, фактически используя это в NodeJS сейчас ... – Tracker1 2012-12-13 00:55:28

5

Это скорее зависит, насколько точно вы хотите быть и что datum лат и долго определяются на. Очень, очень приблизительно вы делаете небольшой сферический тригг, но исправляя тот факт, что земля не является сферой, формулы усложняют.

3

Чтобы рассчитать расстояние между двумя точками на шаре, вам необходимо сделать Great Circle calculation.

Существует несколько библиотек C/C++, которые помогут с проекцией карты на MapTools, если вам нужно перепроверить свои расстояния до плоской поверхности. Для этого вам понадобится проекционная строка различных систем координат.

Вы также можете найти MapWindow полезный инструмент для визуализации точек. Кроме того, как его открытый источник, это полезное руководство по использованию библиотеки proj.dll, которая, как представляется, является основной библиотекой проекций с открытым исходным кодом.

56

Вот C# Реализация:

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

Вы используете экваториальный радиус, но вы должны использовать средний радиус, который равен 6371 км. – 2009-07-10 12:18:21

+7

Не должно быть «double dlon = Radians (lon2 - lon1)» и «double dlat = Radians» (lat2 - lat1) ; ` – 2010-01-15 15:40:33

+0

Я согласен с Крисом Марис. Я использовал оригинальный код, и вычисления были неправильными. Я добавил призыв преобразовать дельты в радианы, и теперь он работает правильно. Я представил изменение и ожидаю, что он будет рассмотрен экспертом. – 2011-12-04 04:53:28

41

Большое спасибо за все это. Я использовал следующий код в моем приложении Objective-C iPhone:

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

широты и долготы в десятичной системе. Я не использовал min() для вызова asin(), поскольку расстояния, которые я использую, настолько малы, что они не требуют этого.

Он дал неправильные ответы, пока я не перешел в значении в радианах - теперь это почти так же, как и значение, полученное из приложения карты от Apple :-)

Дополнительного обновление:

Если вы используете iOS4 или более поздней версии, то Apple, предоставить некоторые методы, чтобы сделать это так же функциональность может быть достигнута:

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

    MKMapPoint start, finish; 


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

    return MKMetersBetweenMapPoints(start, finish)/1000; 
} 
1

Got error- нет Метод «toRad»

Таким образом модифицирована вышеописанную процедуру для вызова toRad

ме-
toRad(lat2-lat1) 

Math.cos(toRad(lat1)) 

и добавил

ме-
//degrees to radians 
function toRad(degree) 
{ 
    rad = degree* Math.PI/ 180; 
    return rad; 
} 
23

я выкладываю здесь мой рабочий пример.

Список всех точек в таблице, имеющих расстояние между назначенной точкой (мы используем случайную точку - лат: 45.20327, long: 23.7806) меньше 50 км, с широтой & долгота, в MySQL (поля таблицы - координаты_коля и координаты):

Список все имеющие РАССТОЯНИЕ < 50, в километрах (радиус Земли считаются 6371 км):

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 

Приведенный выше пример был протестирован в MySQL 5.0.95 и 5.5.16 (Linux).

31

Это простая функция PHP, которая даст очень разумное приближение (под +/- 1% погрешностью).

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

Как указано ранее; Земля НЕ является сферой. Это похоже на старый старый бейсбол, с которым Марк МакГвир решил попрактиковаться - он полон вмятин и ударов. Более простые вычисления (например, это) рассматривают его как сферу.

Различные методы могут быть более или менее точными в зависимости от того, где вы находитесь на этом нерегулярном яйце, И как далеко друг от друга ваши точки (чем ближе они, тем меньше абсолютная погрешность). Чем точнее ваше ожидание, тем сложнее математика.

Для получения дополнительной информации: wikipedia geographic distance

47

Вот реализация Java формулы Haversine.

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

Обратите внимание, что здесь мы округляем ответ до ближайшего километра.

0

Вот простой Javascript функция, которая может быть полезна в этом link .. как-то связаны, но мы используем Google Планета Земля Javascript плагин вместо карт

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

Блоки Тхо не являются на расстоянии, но с точки зрения отношение относительно ваших координат.Есть другие вычисления, связанные вы можете заменить на getApproximateDistanceUnits функционировать link here

Затем я использую эту функцию, чтобы увидеть, если широта и долгота находится в пределах радиуса

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

точка может быть определена как

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

, то вы можете сделать свое дело, чтобы узнать, находится ли точка в пределах области с радиусом:

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

     } 
1

есть хороший пример здесь, чтобы вычислить расстояние с 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; 
    } 
} 
1

Вот реализация VB.NET, эта реализация даст вам результат в КМ или Миль на основе значения Enum вы передаете ,

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 
2

Я сократил вычисление, упростив формулу.

Здесь в 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 
7

Вы можете использовать построить в CLLocationDistance вычислить это:

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

В вашем случае, если вы хотите километры просто разделить на 1000.

6

Хаверсин, безусловно, хорошая формула, вероятно, в большинстве случаев, другие ответы уже включают его, поэтому я не собираюсь занимать пространство. Но важно отметить, что независимо от того, какая формула используется (да, не только одна). Из-за огромного диапазона возможной точности, а также требуемого времени вычисления. Выбор формулы требует немного больше мысли, чем простой простой ответ.

Это сообщение от человека, в НАСА, является одним из лучших я нашел в обсуждении вариантов

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

Например, если вы только сортировка строк с расстоянием в радиусе 100 миль. Формула плоской земли будет намного быстрее, чем хаверсин.

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; 

Обратите внимание, что существует только один косинус и один квадратный корень. Vs 9 из них по формуле Хаверсина.

0
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, действительное для миль также.

226

Мне нужно было рассчитать множество расстояний между точками моего проекта, поэтому я пошел и попытался оптимизировать код, который я нашел здесь. В среднем в разных браузерах моя новая реализация работает в 2 раза быстрее, чем самый лучший ответ.

function distance(lat1, lon1, lat2, lon2) { 
    var p = 0.017453292519943295; // Math.PI/180 
    var c = Math.cos; 
    var a = 0.5 - c((lat2 - lat1) * p)/2 + 
      c(lat1 * p) * c(lat2 * p) * 
      (1 - c((lon2 - lon1) * p))/2; 

    return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km 
} 

Вы можете играть с моим JSPerf и увидеть results here.

Недавно мне нужно сделать то же самое в питоне, так вот реализация по питона:

from math import cos, asin, sqrt 
def distance(lat1, lon1, lat2, lon2): 
    p = 0.017453292519943295  #Pi/180 
    a = 0.5 - cos((lat2 - lat1) * p)/2 + cos(lat1 * p) * cos(lat2 * p) * (1 - cos((lon2 - lon1) * p))/2 
    return 12742 * asin(sqrt(a)) #2*R*asin... 

И для полноты картины: Haversine на вики.

1

Вот моя реализация java для вычисления расстояния через десятичные градусы после некоторого поиска. Я использовал средний радиус мира (из Википедии) в км. Если вы хотите получить мили, то используйте радиус мира в милях.

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

В других ответах отсутствует реализация в .

Расчет расстояния между двумя точками довольно просто с distm функции из geosphere пакета:

distm(p1, p2, fun = distHaversine) 

где:

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

Поскольку земля не идеально сферическими, Vincenty formula for ellipsoids, вероятно, лучший способ рассчитать расстояния. Таким образом, в geosphere пакете используется тогда:

distm(p1, p2, fun = distVincentyEllipsoid) 

Off Конечно, вы не обязательно должны использовать geosphere пакет, вы также можете рассчитать расстояние в базе R с функцией:

hav.dist <- function(long1, lat1, long2, lat2) { 
    R <- 6371 
    diff.long <- (long2 - long1) 
    diff.lat <- (lat2 - lat1) 
    a <- sin(diff.lat/2)^2 + cos(lat1) * cos(lat2) * sin(diff.long/2)^2 
    c <- 2 * asin(pmin(1, sqrt(a))) 
    d = R * c 
    return(d) 
} 
1

В Mysql используйте следующую функцию, передав параметры с использованием 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; 
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; 
    } 
5

Мне не нравится добавлять еще один ответ, но API карт Google v.3 имеет сферическую геометрию (и многое другое). После конвертирования WGS84 в десятичных градусах вы можете сделать это:

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

Нет слов о том, как точные расчеты Google являются или даже какая модель используется (хотя это не сказать «сферический», а не «геоид» Кстати. , расстояние «прямой линии», очевидно, будет отличаться от расстояния, если вы путешествуете по поверхности земли, что, по-видимому, предполагается, что все считают.

0

Я создал этот небольшой объект Javascript LatLng, может быть полезен для кто-либо.

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

Код:

/** 
* 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; 
    } 
}; 
0

Если бы проблема с math.deg в LUA ... если кто-нибудь знает, исправление, пожалуйста, очистить этот код!

А пока это реализация Haversine в LUA (используйте это с 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 

ура!

1
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(position1.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} 
)); 
2

Python implimentation Origin является центром смежных Соединенных Штатов.

from haversine import haversine 
origin = (39.50, 98.35) 
paris = (48.8567, 2.3508) 
haversine(origin, paris, miles=True) 

Чтобы получить ответ в килограммах, просто установите мили = false.

2

Вот принятая реализация ответа, перенесенная на Java, в случае, если это кому-то понадобится.

package com.project529.garage.util; 


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

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

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

    return d; 
} 

public double toRadians(double degrees) { 
    return degrees * (Math.PI/180); 
} 
3

Вот машинописи реализации формулы Haversine

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

Там может быть более простым решением, и правильнее: Периметр земли 40,000Km на экваторе, около 37000 на Гринвич (или любой долгота). Таким образом:

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

Я согласен, что это должно быть доработаны, как я сам сказал, что это эллипсоид, поэтому радиус следует умножить на косинус изменяется. Но это немного более точно. По сравнению с Google Maps, и это значительно уменьшило ошибку.

2

Все приведенные выше ответы предполагают, что земля является сферой. Тем не менее, более точное приближение будет иметь вид сплющенного сфероида.

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=R*math.cos(lat1)*math.cos(lons1) 
    y1=R*math.cos(lat1)*math.sin(lons1) 
    z1=R*math.sin(lat1) 

    lat2=math.radians(lat2) 
    lons2=math.radians(lons2) 
    R1=(((((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=R*math.cos(lat2)*math.cos(lons2) 
    y2=R*math.cos(lat2)*math.sin(lons2) 
    z2=R*math.sin(lat2) 

    return ((x1-x2)**2+(y1-y2)**2+(z1-z2)**2)**0.5 
0

вот пример в Postgres Sql (в км, для миль версии, замените 1.609344 на 0.8684 версии)

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

Этот сценарий [в PHP] вычисляет расстояния между двумя точками.

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

Вот еще превращали в рубин код:

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