두 위도 경도 지점 사이의 거리를 계산 하시겠습니까? (Haversine 공식)


905

위도와 경도로 지정된 두 점 사이의 거리를 어떻게 계산합니까?

명확히하기 위해 거리를 킬로미터 단위로 원합니다. 요점은 WGS84 시스템을 사용하며 사용 가능한 접근 방식의 상대적 정확성을 이해하고 싶습니다.


정확성을
높이려면

3
WGS 84와 같은 회전 타원체에는 Haversine 공식을 적용 할 수 없습니다.이 방법은 반지름이있는 구에만 적용 할 수 있습니다.
Mike T

3
여기에있는 대부분의 답변은 단순한 구형 삼각법을 사용하므로 GPS 시스템에서 사용되는 WGS84 타원체 거리와 비교하여 결과가 다소 조잡합니다. 일부 답변은 타원체에 대한 Vincenty의 공식에 관한 것이지만 그 알고리즘은 1960 년대의 데스크 계산기에서 사용하도록 설계되었으며 안정성 및 정확성 문제가 있습니다. 우리는 지금 더 나은 하드웨어와 소프트웨어를 가지고 있습니다. 다양한 언어로 구현 된 고품질 라이브러리는 GeographicLib 를 참조하십시오 .
PM 2Ring

@MikeT-여기에 많은 대답 이 작은 거리에서도 유용하게 보이지만 사실입니다 .WGS 84에서 위도 / 경도를 가져 와서 Haversine 구체의 점 처럼 적용 하면 오류로 인한 오류가 발생하지 않습니다. 지구의 평탄화 요인, 아마도 더 정확한 공식의 1 % 이내일까요? 단거리 내에서 거리가 멀다는 경고가 있습니다.
ToolmakerSteve

1
이러한 플랫폼의 경우 : Mono / .NET 4.5 / .NET Core / Windows Phone 8.x / Universal Windows 플랫폼 / Xamarin iOS / Xamarin Android는 stackoverflow.com/a/54296314/2736742
A. Morel

답변:


1145

링크 는 거리 계산에 Haversine 공식 사용을 자세히 설명하므로 도움이 될 수 있습니다 .

발췌 :

이 스크립트 [Javascript]는 'Haversine'공식을 사용하여 두 점 사이의 원거리, 즉 지표면에서 가장 짧은 거리를 계산합니다.

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

51
이 계산 / 방법은 지구가 구면체 (완전한 구체가 아님)를 설명합니까? 원래의 질문은 WGS84 지구상의 점들 사이의 거리를 요구했습니다. 완벽한 구를 사용하여 오류가 얼마나 많이 발생하는지 확실하지 않지만 지구상의 지점에 따라 상당히 많은 오차가있을 수 있으므로 그 차이를 고려해야합니다.
redcalx

15
Haversine 공식은 지구가 타원체라고 설명하지 않으므로 그 사실로 인해 약간의 오류가 발생합니다. 0.5 %보다 나은 정확성을 보장 할 수는 없습니다. 그래도 허용 가능한 수준의 오류 일 수도 있고 아닐 수도 있습니다.
Brandon

24
Math.atan2(Math.sqrt(a), Math.sqrt(1-a))대신 Math.asin(Math.sqrt(h))Wikipedia 기사에서 사용하는 수식을 직접 구현하는 대신 사용할 이유 가 있습니까? 더 효율적이고 수치 적으로 안정적입니까?
musiphil

16
@UsmanMutawakil 글쎄, 당신이 얻는 38 마일은 도로에서 거리입니다. 이 알고리즘은 지구 표면의 직선 거리를 계산합니다. Google지도에는 동일한 거리 도구 (왼쪽 하단, '실험실')가 있으며이를 사용하여 비교합니다.
파스칼

4
@ Forte_201092 : 그 필요하지 않기 때문에 - 같은 (sin(x))²등호(sin(-x))²
진 Hominal

359

프로젝트의 포인트 사이의 거리를 많이 계산해야했기 때문에 코드를 최적화하려고했습니다. 다른 브라우저에서 평균적으로 새로운 구현 가장 많이 응답 된 답변보다 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로 게임을하고 결과를 확인할 수 있습니다 .

최근에는 파이썬에서 동일한 작업을 수행해야 했으므로 다음은 파이썬 구현입니다 .

from math import cos, asin, sqrt, pi

def distance(lat1, lon1, lat2, lon2):
    p = 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 .


