Recursively calculate centers of all relations
This commit is contained in:
parent
1b0888c6f0
commit
9b74358c1b
2 changed files with 72 additions and 57 deletions
119
subway_io.py
119
subway_io.py
|
@ -39,58 +39,81 @@ def load_xml(f):
|
|||
elements.append(el)
|
||||
element.clear()
|
||||
|
||||
|
||||
ways = {} # id(int) => (lat, lon)
|
||||
relations = {} # id(int) => (lat, lon)
|
||||
empty_relations = set() # ids(int) of relations without members
|
||||
# or containing only empty relations
|
||||
|
||||
def calculate_way_center(el):
|
||||
center = [0, 0]
|
||||
count = 0
|
||||
for nd in el['nodes']:
|
||||
if nd in nodes:
|
||||
center[0] += nodes[nd][0]
|
||||
center[1] += nodes[nd][1]
|
||||
count += 1
|
||||
if count > 0:
|
||||
el['center'] = {'lat': center[0]/count, 'lon': center[1]/count}
|
||||
ways[el['id']] = (el['center']['lat'], el['center']['lon'])
|
||||
return True
|
||||
return False
|
||||
|
||||
def calculate_relation_center(el):
|
||||
center = [0, 0]
|
||||
count = 0
|
||||
for m in el.get('members', []):
|
||||
if m['type'] == 'relation' and m['ref'] not in relations:
|
||||
if m['ref'] in empty_relations:
|
||||
# Ignore empty child relations
|
||||
continue
|
||||
else:
|
||||
# Center of child relation is not known yet
|
||||
return False
|
||||
member_container = (nodes if m['type'] == 'node' else
|
||||
ways if m['type'] == 'way' else
|
||||
relations)
|
||||
if m['ref'] in member_container:
|
||||
center[0] += member_container[m['ref']][0]
|
||||
center[1] += member_container[m['ref']][1]
|
||||
count += 1
|
||||
if count == 0:
|
||||
empty_relations.add(el['id'])
|
||||
else:
|
||||
el['center'] = {'lat': center[0] / count, 'lon': center[1] / count}
|
||||
relations[el['id']] = (el['center']['lat'], el['center']['lon'])
|
||||
return True
|
||||
|
||||
relations_without_center = []
|
||||
|
||||
# Now make centers, assuming relations go after ways
|
||||
ways = {}
|
||||
relations = {}
|
||||
for el in elements:
|
||||
if el['type'] == 'way' and 'nodes' in el:
|
||||
center = [0, 0]
|
||||
count = 0
|
||||
for nd in el['nodes']:
|
||||
if nd in nodes:
|
||||
center[0] += nodes[nd][0]
|
||||
center[1] += nodes[nd][1]
|
||||
count += 1
|
||||
if count > 0:
|
||||
el['center'] = {'lat': center[0]/count, 'lon': center[1]/count}
|
||||
ways[el['id']] = (el['center']['lat'], el['center']['lon'])
|
||||
elif el['type'] == 'relation' and 'members' in el:
|
||||
center = [0, 0]
|
||||
count = 0
|
||||
for m in el['members']:
|
||||
if m['type'] == 'node' and m['ref'] in nodes:
|
||||
center[0] += nodes[m['ref']][0]
|
||||
center[1] += nodes[m['ref']][1]
|
||||
count += 1
|
||||
elif m['type'] == 'way' and m['ref'] in ways:
|
||||
center[0] += ways[m['ref']][0]
|
||||
center[1] += ways[m['ref']][1]
|
||||
count += 1
|
||||
if count > 0:
|
||||
el['center'] = {'lat': center[0]/count, 'lon': center[1]/count}
|
||||
relations[el['id']] = (el['center']['lat'], el['center']['lon'])
|
||||
calculate_way_center(el)
|
||||
elif el['type'] == 'relation':
|
||||
if not calculate_relation_center(el):
|
||||
relations_without_center.append(el)
|
||||
|
||||
# Iterating again, now filling relations that contain only relations
|
||||
for el in elements:
|
||||
if el['type'] == 'relation' and 'members' in el:
|
||||
center = [0, 0]
|
||||
count = 0
|
||||
for m in el['members']:
|
||||
if m['type'] == 'node' and m['ref'] in nodes:
|
||||
center[0] += nodes[m['ref']][0]
|
||||
center[1] += nodes[m['ref']][1]
|
||||
count += 1
|
||||
elif m['type'] == 'way' and m['ref'] in ways:
|
||||
center[0] += ways[m['ref']][0]
|
||||
center[1] += ways[m['ref']][1]
|
||||
count += 1
|
||||
elif m['type'] == 'relation' and m['ref'] in relations:
|
||||
center[0] += relations[m['ref']][0]
|
||||
center[1] += relations[m['ref']][1]
|
||||
count += 1
|
||||
if count > 0:
|
||||
el['center'] = {'lat': center[0]/count, 'lon': center[1]/count}
|
||||
relations[el['id']] = (el['center']['lat'], el['center']['lon'])
|
||||
# Calculate centers for relations that have no one yet
|
||||
while relations_without_center:
|
||||
new_relations_without_center = []
|
||||
for rel in relations_without_center:
|
||||
if not calculate_relation_center(rel):
|
||||
new_relations_without_center.append(rel)
|
||||
if len(new_relations_without_center) == len(relations_without_center):
|
||||
break
|
||||
relations_without_center = new_relations_without_center
|
||||
|
||||
if relations_without_center:
|
||||
logging.error("Cannot calculate center for the relations (%d in total): %s%s",
|
||||
len(relations_without_center),
|
||||
', '.join(str(rel['id']) for rel in relations_without_center[:20]),
|
||||
", ..." if len(relations_without_center) > 20 else "")
|
||||
if empty_relations:
|
||||
logging.warning("Empty relations (%d in total): %s%s",
|
||||
len(empty_relations),
|
||||
', '.join(str(x) for x in list(empty_relations)[:20]),
|
||||
", ..." if len(empty_relations) > 20 else "")
|
||||
return elements
|
||||
|
||||
|
||||
|
|
|
@ -51,12 +51,6 @@ def el_center(el):
|
|||
if 'lat' in el:
|
||||
return (el['lon'], el['lat'])
|
||||
elif 'center' in el:
|
||||
if el['center']['lat'] == 0.0:
|
||||
# Some relations don't have centers. We need route_masters and stop_area_groups.
|
||||
if el['type'] == 'relation' and 'tags' in el and (
|
||||
el['tags'].get('type') == 'route_master' or
|
||||
el['tags'].get('public_transport') == 'stop_area_group'):
|
||||
return None
|
||||
return (el['center']['lon'], el['center']['lat'])
|
||||
return None
|
||||
|
||||
|
@ -1071,9 +1065,7 @@ class City:
|
|||
if center:
|
||||
return (self.bbox[0] <= center[1] <= self.bbox[2] and
|
||||
self.bbox[1] <= center[0] <= self.bbox[3])
|
||||
if 'tags' not in el:
|
||||
return False
|
||||
return 'route_master' in el['tags'] or 'public_transport' in el['tags']
|
||||
return False
|
||||
|
||||
def add(self, el):
|
||||
if el['type'] == 'relation' and 'members' not in el:
|
||||
|
|
Loading…
Add table
Reference in a new issue