mirror of
https://github.com/openstreetmap/mapnik-stylesheets.git
synced 2025-07-24 09:57:57 +00:00

git-svn-id: http://svn.openstreetmap.org/applications/rendering/mapnik@29155 b9d5c4c9-76e1-0310-9c85-f3177eceb1e4
257 lines
7.8 KiB
Python
Executable File
257 lines
7.8 KiB
Python
Executable File
#!/usr/bin/env python
|
|
from math import pi,cos,sin,log,exp,atan
|
|
from subprocess import call
|
|
import sys, os
|
|
from Queue import Queue
|
|
|
|
import threading
|
|
|
|
try:
|
|
import mapnik2 as mapnik
|
|
except:
|
|
import mapnik
|
|
|
|
DEG_TO_RAD = pi/180
|
|
RAD_TO_DEG = 180/pi
|
|
|
|
# Default number of rendering threads to spawn, should be roughly equal to number of CPU cores available
|
|
NUM_THREADS = 4
|
|
|
|
|
|
def minmax (a,b,c):
|
|
a = max(a,b)
|
|
a = min(a,c)
|
|
return a
|
|
|
|
class GoogleProjection:
|
|
def __init__(self,levels=18):
|
|
self.Bc = []
|
|
self.Cc = []
|
|
self.zc = []
|
|
self.Ac = []
|
|
c = 256
|
|
for d in range(0,levels):
|
|
e = c/2;
|
|
self.Bc.append(c/360.0)
|
|
self.Cc.append(c/(2 * pi))
|
|
self.zc.append((e,e))
|
|
self.Ac.append(c)
|
|
c *= 2
|
|
|
|
def fromLLtoPixel(self,ll,zoom):
|
|
d = self.zc[zoom]
|
|
e = round(d[0] + ll[0] * self.Bc[zoom])
|
|
f = minmax(sin(DEG_TO_RAD * ll[1]),-0.9999,0.9999)
|
|
g = round(d[1] + 0.5*log((1+f)/(1-f))*-self.Cc[zoom])
|
|
return (e,g)
|
|
|
|
def fromPixelToLL(self,px,zoom):
|
|
e = self.zc[zoom]
|
|
f = (px[0] - e[0])/self.Bc[zoom]
|
|
g = (px[1] - e[1])/-self.Cc[zoom]
|
|
h = RAD_TO_DEG * ( 2 * atan(exp(g)) - 0.5 * pi)
|
|
return (f,h)
|
|
|
|
|
|
|
|
class RenderThread:
|
|
def __init__(self, tile_dir, mapfile, q, printLock, maxZoom):
|
|
self.tile_dir = tile_dir
|
|
self.q = q
|
|
self.m = mapnik.Map(256, 256)
|
|
self.printLock = printLock
|
|
# Load style XML
|
|
mapnik.load_map(self.m, mapfile, True)
|
|
# Obtain <Map> projection
|
|
self.prj = mapnik.Projection(self.m.srs)
|
|
# Projects between tile pixel co-ordinates and LatLong (EPSG:4326)
|
|
self.tileproj = GoogleProjection(maxZoom+1)
|
|
|
|
|
|
def render_tile(self, tile_uri, x, y, z):
|
|
|
|
# Calculate pixel positions of bottom-left & top-right
|
|
p0 = (x * 256, (y + 1) * 256)
|
|
p1 = ((x + 1) * 256, y * 256)
|
|
|
|
# Convert to LatLong (EPSG:4326)
|
|
l0 = self.tileproj.fromPixelToLL(p0, z);
|
|
l1 = self.tileproj.fromPixelToLL(p1, z);
|
|
|
|
# Convert to map projection (e.g. mercator co-ords EPSG:900913)
|
|
c0 = self.prj.forward(mapnik.Coord(l0[0],l0[1]))
|
|
c1 = self.prj.forward(mapnik.Coord(l1[0],l1[1]))
|
|
|
|
# Bounding box for the tile
|
|
if hasattr(mapnik,'mapnik_version') and mapnik.mapnik_version() >= 800:
|
|
bbox = mapnik.Box2d(c0.x,c0.y, c1.x,c1.y)
|
|
else:
|
|
bbox = mapnik.Envelope(c0.x,c0.y, c1.x,c1.y)
|
|
render_size = 256
|
|
self.m.resize(render_size, render_size)
|
|
self.m.zoom_to_box(bbox)
|
|
if(self.m.buffer_size < 128):
|
|
self.m.buffer_size = 128
|
|
|
|
# Render image with default Agg renderer
|
|
im = mapnik.Image(render_size, render_size)
|
|
mapnik.render(self.m, im)
|
|
im.save(tile_uri, 'png256')
|
|
|
|
|
|
def loop(self):
|
|
while True:
|
|
#Fetch a tile from the queue and render it
|
|
r = self.q.get()
|
|
if (r == None):
|
|
self.q.task_done()
|
|
break
|
|
else:
|
|
(name, tile_uri, x, y, z) = r
|
|
|
|
exists= ""
|
|
if os.path.isfile(tile_uri):
|
|
exists= "exists"
|
|
else:
|
|
self.render_tile(tile_uri, x, y, z)
|
|
bytes=os.stat(tile_uri)[6]
|
|
empty= ''
|
|
if bytes == 103:
|
|
empty = " Empty Tile "
|
|
self.printLock.acquire()
|
|
print name, ":", z, x, y, exists, empty
|
|
self.printLock.release()
|
|
self.q.task_done()
|
|
|
|
|
|
|
|
def render_tiles(bbox, mapfile, tile_dir, minZoom=1,maxZoom=18, name="unknown", num_threads=NUM_THREADS, tms_scheme=False):
|
|
print "render_tiles(",bbox, mapfile, tile_dir, minZoom,maxZoom, name,")"
|
|
|
|
# Launch rendering threads
|
|
queue = Queue(32)
|
|
printLock = threading.Lock()
|
|
renderers = {}
|
|
for i in range(num_threads):
|
|
renderer = RenderThread(tile_dir, mapfile, queue, printLock, maxZoom)
|
|
render_thread = threading.Thread(target=renderer.loop)
|
|
render_thread.start()
|
|
#print "Started render thread %s" % render_thread.getName()
|
|
renderers[i] = render_thread
|
|
|
|
if not os.path.isdir(tile_dir):
|
|
os.mkdir(tile_dir)
|
|
|
|
gprj = GoogleProjection(maxZoom+1)
|
|
|
|
ll0 = (bbox[0],bbox[3])
|
|
ll1 = (bbox[2],bbox[1])
|
|
|
|
for z in range(minZoom,maxZoom + 1):
|
|
px0 = gprj.fromLLtoPixel(ll0,z)
|
|
px1 = gprj.fromLLtoPixel(ll1,z)
|
|
|
|
# check if we have directories in place
|
|
zoom = "%s" % z
|
|
if not os.path.isdir(tile_dir + zoom):
|
|
os.mkdir(tile_dir + zoom)
|
|
for x in range(int(px0[0]/256.0),int(px1[0]/256.0)+1):
|
|
# Validate x co-ordinate
|
|
if (x < 0) or (x >= 2**z):
|
|
continue
|
|
# check if we have directories in place
|
|
str_x = "%s" % x
|
|
if not os.path.isdir(tile_dir + zoom + '/' + str_x):
|
|
os.mkdir(tile_dir + zoom + '/' + str_x)
|
|
for y in range(int(px0[1]/256.0),int(px1[1]/256.0)+1):
|
|
# Validate x co-ordinate
|
|
if (y < 0) or (y >= 2**z):
|
|
continue
|
|
# flip y to match OSGEO TMS spec
|
|
if tms_scheme:
|
|
str_y = "%s" % ((2**z-1) - y)
|
|
else:
|
|
str_y = "%s" % y
|
|
tile_uri = tile_dir + zoom + '/' + str_x + '/' + str_y + '.png'
|
|
# Submit tile to be rendered into the queue
|
|
t = (name, tile_uri, x, y, z)
|
|
try:
|
|
queue.put(t)
|
|
except KeyboardInterrupt:
|
|
raise SystemExit("Ctrl-c detected, exiting...")
|
|
|
|
# Signal render threads to exit by sending empty request to queue
|
|
for i in range(num_threads):
|
|
queue.put(None)
|
|
# wait for pending rendering jobs to complete
|
|
queue.join()
|
|
for i in range(num_threads):
|
|
renderers[i].join()
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
home = os.environ['HOME']
|
|
try:
|
|
mapfile = os.environ['MAPNIK_MAP_FILE']
|
|
except KeyError:
|
|
mapfile = home + "/svn.openstreetmap.org/applications/rendering/mapnik/osm-local.xml"
|
|
try:
|
|
tile_dir = os.environ['MAPNIK_TILE_DIR']
|
|
except KeyError:
|
|
tile_dir = home + "/osm/tiles/"
|
|
|
|
if not tile_dir.endswith('/'):
|
|
tile_dir = tile_dir + '/'
|
|
|
|
#-------------------------------------------------------------------------
|
|
#
|
|
# Change the following for different bounding boxes and zoom levels
|
|
#
|
|
# Start with an overview
|
|
# World
|
|
bbox = (-180.0,-90.0, 180.0,90.0)
|
|
|
|
render_tiles(bbox, mapfile, tile_dir, 0, 5, "World")
|
|
|
|
minZoom = 10
|
|
maxZoom = 16
|
|
bbox = (-2, 50.0,1.0,52.0)
|
|
render_tiles(bbox, mapfile, tile_dir, minZoom, maxZoom)
|
|
|
|
# Muenchen
|
|
bbox = (11.4,48.07, 11.7,48.22)
|
|
render_tiles(bbox, mapfile, tile_dir, 1, 12 , "Muenchen")
|
|
|
|
# Muenchen+
|
|
bbox = (11.3,48.01, 12.15,48.44)
|
|
render_tiles(bbox, mapfile, tile_dir, 7, 12 , "Muenchen+")
|
|
|
|
# Muenchen++
|
|
bbox = (10.92,47.7, 12.24,48.61)
|
|
render_tiles(bbox, mapfile, tile_dir, 7, 12 , "Muenchen++")
|
|
|
|
# Nuernberg
|
|
bbox=(10.903198,49.560441,49.633534,11.038085)
|
|
render_tiles(bbox, mapfile, tile_dir, 10, 16, "Nuernberg")
|
|
|
|
# Karlsruhe
|
|
bbox=(8.179113,48.933617,8.489252,49.081707)
|
|
render_tiles(bbox, mapfile, tile_dir, 10, 16, "Karlsruhe")
|
|
|
|
# Karlsruhe+
|
|
bbox = (8.3,48.95,8.5,49.05)
|
|
render_tiles(bbox, mapfile, tile_dir, 1, 16, "Karlsruhe+")
|
|
|
|
# Augsburg
|
|
bbox = (8.3,48.95,8.5,49.05)
|
|
render_tiles(bbox, mapfile, tile_dir, 1, 16, "Augsburg")
|
|
|
|
# Augsburg+
|
|
bbox=(10.773251,48.369594,10.883834,48.438577)
|
|
render_tiles(bbox, mapfile, tile_dir, 10, 14, "Augsburg+")
|
|
|
|
# Europe+
|
|
bbox = (1.0,10.0, 20.6,50.0)
|
|
render_tiles(bbox, mapfile, tile_dir, 1, 11 , "Europe+")
|