13
@AngularM과 직선이 아닌 도로를 타면 Google이 거리를 계산할 가능성이 높습니다.
살바도르 달리

3
구글은 운전 거리를 계산, 이것은 "까마귀 비행으로"계산
Hobbyist

4
@Ouadie 그리고 그것은 속도를 향상시킬 것인가? 대부분의 아마 아니,하지만 난 많은 끝낼 것 '물건이 작동하지 않음'오래된 브라우저를 CopyPaste에 사람들을위한
살바도르 달리

4
그래,하지만 무엇을 // 2 * R; R = 6371 km의미 하는가? 현재 방법은 km 또는 마일로 답변을 제공합니까? 더 나은 문서가 필요합니다. 감사합니다
Khalil Khalaf

20
@KhalilKhalaf 당신은 농담 또는 여기 트롤을하려고합니까? km는 킬로미터를 나타냅니다. R이 무엇을 의미한다고 생각합니까 (특히 우리가 슈퍼에 대해 말하면)? km를 이미 본다면 어떤 단위로 답이 될지 추측하십시오. 여기서 어떤 종류의 문서를 찾고 있습니까? 문자 그대로 4 줄이 있습니다.
살바도르 달리

69

다음은 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;
    }

}

14
적도 반경을 사용하고 있지만 평균 반경 인
6371km를 사용해야합니다.

7
이 안 double dlon = Radians(lon2 - lon1);double dlat = Radians(lat2 - lat1);
크리스 Marisic에게

Chris Marisic에 동의합니다. 원래 코드를 사용했으며 계산이 잘못되었습니다. 델타를 라디안으로 변환하라는 호출을 추가했으며 이제 제대로 작동합니다. 수정 사항을 제출했으며 동료 검토를 기다리고 있습니다.
Bryan Bedard

lat1 및 lat2도 라디안으로 변환해야하기 때문에 다른 편집을 제출했습니다. 나는 또한 공식을 일치하도록에 할당의 수식을 개정 코드는 여기에서 찾을 : movable-type.co.uk/scripts/latlong.html
브라이언 베다드

않는 RADIUS다른 답변에서와 같이 6371을 할 수있는 값이 필요?
Chris Hayes

66

Haversine 공식의 Java 구현은 다음과 같습니다.

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

여기서 우리는 답을 가장 가까운 km로 반올림합니다.


2
두 점 사이의 거리를 미터 단위로 계산하려면 더 정확한 방법은 무엇입니까? 6371000지구의 반지름으로 사용하려면 ? (평균 지구 반경은 6371000 미터) 또는 함수에서 킬로미터를 미터로 변환 하시겠습니까?
마이크로

당신은 마일, 여러 결과에 의해하려는 경우0.621371
lasec0203

42

이 모든 것에 대해 대단히 감사합니다. 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;
}

위도와 경도는 10 진수입니다. asin () 호출에 min ()을 사용하지 않았습니다. 사용하는 거리가 너무 작아서 필요하지 않기 때문입니다.

Radians의 값을 전달할 때까지 잘못된 답변을 제공했습니다. 이제 Apple의 Map 앱에서 얻은 값과 거의 동일합니다. :-)

추가 업데이트 :

iOS4 이상을 사용하는 경우 Apple은이를 수행하는 몇 가지 방법을 제공하므로 다음과 같은 기능을 수행 할 수 있습니다.

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

    MKMapPoint  start, finish;


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

    return MKMetersBetweenMapPoints(start, finish) / 1000;
}


괄호 pow(sin(dlat / 2), 2) + cos(convertToRadians(place1.latitude))가 잘못 되었다고 생각합니다 . 그것들을 제거하면 결과는이 페이지에서 다른 구현을 사용할 때 얻는 것과 일치하거나 Wikipedia 의 Haversine 수식 을 처음부터 구현합니다 .
zanedp 2018 년

NYC의 좌표 (40.7127837, -74.0059413) 및 LA의 경우 (34.052234, -118.243685)를 사용하면 그 ()주위에 3869.75가됩니다. 그것들이 없으면 웹 검색이 나타나는 3935.75를 얻습니다.
zanedp

40

이것은 매우 합리적인 근사치 (+/- 1 % 오류 한계)를 제공하는 간단한 PHP 함수입니다.

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


4
이것은 완벽하게 작동합니다! 방금 $ distance_miles = $ km * 0.621371; 그리고 그것이 대략 마일 거리에 필요한 전부입니다! 고마워 토니.

31

