Thu, 30 Jul 2020 21:52:31 +0300
destination processing
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) | |
2 | 36 | if 'boundary' in result: |
37 | shape = [nodes[ref] for ref in shape[:-1]] | |
38 | choose_shapes(result, result['boundary']).append(Polygon(*shape)) | |
39 | return result | |
1 | 40 | |
41 | def parse_boundaries(root, *, nodes): | |
42 | for child in root: | |
43 | if child.tag == 'way': | |
44 | way = parse_way(child, nodes = nodes) | |
45 | if way: | |
46 | yield way | |
47 | ||
48 | def parse_regions(filename): | |
49 | from katakana import transliterate as transliterate_katakana | |
50 | tree = ElementTree.parse(filename) | |
51 | root = tree.getroot() | |
52 | nodes = parse_nodes(root) | |
53 | regions = dict() | |
54 | extra_shapes = list() | |
55 | for way in parse_boundaries(root, nodes = nodes): | |
2 | 56 | if 'boundary' in way and 'ref' in way: |
1 | 57 | # defines a region |
58 | way['via_factor'] = int(way.get('via_factor', 1)) | |
2 | 59 | if way['ref'] in regions: |
1 | 60 | raise ValueError(str.format( |
2 | 61 | 'Region {ref} defined twice', |
62 | ref = repr(way['ref']), | |
1 | 63 | )) |
2 | 64 | regions[way['ref']] = way |
1 | 65 | del way['boundary'] |
66 | if 'external' in way: | |
67 | way['boundary'] = 'minor_region' | |
68 | for prefix in ['', 'short_', 'internal_']: | |
2 | 69 | name_key = prefix + 'name:fi' |
70 | ja_name_key = prefix + 'name:ja' | |
71 | if name_key in way and way[name_key] and ja_name_key not in way: | |
72 | way[ja_name_key] = transliterate_katakana(way[name_key]) | |
1 | 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 |