- Notifications
You must be signed in to change notification settings - Fork 46.7k
/
Copy pathhaversine_distance.py
58 lines (49 loc) · 2.34 KB
/
haversine_distance.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
frommathimportasin, atan, cos, radians, sin, sqrt, tan
AXIS_A=6378137.0
AXIS_B=6356752.314245
RADIUS=6378137
defhaversine_distance(lat1: float, lon1: float, lat2: float, lon2: float) ->float:
"""
Calculate great circle distance between two points in a sphere,
given longitudes and latitudes https://en.wikipedia.org/wiki/Haversine_formula
We know that the globe is "sort of" spherical, so a path between two points
isn't exactly a straight line. We need to account for the Earth's curvature
when calculating distance from point A to B. This effect is negligible for
small distances but adds up as distance increases. The Haversine method treats
the earth as a sphere which allows us to "project" the two points A and B
onto the surface of that sphere and approximate the spherical distance between
them. Since the Earth is not a perfect sphere, other methods which model the
Earth's ellipsoidal nature are more accurate but a quick and modifiable
computation like Haversine can be handy for shorter range distances.
Args:
* `lat1`, `lon1`: latitude and longitude of coordinate 1
* `lat2`, `lon2`: latitude and longitude of coordinate 2
Returns:
geographical distance between two points in metres
>>> from collections import namedtuple
>>> point_2d = namedtuple("point_2d", "lat lon")
>>> SAN_FRANCISCO = point_2d(37.774856, -122.424227)
>>> YOSEMITE = point_2d(37.864742, -119.537521)
>>> f"{haversine_distance(*SAN_FRANCISCO, *YOSEMITE):0,.0f} meters"
'254,352 meters'
"""
# CONSTANTS per WGS84 https://en.wikipedia.org/wiki/World_Geodetic_System
# Distance in metres(m)
# Equation parameters
# Equation https://en.wikipedia.org/wiki/Haversine_formula#Formulation
flattening= (AXIS_A-AXIS_B) /AXIS_A
phi_1=atan((1-flattening) *tan(radians(lat1)))
phi_2=atan((1-flattening) *tan(radians(lat2)))
lambda_1=radians(lon1)
lambda_2=radians(lon2)
# Equation
sin_sq_phi=sin((phi_2-phi_1) /2)
sin_sq_lambda=sin((lambda_2-lambda_1) /2)
# Square both values
sin_sq_phi*=sin_sq_phi
sin_sq_lambda*=sin_sq_lambda
h_value=sqrt(sin_sq_phi+ (cos(phi_1) *cos(phi_2) *sin_sq_lambda))
return2*RADIUS*asin(h_value)
if__name__=="__main__":
importdoctest
doctest.testmod()