|
1
|
|
|
import re |
|
2
|
|
|
from math import acos, cos, pi, radians, sin |
|
3
|
|
|
|
|
4
|
|
|
|
|
5
|
|
|
R = 6371 |
|
6
|
|
|
|
|
7
|
|
|
|
|
8
|
|
|
def extract_position(position_str): |
|
9
|
|
|
items = re.search('(\d+)\D(\d+)\D(\d+)\D(\w)', position_str).groups() |
|
10
|
|
|
if 'W' in position_str or 'S' in position_str: |
|
11
|
|
|
return radians( |
|
12
|
|
|
-(int(items[0]) * 3600 + int(items[1]) * 60 + int(items[2])) / 3600.0 |
|
13
|
|
|
) |
|
14
|
|
|
return radians((int(items[0]) * 3600 + int(items[1]) * 60 + int(items[2])) / 3600.0) |
|
15
|
|
|
|
|
16
|
|
|
|
|
17
|
|
|
def distance(first, second): |
|
18
|
|
|
if len(first.split()) == 2: |
|
19
|
|
|
first = first.split() |
|
20
|
|
|
else: |
|
21
|
|
|
first = first.split(',') |
|
22
|
|
|
if len(second.split()) == 2: |
|
23
|
|
|
second = second.split() |
|
24
|
|
|
else: |
|
25
|
|
|
second = second.split(',') |
|
26
|
|
|
first_latitude, first_longitude, second_latitude, second_longitude = map( |
|
27
|
|
|
extract_position, first + second |
|
28
|
|
|
) |
|
29
|
|
|
direct_distance = sin(first_latitude) * sin(second_latitude) + cos( |
|
30
|
|
|
first_latitude |
|
31
|
|
|
) * cos(second_latitude) * cos(first_longitude - second_longitude) |
|
32
|
|
|
if acos(direct_distance) == 0: |
|
33
|
|
|
return pi * R |
|
34
|
|
|
return round(R * acos(direct_distance), 1) |
|
35
|
|
|
|
|
36
|
|
|
|
|
37
|
|
|
if __name__ == '__main__': |
|
38
|
|
|
# These "asserts" using only for self-checking and not necessary for |
|
39
|
|
|
# auto-testing |
|
40
|
|
|
def almost_equal(checked, correct, significant_digits=1): |
|
41
|
|
|
precision = 0.1 ** significant_digits |
|
42
|
|
|
return correct - precision < checked < correct + precision |
|
43
|
|
|
|
|
44
|
|
|
assert almost_equal( |
|
45
|
|
|
distance(u"51°28′48″N 0°0′0″E", u"46°12′0″N, 6°9′0″E"), 739.2 |
|
46
|
|
|
), "From Greenwich to Geneva" |
|
47
|
|
|
assert almost_equal( |
|
48
|
|
|
distance(u"90°0′0″N 0°0′0″E", u"90°0′0″S, 0°0′0″W"), 20015.1 |
|
49
|
|
|
), "From South to North" |
|
50
|
|
|
assert almost_equal( |
|
51
|
|
|
distance(u"33°51′31″S, 151°12′51″E", u"40°46′22″N 73°59′3″W"), 15990.2 |
|
52
|
|
|
), "Opera Night" |
|
53
|
|
|
distance(u"48°27′0″N,34°59′0″E", u"15°47′56″S 47°52′0″W") |
|
54
|
|
|
|