-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathadd-dist.py
114 lines (94 loc) · 3.21 KB
/
add-dist.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
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
import json
import sys
import re
import csv
from math import acos, sin, cos, pi
iata_city_to_lat_lon = {}
with open('airports.dat') as fp:
airports = csv.reader(fp)
for info in airports:
iata_city = info[4]
lat = float(info[6])
lon = float(info[7])
iata_city_to_lat_lon[iata_city] = (lat, lon)
# special case LHR because we really want LCY
iata_city_to_lat_lon["LHR"] = iata_city_to_lat_lon["LCY"]
instances = []
with open('instances.txt') as fp:
for line in fp:
instances.append(line.strip())
def node_name_to_iata_city(node_name):
# this is the CloudFlare format - so simple!
if len(node_name) == 3:
return node_name.upper()
# this is the CIRA ANY.CA-SERVERS.CA mapping of HOSTNAME.BIND
m = re.search(r'^ns\d\d.([a-z]{3}).ca-servers.ca$', node_name, re.I)
if m:
city = m.group(1).upper()
# special case MTL because the Canadians really mean YUL
if city == "MTL":
city = "YUL"
return city
return None
def great_circle_dist(lat1, lon1, lat2, lon2):
# convert to radians because math
lon1 = lon1 * pi / 180
lat1 = lat1 * pi / 180
lon2 = lon2 * pi / 180
lat2 = lat2 * pi / 180
# maths!
theta = lon2 - lon1
dist = acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(theta))
if (dist < 0):
dist = dist + pi
dist = dist * 6371.2
return dist
all_fixed_json = []
result_total = 0
result_good = 0
for measurement in json.load(sys.stdin):
result_total += 1
fixed_json = measurement.copy()
try:
node_name = fixed_json["result"]["answers"][0]["RDATA"]
except KeyError:
if not 'error' in fixed_json:
print("No result", file=sys.stderr)
print(fixed_json, file=sys.stderr)
continue
result_good += 1
iata_city = node_name_to_iata_city(node_name)
if iata_city not in iata_city_to_lat_lon:
print(iata_city)
print('Missing latitude/longitude for "{}"'.format(node_name),
file=sys.stderr)
sys.exit(1)
fixed_json["dst_city"] = iata_city
lat1, lon1 = iata_city_to_lat_lon[iata_city]
lat2 = fixed_json["latitude"]
lon2 = fixed_json["longitude"]
del fixed_json["latitude"]
del fixed_json["longitude"]
fixed_json["dst_lat"] = lat1
fixed_json["dst_lon"] = lon1
fixed_json["src_lat"] = lat2
fixed_json["src_lon"] = lon2
# this is the distance used
actual_dist = great_circle_dist(lat1, lon1, lat2, lon2)
fixed_json["dist"] = actual_dist
# also figure out all possible distances
best_dist = actual_dist
for instance in instances:
lat1, lon1 = iata_city_to_lat_lon[instance]
dist = great_circle_dist(lat1, lon1, lat2, lon2)
fixed_json["dist_" + instance] = dist
best_dist = min(best_dist, dist)
# best distance
fixed_json["dist_theoretical"] = best_dist
fixed_json["dist_theoretical_improvement"] = actual_dist - best_dist
all_fixed_json.append(json.dumps(fixed_json, indent=2, sort_keys=True))
print("[")
print(",\n".join(all_fixed_json))
print("]")
print("Total results: {}".format(result_total), file=sys.stderr)
print("Good results: {}".format(result_good), file=sys.stderr)