forked from CodeMouse92/DeadSimplePython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathglobal_coordinates.py
More file actions
120 lines (101 loc) · 3.65 KB
/
global_coordinates.py
File metadata and controls
120 lines (101 loc) · 3.65 KB
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from dis import dis
import math
class GlobalCoordinates:
def __init__(self, *, latitude, longitude):
self._lat_deg = latitude[0]
self._lat_min = latitude[1]
self._lat_sec = latitude[2]
self._lat_dir = latitude[3]
self._lon_deg = longitude[0]
self._lon_min = longitude[1]
self._lon_sec = longitude[2]
self._lon_dir = longitude[3]
@staticmethod
def degrees_from_decimal(dec, *, lat):
if lat:
direction = "S" if dec < 0 else "N"
else:
direction = "W" if dec < 0 else "E"
dec = abs(dec)
degrees = int(dec)
dec -= degrees
minutes = int(dec * 60)
dec -= minutes / 60
seconds = round(dec * 3600, 1)
return (degrees, minutes, seconds, direction)
@staticmethod
def decimal_from_degrees(degrees, minutes, seconds, direction):
dec = degrees + minutes / 60 + seconds / 3600
if direction == "S" or direction == "W":
dec = -dec
return round(dec, 6)
@property
def latitude(self):
return self.decimal_from_degrees(
self._lat_deg, self._lat_min, self._lat_sec, self._lat_dir
)
@property
def longitude(self):
return self.decimal_from_degrees(
self._lon_deg, self._lon_min, self._lon_sec, self._lon_dir
)
def __repr__(self):
return (
f"<GlobalCoordinates "
f"lat={self._lat_deg}°{self._lat_min}'"
f"{self._lat_sec}\"{self._lat_dir} "
f"lon={self._lon_deg}°{self._lon_min}'"
f"{self._lon_sec}\"{self._lon_dir}>"
)
def __str__(self):
return (
f"{self._lat_deg}°{self._lat_min}'"
f"{self._lat_sec}\"{self._lat_dir} "
f"{self._lon_deg}°{self._lon_min}'"
f"{self._lon_sec}\"{self._lon_dir}>"
)
def __hash__(self):
return hash((
self._lat_deg, self._lat_min, self._lat_sec, self._lat_dir,
self._lon_deg, self._lon_min, self._lon_sec, self._lon_dir
))
def __eq__(self, other):
if not isinstance(other, GlobalCoordinates):
return NotImplemented
return (
self._lat_deg == other._lat_deg
and self._lat_min == other._lat_min
and self._lat_sec == other._lat_sec
and self._lat_dir == other._lat_dir
and self._lon_deg == other._lon_deg
and self._lon_min == other._lon_min
and self._lon_sec == other._lon_sec
and self._lon_dir == other._lon_dir
)
def __sub__(self, other):
if not isinstance(other, GlobalCoordinates):
return NotImplemented
lat_diff = self.latitude - other.latitude
lon_diff = self.longitude - other.longitude
return (lat_diff, lon_diff)
def __invert__(self):
return GlobalCoordinates(
latitude=self.degrees_from_decimal(-self.latitude, lat=True),
longitude=self.degrees_from_decimal(-self.longitude, lat=False)
)
def __call__(self, other):
EARTH_RADIUS_KM = 6371
distance_lat = math.radians(other.latitude - self.latitude)
distance_lon = math.radians(other.longitude - self.longitude)
lat = math.radians(self.latitude)
lon = math.radians(self.longitude)
a = (
math.sin(distance_lat / 2)
* math.sin(distance_lat / 2)
+ math.sin(distance_lon)
* math.sin(distance_lon / 2)
* math.cos(lat)
* math.cos(lon)
)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
return c * EARTH_RADIUS_KM