compute_regions.py

changeset 1
f9788970fa46
child 2
7378b802ddf8
equal deleted inserted replaced
0:659ab465152e 1:f9788970fa46
1 #!/usr/bin/env python3
2 import sys, json
3 from misc import *
4 from geometry import *
5 from configparser import ConfigParser
6
7 class Blockmap:
8 '''
9 The blockmap is a grid of latitude and longitude lines and models
10 a block -> set relation. A block is a latitude and longitude square.
11 '''
12 block_size = 200.0 # How big are blocks?
13 def __init__(self, blocks = None):
14 from collections import defaultdict
15 self.blocks = blocks or defaultdict(set)
16 def __getitem__(self, blockid):
17 '''
18 Returns a block for block coordinates. The block is a set that can
19 contain anything.
20 '''
21 return self.blocks[blockid]
22 def blockpoint(self, point):
23 '''
24 Returns blockmap coordinates for geographical coordinates.
25 The blockmap coordinates refer to a block in the blockmap.
26 '''
27 block_coordinate = lambda x: int(x * self.block_size)
28 return block_coordinate(point.x), block_coordinate(point.y)
29
30 def blocks_in_shape(blockmap, shape):
31 '''
32 Finds all blocks inside the bounding box of a shape.
33 '''
34 from itertools import product
35 min_x, max_x = minmax(point.x for point in shape.points)
36 min_y, max_y = minmax(point.y for point in shape.points)
37 min_blockpoint = blockmap.blockpoint(Location(min_x, min_y))
38 max_blockpoint = blockmap.blockpoint(Location(max_x, max_y))
39 range_x = range(min_blockpoint[0], max_blockpoint[0] + 1)
40 range_y = range(min_blockpoint[1], max_blockpoint[1] + 1)
41 yield from (blockmap[x, y] for x, y in product(range_x, range_y))
42
43 def create_blockmap(regions):
44 '''
45 Creates a blockmap of regions
46 '''
47 blockmap = Blockmap()
48 for region in regions.values():
49 # Minor shapes contain major shapes, so just use those
50 for shape in (region['minor_shapes'] or region['major_shapes']):
51 for block in blocks_in_shape(blockmap, shape):
52 set.add(block, region['name'])
53 return blockmap
54
55 def get_args():
56 from argparse import ArgumentParser
57 parser = ArgumentParser()
58 parser.add_argument('gtfs_zip')
59 parser.add_argument('profile')
60 return parser.parse_args()
61
62 def test_shapes(shapes, point):
63 return any(shape.contains_point(point) for shape in shapes)
64
65 class RegionalLocation:
66 def __init__(self, *, region, region_class):
67 self.region, self.region_class = region, region_class
68 def __repr__(self):
69 return str.format(
70 'RegionalLocation(region = {region}, region_class = {region_class})',
71 region = repr(self.region),
72 region_class = repr(self.region_class),
73 )
74
75 def locate_regionally(position, region):
76 if test_shapes(region['major_shapes'], position):
77 return RegionalLocation(region = region['name'], region_class = 'major')
78 elif test_shapes(region['minor_shapes'], position):
79 return RegionalLocation(region = region['name'], region_class = 'minor')
80 else:
81 return None
82
83 def find_region_for_point(position, regions, blockmap):
84 for region_name in blockmap[blockmap.blockpoint(position)]:
85 region = regions[region_name]
86 classification = locate_regionally(position, region)
87 if classification:
88 return classification
89
90 class RegionTester:
91 def __init__(self, regions):
92 self.regions = regions
93 self.blockmap = create_blockmap(regions)
94 def __call__(self, latitude, longitude):
95 return find_region_for_point(
96 position = Location(float(latitude), float(longitude)),
97 regions = self.regions,
98 blockmap = self.blockmap,
99 )

mercurial