Wed, 29 Jul 2020 23:45:53 +0300
begin work on bus compiler
1 | 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 |