나는 여기에 작업 예제를 게시합니다.

MySQL에서 위도 및 경도와 함께 50KM 미만의 지정된 점 사이의 거리를 갖는 테이블의 모든 점을 나열합니다 (임의의 점-위도 : 45.20327, 긴 : 23.7806) (테이블 필드는 coord_lat 및 coord_long).

킬로미터에서 거리가 50 미만인 모든 것을 나열하십시오 (지구 반경 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

위의 예제는 MySQL 5.0.95 및 5.5.16 (Linux)에서 테스트되었습니다.


좋은 접근 방식은 근사를 사용하여 결과를 사전 필터링하는 것일 수 있으므로 무거운 수식은 일부 경우에만 적용됩니다. 다른 조건이있는 경우 특히 유용합니다. 나는 이것을 초기 에이프 록스에 사용하고있다 : stackoverflow.com/questions/1253499/…
Pato

28

다른 답변에서 구현 누락.

두 점 사이의 거리를 계산하는 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 공식 은 아마도 거리를 계산하는 가장 좋은 방법 일 것입니다. 따라서 geosphere패키지 에서 다음을 사용하십시오.

distm(p1, p2, fun = distVincentyEllipsoid)

물론 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
  b <- 2 * asin(pmin(1, sqrt(a))) 
  d = R * b
  return(d)
}

내가 말한 것을 분명히하기 위해 : 포스트의 끝에 줄 코드 : 그것은 Vincenty 공식의 구현입니까? 아시다시피 지구권에서 Vincenty에게 전화하는 것과 같은 대답을해야합니까? [지구 나 다른 도서관이 없습니다. 크로스 플랫폼 앱에 포함시킬 코드를 찾고 있습니다. 물론 잘 알려진 계산기에 대해 몇 가지 테스트 사례를 확인하려고합니다.]
ToolmakerSteve

1
@ToolmakerSteve 내 대답 끝에 함수는 Haversine 방법의 구현입니다.
Jaap

안녕하세요 @Jaap 수식의 측정 단위가 무엇인지 물어볼 수 있습니까? 미터 단위입니까?
잭슨

11

haversine은 아마도 대부분의 경우에 좋은 공식입니다. 다른 답변에는 이미 포함되어 있으므로 공간을 차지하지 않을 것입니다. 그러나 어떤 수식을 사용하든 (예 하나가 아니라) 유의해야합니다. 필요한 계산 시간뿐만 아니라 가능한 넓은 범위의 정확도로 인해. 공식을 선택하려면 단순한 무 정답보다 조금 더 많은 생각이 필요합니다.

NASA의 사람이 게시 한이 옵션을 논의 할 때 찾은 최고의 것입니다

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;

하나의 코사인과 하나의 제곱근이 있습니다. Haversine 공식에 대한 9 대.


좋은 가능성입니다. 토론에서 권장되는 최대 거리는 100이 아니라 12 마일이며 지구 위치에 따라 최대 30 미터 (100 피트)까지 오차가 발생할 수 있습니다.
Eric Wu

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으로 나누려면.


7

또 다른 답변을 추가하는 것을 좋아하지 않지만 Google Maps API 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));

구글의 계산이 얼마나 정확한지, 심지어 어떤 모델이 사용되는지에 대해서는 아무 말도하지 않는다. 모든 사람들이 추정하는 지구 표면.


거리는 미터입니다. 다른 방법 하나는 computeLength는 ()를 사용할 수 있습니다
electrobabe

7

파이썬 함축 기원은 인접한 미국의 중심입니다.

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

킬로미터 단위로 답을 얻으려면 단순히 miles = false를 설정하십시오.


1
모든 작업을 수행하는 비표준 패키지를 가져오고 있습니다. 그게 다 유용한 지 모르겠습니다.
Teepeemm

패키지는 PyPI, Python Package Index에 numpy 및 scikit-learn과 함께 Python 3 패키지로 제공됩니다. 왜 패키지에 적용되는지 확실하지 않습니다. 그들은 매우 유용한 경향이 있습니다. 오픈 소스로서 포함 된 메소드를 검사 할 수도 있습니다. 나는 많은 사람들이이 패키지가 유용하다고 생각하므로 downvote에도 불구하고 게시물을 남길 것입니다. 건배. :)
inshelltheshell

7

더 간단한 해결책과 더 정확한 방법이있을 수 있습니다. 지구의 둘레는 적도에서 40,000Km이며 그리니치 (또는 경도)주기에서 약 37,000입니다. 그러므로:

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지도와 비교하여 오류가 크게 줄었습니다.


