source: subversion/applications/rendering/mapnik/generate_tiles_multiprocess.py @ 34655

Last change on this file since 34655 was 29155, checked in by mazdermind, 7 years ago

allow bigger buffer-sizes to be specified in xml

  • Property svn:executable set to *
File size: 7.6 KB
Line 
1#!/usr/bin/env python
2from math import pi,cos,sin,log,exp,atan
3from subprocess import call
4import sys, os
5import multiprocessing
6
7try:
8    import mapnik2 as mapnik
9except:
10    import mapnik
11
12DEG_TO_RAD = pi/180
13RAD_TO_DEG = 180/pi
14
15# Default number of rendering threads to spawn, should be roughly equal to number of CPU cores available
16NUM_THREADS = 4
17
18
19def minmax (a,b,c):
20    a = max(a,b)
21    a = min(a,c)
22    return a
23
24class GoogleProjection:
25    def __init__(self,levels=18):
26        self.Bc = []
27        self.Cc = []
28        self.zc = []
29        self.Ac = []
30        c = 256
31        for d in range(0,levels):
32            e = c/2;
33            self.Bc.append(c/360.0)
34            self.Cc.append(c/(2 * pi))
35            self.zc.append((e,e))
36            self.Ac.append(c)
37            c *= 2
38               
39    def fromLLtoPixel(self,ll,zoom):
40         d = self.zc[zoom]
41         e = round(d[0] + ll[0] * self.Bc[zoom])
42         f = minmax(sin(DEG_TO_RAD * ll[1]),-0.9999,0.9999)
43         g = round(d[1] + 0.5*log((1+f)/(1-f))*-self.Cc[zoom])
44         return (e,g)
45     
46    def fromPixelToLL(self,px,zoom):
47         e = self.zc[zoom]
48         f = (px[0] - e[0])/self.Bc[zoom]
49         g = (px[1] - e[1])/-self.Cc[zoom]
50         h = RAD_TO_DEG * ( 2 * atan(exp(g)) - 0.5 * pi)
51         return (f,h)
52
53
54
55class RenderThread:
56    def __init__(self, tile_dir, mapfile, q, printLock, maxZoom):
57        self.tile_dir = tile_dir
58        self.q = q
59        self.mapfile = mapfile
60        self.maxZoom = maxZoom
61        self.printLock = printLock
62
63    def render_tile(self, tile_uri, x, y, z):
64        # Calculate pixel positions of bottom-left & top-right
65        p0 = (x * 256, (y + 1) * 256)
66        p1 = ((x + 1) * 256, y * 256)
67
68        # Convert to LatLong (EPSG:4326)
69        l0 = self.tileproj.fromPixelToLL(p0, z);
70        l1 = self.tileproj.fromPixelToLL(p1, z);
71
72        # Convert to map projection (e.g. mercator co-ords EPSG:900913)
73        c0 = self.prj.forward(mapnik.Coord(l0[0],l0[1]))
74        c1 = self.prj.forward(mapnik.Coord(l1[0],l1[1]))
75
76        # Bounding box for the tile
77        if hasattr(mapnik,'mapnik_version') and mapnik.mapnik_version() >= 800:
78            bbox = mapnik.Box2d(c0.x,c0.y, c1.x,c1.y)
79        else:
80            bbox = mapnik.Envelope(c0.x,c0.y, c1.x,c1.y)
81        render_size = 256
82        self.m.resize(render_size, render_size)
83        self.m.zoom_to_box(bbox)
84        if(self.m.buffer_size < 128):
85            self.m.buffer_size = 128
86
87        # Render image with default Agg renderer
88        im = mapnik.Image(render_size, render_size)
89        mapnik.render(self.m, im)
90        im.save(tile_uri, 'png256')
91
92
93    def loop(self):
94       
95        self.m = mapnik.Map(256, 256)
96        # Load style XML
97        mapnik.load_map(self.m, self.mapfile, True)
98        # Obtain <Map> projection
99        self.prj = mapnik.Projection(self.m.srs)
100        # Projects between tile pixel co-ordinates and LatLong (EPSG:4326)
101        self.tileproj = GoogleProjection(self.maxZoom+1)
102               
103        while True:
104            #Fetch a tile from the queue and render it
105            r = self.q.get()
106            if (r == None):
107                self.q.task_done()
108                break
109            else:
110                (name, tile_uri, x, y, z) = r
111
112            exists= ""
113            if os.path.isfile(tile_uri):
114                exists= "exists"
115            else:
116                self.render_tile(tile_uri, x, y, z)
117            bytes=os.stat(tile_uri)[6]
118            empty= ''
119            if bytes == 103:
120                empty = " Empty Tile "
121            self.printLock.acquire()
122            print name, ":", z, x, y, exists, empty
123            self.printLock.release()
124            self.q.task_done()
125
126
127
128def render_tiles(bbox, mapfile, tile_dir, minZoom=1,maxZoom=18, name="unknown", num_threads=NUM_THREADS):
129    print "render_tiles(",bbox, mapfile, tile_dir, minZoom,maxZoom, name,")"
130
131    # Launch rendering threads
132    queue = multiprocessing.JoinableQueue(32)
133    printLock = multiprocessing.Lock()
134    renderers = {}
135    for i in range(num_threads):
136        renderer = RenderThread(tile_dir, mapfile, queue, printLock, maxZoom)
137        render_thread = multiprocessing.Process(target=renderer.loop)
138        render_thread.start()
139        #print "Started render thread %s" % render_thread.getName()
140        renderers[i] = render_thread
141
142    if not os.path.isdir(tile_dir):
143         os.mkdir(tile_dir)
144
145    gprj = GoogleProjection(maxZoom+1) 
146
147    ll0 = (bbox[0],bbox[3])
148    ll1 = (bbox[2],bbox[1])
149
150    for z in range(minZoom,maxZoom + 1):
151        px0 = gprj.fromLLtoPixel(ll0,z)
152        px1 = gprj.fromLLtoPixel(ll1,z)
153
154        # check if we have directories in place
155        zoom = "%s" % z
156        if not os.path.isdir(tile_dir + zoom):
157            os.mkdir(tile_dir + zoom)
158        for x in range(int(px0[0]/256.0),int(px1[0]/256.0)+1):
159            # Validate x co-ordinate
160            if (x < 0) or (x >= 2**z):
161                continue
162            # check if we have directories in place
163            str_x = "%s" % x
164            if not os.path.isdir(tile_dir + zoom + '/' + str_x):
165                os.mkdir(tile_dir + zoom + '/' + str_x)
166            for y in range(int(px0[1]/256.0),int(px1[1]/256.0)+1):
167                # Validate x co-ordinate
168                if (y < 0) or (y >= 2**z):
169                    continue
170                str_y = "%s" % y
171                tile_uri = tile_dir + zoom + '/' + str_x + '/' + str_y + '.png'
172                # Submit tile to be rendered into the queue
173                t = (name, tile_uri, x, y, z)
174                queue.put(t)
175
176    # Signal render threads to exit by sending empty request to queue
177    for i in range(num_threads):
178        queue.put(None)
179    # wait for pending rendering jobs to complete
180    queue.join()
181    for i in range(num_threads):
182        renderers[i].join()
183
184
185
186if __name__ == "__main__":
187       
188    home = os.environ['HOME']
189    try:
190        mapfile = os.environ['MAPNIK_MAP_FILE']
191    except KeyError:
192        mapfile = home + "/svn.openstreetmap.org/applications/rendering/mapnik/osm-local.xml"
193    try:
194        tile_dir = os.environ['MAPNIK_TILE_DIR']
195    except KeyError:
196        tile_dir = home + "/osm/tiles/"
197
198    if not tile_dir.endswith('/'):
199        tile_dir = tile_dir + '/'
200
201    #-------------------------------------------------------------------------
202    #
203    # Change the following for different bounding boxes and zoom levels
204    #
205    # Start with an overview
206    # World
207    bbox = (-180.0,-90.0, 180.0,90.0)
208
209    render_tiles(bbox, mapfile, tile_dir, 0, 5, "World")
210
211    minZoom = 10
212    maxZoom = 16
213    bbox = (-2, 50.0,1.0,52.0)
214    render_tiles(bbox, mapfile, tile_dir, minZoom, maxZoom)
215
216    # Muenchen
217    bbox = (11.4,48.07, 11.7,48.22)
218    render_tiles(bbox, mapfile, tile_dir, 1, 12 , "Muenchen")
219
220    # Muenchen+
221    bbox = (11.3,48.01, 12.15,48.44)
222    render_tiles(bbox, mapfile, tile_dir, 7, 12 , "Muenchen+")
223
224    # Muenchen++
225    bbox = (10.92,47.7, 12.24,48.61)
226    render_tiles(bbox, mapfile, tile_dir, 7, 12 , "Muenchen++")
227
228    # Nuernberg
229    bbox=(10.903198,49.560441,49.633534,11.038085)
230    render_tiles(bbox, mapfile, tile_dir, 10, 16, "Nuernberg")
231
232    # Karlsruhe
233    bbox=(8.179113,48.933617,8.489252,49.081707)
234    render_tiles(bbox, mapfile, tile_dir, 10, 16, "Karlsruhe")
235
236    # Karlsruhe+
237    bbox = (8.3,48.95,8.5,49.05)
238    render_tiles(bbox, mapfile, tile_dir, 1, 16, "Karlsruhe+")
239
240    # Augsburg
241    bbox = (8.3,48.95,8.5,49.05)
242    render_tiles(bbox, mapfile, tile_dir, 1, 16, "Augsburg")
243
244    # Augsburg+
245    bbox=(10.773251,48.369594,10.883834,48.438577)
246    render_tiles(bbox, mapfile, tile_dir, 10, 14, "Augsburg+")
247
248    # Europe+
249    bbox = (1.0,10.0, 20.6,50.0)
250    render_tiles(bbox, mapfile, tile_dir, 1, 11 , "Europe+")
Note: See TracBrowser for help on using the repository browser.