-
Notifications
You must be signed in to change notification settings - Fork 9
/
ivtile
executable file
·115 lines (84 loc) · 4.69 KB
/
ivtile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env python
# Inspired by generate_tiles.py, part of the Open Street Map project:
# http://svn.openstreetmap.org/applications/rendering/mapnik/generate_tiles.py
import multiprocessing
import os
import invar
DEFAULT_MIN_ZOOM = 9
DEFAULT_MAX_ZOOM = 12
MAX_QUEUE_SIZE = 20000
class IVTile(invar.InvarUtility):
description = 'Render tiles for a given bounding box from a Mapnik2 XML configuration file.'
def add_arguments(self):
self.argparser.add_argument('lat_1', type=float, help="Most nortern latitude")
self.argparser.add_argument('lon_1', type=float, help="Most western longitude")
self.argparser.add_argument('lat_2', type=float, help="Most southern latitude")
self.argparser.add_argument('lon_2', type=float, help="Most eastern longitude")
self.argparser.add_argument('min_zoom', help="Minimum zoom level to render", type=int, default=DEFAULT_MIN_ZOOM)
self.argparser.add_argument('max_zoom', help="Maximum zoom level to render", type=int, default=DEFAULT_MAX_ZOOM)
self.argparser.add_argument('--grid', action="store_true", help="Force grid JSON to be rendered alongside each tile. If -k or -f options are provided, this is inferred and need not be specified.")
self.argparser.add_argument('--key', help="For grid rendering, the column in the associated dataset which is a unique ID for a feature. If not specified, will use mapnik default ('__id__')")
self.argparser.add_argument('--fields', help="For grid rendering, a comma separated list of fields associated with each feature which will be included in grid JSON.")
def main(self):
if not os.path.isdir(self.args.output_dir):
os.mkdir(self.args.output_dir)
tile_projection = invar.GoogleProjection(self.args.max_zoom)
ll0 = (self.args.lon_1, self.args.lat_1)
ll1 = (self.args.lon_2, self.args.lat_2)
tile_queues = []
tile_queue = multiprocessing.JoinableQueue(maxsize=MAX_QUEUE_SIZE)
tile_count = 0
for zoom in range(self.args.min_zoom, self.args.max_zoom + 1):
px0 = tile_projection.fromLLtoPixel(ll0, zoom)
px1 = tile_projection.fromLLtoPixel(ll1, zoom)
tile_x1 = int(px0[0] / 256.0)
tile_x2 = int(px1[0] / 256.0) + 1
tile_y1 = int(px0[1] / 256.0)
tile_y2 = int(px1[1] / 256.0) + 1
zoom_dir = os.path.join(self.args.output_dir, str(zoom))
if not os.path.isdir(zoom_dir):
os.mkdir(zoom_dir)
for tile_x in range(tile_x1, tile_x2):
# Validate x coordinate
if (tile_x < 0) or (tile_x >= 2 ** zoom):
continue
x_dir = os.path.join(zoom_dir, str(tile_x))
if not os.path.isdir(x_dir):
os.mkdir(x_dir)
for tile_y in range(tile_y1, tile_y2):
# Validate y coordinate
if (tile_y < 0) or (tile_y >= 2 ** zoom):
continue
filename = os.path.join(x_dir, '%s.png' % str(tile_y))
# Submit tile to be rendered into the queue
t = (filename, tile_x, tile_y, zoom)
# Because mulitprocessing.JoinableQueue has a fixed maxsize, we instantiate
# an array of such queues and fill them iteratively
if tile_count != 0 and (tile_count % MAX_QUEUE_SIZE) == 0:
tile_queues.append(tile_queue)
tile_queue = multiprocessing.JoinableQueue(maxsize=MAX_QUEUE_SIZE)
tile_queue.put(t)
tile_count += 1
# Append first (or last) queue to list
if (tile_count % MAX_QUEUE_SIZE) != 0:
tile_queues.append(tile_queue)
print 'Using %i processes to render %i tiles' % (self.args.process_count, tile_count)
processes = []
try:
fields = self.args.fields.split(",")
except:
fields = None
for i in range(self.args.process_count):
grid = (self.args.grid or self.args.fields or self.args.key)
renderer = invar.TileRenderer(self.args.output_dir, tile_queues, self.args.config, self.args.width, self.args.height, buffer_size=self.args.buffer, skip_existing=self.args.skip_existing, grid=grid, key=self.args.key, fields=fields)
renderer.start()
processes.append(renderer)
try:
for tile_queue in tile_queues:
tile_queue.join()
except KeyboardInterrupt:
for p in processes:
p.terminate()
if __name__ == "__main__":
ivtile = IVTile()
ivtile.main()