이 함수는 거리를 킬로미터 단위로 반환합니까?
Wikki

적도와 경도주기가 Km이기 때문입니다. 마일의 경우 40000과 37000을 1.6으로 나눕니다. 괴짜를 느끼면, 그것을 Ris, multiplyung로 약 7로 바꾸거나 parasang으로 변환 할 수 있습니다. 2.2 ;-)
Meymann

이것은 여기에 제공된 최고의 답변 인 것 같습니다. 사용하고 싶지만이 알고리즘의 정확성을 확인할 수있는 방법이 있는지 궁금합니다. 나는 f (50,5,58,3)를 테스트했습니다. 반면, 그것은 832km 제공 movable-type.co.uk/scripts/latlong.html '하버 사인'수식 899km를 제공하여. 큰 차이가 있습니까?
종 립 팡

또한 위의 코드에서 반환 된 값은 km가 아니라 m 단위라고 생각합니다.
Chong Lip Phang

@ChongLipPhang-주의 : 피타고라스 정리는 지구가 평평하다고 가정하기 때문에 작은 지역에 대해서만 합리적인 근사치 입니다 . 극단적 인 경우, 적도에서 시작하여 동쪽으로 90도, 북쪽으로 90도 이동하십시오. 물론 최종 결과는 북극이며 0도 동쪽과 90도 북쪽으로 움직이는 것과 같습니다. 따라서 sqrt (sqr (dx) + sqr (dy))를 수행하면 첫 번째 경우에 크게 벗어납니다. ~ sqrt (10km sqr + 10km sqr) ~ = 14.4km vs 정확한 거리 ~ 10km.
ToolmakerSteve

7

위의 모든 대답은 지구가 구체라고 가정합니다. 그러나,보다 정확한 근사치는 편원 구형의 근사치 일 것입니다.

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

6

다음은 km 단위의 거리를 계산하는 SQL 구현입니다.

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;

langugage를 프로그래밍하여 구현에 대한 자세한 내용을 보려면 여기에 제공된 PHP 스크립트를 사용 하십시오.


5

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

5

지적한 바와 같이, 정확한 계산은 지구가 완벽한 구체가 아니라는 점을 고려해야합니다. 여기에 제공된 다양한 알고리즘을 비교 한 것입니다.

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

먼 거리에서 Keerthana의 알고리즘은 Google Maps의 알고리즘과 일치하는 것 같습니다. Google지도는 간단한 알고리즘을 따르지 않는 것 같습니다. 여기에서 가장 정확한 방법 일 수 있습니다.

어쨌든 다음은 Keerthana 알고리즘의 Javascript 구현입니다.

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

4

이 스크립트 (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;
        }
    }

4

Haversine 공식 에 따른 Java 구현

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
}

3

구의 두 점 사이의 거리를 계산하려면 Great Circle 계산 을 수행해야합니다 .

거리를 평평한 표면으로 재 투영해야하는 경우 MapTools 에서지도 투영에 도움이되는 여러 C / C ++ 라이브러리가 있습니다. 이렇게하려면 다양한 좌표계의 투영 문자열이 필요합니다.

당신은 또한 찾을 수 있습니다 MapWindow에게 포인트를 시각화하는 유용한 도구. 또한 오픈 소스로서 핵심 오픈 소스 프로젝션 라이브러리로 보이는 proj.dll 라이브러리를 사용하는 방법에 대한 유용한 안내서입니다.


3

다음은 누구나 필요로하는 경우 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);
}

2

다음은 VB.NET 구현입니다.이 구현은 전달한 Enum 값을 기반으로 KM 또는 마일 단위로 결과를 제공합니다.

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

"a"를 계산할 때 실수로 Math.Sin ( dLat ..)을 두 번 썼 습니까?
Marco Ottina

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

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

척의 솔루션, 마일에도 유효합니다.


2

다음은 일부 검색 후 십진도를 통한 계산 거리에 대한 Java 구현입니다. 나는 wikipedia에서 세계의 평균 반경을 km 단위로 사용했습니다. 결과 마일을 원하면 세계 반경을 마일 단위로 사용하십시오.

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

2

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;

2
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

다음은 postgres sql 의 예입니다 (km 단위의 경우 km 단위로 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;

2

다음은 또 다른 Ruby 코드 로 변환 된 것입니다 .

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

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;
     }
 }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.