regions.py

changeset 1
f9788970fa46
child 2
7378b802ddf8
equal deleted inserted replaced
0:659ab465152e 1:f9788970fa46
1 #!/usr/bin/env python3
2 from xml.etree import ElementTree
3 from geometry import *
4
5 REGION_TYPES = ['major', 'minor']
6 REGION_KEY_VALUES = [x + '_region' for x in REGION_TYPES]
7 SHAPE_KEYS = [x + '_shapes' for x in REGION_TYPES]
8
9 def parse_nodes(root):
10 nodes = {}
11 for child in root:
12 if child.tag == 'node':
13 lat, lon = float(child.attrib['lat']), float(child.attrib['lon'])
14 nodes[child.attrib['id']] = Location(lat, lon)
15 return nodes
16
17 def parse_way(way, nodes):
18 def choose_shapes(way, boundary):
19 return (way['major_shapes']
20 if boundary == 'major_region'
21 else way['minor_shapes'])
22 result = {'minor_shapes': [], 'major_shapes': []}
23 shape = []
24 for child in way:
25 if child.tag == 'nd':
26 shape.append(child.attrib['ref'])
27 elif child.tag == 'tag':
28 key = child.attrib['k']
29 if key in SHAPE_KEYS:
30 raise ValueError(str.format('tag "{}" is not allowed', key))
31 result[key] = child.attrib['v']
32 if key == 'boundary' and result['boundary'] not in REGION_KEY_VALUES:
33 return None # we're not interested in it!
34 if shape[-1] != shape[0]:
35 raise ValueError('polygon is not closed: %r' % result)
36 if 'boundary' not in result:
37 raise ValueError('polygon not tagged as a boundary: %r' % result)
38 shape = [nodes[ref] for ref in shape[:-1]]
39 choose_shapes(result, result['boundary']).append(Polygon(*shape))
40 return result
41
42 def parse_boundaries(root, *, nodes):
43 for child in root:
44 if child.tag == 'way':
45 way = parse_way(child, nodes = nodes)
46 if way:
47 yield way
48
49 def parse_regions(filename):
50 from katakana import transliterate as transliterate_katakana
51 tree = ElementTree.parse(filename)
52 root = tree.getroot()
53 nodes = parse_nodes(root)
54 regions = dict()
55 extra_shapes = list()
56 for way in parse_boundaries(root, nodes = nodes):
57 if 'boundary' in way and way['boundary'] != 'subregion' and 'name' in way:
58 # defines a region
59 way['via_factor'] = int(way.get('via_factor', 1))
60 if way['name'] in regions:
61 raise ValueError(str.format(
62 'Region {name} defined twice',
63 name = repr(way['name']),
64 ))
65 regions[way['name']] = way
66 del way['boundary']
67 if 'external' in way:
68 way['boundary'] = 'minor_region'
69 for prefix in ['', 'short_', 'internal_']:
70 name_key = prefix + 'name'
71 if name_key in way and way[name_key] and name_key + ':ja' not in way:
72 way[name_key + ':ja'] = transliterate_katakana(way[name_key])
73 elif 'boundary' in way and 'is_in' in way:
74 # adds an extra shape to an existing region
75 extra_shapes.append(way)
76 for extra_shape in extra_shapes:
77 name = extra_shape['is_in']
78 try:
79 region = regions[name]
80 except KeyError:
81 raise ValueError(str.format(
82 'Extra shape refers to {name} which was not found: {extra_shape}',
83 name = repr(name),
84 extra_shape = repr(extra_shape),
85 ))
86 for key in SHAPE_KEYS:
87 region[key].extend(extra_shape[key])
88 return regions

mercurial