-
Notifications
You must be signed in to change notification settings - Fork 1
/
generators.py
213 lines (194 loc) · 7.3 KB
/
generators.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import context
import validator
import re
import rendering
from profiles.base.public_transport import PublicTransportProfile
from network import RouteNetwork
show_additional_tags = ['ref', 'colour', 'name']
def generate_index(profiles):
rendering.render('index.j2', context.custom_output_file_path('index.htm'), profiles=profiles)
def generate_relation_overview(n: RouteNetwork, p: PublicTransportProfile):
v = validator.Validator(n, p)
error_classes = {}
lines_tpl = []
for relation in sorted(n.relations.values(), key=get_sortkey):
rid, tags, members = relation
l = {}
l['osmid'] = rid
l["fixme"] = ""
for tag in ['type', 'route', 'route_master', 'note', 'fixme']:
l[tag] = tags[tag] if tag in tags else ""
for tag in show_additional_tags:
l[tag] = tags[tag] if tag in tags else ""
if "FIXME" in tags:
l["fixme"] += tags["FIXME"]
l['errors'] = v.validate_relation(relation)
for e in l["errors"]:
if e[0] not in error_classes:
error_classes[e[0]] = 1
else:
error_classes[e[0]] += 1
members = count_member_types(relation)
l['relations'] = members['relation']
l['ways'] = members['way']
l['nodes'] = members['node']
lines_tpl.append(l)
rendering.render('relations.j2', context.output_file_path(p), lines=lines_tpl, mtime=n.mtime, profile=p, additional_tags=show_additional_tags, error_classes=error_classes)
def generate_stop_plan(n: RouteNetwork, p: PublicTransportProfile):
# print list of stations of a route
# within the directions of a route the stations are identified by their name
# (which will cause problems in routes like M1 having "U Oranienburger Tor" 2 times)
lines = []
for relation in sorted(n.relations.values(), key=get_sortkey):
rid, tags, members = relation
if "type" not in tags or tags["type"] != "route_master" or "ref" not in tags:
continue
if not p.filter(relation):
continue
routes = filter(lambda m: m[0] in n.relations and m[1] == "relation", members)
routes = list(map(lambda m: n.relations[m[0]], routes))
pairs = []
for i in range(0, len(routes)):
if not "from" in routes[i][1] or not "to" in routes[i][1]:
continue
for j in range(i + 1, len(routes)):
if not "from" in routes[j][1] or not "to" in routes[j][1]:
continue
if routes[i][1]['from'] == routes[j][1]['to'] and routes[i][1]['to'] == routes[j][1]['from']:
pairs.append((routes[i], routes[j]))
if len(pairs) == 0:
# only output routes of route_masters that have matching from and to
continue
variations = []
for pair in pairs:
# get stops for each direction
rid1, tags1, members1 = pair[0]
stops1 = filter(lambda m: re.match(p.route_node_roles_pattern, m[2]), members1)
stops1 = list(map(lambda s: s[0], stops1))
rid2, tags2, members2 = pair[1]
stops2 = filter(lambda m: re.match(p.route_node_roles_pattern, m[2]), members2)
stops2 = list(map(lambda s: s[0], stops2))
stops2.reverse()
# collect names and changes for each direction
names1 = []
names2 = []
changes = {}
for s in stops1:
if s in n.nodes and n.nodes[s] != None:
nid, tags, coords= n.nodes[s]
if "name" in tags:
if tags["name"] not in names1:
names1.append(tags["name"])
if tags["name"] not in changes:
changes[tags["name"]] = []
for parent in n.parents[("node", nid)]:
if parent[0] != "relation":
continue
# TODO: check if not available?
r = n.relations[parent[1]]
if "ref" in r[1] and r[1]["ref"] != relation[1]["ref"] and r[1]["ref"] not in changes[tags["name"]]:
changes[tags["name"]].append(r[1]["ref"])
for s in stops2:
if s in n.nodes and n.nodes[s] != None:
nid, tags, coords= n.nodes[s]
if "name" in tags:
if tags["name"] not in names2:
names2.append(tags["name"])
if tags["name"] not in changes:
changes[tags["name"]] = []
for parent in n.parents[("node", nid)]:
if parent[0] != "relation":
continue
# TODO: check if not available?
r = n.relations[parent[1]]
if "ref" in r[1] and r[1]["ref"] != relation[1]["ref"] and r[1]["ref"] not in changes[tags["name"]]:
changes[tags["name"]].append(r[1]["ref"])
stops = []
i = 0;
j = 0;
while i < len(names1) or j < len(names2):
# TODO: logic correct??
if i == len(names1):
symbol = u"▲"
name = names2[j]
j += 1
elif j == len(names2):
symbol = u"▼"
name = names1[i]
i += 1
elif names1[i] == names2[j]:
symbol = u"●"
name = names1[i]
i += 1
j += 1
elif not names1[i] in names2:
symbol = u"▼"
name = names1[i]
i += 1
else:
symbol = u"▲"
name = names2[j]
j += 1
stops.append((symbol, name, changes[name]))
variations.append({
"from": pair[0][1]["from"],
"to": pair[0][1]["to"],
"ids": (pair[0][0], pair[1][0]),
"stops": stops
})
lines.append({
'id': rid,
'name': relation[1]['name'] if "name" in relation[1] else "",
'ref': relation[1]['ref'] if "ref" in relation[1] else "",
'variations': variations
})
rendering.render('routes.j2', context.output_file_path(p, '_lines'), lines=lines, mtime=n.mtime, profile=p)
def generate_network_map(n: RouteNetwork, p: PublicTransportProfile, mapkey):
lines = []
for relation in n.relations.values():
rid, tags, members = relation
if "type" not in tags or tags["type"] != "route":
# ignore route_master, only print individual routes
continue
if not p.maps[mapkey][1](relation):
continue
stations = []
for member in members:
mid, typ, role = member
if typ != "node" or not re.match(p.route_node_roles_pattern, role):
continue
if not mid in n.nodes or n.nodes[mid] == None:
# station hasn't been collected - probably not in pbf
continue
stations.append(n.nodes[mid])
lines.append([rid, tags, stations])
rendering.render('map.j2', context.output_file_path(p, '_map_' + mapkey), lines=lines, mtime=n.mtime, profile=p, mapkey=mapkey)
def count_member_types(relation):
# count how many members of each type the relation has
rid, tags, members = relation
types = {'relation': 0, 'node': 0, 'way': 0}
for member in members:
mid, typ, role = member
types[typ] += 1
return types
def get_sortkey(relation):
rid, tags, members = relation
key = ""
if "route_master" in tags:
key += tags["route_master"]
elif "route" in tags:
key += tags["route"]
key += "_"
if "ref" in tags:
ref = tags["ref"]
for number in set(re.findall("[0-9]+", ref)):
# append a lot of leading zeroes to each number
ref = ref.replace(number, "%010i" % int(number))
key += ref
key += "_"
if "type" in tags and tags["type"] == "route_master":
# for same refs put route_master at top
key += "0"
else:
key += "1"
return key