Python의 Haversine 공식 (두 GPS 지점 사이의 방향 및 거리)


119

문제

2 개의 GPS 지점 사이거리와 방위 를 확인하는 방법을 알고 싶습니다 . 나는 haversine 공식에 대해 연구했습니다. 누군가 저에게 동일한 데이터를 사용하여 베어링을 찾을 수 있다고 말했습니다.

편집하다

모든 것이 잘 작동하지만 베어링은 아직 제대로 작동하지 않습니다. 베어링 출력은 음수이지만 0-360도 사이 여야합니다. 세트 데이터는 수평 방위를 만들어야하며 96.02166666666666 다음과 같습니다.

Start point: 53.32055555555556 , -1.7297222222222221   
Bearing:  96.02166666666666  
Distance: 2 km  
Destination point: 53.31861111111111, -1.6997222222222223  
Final bearing: 96.04555555555555

내 새 코드는 다음과 같습니다.

from math import *

Aaltitude = 2000
Oppsite  = 20000

lat1 = 53.32055555555556
lat2 = 53.31861111111111
lon1 = -1.7297222222222221
lon2 = -1.6997222222222223

lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
Base = 6371 * c


Bearing =atan2(cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1), sin(lon2-lon1)*cos(lat2)) 

Bearing = degrees(Bearing)
print ""
print ""
print "--------------------"
print "Horizontal Distance:"
print Base
print "--------------------"
print "Bearing:"
print Bearing
print "--------------------"


Base2 = Base * 1000
distance = Base * 2 + Oppsite * 2 / 2
Caltitude = Oppsite - Aaltitude

a = Oppsite/Base
b = atan(a)
c = degrees(b)

distance = distance / 1000

print "The degree of vertical angle is:"
print c
print "--------------------"
print "The distance between the Balloon GPS and the Antenna GPS is:"
print distance
print "--------------------"

Python haversine 구현은 codecodex.com/wiki/… 에서 찾을 수 있습니다 . 그러나 단거리 계산의 경우 매우 간단한 방법이 있습니다. 이제 예상되는 최대 거리는 얼마입니까? 일부 지역 데카르트 좌표계에서 좌표를 얻을 수 있습니까?
2013


1
@James Dyson : 15km와 같은 거리에서 creat circle은 아무 것도 계산하지 않습니다. 내 제안 : 먼저 유클리드 거리에 대한 해결책을 찾으십시오! 그러면 작업 솔루션이 제공되고 나중에 거리가 훨씬 길어지면 응용 프로그램을 조정하십시오. 감사합니다
식사

1
@James Dyson : 위의 의견이 저를 겨냥한 경우 (그리고 이전 제안에 대한 것이라면) 대답은 확실히 (그리고 아주 '사소한'것입니다). 몇 가지 예제 코드를 제공 할 수는 있지만 삼각법보다는 기하학을 사용하지 않을 것입니다 (그래서 이것이 도움이 될지 확신 할 수 없습니다. 벡터 개념에 전혀 익숙합니까? 귀하의 경우 위치 및 방향은 벡터로 가장 간단하게 처리 할 수 ​​있습니다).
먹을

1
atan2(sqrt(a), sqrt(1-a))과 동일asin(sqrt(a))
user102008

답변:


241

다음은 Python 버전입니다.

from math import radians, cos, sin, asin, sqrt

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    """
    # convert decimal degrees to radians 
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 
    r = 6371 # Radius of earth in kilometers. Use 3956 for miles
    return c * r

10
pi / 180을 곱하는 대신 math.radians () 함수를 사용할 수 있습니다-동일한 효과이지만 좀 더 자체 문서화입니다.
Hugh Bothwell

4
당신이 말한다면 당신은 할 수 있지만, import math당신은 지정해야합니다 math.pi, math.sin함께 등 from math import *모든 모듈의 내용에 직접 액세스 할 수 있습니다. Python 자습서 (예 : docs.python.org/tutorial/modules.html ) 에서 "네임 스페이스"를 확인하십시오.
Michael Dunn

2
asin (sqrt (a)) 대신 atan2 (sqrt (a), sqrt (1-a))를 사용하는 이유는 무엇입니까? 이 경우 atan2가 더 정확합니까?
Eyal

4
평균 지구 반경이 6371km로 정의되면 3956 마일이 아니라 3959 마일에 해당합니다. 이러한 값을 계산하는 다양한 방법 은 글로벌 평균 반경 을 참조하십시오 .
ekhumoro

3
이 반환은 무엇입니까? 방위 또는 거리?
AesculusMaximus

11

이러한 답변의 대부분은 지구 반경을 "반올림"합니다. 다른 거리 계산기 (예 : geopy)와 비교하여 확인하면이 기능이 꺼집니다.

이것은 잘 작동합니다.

from math import radians, cos, sin, asin, sqrt

def haversine(lat1, lon1, lat2, lon2):

      R = 3959.87433 # this is in miles.  For Earth radius in kilometers use 6372.8 km

      dLat = radians(lat2 - lat1)
      dLon = radians(lon2 - lon1)
      lat1 = radians(lat1)
      lat2 = radians(lat2)

      a = sin(dLat/2)**2 + cos(lat1)*cos(lat2)*sin(dLon/2)**2
      c = 2*asin(sqrt(a))

      return R * c

# Usage
lon1 = -103.548851
lat1 = 32.0004311
lon2 = -103.6041946
lat2 = 33.374939

print(haversine(lat1, lon1, lat2, lon2))

2
이것은 위의 예보다 훨씬 더 정확합니다!
Alex van Es

이것은 극지방에서 R. 6356.752 km의 변화를 적도에서 6378.137 km로 변경하지 않습니다
ldmtwo

3
이 오류가 응용 프로그램에 정말 중요한가요? cs.nyu.edu/visual/home/proj/tiger/gisfaq.html
Tejas Kale

8

좌표에 스칼라 값 대신 4 개의 numpy 배열을 사용할 수 있는 벡터화 된 구현 도 있습니다 .

def distance(s_lat, s_lng, e_lat, e_lng):

   # approximate radius of earth in km
   R = 6373.0

   s_lat = s_lat*np.pi/180.0                      
   s_lng = np.deg2rad(s_lng)     
   e_lat = np.deg2rad(e_lat)                       
   e_lng = np.deg2rad(e_lng)  

   d = np.sin((e_lat - s_lat)/2)**2 + np.cos(s_lat)*np.cos(e_lat) * np.sin((e_lng - s_lng)/2)**2

   return 2 * R * np.arcsin(np.sqrt(d))

4

베어링 계산이 잘못되었습니다. 입력을 atan2로 바꿔야합니다.

    bearing = atan2(sin(long2-long1)*cos(lat2), cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(long2-long1))
    bearing = degrees(bearing)
    bearing = (bearing + 360) % 360

이것은 당신에게 정확한 방위를 줄 것입니다.


나는 실제로 논문을 읽는 동안 이러한 방정식이 어떻게 파생되었는지 이해하기 위해 고군분투하고 있습니다. 당신은 나에게 포인터를 주셨습니다. haversine formula처음으로 이것을 들었습니다. 감사합니다.
arilwan

4

다음을 시도 할 수 있습니다.

from haversine import haversine
haversine((45.7597, 4.8422),(48.8567, 2.3508), unit='mi')
243.71209416020253

장고의 ORM 쿼리에서 이것을 어떻게 사용할 수 있습니까?
Gocht

3

@Michael Dunn이 제공 한 Haversine 공식의 수많은 벡터화 된 구현은 큰 벡터에 비해 10 ~ 50 배 향상되었습니다.

from numpy import radians, cos, sin, arcsin, sqrt

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    """

    #Convert decimal degrees to Radians:
    lon1 = np.radians(lon1.values)
    lat1 = np.radians(lat1.values)
    lon2 = np.radians(lon2.values)
    lat2 = np.radians(lat2.values)

    #Implementing Haversine Formula: 
    dlon = np.subtract(lon2, lon1)
    dlat = np.subtract(lat2, lat1)

    a = np.add(np.power(np.sin(np.divide(dlat, 2)), 2),  
                          np.multiply(np.cos(lat1), 
                                      np.multiply(np.cos(lat2), 
                                                  np.power(np.sin(np.divide(dlon, 2)), 2))))
    c = np.multiply(2, np.arcsin(np.sqrt(a)))
    r = 6371

    return c*r

2

360 °를 추가하여 부정적인 베어링 문제를 해결할 수 있습니다. 불행히도 이것은 포지티브 베어링의 경우 360 °보다 큰 베어링이 될 수 있습니다. 이것은 모듈로 연산자에 대한 좋은 후보이므로 모두 다음 줄을 추가해야합니다.

Bearing = (Bearing + 360) % 360

당신의 방법의 끝에.


1
% 360 베어링 = 베어링 : 난 그냥 생각
홀거 Bille

1

atan2의 Y는 기본적으로 첫 번째 매개 변수입니다. 다음은 문서 입니다. 올바른 베어링 각도를 얻으려면 입력을 전환해야합니다.

bearing = atan2(sin(lon2-lon1)*cos(lat2), cos(lat1)*sin(lat2)in(lat1)*cos(lat2)*cos(lon2-lon1))
bearing = degrees(bearing)
bearing = (bearing + 360) % 360


0

다음은 이전 메시지의 코드와 https://gist.github.com/jeromer/2005586 (명확성을 위해 두 함수에 대해 위도, 경도 형식의 지리적 지점에 대한 튜플 유형 추가)을 기반으로 거리와 방위를 계산 하는 두 가지 함수입니다. ). 두 기능을 모두 테스트했는데 제대로 작동하는 것 같습니다.

#coding:UTF-8
from math import radians, cos, sin, asin, sqrt, atan2, degrees

def haversine(pointA, pointB):

    if (type(pointA) != tuple) or (type(pointB) != tuple):
        raise TypeError("Only tuples are supported as arguments")

    lat1 = pointA[0]
    lon1 = pointA[1]

    lat2 = pointB[0]
    lon2 = pointB[1]

    # convert decimal degrees to radians 
    lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2]) 

    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 
    r = 6371 # Radius of earth in kilometers. Use 3956 for miles
    return c * r


def initial_bearing(pointA, pointB):

    if (type(pointA) != tuple) or (type(pointB) != tuple):
        raise TypeError("Only tuples are supported as arguments")

    lat1 = radians(pointA[0])
    lat2 = radians(pointB[0])

    diffLong = radians(pointB[1] - pointA[1])

    x = sin(diffLong) * cos(lat2)
    y = cos(lat1) * sin(lat2) - (sin(lat1)
            * cos(lat2) * cos(diffLong))

    initial_bearing = atan2(x, y)

    # Now we have the initial bearing but math.atan2 return values
    # from -180° to + 180° which is not what we want for a compass bearing
    # The solution is to normalize the initial bearing as shown below
    initial_bearing = degrees(initial_bearing)
    compass_bearing = (initial_bearing + 360) % 360

    return compass_bearing

pA = (46.2038,6.1530)
pB = (46.449, 30.690)

print haversine(pA, pB)

print initial_bearing(pA, pB)

이 방법은 위의 다른 모든 방법과 다른 결과를 제공합니다!
바실리스크
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.