Delete unneeded files

This commit is contained in:
Ilya Zverev 2015-09-21 20:04:37 +03:00
parent acbdfc180b
commit abd549bf91
62 changed files with 0 additions and 14015 deletions

View file

@ -1 +0,0 @@
# -*- coding: utf-8 -*-

View file

@ -1 +0,0 @@
# -*- coding: utf-8 -*-

View file

@ -1,150 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
# from debug import debug
from twms import projections
import psycopg2
import shapely.wkb
class Empty:
def copy(self):
a = Empty()
a.tags = self.tags.copy()
a.coords = self.coords[:]
a.center = self.center
a.cs = self.cs[:]
return a
class Way:
def __init__(self, tags, geom):
self.cs = []
# print [x.split("=") for x in tags.split(";")]
self.tags = tags
# calculating center point
# c= geom
# sumz = [(c[0],c[1])]
# for k in range(2, len(c), 2):
# sumz.append((c[k], c[k + 1]))
self.coords = geom
# left for the better times:
self.center = reduce(lambda x, y: (x[0] + y[0], x[1] + y[1]), self.coords)
self.center = (self.center[0] / len(self.coords), self.center[1] / len(self.coords))
# debug(self.center)
def copy(self):
a = Empty()
a.tags = self.tags.copy()
a.coords = self.coords[:]
a.center = self.center
a.cs = self.cs[:]
return a
class PostGisBackend:
"""
A class that gives out vector data on demand.
"""
def __init__(self, database="dbname=gis user=mapz host=komzpa.net", max_zoom=16, proj="EPSG:3857", path="tiles", lang="ru", ):
# debug("Bakend created")
self.database = database
self.max_zoom = max_zoom # no better tiles available
self.path = path # path to tile files
self.lang = lang # map language to use
self.tiles = {} # loaded vector tiles go here
self.proj = proj # which projection used to cut map in tiles
self.keep_tiles = 190 # a number of tiles to cache in memory
self.tile_load_log = [] # used when selecting which tile to unload
def get_vectors(self, bbox, zoom, sql_hint=None, tags_hint=None):
"""
Fetches vectors for given bbox.
sql_hint is a list of sets of (key, sql_for_key)
"""
a = psycopg2.connect(self.database)
b = a.cursor()
bbox = tuple(projections.from4326(bbox, self.proj))
### FIXME: hardcoded EPSG:3857 in database
tables = ("planet_osm_line", "planet_osm_polygon") # FIXME: points
resp = {}
for table in tables:
add = ""
taghint = "*"
if sql_hint:
adp = []
for tp in sql_hint:
add = []
b.execute("SELECT * FROM %s LIMIT 1;" % table)
names = [q[0] for q in b.description]
for j in tp[0]:
if j not in names:
break
else:
add.append(tp[1])
if add:
add = " OR ".join(add)
add = "(" + add + ")"
adp.append(add)
if tags_hint:
taghint = ", ".join(['"' + j + '"' for j in tags_hint if j in names]) + ", way, osm_id"
adp = " OR ".join(adp)
req = "SELECT %s FROM %s WHERE (%s) and way && SetSRID('BOX3D(%s %s,%s %s)'::box3d,900913);" % (taghint, table, adp, bbox[0], bbox[1], bbox[2], bbox[3])
print req
b.execute(req)
names = [q[0] for q in b.description]
for row in b.fetchall():
row_dict = dict(map(None, names, row))
for k, v in row_dict.items():
if not v:
del row_dict[k]
geom = shapely.wkb.loads(row_dict["way"].decode('hex'))
### FIXME: a dirty hack to basically support polygons, needs lots of rewrite
try:
geom = list(geom.coords)
except NotImplementedError:
"trying polygons"
try:
geom = geom.boundary
geom = list(geom.coords)
row_dict[":area"] = "yes"
except NotImplementedError:
"multipolygon"
continue
### FIXME
# geom = projections.to4326(geom, self.proj)
del row_dict["way"]
oid = row_dict["osm_id"]
del row_dict["osm_id"]
w = Way(row_dict, geom)
# print row_dict
resp[oid] = w
a.close()
del a
return resp

View file

@ -1,148 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
from twms import projections
import twms.bbox
class Empty:
def copy(self):
a = Empty()
a.tags = self.tags.copy()
a.coords = self.coords[:]
a.center = self.center
a.cs = self.cs[:]
a.bbox = self.bbox
return a
class Way:
def __init__(self, tags, coords):
self.cs = []
# print [x.split("=") for x in tags.split(";")]
self.tags = dict((x.split("=") for x in tags.split(";")))
# calculating center point
c = coords
sumz = [(c[0], c[1])]
for k in range(2, len(c), 2):
sumz.append((c[k], c[k + 1]))
self.coords = sumz
# left for the better times:
self.center = reduce(lambda x, y: (x[0] + y[0], x[1] + y[1]), self.coords)
self.center = (self.center[0] / len(self.coords), self.center[1] / len(self.coords))
self.bbox = reduce(lambda x, y: (min(x[0], y[0]), min(x[1], y[1]), max(x[2], y[0]), max(x[3], y[1])), self.coords, (9999, 9999, -9999, -9999))
# debug(self.center)
def copy(self):
a = Empty()
a.tags = self.tags.copy()
a.coords = self.coords[:]
a.center = self.center
a.cs = self.cs[:]
a.bbox = self.bbox
return a
class QuadTileBackend:
"""
A class that gives out vector data on demand.
"""
def __init__(self, max_zoom=16, proj="EPSG:4326", path="tiles", lang="ru"):
self.max_zoom = max_zoom # no better tiles available
self.path = path # path to tile files
self.lang = lang # map language to use
self.tiles = {} # loaded vector tiles go here
self.proj = proj # which projection used to cut map in tiles
self.keep_tiles = 15 # a number of tiles to cache in memory
self.tile_load_log = [] # used when selecting which tile to unload
def filename(self, (z, x, y)):
return "%s/z%s/%s/x%s/%s/y%s.vtile" % (self.path, z, x / 1024, x, y / 1024, y)
def load_tile(self, k):
# debug("loading tile: %s"% (k,))
try:
f = open(self.filename(k))
except IOError:
print ("Failed open: '%s'" % self.filename(k))
return {}
t = {}
for line in f:
# debug(line)
a = line.split(" ")
w = Way(a[0], [float(x) for x in a[2:]])
t[int(a[1])] = w
f.close()
return t
def collect_garbage(self):
"""
Cleans up some RAM by removing least accessed tiles.
"""
if len(self.tiles) > self.keep_tiles:
# debug("Now %s tiles cached, trying to kill %s"%(len(self.tiles),len(self.tiles)-self.keep_tiles))
for tile in self.tile_load_log[0:len(self.tiles) - self.keep_tiles]:
try:
del self.tiles[tile]
self.tile_load_log.remove(tile)
# debug ("killed tile: %s" % (tile,))
except KeyError, ValueError:
pass
# debug ("tile killed not by us: %s" % (tile,))
def get_vectors(self, bbox, zoom, sql_hint=None, itags=None):
zoom = int(zoom)
zoom = min(zoom, self.max_zoom) # If requested zoom is better than the best, take the best
zoom = max(zoom, 0) # Negative zooms are nonsense
a, d, c, b = [int(x) for x in projections.tile_by_bbox(bbox, zoom, self.proj)]
resp = {}
hint = set()
for j in [x[0] for x in sql_hint]:
hint.update(j)
for tile in set([(zoom, i, j) for i in range(a, c + 1) for j in range(b, d + 1)]):
# Loading current vector tile
try:
ti = self.tiles[tile]
except KeyError:
ti = self.load_tile(tile)
self.tiles[tile] = ti
try:
self.tile_load_log.remove(tile)
except ValueError:
pass
self.tile_load_log.append(tile)
for obj in ti:
"filling response with interesting-tagged objects"
need = False
for tag in ti[obj].tags:
# if tag in hint:
need = True
break
if need:
if twms.bbox.bbox_is_in(bbox, ti[obj].bbox, fully=False):
resp[obj] = ti[obj]
self.collect_garbage()
return resp

View file

@ -1,40 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
import datetime
import sys
def debug(st):
"""
Debug write to stderr
"""
sys.stderr.write(str(st) + "\n")
sys.stderr.flush()
class Timer:
"""
A small timer for debugging
"""
def __init__(self, comment):
self.time = datetime.datetime.now()
self.comment = comment
debug("%s started" % comment)
def stop(self):
debug("%s finished in %s" % (self.comment, str(datetime.datetime.now() - self.time)))

View file

@ -1,55 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
from debug import debug, Timer
from backend.vtile import QuadTileBackend as DataBackend
# from backend.postgis import PostGisBackend as DataBackend
# from style import Styling
from mapcss import MapCSS
from render import RasterTile
svg = False
if svg:
import cairo
style = MapCSS(1, 19) # zoom levels
style.parse(open("styles/default.mapcss", "r").read())
bbox = (27.115768874532, 53.740327031764, 28.028320754378, 54.067187302158)
w, h = 630 * 4, 364 * 4
z = 10
db = DataBackend()
# style = Styling()
res = RasterTile(w, h, z, db)
if svg:
file = open("test.svg", "wb")
res.surface = cairo.SVGSurface(file.name, w, h)
res.update_surface(bbox, z, style)
if not svg:
res.surface.write_to_png("test.png")
else:
res.surface.finish()

View file

@ -1,105 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from mapcss import MapCSS
import mapcss.webcolors
whatever_to_hex = mapcss.webcolors.webcolors.whatever_to_hex
import json
import cairo
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
minzoom = 0
maxzoom = 18
sample_width = 80
style = MapCSS(minzoom, maxzoom)
style.parse(open(sys.argv[1], "r").read(), clamp=False)
tags = [json.loads(x) for x in open("data/tags.list", "r")]
print len(tags)
# a = cairo.PDFSurface("legend.pdf",100,100*len(tags))
maxzoom += 1
a = cairo.ImageSurface(cairo.FORMAT_ARGB32, maxzoom * sample_width, 50 * len(tags))
cr = cairo.Context(a)
cr.translate(0, 0.5)
i = 0
icons = {}
for tag in tags:
had_lines = False
for zoom in range(minzoom, maxzoom):
styles = style.get_style_dict("node", tag, zoom, olddict={})
styles = style.get_style_dict("area", tag, zoom, olddict=styles.copy())
styles = style.get_style_dict("line", tag, zoom, olddict=styles.copy())
styles = styles.values()
styles.sort(key=lambda x: x.get('z-index', 0))
if len(styles) > 0:
for st in styles:
if "fill-color" in st and st.get("fill-opacity", 1) > 0:
color = st.get('fill-color', (0., 0., 0.))
cr.set_source_rgba(color[0], color[1], color[2], st.get("fill-opacity", 1))
cr.move_to(0 + sample_width * zoom, 20 + 50 * i)
cr.line_to(sample_width + sample_width * zoom, 20 + 50 * i)
cr.line_to(sample_width + sample_width * zoom, 55 + 50 * i)
cr.line_to(0 + sample_width * zoom, 20 + 50 * i)
had_lines = True
cr.fill()
for st in styles:
if "casing-width" in st and st.get("casing-opacity", 1) > 0:
color = st.get('casing-color', (0., 0., 0.))
cr.set_source_rgba(color[0], color[1], color[2], st.get("casing-opacity", 1))
cr.set_line_width(st.get("width", 0) + 2 * st.get("casing-width", 0))
cr.set_dash(st.get('casing-dashes', st.get('dashes', [])))
cr.move_to(0 + sample_width * zoom, 50 + 50 * i)
cr.line_to(sample_width + sample_width * zoom, 50 + 50 * i)
had_lines = True
cr.stroke()
for st in styles:
if "width" in st and st.get("opacity", 1) > 0:
color = st.get('color', (0., 0., 0.))
cr.set_source_rgba(color[0], color[1], color[2], st.get("opacity", 1))
cr.set_line_width(st.get("width", 0))
cr.set_dash(st.get('dashes', []))
cr.move_to(0 + sample_width * zoom, 50 + 50 * i)
cr.line_to(sample_width + sample_width * zoom, 50 + 50 * i)
had_lines = True
cr.stroke()
if "icon-image" in st:
icons[st["icon-image"]] = icons.get(st["icon-image"], set())
icons[st["icon-image"]].add('[' + ']['.join([k + "=" + v for k, v in tag.iteritems()]) + ']')
if had_lines:
cr.move_to(0 + sample_width * zoom, 25 + 50 * i)
cr.set_source_rgb(0, 0, 0)
cr.show_text('z' + str(zoom))
if had_lines:
text = '[' + ']['.join([k + "=" + v for k, v in tag.iteritems()]) + ']'
cr.move_to(10, 20 + 50 * i)
cr.set_source_rgb(0, 0, 0)
cr.show_text(text)
cr.set_line_width(1)
cr.set_dash([])
cr.move_to(0, 60 + 50 * i)
cr.line_to(maxzoom * sample_width, 60 + 50 * i)
cr.stroke()
i += 1
# a.finish()\
ss = open("icons.html", "w")
print >> ss, "<html><body><table border=1>"
for k, v in icons.iteritems():
print >> ss, "<tr><td><img src='%s' width='24' height='24'></td><td>%s</td><td>%s</td></tr>\n" % (k.lower(), k.lower(), "<br>".join(list(v)))
print >> ss, "</table></body></html>"
a.write_to_png("legend.png")

View file

@ -1,117 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
import pygtk
pygtk.require('2.0')
import gtk
import cairo
import math
import string
import threading
import time
import Queue
import os
# from backend.postgis import PostGisBackend as DataBackend
from backend.vtile import QuadTileBackend as DataBackend
from mapcss import MapCSS as Styling
from gtk_widget import KothicWidget
try:
import psyco
psyco.full()
except ImportError:
pass
# debug("Psyco import failed. Program may run slower. Ir you run it on i386 machine, please install Psyco to get best performance.")
class KothicApp:
def __init__(self):
self.width, self.height = 800, 480
self.center_coord = (27.6549791, 53.8698)
self.zoom = 17.
self.data_projection = "EPSG:4326"
self.data = DataBackend()
self.load_style()
self.request_d = (0, 0)
self.window = gtk.Window()
self.window.set_size_request(self.width, self.height)
self.window.connect("destroy", gtk.main_quit)
self.window.set_title("Kothic renderer")
menu = gtk.MenuBar()
filemenu = gtk.Menu()
filem = gtk.MenuItem("File")
filem.set_submenu(filemenu)
i = gtk.MenuItem("Reload style")
i.connect("activate", self.load_style)
filemenu.append(i)
stylemenu = gtk.Menu()
stylem = gtk.MenuItem("Style")
stylem.set_submenu(stylemenu)
styles = [name for name in os.listdir("styles") if ".mapcss" in name]
for style in styles:
i = gtk.MenuItem(style)
i.StyleName = style
i.connect("activate", self.reload_style)
stylemenu.append(i)
i = gtk.MenuItem("Exit")
i.connect("activate", gtk.main_quit)
filemenu.append(i)
menu.append(filem)
menu.append(stylem)
vbox = gtk.VBox(False, 2)
vbox.pack_start(menu, False, False, 0)
self.KothicWidget = KothicWidget(self.data, self.style)
self.KothicWidget.set_zoom(self.zoom)
self.KothicWidget.jump_to(self.center_coord)
vbox.pack_end(self.KothicWidget)
self.window.add(vbox)
def load_style(self):
self.style = Styling(0, 25)
self.style.parse(open("styles/osmosnimki-maps.mapcss", "r").read())
def reload_style(self, w):
self.style = Styling(0, 25)
self.style.parse(open("styles/%s" % w.StyleName, "r").read())
self.KothicWidget.style_backend = self.style
self.KothicWidget.redraw()
def main(self):
self.window.show_all()
gtk.main()
exit()
if __name__ == "__main__":
gtk.gdk.threads_init()
kap = KothicApp()
kap.main()

View file

@ -1,291 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
import pygtk
pygtk.require('2.0')
import gtk
import gobject
import cairo
import math
import string
import threading
import datetime
import time
import Queue
import os
from render import RasterTile
from debug import debug, Timer
import twms.bbox
from twms import projections
class KothicWidget(gtk.DrawingArea):
def __init__(self, data, style):
gtk.DrawingArea.__init__(self)
self.data_backend = data
self.style_backend = style
self.request_d = (0, 0)
self.tiles = TileSource(data, style, callback=self.redraw)
self.dx = 0
self.dy = 0
self.drag_x = 0
self.drag_y = 0
self.drag = False
self.rastertile = None
self.f = True
self.width = 0
self.height = 0
self.max_zoom = 25
self.zoom = 0
self.center_coord = (0.0, 0.0)
self.old_zoom = 1
self.old_center_coord = (0.0, 0.1)
self.tilebox = [] # bbox of currently seen tiles
self.bbox = []
self.add_events(gtk.gdk.BUTTON1_MOTION_MASK)
self.add_events(gtk.gdk.POINTER_MOTION_MASK)
self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
self.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
self.add_events(gtk.gdk.SCROLL)
# self.window.add_events(gtk.gdk.BUTTON1_MOTION_MASK)
self.connect("expose_event", self.expose_ev)
self.connect("motion_notify_event", self.motion_ev)
self.connect("button_press_event", self.press_ev)
self.connect("button_release_event", self.release_ev)
self.connect("scroll_event", self.scroll_ev)
# self.surface = cairo.ImageSurfaceicreate(gtk.RGB24, self.width, self.height)
def set_zoom(self, zoom):
self.zoom = zoom
self.queue_draw()
def jump_to(self, lonlat):
self.center_coord = lonlat
self.queue_draw()
def zoom_to(self, bbox):
self.zoom = twms.bbox.zoom_for_bbox(bbox, (self.width, self.height), {"proj": "EPSG:3857", "max_zoom": self.max_zoom}) - 1
print "Zoom:", self.zoom
self.center_coord = ((bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2)
print self.center_coord
self.redraw()
def motion_ev(self, widget, event):
if self.drag:
self.dx = event.x - self.drag_x
self.dy = event.y - self.drag_y
# if((abs(self.dx) > 3 or abs(self.dy) > 3) and self.f):
if True:
# x = event.x
# y = event.y
# lo1, la1, lo2, la2 = self.tilebox
# self.center_coord = projections.coords_by_tile(self.zoom,1.*x/self.width*(lo2-lo1)+lo1, la1+(1.*y/(self.height)*(la2-la1)),"EPSG:3857")
widget.queue_draw()
def press_ev(self, widget, event):
if event.button == 1:
# debug("Start drag")
self.drag = True
self.drag_x = event.x
self.drag_y = event.y
self.timer = Timer("Drag")
# elif event.button == 2:
# debug("Button2")
# elif event.button == 3:
# debug("Button3")
def release_ev(self, widget, event):
if event.button == 1:
# debug("Stop drag")
self.drag = False
self.timer.stop()
# debug("dd: %s,%s "%(self.dx, self.dy))
x = event.x
y = event.y
lo1, la1, lo2, la2 = projections.from4326(self.bbox, "EPSG:3857")
print lo1, la1, lo2, la2
# self.center_coord = projections.to4326((0.5*(self.width+self.dx)/self.width*(lo1-lo2)+lo2, la1+(0.5*(self.height+self.dy)/self.height*(la2-la1))),"EPSG:3857")
self.center_coord = projections.to4326((0.5 * (self.width + 2 * self.dx) / self.width * (lo1 - lo2) + lo2, la1 + (0.5 * (self.height + 2 * self.dy) / self.height * (la2 - la1))), "EPSG:3857")
# self.rastertile.screen2lonlat(self.rastertile.w/2 - self.dx, self.rastertile.h/2 - self.dy);
self.dx = 0
self.dy = 0
self.redraw()
def scroll_ev(self, widget, event):
if event.direction == gtk.gdk.SCROLL_UP:
if self.zoom + 0.5 <= self.max_zoom:
self.zoom += 0.5
# debug("Zoom in")
elif event.direction == gtk.gdk.SCROLL_DOWN:
if self.zoom >= 0: # negative zooms are nonsense
self.zoom -= 0.5
# debug("Zoom out")
# self.redraw()
debug("new zoom: %s" % (self.zoom))
widget.queue_draw()
def redraw(self):
"""
Force screen redraw.
"""
# res = RasterTile(3*self.width, 3*self.height, self.zoom, self.data_backend)
# res.update_surface_by_center(self.center_coord, self.zoom, self.style_backend)
# self.rastertile = res
self.queue_draw()
def expose_ev(self, widget, event):
if(widget.allocation.width != self.width or widget.allocation.height != self.height):
# debug("Rrresize!")
self.width = widget.allocation.width
self.height = widget.allocation.height
cr = widget.window.cairo_create()
if self.old_center_coord != self.center_coord or self.old_zoom != self.zoom:
# print "Recentered!"
xy = projections.from4326(self.center_coord, "EPSG:3857")
xy1 = projections.to4326((xy[0] - 40075016. * (0.5 ** (self.zoom)) / self.tiles.tilewidth * self.width, xy[1] - 40075016. * (0.5 ** (self.zoom)) / self.tiles.tileheight * self.height), "EPSG:3857")
xy2 = projections.to4326((xy[0] + 40075016. * (0.5 ** (self.zoom)) / self.tiles.tilewidth * self.width, xy[1] + 40075016. * (0.5 ** (self.zoom)) / self.tiles.tileheight * self.height), "EPSG:3857")
self.bbox = (xy1[0], xy1[1], xy2[0], xy2[1])
self.tilebox = projections.tile_by_bbox(self.bbox, self.zoom, "EPSG:3857")
self.old_center_coord = self.center_coord
self.old_zoom = self.zoom
from_tile_x, from_tile_y, to_tile_x, to_tile_y = self.tilebox
dx = 1. * (from_tile_x - int(from_tile_x)) * self.tiles.tilewidth
dy = 1. * (from_tile_y - int(from_tile_y)) * self.tiles.tileheight
print dx, dy
# print self.dx, self.dy
onscreen_tiles = set()
for x in range(int(from_tile_x), int(to_tile_x) + 1):
for y in range(int(to_tile_y), int(from_tile_y) + 1):
onscreen_tiles.add((self.zoom, x, y))
self.tiles.onscreen = onscreen_tiles
for z, x, y in onscreen_tiles:
tile = self.tiles[(self.zoom, x, y)]
# print dx+(x-from_tile_x)*self.tiles.tilewidth-self.width
# print dy+(y-from_tile_y)*self.tiles.tileheight-self.height
# cr.set_source_surface(tile, int(self.dx-dx+(x-int(from_tile_x))*self.tiles.tilewidth-self.width), int(self.dy-dy-(int(from_tile_y)-y)*self.tiles.tileheight+self.height))
cr.set_source_surface(tile, int(self.dx - dx + (x - int(from_tile_x)) * self.tiles.tilewidth), int(self.dy - dy - (int(from_tile_y) - y) * self.tiles.tileheight + self.height))
cr.paint()
# cr.set_source_surface(self.rastertile.surface, self.dx-self.width + self.rastertile.offset_x, self.dy - self.height + self.rastertile.offset_y)
# self.comm[3].release()
class TileSource:
def __init__(self, data, style, callback=lambda: None):
self.tiles = {}
self.tilewidth = 2048
self.tileheight = 2048
self.max_tiles = 32
self.data_backend = data
self.style_backend = style
self.callback = callback
self.onscreen = set()
self._singlethread = False
self._prerender = True
def __getitem__(self, (z, x, y), wait=False):
try:
# if "surface" in self.tiles[(z,x,y)] and not wait:
# self._callback((z,x,y), True)
print "Tiles count:", len(self.tiles)
return self.tiles[(z, x, y)]["surface"]
except:
self.tiles[(z, x, y)] = {"tile": RasterTile(self.tilewidth, self.tileheight, z, self.data_backend)}
self.tiles[(z, x, y)]["start_time"] = datetime.datetime.now()
if self._singlethread:
self.tiles[(z, x, y)]["surface"] = self.tiles[(z, x, y)]["tile"].surface
self.tiles[(z, x, y)]["tile"].update_surface(projections.bbox_by_tile(z, x, y, "EPSG:3857"), z, self.style_backend, lambda p=False: self._callback((z, x, y), p))
del self.tiles[(z, x, y)]["tile"]
else:
self.tiles[(z, x, y)]["surface"] = self.tiles[(z, x, y)]["tile"].surface.create_similar(cairo.CONTENT_COLOR_ALPHA, self.tilewidth, self.tileheight)
self.tiles[(z, x, y)]["thread"] = threading.Thread(None, self.tiles[(z, x, y)]["tile"].update_surface, None, (projections.bbox_by_tile(z, x, y, "EPSG:3857"), z, self.style_backend, lambda p=False: self._callback((z, x, y), p)))
self.tiles[(z, x, y)]["thread"].start()
if wait:
self.tiles[(z, x, y)]["thread"].join()
return self.tiles[(z, x, y)]["surface"]
def _callback(self, (z, x, y), last):
# if last:
# print last, "dddddddddddddddddd"
if not self._singlethread:
if ((z, x, y) in self.onscreen or last) and "tile" in self.tiles[(z, x, y)]:
cr = cairo.Context(self.tiles[(z, x, y)]["surface"])
cr.set_source_surface(self.tiles[(z, x, y)]["tile"].surface, 0, 0)
cr.paint()
if last:
try:
del self.tiles[(z, x, y)]["thread"]
del self.tiles[(z, x, y)]["tile"]
except KeyError:
pass
self.tiles[(z, x, y)]["finish_time"] = datetime.datetime.now() - self.tiles[(z, x, y)]["start_time"]
gobject.idle_add(self.callback)
self.collect_grabage()
if last and self._prerender:
if (z, x, y) in self.onscreen:
a = self.__getitem__((z - 1, x / 2, y / 2), True)
if (z, x, y) in self.onscreen:
a = self.__getitem__((z + 1, x * 2, y * 2), True)
if (z, x, y) in self.onscreen:
a = self.__getitem__((z + 1, x * 2 + 1, y * 2), True)
if (z, x, y) in self.onscreen:
a = self.__getitem__((z + 1, x * 2, y * 2 + 1), True)
if (z, x, y) in self.onscreen:
a = self.__getitem__((z + 1, x * 2 + 1, y * 2 + 1), True)
if (z, x, y) in self.onscreen:
a = self.__getitem__((z, x + 1, y), True)
if (z, x, y) in self.onscreen:
a = self.__getitem__((z, x, y + 1), True)
if (z, x, y) in self.onscreen:
a = self.__getitem__((z, x - 1, y), True)
if (z, x, y) in self.onscreen:
a = self.__getitem__((z, x, y - 1), True)
def collect_grabage(self):
if len(self.tiles) > self.max_tiles:
# let's kick out the fastest rendered tiles - it's easy to rerender those
# don't touch onscreen tiles
cand = set(self.tiles.keys())
cand.difference_update(self.onscreen)
cand = [i for i in cand if "finish_time" in self.tiles[i]]
cand.sort(lambda i, j: self.tiles[i]["finish_time"] < self.tiles[i]["finish_time"])
while cand:
if (len(self.tiles) > self.max_tiles):
c = cand.pop()
try:
print "Killed tile ", c, " - finished in ", str(self.tiles[c]["finish_time"]), ", ago:", str(datetime.datetime.now() - self.tiles[c]["start_time"])
del self.tiles[c]
except KeyError:
pass
else:
break
if __name__ == "__main__":
gtk.gdk.threads_init()
kap = KothicApp()
kap.main()

View file

@ -1,26 +0,0 @@
CanvasRenderingContext2D.prototype.dashTo = function (X2, Y2, Ptrn) { // segment of dasked line set
// X2 Y2 : X & Y to go TO ; internal X1 Y1 to go FROM
// Ptrn as [6,4, 1,4] // mark-space pairs indexed by Seg
// supply Ptrn only for the first point of a dashed line set
if (Ptrn) {
this.Obj = {Patn:Ptrn, Seg:0, Phs:0, X1:X2, Y1:Y2} ; return }
var XDis, YDis, Dist, X, More, T, Ob = this.Obj
XDis = X2 - Ob.X1 // DeltaX
YDis = Y2 - Ob.Y1 // DeltaY
Dist = Math.sqrt(XDis*XDis + YDis*YDis) // length
//if (Dist<0.00000001){return}
this.save()
this.translate(Ob.X1, Ob.Y1)
this.rotate(Math.atan2(YDis, XDis))
this.moveTo(0, 0) ; X = 0 // Now dash pattern from 0,0 to Dist,0
do {
T = Ob.Patn[Ob.Seg] // Full segment
X += T - Ob.Phs // Move by unused seg
More = X < Dist // Not too far?
if (!More) { Ob.Phs = T - (X - Dist) ; X = Dist } // adjust
Ob.Seg%2 ? this.moveTo(X, 0) : this.lineTo(X, 0)
if (More) { Ob.Phs = 0 ; Ob.Seg = ++Ob.Seg % Ob.Patn.length }
} while (More)
Ob.X1 = X2 ; Ob.Y1 = Y2
this.restore() };

View file

@ -1,35 +0,0 @@
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
document.createElement("canvas").getContext||(function(){var s=Math,j=s.round,F=s.sin,G=s.cos,V=s.abs,W=s.sqrt,k=10,v=k/2;function X(){return this.context_||(this.context_=new H(this))}var L=Array.prototype.slice;function Y(b,a){var c=L.call(arguments,2);return function(){return b.apply(a,c.concat(L.call(arguments)))}}var M={init:function(b){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var a=b||document;a.createElement("canvas");a.attachEvent("onreadystatechange",Y(this.init_,this,a))}},init_:function(b){b.namespaces.g_vml_||
b.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML");b.namespaces.g_o_||b.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML");if(!b.styleSheets.ex_canvas_){var a=b.createStyleSheet();a.owningElement.id="ex_canvas_";a.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}g_o_\\:*{behavior:url(#default#VML)}"}var c=b.getElementsByTagName("canvas"),d=0;for(;d<c.length;d++)this.initElement(c[d])},
initElement:function(b){if(!b.getContext){b.getContext=X;b.innerHTML="";b.attachEvent("onpropertychange",Z);b.attachEvent("onresize",$);var a=b.attributes;if(a.width&&a.width.specified)b.style.width=a.width.nodeValue+"px";else b.width=b.clientWidth;if(a.height&&a.height.specified)b.style.height=a.height.nodeValue+"px";else b.height=b.clientHeight}return b}};function Z(b){var a=b.srcElement;switch(b.propertyName){case "width":a.style.width=a.attributes.width.nodeValue+"px";a.getContext().clearRect();
break;case "height":a.style.height=a.attributes.height.nodeValue+"px";a.getContext().clearRect();break}}function $(b){var a=b.srcElement;if(a.firstChild){a.firstChild.style.width=a.clientWidth+"px";a.firstChild.style.height=a.clientHeight+"px"}}M.init();var N=[],B=0;for(;B<16;B++){var C=0;for(;C<16;C++)N[B*16+C]=B.toString(16)+C.toString(16)}function I(){return[[1,0,0],[0,1,0],[0,0,1]]}function y(b,a){var c=I(),d=0;for(;d<3;d++){var f=0;for(;f<3;f++){var h=0,g=0;for(;g<3;g++)h+=b[d][g]*a[g][f];c[d][f]=
h}}return c}function O(b,a){a.fillStyle=b.fillStyle;a.lineCap=b.lineCap;a.lineJoin=b.lineJoin;a.lineWidth=b.lineWidth;a.miterLimit=b.miterLimit;a.shadowBlur=b.shadowBlur;a.shadowColor=b.shadowColor;a.shadowOffsetX=b.shadowOffsetX;a.shadowOffsetY=b.shadowOffsetY;a.strokeStyle=b.strokeStyle;a.globalAlpha=b.globalAlpha;a.arcScaleX_=b.arcScaleX_;a.arcScaleY_=b.arcScaleY_;a.lineScale_=b.lineScale_}function P(b){var a,c=1;b=String(b);if(b.substring(0,3)=="rgb"){var d=b.indexOf("(",3),f=b.indexOf(")",d+
1),h=b.substring(d+1,f).split(",");a="#";var g=0;for(;g<3;g++)a+=N[Number(h[g])];if(h.length==4&&b.substr(3,1)=="a")c=h[3]}else a=b;return{color:a,alpha:c}}function aa(b){switch(b){case "butt":return"flat";case "round":return"round";case "square":default:return"square"}}function H(b){this.m_=I();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.fillStyle=this.strokeStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=k*1;this.globalAlpha=1;this.canvas=b;
var a=b.ownerDocument.createElement("div");a.style.width=b.clientWidth+"px";a.style.height=b.clientHeight+"px";a.style.overflow="hidden";a.style.position="absolute";b.appendChild(a);this.element_=a;this.lineScale_=this.arcScaleY_=this.arcScaleX_=1}var i=H.prototype;i.clearRect=function(){this.element_.innerHTML=""};i.beginPath=function(){this.currentPath_=[]};i.moveTo=function(b,a){var c=this.getCoords_(b,a);this.currentPath_.push({type:"moveTo",x:c.x,y:c.y});this.currentX_=c.x;this.currentY_=c.y};
i.lineTo=function(b,a){var c=this.getCoords_(b,a);this.currentPath_.push({type:"lineTo",x:c.x,y:c.y});this.currentX_=c.x;this.currentY_=c.y};i.bezierCurveTo=function(b,a,c,d,f,h){var g=this.getCoords_(f,h),l=this.getCoords_(b,a),e=this.getCoords_(c,d);Q(this,l,e,g)};function Q(b,a,c,d){b.currentPath_.push({type:"bezierCurveTo",cp1x:a.x,cp1y:a.y,cp2x:c.x,cp2y:c.y,x:d.x,y:d.y});b.currentX_=d.x;b.currentY_=d.y}i.quadraticCurveTo=function(b,a,c,d){var f=this.getCoords_(b,a),h=this.getCoords_(c,d),g={x:this.currentX_+
0.6666666666666666*(f.x-this.currentX_),y:this.currentY_+0.6666666666666666*(f.y-this.currentY_)};Q(this,g,{x:g.x+(h.x-this.currentX_)/3,y:g.y+(h.y-this.currentY_)/3},h)};i.arc=function(b,a,c,d,f,h){c*=k;var g=h?"at":"wa",l=b+G(d)*c-v,e=a+F(d)*c-v,m=b+G(f)*c-v,r=a+F(f)*c-v;if(l==m&&!h)l+=0.125;var n=this.getCoords_(b,a),o=this.getCoords_(l,e),q=this.getCoords_(m,r);this.currentPath_.push({type:g,x:n.x,y:n.y,radius:c,xStart:o.x,yStart:o.y,xEnd:q.x,yEnd:q.y})};i.rect=function(b,a,c,d){this.moveTo(b,
a);this.lineTo(b+c,a);this.lineTo(b+c,a+d);this.lineTo(b,a+d);this.closePath()};i.strokeRect=function(b,a,c,d){var f=this.currentPath_;this.beginPath();this.moveTo(b,a);this.lineTo(b+c,a);this.lineTo(b+c,a+d);this.lineTo(b,a+d);this.closePath();this.stroke();this.currentPath_=f};i.fillRect=function(b,a,c,d){var f=this.currentPath_;this.beginPath();this.moveTo(b,a);this.lineTo(b+c,a);this.lineTo(b+c,a+d);this.lineTo(b,a+d);this.closePath();this.fill();this.currentPath_=f};i.createLinearGradient=function(b,
a,c,d){var f=new D("gradient");f.x0_=b;f.y0_=a;f.x1_=c;f.y1_=d;return f};i.createRadialGradient=function(b,a,c,d,f,h){var g=new D("gradientradial");g.x0_=b;g.y0_=a;g.r0_=c;g.x1_=d;g.y1_=f;g.r1_=h;return g};i.drawImage=function(b){var a,c,d,f,h,g,l,e,m=b.runtimeStyle.width,r=b.runtimeStyle.height;b.runtimeStyle.width="auto";b.runtimeStyle.height="auto";var n=b.width,o=b.height;b.runtimeStyle.width=m;b.runtimeStyle.height=r;if(arguments.length==3){a=arguments[1];c=arguments[2];h=g=0;l=d=n;e=f=o}else if(arguments.length==
5){a=arguments[1];c=arguments[2];d=arguments[3];f=arguments[4];h=g=0;l=n;e=o}else if(arguments.length==9){h=arguments[1];g=arguments[2];l=arguments[3];e=arguments[4];a=arguments[5];c=arguments[6];d=arguments[7];f=arguments[8]}else throw Error("Invalid number of arguments");var q=this.getCoords_(a,c),t=[];t.push(" <g_vml_:group",' coordsize="',k*10,",",k*10,'"',' coordorigin="0,0"',' style="width:',10,"px;height:",10,"px;position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]){var E=[];E.push("M11=",
this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",j(q.x/k),",","Dy=",j(q.y/k),"");var p=q,z=this.getCoords_(a+d,c),w=this.getCoords_(a,c+f),x=this.getCoords_(a+d,c+f);p.x=s.max(p.x,z.x,w.x,x.x);p.y=s.max(p.y,z.y,w.y,x.y);t.push("padding:0 ",j(p.x/k),"px ",j(p.y/k),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",E.join(""),", sizingmethod='clip');")}else t.push("top:",j(q.y/k),"px;left:",j(q.x/k),"px;");t.push(' ">','<g_vml_:image src="',b.src,
'"',' style="width:',k*d,"px;"," height:",k*f,'px;"',' cropleft="',h/n,'"',' croptop="',g/o,'"',' cropright="',(n-h-l)/n,'"',' cropbottom="',(o-g-e)/o,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",t.join(""))};i.stroke=function(b){var a=[],c=P(b?this.fillStyle:this.strokeStyle),d=c.color,f=c.alpha*this.globalAlpha;a.push("<g_vml_:shape",' filled="',!!b,'"',' style="position:absolute;width:',10,"px;height:",10,'px;"',' coordorigin="0 0" coordsize="',k*10," ",k*10,'"',' stroked="',
!b,'"',' path="');var h={x:null,y:null},g={x:null,y:null},l=0;for(;l<this.currentPath_.length;l++){var e=this.currentPath_[l];switch(e.type){case "moveTo":a.push(" m ",j(e.x),",",j(e.y));break;case "lineTo":a.push(" l ",j(e.x),",",j(e.y));break;case "close":a.push(" x ");e=null;break;case "bezierCurveTo":a.push(" c ",j(e.cp1x),",",j(e.cp1y),",",j(e.cp2x),",",j(e.cp2y),",",j(e.x),",",j(e.y));break;case "at":case "wa":a.push(" ",e.type," ",j(e.x-this.arcScaleX_*e.radius),",",j(e.y-this.arcScaleY_*e.radius),
" ",j(e.x+this.arcScaleX_*e.radius),",",j(e.y+this.arcScaleY_*e.radius)," ",j(e.xStart),",",j(e.yStart)," ",j(e.xEnd),",",j(e.yEnd));break}if(e){if(h.x==null||e.x<h.x)h.x=e.x;if(g.x==null||e.x>g.x)g.x=e.x;if(h.y==null||e.y<h.y)h.y=e.y;if(g.y==null||e.y>g.y)g.y=e.y}}a.push(' ">');if(b)if(typeof this.fillStyle=="object"){var m=this.fillStyle,r=0,n={x:0,y:0},o=0,q=1;if(m.type_=="gradient"){var t=m.x1_/this.arcScaleX_,E=m.y1_/this.arcScaleY_,p=this.getCoords_(m.x0_/this.arcScaleX_,m.y0_/this.arcScaleY_),
z=this.getCoords_(t,E);r=Math.atan2(z.x-p.x,z.y-p.y)*180/Math.PI;if(r<0)r+=360;if(r<1.0E-6)r=0}else{var p=this.getCoords_(m.x0_,m.y0_),w=g.x-h.x,x=g.y-h.y;n={x:(p.x-h.x)/w,y:(p.y-h.y)/x};w/=this.arcScaleX_*k;x/=this.arcScaleY_*k;var R=s.max(w,x);o=2*m.r0_/R;q=2*m.r1_/R-o}var u=m.colors_;u.sort(function(ba,ca){return ba.offset-ca.offset});var J=u.length,da=u[0].color,ea=u[J-1].color,fa=u[0].alpha*this.globalAlpha,ga=u[J-1].alpha*this.globalAlpha,S=[],l=0;for(;l<J;l++){var T=u[l];S.push(T.offset*q+
o+" "+T.color)}a.push('<g_vml_:fill type="',m.type_,'"',' method="none" focus="100%"',' color="',da,'"',' color2="',ea,'"',' colors="',S.join(","),'"',' opacity="',ga,'"',' g_o_:opacity2="',fa,'"',' angle="',r,'"',' focusposition="',n.x,",",n.y,'" />')}else a.push('<g_vml_:fill color="',d,'" opacity="',f,'" />');else{var K=this.lineScale_*this.lineWidth;if(K<1)f*=K;a.push("<g_vml_:stroke",' opacity="',f,'"',' joinstyle="',this.lineJoin,'"',' miterlimit="',this.miterLimit,'"',' endcap="',aa(this.lineCap),
'"',' weight="',K,'px"',' color="',d,'" />')}a.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",a.join(""))};i.fill=function(){this.stroke(true)};i.closePath=function(){this.currentPath_.push({type:"close"})};i.getCoords_=function(b,a){var c=this.m_;return{x:k*(b*c[0][0]+a*c[1][0]+c[2][0])-v,y:k*(b*c[0][1]+a*c[1][1]+c[2][1])-v}};i.save=function(){var b={};O(this,b);this.aStack_.push(b);this.mStack_.push(this.m_);this.m_=y(I(),this.m_)};i.restore=function(){O(this.aStack_.pop(),
this);this.m_=this.mStack_.pop()};function ha(b){var a=0;for(;a<3;a++){var c=0;for(;c<2;c++)if(!isFinite(b[a][c])||isNaN(b[a][c]))return false}return true}function A(b,a,c){if(!!ha(a)){b.m_=a;if(c)b.lineScale_=W(V(a[0][0]*a[1][1]-a[0][1]*a[1][0]))}}i.translate=function(b,a){A(this,y([[1,0,0],[0,1,0],[b,a,1]],this.m_),false)};i.rotate=function(b){var a=G(b),c=F(b);A(this,y([[a,c,0],[-c,a,0],[0,0,1]],this.m_),false)};i.scale=function(b,a){this.arcScaleX_*=b;this.arcScaleY_*=a;A(this,y([[b,0,0],[0,a,
0],[0,0,1]],this.m_),true)};i.transform=function(b,a,c,d,f,h){A(this,y([[b,a,0],[c,d,0],[f,h,1]],this.m_),true)};i.setTransform=function(b,a,c,d,f,h){A(this,[[b,a,0],[c,d,0],[f,h,1]],true)};i.clip=function(){};i.arcTo=function(){};i.createPattern=function(){return new U};function D(b){this.type_=b;this.r1_=this.y1_=this.x1_=this.r0_=this.y0_=this.x0_=0;this.colors_=[]}D.prototype.addColorStop=function(b,a){a=P(a);this.colors_.push({offset:b,color:a.color,alpha:a.alpha})};function U(){}G_vmlCanvasManager=
M;CanvasRenderingContext2D=H;CanvasGradient=D;CanvasPattern=U})();

View file

@ -1,104 +0,0 @@
function ST_Simplify( points, tolerance ) {
// helper classes
var Vector = function( x, y ) {
this.x = x;
this.y = y;
};
var Line = function( p1, p2 ) {
this.p1 = p1;
this.p2 = p2;
this.distanceToPoint = function( point ) {
// slope
var m = ( this.p2.y - this.p1.y ) / ( this.p2.x - this.p1.x );
// y offset
var b = this.p1.y - ( m * this.p1.x );
var d = [];
// distance to the linear equation
d.push( Math.abs( point.y - ( m * point.x ) - b ) / Math.sqrt( Math.pow( m, 2 ) + 1 ) )
// distance to p1
d.push( Math.sqrt( Math.pow( ( point.x - this.p1.x ), 2 ) + Math.pow( ( point.y - this.p1.y ), 2 ) ) )
// distance to p2
d.push( Math.sqrt( Math.pow( ( point.x - this.p2.x ), 2 ) + Math.pow( ( point.y - this.p2.y ), 2 ) ) );
// return the smallest distance
return d.sort( function( a, b ) {
return ( a - b ) //causes an array to be sorted numerically and ascending
} )[0];
}
};
var douglasPeucker = function( points, tolerance ) {
var returnPoints = [];
if ( points.length <= 2 ) {
return [points[0]];
}
// make line from start to end
var line = new Line( points[0], points[points.length - 1] );
// find the largest distance from intermediate poitns to this line
var maxDistance = 0;
var maxDistanceIndex = 0;
for( var i = 1; i <= points.length - 2; i++ ) {
var distance = line.distanceToPoint( points[ i ] );
if( distance > maxDistance ) {
maxDistance = distance;
maxDistanceIndex = i;
}
}
// check if the max distance is greater than our tollerance allows
if ( maxDistance >= tolerance ) {
var p = points[maxDistanceIndex];
line.distanceToPoint( p, true );
// include this point in the output
returnPoints = returnPoints.concat( douglasPeucker( points.slice( 0, maxDistanceIndex + 1 ), tolerance ) );
// returnPoints.push( points[maxDistanceIndex] );
returnPoints = returnPoints.concat( douglasPeucker( points.slice( maxDistanceIndex, points.length ), tolerance ) );
} else {
// ditching this point
var p = points[maxDistanceIndex];
line.distanceToPoint( p, true );
returnPoints = [points[0]];
}
return returnPoints;
};
var arr = douglasPeucker( points, tolerance );
// always have to push the very last point on so it doesn't get left off
arr.push( points[points.length - 1 ] );
return arr;
};
function ST_AngleAndCoordsAtLength(geom, len){
var length = 0;
var seglen = 0;
var x,y,p,l;
var pc = geom[0];
//alert(len);
for (c in geom){
c = geom[c];
if (c==pc) continue;
seglen = Math.sqrt(((pc[0]-c[0])*(pc[0]-c[0]))+((pc[1]-c[1])*(pc[1]-c[1])));
if ((length+seglen)>=len){
length = len - length;
x = (c[0]-pc[0])*length/seglen + pc[0]; //x on length
y = (c[1]-pc[1])*length/seglen + pc[1]; //y on length
p = Math.atan2(c[1]-pc[1],c[0]-pc[0]); // angle on length
l = Math.sqrt(((x-c[0])*(x-c[0]))+((y-c[1])*(y-c[1]))); // how many pixels left with same angle
return [p,x,y,l];
}
pc=c;
length += seglen;
}
}
function ST_Length(geom){ // length for a line formed by coordinates array
var length = 0;
var pc = geom[0];
for (c in geom){
c = geom[c];
length += Math.sqrt((pc[0]-c[0])*(pc[0]-c[0])+(pc[1]-c[1])*(pc[1]-c[1]));
pc=c;
}
return length;
}

View file

@ -1 +0,0 @@
imagesQ={onComplete:function(){},onLoaded:function(){},current:null,qLength:0,images:[],inProcess:false,queue:[],queue_images:function(){var arg=arguments;for(var i=0;i<arg.length;i++){if(arg[i].constructor===Array){this.queue=this.queue.concat(arg[i])}else if(typeof arg[i]==='string'){this.queue.push(arg[i])}}},process_queue:function(){this.inProcess=true;this.qLength+=this.queue.length;while(this.queue.length>0){this.load_image(this.queue.shift())}this.inProcess=false},load_image:function(imageSrc){var th=this;var im=new Image;im.onload=function(){th.current=im;th.images.push(im);(th.onLoaded)();if(th.queue.length>0&&!th.inProcess){th.process_queue()}if(th.qLength==th.images.length){(th.onComplete)()}};im.src='icons/'+imageSrc}}

View file

@ -1,157 +0,0 @@
function pathGeoJSON(ctx, val, ws, hs, gran, dashes, fill){
ctx.beginPath();
//alert(val.type);
if (val.type == "Polygon"){
var firstpoint = val.coordinates[0][0]
for (coordseq in val.coordinates) {
coordseq = val.coordinates[coordseq];
ctx.moveTo(ws*coordseq[0][0], hs*(gran-coordseq[0][1]));
var prevcoord = coordseq[0];
if (fill){
for (coord in coordseq) {
coord = coordseq[coord];
ctx.lineTo(ws*coord[0], hs*(gran-coord[1]));
};
}
else {
for (coord in coordseq) {
coord = coordseq[coord];
if ((prevcoord[0]==coord[0]&&(coord[0]==0||coord[0]==gran)) ||(prevcoord[1]==coord[1]&&(coord[1]==0||coord[1]==gran))) //hide boundaries
{ctx.moveTo(ws*coord[0], hs*(gran-coord[1]));}
else
{ctx.lineTo(ws*coord[0], hs*(gran-coord[1]));};
};
};
ctx.moveTo(ws*firstpoint[0], hs*(gran-firstpoint[1]));
};
}
if (val.type == "LineString"){
if (dashes!="aaa"){ctx.dashTo(ws*val.coordinates[0][0], hs*(gran-val.coordinates[0][1]),dashes);};
for (coord in val.coordinates) {
coord = val.coordinates[coord];
if (dashes=="aaa") {ctx.lineTo(ws*coord[0], hs*(gran-coord[1]));}
else {ctx.dashTo(ws*coord[0], hs*(gran-coord[1]));}
};
}
}
function textOnGeoJSON(ctx, val, ws, hs, gran, halo, collide, text){
if (val.type == "LineString"){
var projcoords = new Array();
var textwidth = 0;
var i = 0;
while (i<text.length){
var letter = text.substr(i,1);
textwidth += ctx.measureText(letter).width;
i++;
};
var aspect = textwidth / ctx.measureText(text).width;
for (coord in val.coordinates) {
coord = val.coordinates[coord];
projcoords.push([ws*coord[0], hs*(gran-coord[1])]);
};
//projcoords = ST_Simplify(projcoords, 1);
var linelength = ST_Length(projcoords);
if (linelength>textwidth) {
//alert("text: "+text+" width:"+textwidth+" space:"+linelength);
var widthused = 0;
var i = 0;
var prevangle = "aaa";
var positions = new Array();
var solution = 0;
var flipcount = 0;
var flipped = false;
while (solution < 2) {
if (solution == 0) widthused = linelength-textwidth/2;
if (solution == 1) widthused = 0;
flipcount = 0;
i = 0;
prevangle = "aaa";
positions = new Array();
while (i<text.length){
var letter = text.substr(i,1);
var letterwidth = ctx.measureText(letter).width/aspect;
var axy = ST_AngleAndCoordsAtLength(projcoords, widthused);
if (widthused>=linelength || !axy){
//alert("cannot fit text: "+text+" widthused:"+ widthused +" width:"+textwidth+" space:"+linelength+" letter:"+letter+" aspect:"+aspect);
solution++;
positions = new Array();
if (flipped) {projcoords.reverse(); flipped=false;}
break;
} // cannot fit
if (prevangle=="aaa") prevangle = axy[0];
if (
collide.checkPointWH([axy[1], axy[2]],
2.5*letterwidth,
2.5*letterwidth)
|| Math.abs(prevangle-axy[0])>0.2){
i = 0;
positions = new Array();
letter = text.substr(i,1);
widthused += letterwidth;
continue;
}
/*while (letterwidth > axy[3] && i<text.length){
i++;
letter += text.substr(i,1);
letterwidth = ctx.measureText(letter).width;
if (
collide.checkPointWH([axy[1]+0.5*Math.cos(axy[3])*letterwidth,
axy[2]+0.5*Math.sin(axy[3])*letterwidth],
2.5*letterwidth,
2.5*letterwidth)
|| Math.abs(prevangle-axy[0])>0.2){
i = 0;
positions = new Array();
letter = text.substr(i,1);
break;
}
}*/
if (axy[0]>Math.PI/2||axy[0]<-Math.PI/2){flipcount+=letter.length};
prevangle = axy[0];
axy.push(letter);
positions.push(axy);
widthused += letterwidth;
i++;
}
if (flipped && flipcount>text.length/2) {projcoords.reverse(); flipped=false;positions = new Array(); solution++; flipcount=0;}
if (!flipped && flipcount>text.length/2) {projcoords.reverse(); flipped=true;positions = new Array();}
if (solution>=2){ return}
if (positions.length>0) {break}
}
if (solution>=2){ return}
i = 0;
while (halo && i<positions.length){
var axy = positions[i];
var letter = axy[4];
ctx.save();
ctx.translate(axy[1],axy[2]);
ctx.rotate(axy[0]);
ctx.strokeText(letter, 0, 0);
ctx.restore();
i++;
}
i=0;
while (i<positions.length){
var axy = positions[i];
var letter = axy[4];
var letterwidth = ctx.measureText(letter).width;
ctx.save();
ctx.translate(axy[1],axy[2]);
ctx.rotate(axy[0]);
collide.addPointWH([axy[1]+0.5*Math.cos(axy[3])*letterwidth,
axy[2]+0.5*Math.sin(axy[3])*letterwidth],
2.5*letterwidth,
2.5*letterwidth)
//collide.addPointWH([axy[1],axy[2]],2.5*letterwidth+20,2.5*letterwidth+20);
ctx.fillText(letter, 0, 0);
ctx.restore();
i++;
}
};
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,21 +0,0 @@
<html>
<head>
<title>A canvas Map of Minsk</title>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<!--[if lt IE 9]><script src="excanvas.js"></script><![endif]-->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script src="stylesheet.js"></script>
<script src="canvas.js"></script>
<script src="jsondraw.js"></script>
<script src="imagesq.js"></script>
<script src="render.js"></script>
<script src="rgbcolor.js"></script>
<script src="geomops.js"></script>
</head>
<body onload="draw();">
<canvas id="canvas" width="1356" height="856"></canvas>
</body>
</html>

View file

@ -1,272 +0,0 @@
draw = function () {
imagesQ.queue_images(imagesToLoad);
imagesQ.process_queue();
$.getJSON('/z12.json',function(data) {
var start = new Date().getTime();
var ctxa = document.getElementById('canvas');
ctxa.width = 2*ctxa.width;
ctxa.height = 2*ctxa.height;
var ctx = ctxa.getContext('2d');
var ws = ctxa.width/data.granularity;
var hs = ctxa.height/data.granularity;
var zoom = 13;
var style = restyle({}, zoom, "canvas")["default"];
if ("fill-color" in style){ctx.fillStyle = style["fill-color"];};
if ("opacity" in style){ctx.globalAlpha = style["opacity"];};
if ("fill-opacity" in style){ctx.globalAlpha = style["fill-opacity"];};
var style = restyle({"natural":"coastline"}, zoom, "Polygon")["default"];
if ("fill-color" in style){ctx.fillStyle = style["fill-color"];};
if ("opacity" in style){ctx.globalAlpha = style["opacity"];};
if ("fill-opacity" in style){ctx.globalAlpha = style["fill-opacity"]};
ctx.fillRect (-1, -1, ctxa.width+1, ctxa.height+1);
ctx.strokeStyle = "rgba(0,0,0,0.5)";
ctx.fillStyle = "rgba(0,0,0,0.5)";
ctx.lineWidth = 1;
ctx.lineCap = "round";
ctx.lineJoin = "round";
var styledfeatures = new Array();
$.each(data.features, function(key, val) {
if (!("layer" in val.properties )){val.properties.layer=0};
$.each(restyle(val.properties, zoom, val.type), function(k,v){
var newObject = jQuery.extend({}, val);
newObject.style = v;
if ("z-index" in newObject.style) {newObject.style["z-index"] = parseFloat(newObject.style["z-index"]);}
else {newObject.style["z-index"] = 0;}
styledfeatures.push(newObject);
});
});
data.features = styledfeatures
data.features.sort(function (a,b){
//if ("layer" in a.properties && "layer" in b.properties && a.properties.layer!=b.properties.layer){return a.properties.layer-b.properties.layer};
return a.style["z-index"]-b.style["z-index"];
});
var zlayers = new Object();
var layerlist = new Array();
$.each(data.features, function(key, val) {
val.properties.layer=parseFloat(val.properties.layer);
if (isNaN(val.properties.layer)){val.properties.layer=0;};
if (val.style["-x-mapnik-layer"]=="top" ){val.properties.layer=10000};
if (val.style["-x-mapnik-layer"]=="bottom" ){val.properties.layer=-10000};
if (!(val.properties.layer in zlayers)) {
zlayers[val.properties.layer] = new Array();
layerlist.push(val.properties.layer);
};
zlayers[val.properties.layer].push(val);
});
layerlist.sort();
$.each(layerlist, function(key, sublay){ // polygons pass
var dat = zlayers[sublay];
$.each(dat, function(key, val) {
ctx.save()
style = val.style;
if ("fill-color" in style) {
ctx.fillStyle = style["fill-color"];
if ("opacity" in style){ctx.globalAlpha = style["opacity"]};
if ("fill-opacity" in style){ctx.globalAlpha = style["fill-opacity"]};
pathGeoJSON(ctx, val, ws, hs, data.granularity, "aaa", true);
ctx.fill();
};
ctx.restore();
});
ctx.lineCap = "butt";
$.each(dat, function(key, val) { // casings pass
ctx.save()
style = val.style;
if ("casing-width" in style) {
var width = 2*style["casing-width"];
var dashes = "aaa";
if ("width" in style){width += style["width"]};
ctx.lineWidth = width;
if ("color" in style){ctx.strokeStyle = style["color"]};
if ("linecap" in style){ctx.lineCap = style["linecap"]};
if ("linejoin" in style){ctx.lineJoin = style["linejoin"]};
if ("dashes" in style){dashes = style["dashes"].split(",")};
if ("opacity" in style){ctx.globalAlpha = style["opacity"]};
if ("casing-color" in style){ctx.strokeStyle = style["casing-color"]};
if ("casing-linecap" in style){ctx.lineCap = style["casing-linecap"]};
if ("casing-linejoin" in style){ctx.lineJoin = style["casing-linejoin"]};
if ("casing-dashes" in style){dashes = style["casing-dashes"].split(",")};
if ("casing-opacity" in style){ctx.globalAlpha = style["casing-opacity"]};
pathGeoJSON(ctx, val, ws, hs, data.granularity, dashes);
ctx.stroke();
};
ctx.restore();
});
ctx.lineCap = "round";
$.each(dat, function(key, val) { // lines pass
ctx.save()
style = val.style;
if ("width" in style) {
var dashes = "aaa";
if ("color" in style){ctx.strokeStyle = style["color"]};
if ("linecap" in style){ctx.lineCap = style["linecap"]};
if ("linejoin" in style){ctx.lineJoin = style["linejoin"]};
if ("dashes" in style){dashes = style["dashes"].split(",")};
if ("opacity" in style){ctx.globalAlpha = style["opacity"]};
ctx.lineWidth = style["width"];
pathGeoJSON(ctx, val, ws, hs, data.granularity, dashes);
ctx.stroke();
};
ctx.restore();
});
});
var collides = new collisionBuffer();
layerlist.reverse();
$.each(layerlist, function(key, sublay){
var dat = zlayers[sublay];
dat.reverse();
$.each(dat, function(key, val) { // icons pass
ctx.save()
style = val.style;
if ("icon-image" in style) {
var img = new Image();
img.src = 'icons/'+style["icon-image"];
var offset = 0;
var opacity = 1;
var mindistance = 0;
var textwidth = 0;
if ("text-offset" in style){offset = style["text-offset"]};
if ("text-color" in style){ctx.fillStyle = style["text-color"];};
if ("text-halo-radius" in style){ctx.lineWidth = style["text-halo-radius"]+2};
if ("text-halo-color" in style){ctx.strokeStyle = style["text-halo-color"]};
if ("opacity" in style){opacity = style["opacity"]};
if ("text-opacity" in style){opacity = style["text-opacity"]};
if ("-x-mapnik-min-distance" in style){mindistance = style["-x-mapnik-min-distance"]};
var point;
if (val.type == "Point"){ point = [ws*val.coordinates[0],hs*(data.granularity-val.coordinates[1])]};
if (val.type == "Polygon"){ point = [ws*val.reprpoint[0],hs*(data.granularity-val.reprpoint[1])]};
//alert(collides.checkPointWH(point, img.width, img.height));
if (style["text"]){ctx.font = fontString(style["font-family"],style["font-size"]);};
if (collides.checkPointWH(point, img.width, img.height)){return;}
if (style["text"]){
textwidth = ctx.measureText(style["text"]).width;
if (!(style["text-allow-overlap"]=="true")&&collides.checkPointWH([point[0],point[1]+offset], textwidth, 10)){return;}
}
if (opacity <1){
ctx.fillStyle = new RGBColor(ctx.fillStyle, opacity).toRGBA();
ctx.strokeStyle = new RGBColor(ctx.strokeStyle, opacity).toRGBA();
}
ctx.textAlign = "center";
ctx.textBaseline = "middle";
if(style["text"]){
if ("text-halo-radius" in style)
ctx.strokeText(style["text"], point[0],point[1]+offset);
ctx.fillText(style["text"], point[0],point[1]+offset);
}
ctx.drawImage(img, point[0]-img.width/2,point[1]-img.height/2);
collides.addPointWH(point, img.width, img.height,mindistance);
collides.addPointWH([point[0],point[1]+offset], textwidth, 10, mindistance);
};
ctx.restore();
});
$.each(dat, function(key, val) { // text pass
ctx.save()
style = val.style;
if ("text" in style && !("icon-image" in style) && style["text"]!="") {
var offset = 0;
var opacity = 1;
var mindistance = 0;
if ("text-offset" in style){offset = style["text-offset"]};
if ("text-color" in style){ctx.fillStyle = style["text-color"];};
if ("text-halo-radius" in style){ctx.lineWidth = style["text-halo-radius"]+2};
if ("text-halo-color" in style){ctx.strokeStyle = style["text-halo-color"]};
if ("opacity" in style){opacity = style["opacity"]};
if ("text-opacity" in style){opacity = style["text-opacity"]};
if ("-x-mapnik-min-distance" in style){mindistance = style["-x-mapnik-min-distance"]};
var point;
if (val.type == "Point"){ point = [ws*val.coordinates[0],hs*(data.granularity-val.coordinates[1])]};
if (val.type == "Polygon"){ point = [ws*val.reprpoint[0],hs*(data.granularity-val.reprpoint[1])]};
if (val.type == "LineString"){ point = [ws*val.coordinates[0][0],hs*(data.granularity-val.coordinates[0][1])]};
if (style["text"]){ctx.font = fontString(style["font-family"],style["font-size"]);};
textwidth = ctx.measureText(style["text"]).width;
if (!(style["text-allow-overlap"]=="true")&&collides.checkPointWH([point[0],point[1]+offset], textwidth, 5)) return;
if (opacity <1){
ctx.fillStyle = new RGBColor(ctx.fillStyle, opacity).toRGBA();
ctx.strokeStyle = new RGBColor(ctx.strokeStyle, opacity).toRGBA();
}
ctx.textAlign = "center";
ctx.textBaseline = "middle";
if (val.type=="Polygon" || val.type == "Point"){
if ("text-halo-radius" in style)
ctx.strokeText(style["text"], point[0],point[1]+offset);
ctx.fillText(style["text"], point[0],point[1]+offset);
collides.addPointWH([point[0],point[1]+offset], textwidth, 10, mindistance);
}
else{//Linestring
textOnGeoJSON(ctx, val, ws, hs, data.granularity, ("text-halo-radius" in style), collides, style["text"])
};
};
ctx.restore();
});
collides.buffer = new Array();
for (poly in collides.buffer){
poly = collides.buffer[poly];
ctx.fillRect(poly[0],poly[1],poly[2]-poly[0],poly[3]-poly[1])
}
});
var elapsed = new Date().getTime()-start;
alert(elapsed);
});
};
fontString = function(name, size){
var weight = "400";
var family = "sans";
var italic = "";
if (!size) size = 9;
if (!name) name = "sans";
name = name.toLowerCase();
if (name.indexOf("italic")>=0) italic = "italic";
if (name.indexOf("oblique")>=0) italic = "italic";
if (name.indexOf("bold")>=0) weight = "700";
//alert(name);
if (name.indexOf("serif")>=0) family = "sans-serif";
if (name.indexOf("dejavu sans")>=0) family = '"DejaVu Sans", Arial, sans';
if (name.indexOf("dejavu sans book")>=0) family = '"DejaVu Sans Book", "DejaVu Sans", Arial, sans';
//if (name.indexOf("dejavu sans oblique")>=0) family = '"Deja Vu Sans Oblique", sans-serif';
if (name.indexOf("dejavu sans extralight")>=0) family = '"DejaVu Sans ExtraLight", "DejaVu Sans", Arial, sans';
if (name.indexOf("dejavu serif")>=0) family = '"DejaVu Serif", "Times New Roman", sans-serif';
if (name.indexOf("dejavu sans mono")>=0) family = '"DejaVu Sans Mono", Terminal, monospace';
if (name.indexOf("dejavu sans mono book")>=0) family = '"DejaVu Sans Mono Book", "DejaVu Sans Mono", Terminal, monospace';
font = weight + " " + italic + " " + size +"px " + family;
//alert(font);
return font;
}
function collisionBuffer(){
this.buffer = new Array();
this.addBox = function(box){
this.buffer.push(box);
}
this.addPointWH = function(point, w, h, d){
if (!d)d=0;
this.buffer.push([point[0]-w/2-d, point[1]-h/2-d, point[0]+w/2-d, point[1]+w/2-d]);
}
this.checkBox = function(b){
for (i in this.buffer){
c = this.buffer[i];
//alert([b,c])
if ((c[0]<=b[2] && c[1]<=b[3] && c[2]>=b[0] && c[3]>=b[1])){return true;};
}
return false;
}
this.checkPointWH = function(point, w, h){
return this.checkBox([point[0]-w/2, point[1]-h/2, point[0]+w/2, point[1]+w/2]);
}
}

View file

@ -1,295 +0,0 @@
/**
* A class to parse color values
* @author Stoyan Stefanov <sstoo@gmail.com>
* @link http://www.phpied.com/rgb-color-parser-in-javascript/
* @license Use it if you like it
*/
function RGBColor(color_string, alpha)
{
this.ok = false;
// strip any leading #
if (color_string.charAt(0) == '#') { // remove # if any
color_string = color_string.substr(1,6);
}
color_string = color_string.replace(/ /g,'');
color_string = color_string.toLowerCase();
// before getting into regexps, try simple matches
// and overwrite the input
var simple_colors = {
aliceblue: 'f0f8ff',
antiquewhite: 'faebd7',
aqua: '00ffff',
aquamarine: '7fffd4',
azure: 'f0ffff',
beige: 'f5f5dc',
bisque: 'ffe4c4',
black: '000000',
blanchedalmond: 'ffebcd',
blue: '0000ff',
blueviolet: '8a2be2',
brown: 'a52a2a',
burlywood: 'deb887',
cadetblue: '5f9ea0',
chartreuse: '7fff00',
chocolate: 'd2691e',
coral: 'ff7f50',
cornflowerblue: '6495ed',
cornsilk: 'fff8dc',
crimson: 'dc143c',
cyan: '00ffff',
darkblue: '00008b',
darkcyan: '008b8b',
darkgoldenrod: 'b8860b',
darkgray: 'a9a9a9',
darkgreen: '006400',
darkkhaki: 'bdb76b',
darkmagenta: '8b008b',
darkolivegreen: '556b2f',
darkorange: 'ff8c00',
darkorchid: '9932cc',
darkred: '8b0000',
darksalmon: 'e9967a',
darkseagreen: '8fbc8f',
darkslateblue: '483d8b',
darkslategray: '2f4f4f',
darkturquoise: '00ced1',
darkviolet: '9400d3',
deeppink: 'ff1493',
deepskyblue: '00bfff',
dimgray: '696969',
dodgerblue: '1e90ff',
feldspar: 'd19275',
firebrick: 'b22222',
floralwhite: 'fffaf0',
forestgreen: '228b22',
fuchsia: 'ff00ff',
gainsboro: 'dcdcdc',
ghostwhite: 'f8f8ff',
gold: 'ffd700',
goldenrod: 'daa520',
gray: '808080',
green: '008000',
greenyellow: 'adff2f',
honeydew: 'f0fff0',
hotpink: 'ff69b4',
indianred : 'cd5c5c',
indigo : '4b0082',
ivory: 'fffff0',
khaki: 'f0e68c',
lavender: 'e6e6fa',
lavenderblush: 'fff0f5',
lawngreen: '7cfc00',
lemonchiffon: 'fffacd',
lightblue: 'add8e6',
lightcoral: 'f08080',
lightcyan: 'e0ffff',
lightgoldenrodyellow: 'fafad2',
lightgrey: 'd3d3d3',
lightgreen: '90ee90',
lightpink: 'ffb6c1',
lightsalmon: 'ffa07a',
lightseagreen: '20b2aa',
lightskyblue: '87cefa',
lightslateblue: '8470ff',
lightslategray: '778899',
lightsteelblue: 'b0c4de',
lightyellow: 'ffffe0',
lime: '00ff00',
limegreen: '32cd32',
linen: 'faf0e6',
magenta: 'ff00ff',
maroon: '800000',
mediumaquamarine: '66cdaa',
mediumblue: '0000cd',
mediumorchid: 'ba55d3',
mediumpurple: '9370d8',
mediumseagreen: '3cb371',
mediumslateblue: '7b68ee',
mediumspringgreen: '00fa9a',
mediumturquoise: '48d1cc',
mediumvioletred: 'c71585',
midnightblue: '191970',
mintcream: 'f5fffa',
mistyrose: 'ffe4e1',
moccasin: 'ffe4b5',
navajowhite: 'ffdead',
navy: '000080',
oldlace: 'fdf5e6',
olive: '808000',
olivedrab: '6b8e23',
orange: 'ffa500',
orangered: 'ff4500',
orchid: 'da70d6',
palegoldenrod: 'eee8aa',
palegreen: '98fb98',
paleturquoise: 'afeeee',
palevioletred: 'd87093',
papayawhip: 'ffefd5',
peachpuff: 'ffdab9',
peru: 'cd853f',
pink: 'ffc0cb',
plum: 'dda0dd',
powderblue: 'b0e0e6',
purple: '800080',
red: 'ff0000',
rosybrown: 'bc8f8f',
royalblue: '4169e1',
saddlebrown: '8b4513',
salmon: 'fa8072',
sandybrown: 'f4a460',
seagreen: '2e8b57',
seashell: 'fff5ee',
sienna: 'a0522d',
silver: 'c0c0c0',
skyblue: '87ceeb',
slateblue: '6a5acd',
slategray: '708090',
snow: 'fffafa',
springgreen: '00ff7f',
steelblue: '4682b4',
tan: 'd2b48c',
teal: '008080',
thistle: 'd8bfd8',
tomato: 'ff6347',
turquoise: '40e0d0',
violet: 'ee82ee',
violetred: 'd02090',
wheat: 'f5deb3',
white: 'ffffff',
whitesmoke: 'f5f5f5',
yellow: 'ffff00',
yellowgreen: '9acd32'
};
for (var key in simple_colors) {
if (color_string == key) {
color_string = simple_colors[key];
}
}
// emd of simple type-in colors
// array of color definition objects
var color_defs = [
{
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
process: function (bits){
return [
parseInt(bits[1]),
parseInt(bits[2]),
parseInt(bits[3])
];
}
},
{
re: /^(\w{2})(\w{2})(\w{2})$/,
example: ['#00ff00', '336699'],
process: function (bits){
return [
parseInt(bits[1], 16),
parseInt(bits[2], 16),
parseInt(bits[3], 16)
];
}
},
{
re: /^(\w{1})(\w{1})(\w{1})$/,
example: ['#fb0', 'f0f'],
process: function (bits){
return [
parseInt(bits[1] + bits[1], 16),
parseInt(bits[2] + bits[2], 16),
parseInt(bits[3] + bits[3], 16)
];
}
}
];
// search through the definitions to find a match
for (var i = 0; i < color_defs.length; i++) {
var re = color_defs[i].re;
var processor = color_defs[i].process;
var bits = re.exec(color_string);
if (bits) {
channels = processor(bits);
this.r = channels[0];
this.g = channels[1];
this.b = channels[2];
this.ok = true;
}
}
// validate/cleanup values
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
if (alpha) this.a = alpha
else this.a = 1;
// some getters
this.toRGB = function () {
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
}
this.toRGBA = function () {
return 'rgba(' + this.r + ', ' + this.g + ', ' + this.b + ', ' + this.a + ')';
}
this.toHex = function () {
var r = this.r.toString(16);
var g = this.g.toString(16);
var b = this.b.toString(16);
if (r.length == 1) r = '0' + r;
if (g.length == 1) g = '0' + g;
if (b.length == 1) b = '0' + b;
return '#' + r + g + b;
}
// help
this.getHelpXML = function () {
var examples = new Array();
// add regexps
for (var i = 0; i < color_defs.length; i++) {
var example = color_defs[i].example;
for (var j = 0; j < example.length; j++) {
examples[examples.length] = example[j];
}
}
// add type-in colors
for (var sc in simple_colors) {
examples[examples.length] = sc;
}
var xml = document.createElement('ul');
xml.setAttribute('id', 'rgbcolor-examples');
for (var i = 0; i < examples.length; i++) {
try {
var list_item = document.createElement('li');
var list_color = new RGBColor(examples[i]);
var example_div = document.createElement('div');
example_div.style.cssText =
'margin: 3px; '
+ 'border: 1px solid black; '
+ 'background:' + list_color.toHex() + '; '
+ 'color:' + list_color.toHex()
;
example_div.appendChild(document.createTextNode('test'));
var list_item_value = document.createTextNode(
' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex()
);
list_item.appendChild(example_div);
list_item.appendChild(list_item_value);
xml.appendChild(list_item);
} catch(e){}
}
return xml;
}
}

View file

@ -1,243 +0,0 @@
# -*- coding: utf-8 -*-
from twms import projections
from libkomapnik import pixel_size_at_zoom
import json
import psycopg2
from mapcss import MapCSS
import cgi
import os
import sys
reload(sys)
sys.setdefaultencoding("utf-8") # a hack to support UTF-8
try:
import psyco
psyco.full()
except ImportError:
pass
# print >>sys.stderr, "Psyco import failed. Program may run slower. If you run it on i386 machine, please install Psyco to get best performance."
def get_vectors(bbox, zoom, style, vec="polygon"):
bbox_p = projections.from4326(bbox, "EPSG:3857")
geomcolumn = "way"
database = "dbname=gis user=gis"
pxtolerance = 1.8
intscalefactor = 10000
ignore_columns = set(["way_area", "osm_id", geomcolumn, "tags", "z_order"])
table = {"polygon": "planet_osm_polygon", "line": "planet_osm_line", "point": "planet_osm_point", "coastline": "coastlines"}
a = psycopg2.connect(database)
b = a.cursor()
if vec != "coastline":
b.execute("SELECT * FROM %s LIMIT 1;" % table[vec])
names = [q[0] for q in b.description]
for i in ignore_columns:
if i in names:
names.remove(i)
names = ",".join(['"' + i + '"' for i in names])
taghint = "*"
types = {"line": "line", "polygon": "area", "point": "node"}
adp = ""
if "get_sql_hints" in dir(style):
sql_hint = style.get_sql_hints(types[vec], zoom)
adp = []
for tp in sql_hint:
add = []
for j in tp[0]:
if j not in names:
break
else:
add.append(tp[1])
if add:
add = " OR ".join(add)
add = "(" + add + ")"
adp.append(add)
adp = " OR ".join(adp)
if adp:
adp = adp.replace("&lt;", "<")
adp = adp.replace("&gt;", ">")
if vec == "polygon":
query = """select ST_AsGeoJSON(ST_TransScale(ST_ForceRHR(ST_Intersection(way,SetSRID('BOX3D(%s %s,%s %s)'::box3d,900913))),%s,%s,%s,%s),0) as %s,
ST_AsGeoJSON(ST_TransScale(ST_ForceRHR(ST_PointOnSurface(way)),%s,%s,%s,%s),0) as reprpoint, %s from
(select (ST_Dump(ST_Multi(ST_SimplifyPreserveTopology(ST_Buffer(way,-%s),%s)))).geom as %s, %s from
(select ST_Union(way) as %s, %s from
(select ST_Buffer(way, %s) as %s, %s from
%s
where (%s)
and way && SetSRID('BOX3D(%s %s,%s %s)'::box3d,900913)
and way_area > %s
) p
group by %s
) p
where ST_Area(way) > %s
order by ST_Area(way)
) p
""" % (bbox_p[0], bbox_p[1], bbox_p[2], bbox_p[3],
-bbox_p[0], -bbox_p[1], intscalefactor / (bbox_p[2] - bbox_p[0]), intscalefactor / (bbox_p[3] - bbox_p[1]),
geomcolumn,
-bbox_p[0], -bbox_p[1], intscalefactor / (bbox_p[2] - bbox_p[0]), intscalefactor / (bbox_p[3] - bbox_p[1]),
names,
pixel_size_at_zoom(zoom, pxtolerance), pixel_size_at_zoom(zoom, pxtolerance),
geomcolumn, names,
geomcolumn, names,
pixel_size_at_zoom(zoom, pxtolerance),
geomcolumn, names,
table[vec],
adp,
bbox_p[0], bbox_p[1], bbox_p[2], bbox_p[3],
(pixel_size_at_zoom(zoom, pxtolerance) ** 2) / pxtolerance,
names,
pixel_size_at_zoom(zoom, pxtolerance) ** 2
)
elif vec == "line":
query = """select ST_AsGeoJSON(ST_TransScale(ST_Intersection(way,SetSRID('BOX3D(%s %s,%s %s)'::box3d,900913)),%s,%s,%s,%s),0) as %s, %s from
(select (ST_Dump(ST_Multi(ST_SimplifyPreserveTopology(ST_LineMerge(way),%s)))).geom as %s, %s from
(select ST_Union(way) as %s, %s from
%s
where (%s)
and way && SetSRID('BOX3D(%s %s,%s %s)'::box3d,900913)
group by %s
) p
) p
""" % (bbox_p[0], bbox_p[1], bbox_p[2], bbox_p[3],
-bbox_p[0], -bbox_p[1], intscalefactor / (bbox_p[2] - bbox_p[0]), intscalefactor / (bbox_p[3] - bbox_p[1]),
geomcolumn, names,
pixel_size_at_zoom(zoom, pxtolerance),
geomcolumn, names,
geomcolumn, names,
table[vec],
adp,
bbox_p[0], bbox_p[1], bbox_p[2], bbox_p[3],
names,
)
elif vec == "point":
query = """select ST_AsGeoJSON(ST_TransScale(way,%s,%s,%s,%s),0) as %s, %s
from %s where
(%s)
and way && SetSRID('BOX3D(%s %s,%s %s)'::box3d,900913)
limit 10000
""" % (
-bbox_p[0], -bbox_p[1], intscalefactor / (bbox_p[2] - bbox_p[0]), intscalefactor / (bbox_p[3] - bbox_p[1]),
geomcolumn, names,
table[vec],
adp,
bbox_p[0], bbox_p[1], bbox_p[2], bbox_p[3],
)
elif vec == "coastline":
query = """select ST_AsGeoJSON(ST_TransScale(ST_ForceRHR(ST_Intersection(way,SetSRID('BOX3D(%s %s,%s %s)'::box3d,900913))),%s,%s,%s,%s),0) as %s, 'coastline' as "natural" from
(select (ST_Dump(ST_Multi(ST_SimplifyPreserveTopology(ST_Buffer(way,-%s),%s)))).geom as %s from
(select ST_Union(way) as %s from
(select ST_Buffer(SetSRID(the_geom,900913), %s) as %s from
%s
where
SetSRID(the_geom,900913) && SetSRID('BOX3D(%s %s,%s %s)'::box3d,900913)
) p
) p
where ST_Area(way) > %s
) p
""" % (bbox_p[0], bbox_p[1], bbox_p[2], bbox_p[3],
-bbox_p[0], -bbox_p[1], intscalefactor / (bbox_p[2] - bbox_p[0]), intscalefactor / (bbox_p[3] - bbox_p[1]),
geomcolumn,
pixel_size_at_zoom(zoom, pxtolerance), pixel_size_at_zoom(zoom, pxtolerance),
geomcolumn,
geomcolumn,
pixel_size_at_zoom(zoom, pxtolerance),
geomcolumn,
table[vec],
bbox_p[0], bbox_p[1], bbox_p[2], bbox_p[3],
pixel_size_at_zoom(zoom, pxtolerance) ** 2
)
# print query
a = psycopg2.connect(database)
b = a.cursor()
b.execute(query)
names = [q[0] for q in b.description]
ROWS_FETCHED = 0
polygons = []
for row in b.fetchall():
ROWS_FETCHED += 1
geom = dict(map(None, names, row))
for t in geom.keys():
if not geom[t]:
del geom[t]
geojson = json.loads(geom[geomcolumn])
del geom[geomcolumn]
if geojson["type"] == "GeometryCollection":
continue
if "reprpoint" in geom:
geojson["reprpoint"] = json.loads(geom["reprpoint"])["coordinates"]
del geom["reprpoint"]
prop = {}
for k, v in geom.iteritems():
prop[k] = v
try:
if int(v) == float(v):
prop[k] = int(v)
else:
prop[k] = float(v)
if str(prop[k]) != v: # leading zeros etc.. should be saved
prop[k] = v
except:
pass
geojson["properties"] = prop
polygons.append(geojson)
return {"bbox": bbox, "granularity": intscalefactor, "features": polygons}
print "Content-Type: text/html"
print
form = cgi.FieldStorage()
if "z" not in form:
print "need z"
exit()
if "x" not in form:
print "need x"
exit()
if "y" not in form:
print "need y"
exit()
z = int(form["z"].value)
x = int(form["x"].value)
y = int(form["y"].value)
if z > 22:
exit()
callback = "onKothicDataResponse"
bbox = projections.bbox_by_tile(z + 1, x, y, "EPSG:3857")
style = MapCSS(0, 30)
style.parse(open("styles/osmosnimki-maps.mapcss", "r").read())
zoom = z + 2
aaaa = get_vectors(bbox, zoom, style, "coastline")
aaaa["features"].extend(get_vectors(bbox, zoom, style, "polygon")["features"])
aaaa["features"].extend(get_vectors(bbox, zoom, style, "line")["features"])
aaaa["features"].extend(get_vectors(bbox, zoom, style, "point")["features"])
aaaa = callback + "(" + json.dumps(aaaa, True, False, separators=(',', ':')) + ",%s,%s,%s);" % (z, x, y)
print aaaa
dir = "/var/www/vtile/%s/%s/" % (z, x)
file = "%s.js" % y
try:
if not os.path.exists(dir):
os.makedirs(dir)
except:
pass
file = open(dir + file, "w")
file.write(aaaa)
file.flush()
file.close()

View file

@ -1,16 +0,0 @@
[mapnik]
map_proj = +init=epsg:3857
db_proj = +init=epsg:3857
table_prefix = planet_osm_
db_user = gis
db_name = gis
db_srid = 900913
icons_path = /home/gis/mapnik/kosmo/icons/
world_bnd_path = /home/gis/mapnik/world_boundaries/
cleantopo_dem_path = /raid/srtm/Full/CleanTOPO2merc.tif
srtm_dem_path = /raid/srtm/srtmm.vrt
cleantopo_hs_path = /raid/srtm/Full/CleanTOPO2merchs.tif
srtm_hs_path = /raid/srtm/srtmhs.vrt
default_font_family = DejaVu Sans Book
max_char_angle_delta = 17
font_tracking = 0

View file

@ -1,895 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
from debug import debug, Timer
from mapcss import MapCSS
import gc
gc.disable()
import mapcss.webcolors
whatever_to_hex = mapcss.webcolors.webcolors.whatever_to_hex
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
import os
try:
import Image
except ImportError:
pass
from optparse import OptionParser
import ConfigParser
import csv
import math
config = ConfigParser.ConfigParser()
def relaxedFloat(x):
try:
return float(x) if int(float(x)) != float(x) else int(x)
except ValueError:
return float(str(x).replace(",", "."))
parser = OptionParser()
parser.add_option("-r", "--renderer", dest="renderer", default="mapnik",
help="which renderer stylesheet to generate", metavar="ENGINE")
parser.add_option("-s", "--stylesheet", dest="filename",
help="read MapCSS stylesheet from FILE", metavar="FILE")
parser.add_option("-f", "--minzoom", dest="minzoom", default=0, type="int",
help="minimal available zoom level", metavar="ZOOM")
parser.add_option("-t", "--maxzoom", dest="maxzoom", default=19, type="int",
help="maximal available zoom level", metavar="ZOOM")
parser.add_option("-l", "--locale", dest="locale",
help="language that should be used for labels (ru, en, be, uk..)", metavar="LANG")
parser.add_option("-o", "--output-file", dest="outfile", default="-",
help="output filename (defaults to stdout)", metavar="FILE")
parser.add_option("-p", "--osm2pgsql-style", dest="osm2pgsqlstyle", default="-",
help="osm2pgsql stylesheet filename", metavar="FILE")
parser.add_option("-b", "--background-only", dest="bgonly", action="store_true", default=False,
help="Skip rendering of icons and labels", metavar="BOOL")
parser.add_option("-T", "--text-scale", dest="textscale", default=1, type="float",
help="text size scale", metavar="SCALE")
parser.add_option("-c", "--config", dest="conffile", default="komap.conf",
help="config file name", metavar="FILE")
(options, args) = parser.parse_args()
if (options.filename is None):
parser.error("MapCSS stylesheet filename is required")
def escape_sql_column(name, type="way", asname=False):
if name in mapped_cols:
return name # already escaped
name = name.strip().strip('"')
type = {'line': 'way', 'area': 'way'}.get(type, type)
if type in osm2pgsql_avail_keys.get(name, ()) or not osm2pgsql_avail_keys:
return '"' + name + '"'
elif not asname:
return "(tags->'" + name + "')"
else:
return "(tags->'" + name + "') as \"" + name + '"'
style = MapCSS(options.minzoom, options.maxzoom + 1) # zoom levels
style.parse(filename = options.filename)
if options.renderer == "mapswithme":
from libkomwm import *
komap_mapswithme(options, style, options.filename)
exit()
if options.outfile == "-":
mfile = sys.stdout
else:
mfile = open(options.outfile, "w")
if options.renderer == "js":
from libkojs import *
komap_js(mfile, style)
if options.renderer == "mapnik":
import libkomapnik
config.read(['komap.conf', os.path.expanduser('~/.komap/komap.conf'), options.conffile])
libkomapnik.map_proj = config.get("mapnik", "map_proj")
libkomapnik.db_proj = config.get("mapnik", "db_proj")
libkomapnik.table_prefix = config.get("mapnik", "table_prefix")
libkomapnik.db_user = config.get("mapnik", "db_user")
libkomapnik.db_name = config.get("mapnik", "db_name")
libkomapnik.db_srid = config.get("mapnik", "db_srid")
libkomapnik.icons_path = config.get("mapnik", "icons_path")
libkomapnik.world_bnd_path = config.get("mapnik", "world_bnd_path")
libkomapnik.cleantopo_dem_path = config.get("mapnik", "cleantopo_dem_path")
libkomapnik.srtm_dem_path = config.get("mapnik", "srtm_dem_path")
libkomapnik.cleantopo_hs_path = config.get("mapnik", "cleantopo_hs_path")
libkomapnik.srtm_hs_path = config.get("mapnik", "srtm_hs_path")
libkomapnik.text_scale = options.textscale
libkomapnik.default_font_family = config.get("mapnik", "default_font_family")
libkomapnik.max_char_angle_delta = config.get("mapnik", "max_char_angle_delta")
libkomapnik.font_tracking = config.get("mapnik", "font_tracking")
from libkomapnik import *
osm2pgsql_avail_keys = {} # "column" : ["node", "way"]
if options.osm2pgsqlstyle != "-":
mf = open(options.osm2pgsqlstyle, "r")
for line in mf:
line = line.strip().split()
if line and line[0][0] != "#" and not ("phstore" in line):
osm2pgsql_avail_keys[line[1]] = tuple(line[0].split(","))
osm2pgsql_avail_keys["tags"] = ("node", "way")
columnmap = {}
if options.locale == "en":
columnmap["name"] = (u"""COALESCE(
"name:en",
"int_name",
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace
(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace
(replace(replace
(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(translate("name:be",'АБВГДЖЗІЙКЛМНОПРСТУЎФЦЧШЫЭабвгджзійклмнопрстуўфцчшыэ', 'ABVHDŽZIJKLMNOPRSTUŬFСČŠYEabvhdžzijklmnoprstuŭfсčšye'), 'х', 'ch'), 'Х', 'Ch'), 'BЕ', 'BIe'), '', 'BIo'), '', 'BIu'), '', 'BIa'), 'Bе', 'Bie'), '', 'Bio'), '', 'Biu'), '', 'Bia'), 'VЕ', 'VIe'), '', 'VIo'), '', 'VIu'), '', 'VIa'), 'Vе', 'Vie'), '', 'Vio'), '', 'Viu'), '', 'Via'), 'HЕ',
'HIe'), '',
'HIo'), '', 'HIu'), '', 'HIa'), 'Hе', 'Hie'), '', 'Hio'), '', 'Hiu'), '', 'Hia'), 'DЕ', 'DIe'), '', 'DIo'), '', 'DIu'), '', 'DIa'), 'Dе', 'Die'), '', 'Dio'), '', 'Diu'), '', 'Dia'), 'ŽЕ', 'ŽIe'), 'ŽЁ', 'ŽIo'), 'ŽЮ', 'ŽIu'), 'ŽЯ', 'ŽIa'), 'Žе', 'Žie'), 'Žё', 'Žio'), 'Žю', 'Žiu'), 'Žя', 'Žia'), 'ZЕ', 'ZIe'), '', 'ZIo'), '', 'ZIu'), '', 'ZIa'), 'Zе', 'Zie'), '', 'Zio'), '', 'Ziu'), '', 'Zia'), 'JЕ', 'JIe'), '', 'JIo'), '', 'JIu'), '', 'JIa'), 'Jе', 'Jie'), '', 'Jio'), '', 'Jiu'),
'', 'Jia'), 'КЕ', 'КIe'), 'КЁ', 'КIo'), 'КЮ', 'КIu'), 'КЯ', 'КIa'), 'Ке', 'Кie'), 'Кё', 'Кio'), 'Кю', 'Кiu'), 'Кя', 'Кia'), 'LЕ', 'LIe'), '', 'LIo'), '', 'LIu'), '', 'LIa'), 'Lе', 'Lie'), '', 'Lio'), '', 'Liu'), '', 'Lia'), 'MЕ', 'MIe'), '', 'MIo'), '', 'MIu'), '', 'MIa'), 'Mе', 'Mie'), '', 'Mio'), '', 'Miu'), '', 'Mia'), 'NЕ', 'NIe'), '', 'NIo'), '', 'NIu'), '', 'NIa'), 'Nе', 'Nie'), '', 'Nio'), '', 'Niu'), '', 'Nia'), 'PЕ', 'PIe'), '', 'PIo'), '',
'PIu'), '', 'PIa'), 'Pе', 'Pie'), '', 'Pio'), '', 'Piu'), '', 'Pia'), 'RЕ', 'RIe'), '', 'RIo'), '', 'RIu'), '', 'RIa'), 'Rе', 'Rie'), '', 'Rio'), '', 'Riu'), '', 'Ria'), 'SЕ', 'SIe'), '', 'SIo'), '', 'SIu'), '', 'SIa'), 'Sе', 'Sie'), '', 'Sio'), '', 'Siu'), '', 'Sia'), 'TЕ', 'TIe'), '', 'TIo'), '', 'TIu'), '', 'TIa'), 'Tе', 'Tie'), '', 'Tio'), '', 'Tiu'), '', 'Tia'), 'ŬЕ', 'ŬIe'), 'ŬЁ', 'ŬIo'), 'ŬЮ', 'ŬIu'), 'ŬЯ', 'ŬIa'), 'Ŭе', 'Ŭie'), 'Ŭё', 'Ŭio'), 'Ŭю', 'Ŭiu'), 'Ŭя', 'Ŭia'), 'FЕ', 'FIe'), '', 'FIo'), '', 'FIu'), '', 'FIa'), 'Fе', 'Fie'), '', 'Fio'), '', 'Fiu'), '', 'Fia'), 'СЕ', 'СIe'), 'СЁ', 'СIo'), 'СЮ', 'СIu'),
'СЯ', 'СIa'), 'Се', 'Сie'), 'Сё', 'Сio'), 'Сю', 'Сiu'), 'Ся', 'Сia'), 'ČЕ', 'ČIe'), 'ČЁ', 'ČIo'), 'ČЮ', 'ČIu'), 'ČЯ', 'ČIa'), 'Čе', 'Čie'), 'Čё', 'Čio'), 'Čю', 'Čiu'), 'Čя', 'Čia'), 'ŠЕ', 'ŠIe'), 'ŠЁ', 'ŠIo'), 'ŠЮ', 'ŠIu'), 'ŠЯ', 'ŠIa'), 'Šе', 'Šie'), 'Šё', 'Šio'), 'Šю', 'Šiu'), 'Šя', 'Šia'), 'bЕ', 'bIe'), '', 'bIo'), '', 'bIu'), '',
'bIa'), 'bе', 'bie'), '', 'bio'), '', 'biu'), '', 'bia'), 'vЕ', 'vIe'), '', 'vIo'), '', 'vIu'), '', 'vIa'), 'vе', 'vie'), '', 'vio'), '', 'viu'), '', 'via'), 'hЕ', 'hIe'), '', 'hIo'), '', 'hIu'), '', 'hIa'), 'hе', 'hie'), '', 'hio'), '', 'hiu'), '', 'hia'), 'dЕ', 'dIe'), '', 'dIo'), '', 'dIu'), '', 'dIa'), 'dе', 'die'), '', 'dio'), '', 'diu'), '', 'dia'), 'žЕ', 'žIe'), 'žЁ', 'žIo'), 'žЮ', 'žIu'), 'žЯ', 'žIa'), 'žе', 'žie'), 'žё', 'žio'), 'žю', 'žiu'), 'žя', 'žia'), 'zЕ', 'zIe'), '', 'zIo'), '', 'zIu'), '', 'zIa'), 'zе', 'zie'), '', 'zio'), '', 'ziu'), '', 'zia'), 'jЕ', 'jIe'), '', 'jIo'), '', 'jIu'), '', 'jIa'), 'jе', 'jie'), '', 'jio'), '', 'jiu'), '', 'jia'), 'кЕ', 'кIe'), 'кЁ', 'кIo'), 'кЮ', 'кIu'), 'кЯ', 'кIa'), 'ке', 'кie'), 'кё', 'кio'), 'кю', 'кiu'), 'кя', 'кia'), 'lЕ', 'lIe'),
'', 'lIo'), '', 'lIu'), '', 'lIa'), 'lе', 'lie'), '', 'lio'), '', 'liu'), '', 'lia'), 'mЕ', 'mIe'), '', 'mIo'), '', 'mIu'), '', 'mIa'), 'mе', 'mie'), '', 'mio'), '', 'miu'), '', 'mia'), 'nЕ', 'nIe'), '', 'nIo'), '', 'nIu'), '', 'nIa'), 'nе', 'nie'), '', 'nio'), '', 'niu'), '', 'nia'), 'pЕ', 'pIe'), '', 'pIo'), '', 'pIu'), '', 'pIa'), 'pе', 'pie'), '', 'pio'), '', 'piu'), '', 'pia'), 'rЕ', 'rIe'), '', 'rIo'), '', 'rIu'), '', 'rIa'), 'rе', 'rie'), '', 'rio'), '', 'riu'), '', 'ria'), 'sЕ', 'sIe'), '',
'sIo'), '', 'sIu'), '', 'sIa'), 'sе', 'sie'), '', 'sio'), '', 'siu'), '', 'sia'), 'tЕ', 'tIe'), '', 'tIo'), '', 'tIu'), '', 'tIa'), 'tе', 'tie'), '', 'tio'), '', 'tiu'), '', 'tia'), 'ŭЕ', 'ŭIe'), 'ŭЁ', 'ŭIo'), 'ŭЮ', 'ŭIu'), 'ŭЯ', 'ŭIa'), 'ŭе', 'ŭie'), 'ŭё', 'ŭio'), 'ŭю', 'ŭiu'), 'ŭя', 'ŭia'), 'fЕ', 'fIe'), '', 'fIo'), '', 'fIu'), '', 'fIa'), 'fе', 'fie'), '', 'fio'), '', 'fiu'), '', 'fia'), 'сЕ', 'сIe'), 'сЁ', 'сIo'), 'сЮ', 'сIu'), 'сЯ', 'сIa'), 'се', 'сie'), 'сё', 'сio'), 'сю', 'сiu'), 'ся', 'сia'), 'čЕ', 'čIe'), 'čЁ', 'čIo'), 'čЮ', 'čIu'), 'čЯ', 'čIa'), 'čе', 'čie'), 'čё',
'čio'), 'čю', 'čiu'), 'čя', 'čia'), 'šЕ', 'šIe'), 'šЁ', 'šIo'), 'šЮ', 'šIu'), 'šЯ', 'šIa'), 'šе', 'šie'), 'šё', 'šio'), 'šю', 'šiu'), 'šя', 'šia'), 'Е', 'Je'), 'Ё', 'Jo'), 'Ю', 'Ju'), 'Я', 'Ja'), 'е', 'je'), 'ё', 'jo'), 'ю', 'ju'), 'я', 'ja'), 'Ь', '\u0301'), 'ь', '\u0301'),'', ''),
replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(translate("name",'абвгдезиклмнопрстуфьАБВГДЕЗИКЛМНОПРСТУФЬ','abvgdeziklmnoprstufABVGDEZIKLMNOPRSTUF'),'х','kh'),'Х','Kh'),'ц','ts'),'Ц','Ts'),'ч','ch'),'Ч','Ch'),'ш','sh'),'Ш','Sh'),'щ','shch'),'Щ','Shch'),'ъ',''),'Ъ',''),'ё','yo'),'Ё','Yo'),'ы','y'),'Ы','Y'),'э','·e'),'Э','E'),'ю','yu'),'Ю','Yu'),'й','y'),'Й','Y'),'я','ya'),'Я','Ya'),'ж','zh'),'Ж','Zh')) AS name""", ('name:en', 'int_name', 'name:be'))
elif options.locale == "be":
columnmap["name"] = ("""COALESCE("name:be",
"name:ru",
"int_name",
"name:en",
"name"
) AS name""", ('name:be', "name:ru", "int_name", "name:en"))
elif options.locale and ("name:" + options.locale in osm2pgsql_avail_keys or not osm2pgsql_avail_keys):
columnmap["name"] = ('COALESCE("name:' + options.locale + '", "name") AS name', ('name:' + options.locale,))
elif options.locale:
columnmap["name"] = ("COALESCE(tags->'name:" + options.locale + '\', "name") AS name', ('tags',))
mapped_cols = [i[0] for i in columnmap.values()]
numerics = set() # set of number-compared things, like "population<10000" needs population as number, not text
mapniksheet = {}
# {zoom: {z-index: [{sql:sql_hint, cond: mapnikfiltercondition, subject: subj, style: {a:b,c:d..}},{r2}...]...}...}
coast = {}
fonts = set()
demhack = False
for zoom in xrange(options.minzoom, options.maxzoom + 1):
mapniksheet[zoom] = {}
zsheet = mapniksheet[zoom]
for chooser in style.choosers:
if chooser.get_sql_hints(chooser.ruleChains[0].subject, zoom)[1]:
# sys.stderr.write(str(chooser.get_sql_hints(chooser.ruleChains[0][0].subject, zoom)[1])+"\n")
styles = chooser.styles[0]
zindex = styles.get("z-index", 0)
if zindex not in zsheet:
zsheet[zindex] = []
chooser_entry = {}
ttypes = list(set([x.subject for x in chooser.ruleChains]))
sql = "(" + chooser.get_sql_hints(chooser.ruleChains[0].subject, zoom)[1] + ")"
sql = sql.split('"')
sq = ""
odd = True
for i in sql:
if not odd:
sq += escape_sql_column(i)
else:
sq += i
odd = not odd
chooser_entry["sql"] = sq
chooser_entry["style"] = styles
fonts.add(styles.get("font-family", libkomapnik.default_font_family))
chooser_entry["rule"] = [i.conditions for i in chooser.ruleChains if i.test_zoom(zoom)]
numerics.update(chooser.get_numerics())
# print chooser_entry["rule"]
chooser_entry["rulestring"] = " or ".join(["(" + " and ".join([i.get_mapnik_filter() for i in rule if i.get_mapnik_filter()]) + ")" for rule in chooser_entry["rule"]])
chooser_entry["chooser"] = chooser
for ttype in ttypes:
if ttype == "ele":
demhack = True
if ttype == "area" and "[natural] = 'coastline'" in chooser_entry["rulestring"]:
coast[zoom] = chooser_entry["style"]
else:
che = chooser_entry.copy()
che["type"] = ttype
zsheet[zindex].append(che)
# sys.stderr.write(str(numerics)+"\n")
# print mapniksheet
def add_numerics_to_itags(itags, escape=True):
tt = set()
nitags = set()
if escape:
escape = escape_sql_column
else:
def escape(i, asname=False):
if i in mapped_cols:
return i # already escaped
return '"' + i + '"'
for i in itags:
if i in numerics:
tt.add("""(CASE WHEN %s ~ E'^[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST (%s AS FLOAT) ELSE NULL END) as %s__num""" % (escape(i), escape(i), i))
nitags.add(escape(i, asname=True))
itags = nitags
itags.update(tt)
return itags
bgcolor = style.get_style("canvas", {}, options.maxzoom + 1)[0].get("fill-color", "")
opacity = style.get_style("canvas", {}, options.maxzoom + 1)[0].get("opacity", 1)
hshack = style.get_style("canvas", {}, options.maxzoom + 1)[0].get("-x-kot-hs-hack", False)
if (opacity == 1) and bgcolor:
mfile.write(xml_start(bgcolor))
else:
mfile.write(xml_start("transparent"))
conf_full_layering = style.get_style("canvas", {}, options.maxzoom + 1)[0].get("-x-kot-true-layers", "true").lower() == 'true'
for font in fonts:
mfile.write(xml_fontset(font, True))
for zoom, zsheet in mapniksheet.iteritems():
x_scale = xml_scaledenominator(zoom)
ta = zsheet.keys()
ta.sort(key=float)
demcolors = {}
demramp = {"ground": "", "ocean": ""}
if demhack:
for zindex in ta:
for entry in zsheet[zindex]:
if entry["type"] in ("ele",):
ele = int(entry["rule"][0][0].params[0])
demcolors[ele] = (whatever_to_hex(entry["style"].get('fill-color', '#ffffff')), entry["style"].get('fill-opacity', '1'))
dk = demcolors.keys()
dk.sort()
for ele in dk:
(color, opacity) = demcolors[ele]
demramp["ocean"] += '<stop value="%s" color="rgba(%s,%s,%s,%s)"/>' % (ele + 10701, int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16), opacity)
demramp["ground"] += '<stop value="%s" color="rgba(%s,%s,%s,%s)"/>' % (ele, int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16), opacity)
if demhack and zoom >= 7:
xml = xml_cleantopo(zoom, x_scale, demramp["ocean"])
mfile.write(xml)
if zoom in coast:
xml = xml_style_start()
xml += xml_rule_start()
xml += x_scale
if "fill-color" in coast[zoom]:
xml += xml_polygonsymbolizer(coast[zoom].get("fill-color", "#ffffff"), relaxedFloat(coast[zoom].get("fill-opacity", "1")), relaxedFloat(coast[zoom].get("smooth", "0")))
if "fill-image" in coast[zoom]:
xml += xml_polygonpatternsymbolizer(coast[zoom].get("fill-image", ""))
xml += xml_rule_end()
xml += xml_style_end()
xml += xml_layer("coast", zoom=zoom)
mfile.write(xml)
if demhack and zoom < 7:
xml = xml_cleantopo(zoom, x_scale, demramp["ocean"])
mfile.write(xml)
if demhack and zoom >= 7:
xml = xml_srtm(zoom, x_scale, demramp["ground"])
mfile.write(xml)
sql_g = set()
there_are_dashed_lines = False
itags_g = set()
xml_g = ""
for zindex in ta:
## background areas pass
sql = set()
itags = set()
xml = xml_style_start()
for entry in zsheet[zindex]:
if entry["type"] in ("way", "area", "polygon"):
if ("fill-color" in entry["style"] or "fill-image" in entry["style"]) and (entry["style"].get("fill-position", "foreground") == "background"):
xml += xml_rule_start()
xml += x_scale
xml += xml_filter(entry["rulestring"])
if "fill-color" in entry["style"]:
xml += xml_polygonsymbolizer(entry["style"].get("fill-color", "black"), relaxedFloat(entry["style"].get("fill-opacity", "1")), relaxedFloat(entry["style"].get("smooth", "0")))
if "fill-image" in entry["style"]:
xml += xml_polygonpatternsymbolizer(entry["style"].get("fill-image", ""))
sql.add(entry["sql"])
itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom))
xml += xml_rule_end()
xml += xml_style_end()
sql.discard("()")
if sql:
sql_g.update(sql)
xml_g += xml
itags_g.update(itags)
else:
xml_nosubstyle()
sql = sql_g
itags = itags_g
if sql:
mfile.write(xml_g)
sql = "(" + " OR ".join(sql) + ")" # and way &amp;&amp; !bbox!"
itags = add_numerics_to_itags(itags)
mfile.write(xml_layer("postgis", "polygon", itags, sql, zoom=zoom))
else:
xml_nolayer()
if hshack:
xml = xml_hillshade(zoom, x_scale)
mfile.write(xml)
index_range = range(-6, 7)
full_layering = conf_full_layering
if (zoom < 9) or not conf_full_layering:
index_range = (-6, 0, 6)
full_layering = False
def check_if_roads_table(rulestring):
roads = set([
"[highway] = 'secondary'",
"[highway] = 'secondary_link'",
"[highway] = 'primary'",
"[highway] = 'primary_link'",
"[highway] = 'trunk'",
"[highway] = 'trunk_link'",
"[highway] = 'motorway'",
"[highway] = 'motorway_link'",
"[boundary] = 'administrative'",
"[railway] "
])
for a in rulestring.split(') or ('):
for r in roads:
if r not in a:
return False
return True
for zlayer in index_range:
for layer_type, entry_types in [("line", ("way", "line")), ("polygon", ("way", "area"))]:
sql_g = set()
there_are_dashed_lines = False
itags_g = set()
xml_g = ""
roads = (layer_type == 'line') # whether to use planet_osm_roads
## casings pass
for zindex in ta:
sql = set()
itags = set()
xml = xml_style_start()
for entry in zsheet[zindex]:
if entry["type"] in entry_types:
if "-x-kot-layer" in entry["style"]:
if zlayer != -6 and entry["style"]["-x-kot-layer"] == "bottom":
continue
if zlayer != 6 and entry["style"]["-x-kot-layer"] == "top":
continue
elif zlayer not in range(-5, 6):
continue
if "casing-width" in entry["style"]:
xml += xml_rule_start()
xml += x_scale
xml += xml_filter(entry["rulestring"])
if not check_if_roads_table(entry["rulestring"]):
roads = False
twidth = 2 * float(entry["style"].get("casing-width", 1)) + float(entry["style"].get("width", 0))
tlinejoin = "round"
if twidth < 3:
tlinejoin = "miter"
xml += xml_linesymbolizer(color=entry["style"].get("casing-color", "black"),
width=twidth,
opacity=relaxedFloat(entry["style"].get("casing-opacity", entry["style"].get("opacity", "1"))),
linecap=entry["style"].get("casing-linecap", entry["style"].get("linecap", "butt")),
linejoin=entry["style"].get("casing-linejoin", entry["style"].get("linejoin", "round")),
dashes=entry["style"].get("casing-dashes", entry["style"].get("dashes", "")),
smooth=relaxedFloat(entry["style"].get("smooth", "0")),
zoom=zoom)
sql.add(entry["sql"])
itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom))
xml += xml_rule_end()
xml += xml_style_end()
sql.discard("()")
if sql:
sql_g.update(sql)
xml_g += xml
itags_g.update(itags)
else:
xml_nosubstyle()
sql = sql_g
itags = itags_g
if sql:
mfile.write(xml_g)
sql = "(" + " OR ".join(sql) + ")" # and way &amp;&amp; !bbox!"
if zlayer == 0 and full_layering:
sql = "(" + sql + ') and ("layer" not in (' + ", ".join(['\'%s\'' % i for i in range(-5, 6) if i != 0]) + ") or \"layer\" is NULL)"
elif zlayer <= 5 and zlayer >= -5 and full_layering:
sql = "(" + sql + ') and "layer" = \'%s\'' % zlayer
itags = add_numerics_to_itags(itags)
if roads:
layer_type = 'roads'
mfile.write(xml_layer("postgis", layer_type, itags, sql, zoom=zoom))
else:
xml_nolayer()
for zindex in ta:
for layer_type, entry_types in [("line", ("way", "line")), ("polygon", ("way", "area"))]:
## lines and polygons pass
sql_g = set()
there_are_dashed_lines = False
there_are_line_patterns = False
itags_g = set()
roads = (layer_type == 'line') # whether to use planet_osm_roads
xml_g = ""
sql = set()
itags = set()
xml = xml_style_start()
for entry in zsheet[zindex]:
if entry["type"] in entry_types:
if "-x-kot-layer" in entry["style"]:
if zlayer != -6 and entry["style"]["-x-kot-layer"] == "bottom":
continue
if zlayer != 6 and entry["style"]["-x-kot-layer"] == "top":
continue
elif zlayer not in range(-5, 6):
continue
if "width" in entry["style"] or "pattern-image" in entry["style"] or (("fill-color" in entry["style"] or "fill-image" in entry["style"]) and (layer_type == "polygon") and (entry["style"].get("fill-position", "foreground") == "foreground")):
xml += xml_rule_start()
xml += x_scale
xml += xml_filter(entry["rulestring"])
if not check_if_roads_table(entry["rulestring"]):
roads = False
if layer_type == "polygon" and (entry["style"].get("fill-position", "foreground") == "foreground"):
if "fill-color" in entry["style"]:
xml += xml_polygonsymbolizer(entry["style"].get("fill-color", "black"), relaxedFloat(entry["style"].get("fill-opacity", "1")), relaxedFloat(entry["style"].get("smooth", "0")))
if "fill-image" in entry["style"]:
xml += xml_polygonpatternsymbolizer(entry["style"].get("fill-image", ""))
if "width" in entry["style"]:
twidth = relaxedFloat(entry["style"].get("width", "1"))
# linejoins are round, but for thin roads they're miter
tlinejoin = "round"
if twidth <= 2:
tlinejoin = "miter"
tlinejoin = entry["style"].get("linejoin", tlinejoin)
# linecaps are round for roads, and butts for roads on non-default layer=
tlinecap = "round"
if zlayer != 0:
tlinecap = "butt"
tlinecap = entry["style"].get("linecap", tlinecap)
xml += xml_linesymbolizer(color=entry["style"].get("color", "black"),
width=twidth,
opacity=relaxedFloat(entry["style"].get("opacity", "1")),
linecap=tlinecap,
linejoin=tlinejoin,
dashes=entry["style"].get("dashes", ""),
smooth=relaxedFloat(entry["style"].get("smooth", "0")),
zoom=zoom)
if entry["style"].get("dashes", ""):
there_are_dashed_lines = True
# print "dashes!!!"
if "pattern-image" in entry["style"]:
there_are_line_patterns = True
if entry["style"]["pattern-image"] == "arrows":
xml += xml_hardcoded_arrows()
else:
if "pattern-rotate" in entry["style"] or "pattern-spacing" in entry["style"]:
fname = entry["style"]["pattern-image"]
try:
im = Image.open(icons_path + fname).convert("RGBA")
fname = "f" + fname
if "pattern-rotate" in entry["style"]:
im = im.rotate(relaxedFloat(entry["style"]["pattern-rotate"]))
fname = "r" + str(relaxedFloat(entry["style"]["pattern-rotate"])) + fname
if "pattern-scale" in entry["style"]:
sc = relaxedFloat(entry["style"]["pattern-scale"]) * 1.
ns = (max(int(round(im.size[0] * sc)), 1), max(int(round(im.size[1] * sc)), 1))
im = im.resize(ns, Image.BILINEAR)
fname = "z" + str(sc) + fname
if "pattern-spacing" in entry["style"]:
im2 = Image.new("RGBA", (im.size[0] + int(relaxedFloat(entry["style"]["pattern-spacing"])), im.size[1]))
im2.paste(im, (0, 0))
im = im2
fname = "s" + str(int(relaxedFloat(entry["style"]["pattern-spacing"]))) + fname
if not os.path.exists(icons_path + "komap/"):
os.makedirs(icons_path + "komap/")
if not os.path.exists(icons_path + "komap/" + fname):
im.save(icons_path + "komap/" + fname, "PNG")
xml += xml_linepatternsymbolizer("komap/" + fname)
except:
print >> sys.stderr, "Error writing to ", icons_path + "komap/" + fname
else:
if entry["style"].get("-x-kot-render", "none") == "svg":
xml += xml_linemarkerssymbolizer(entry["style"]["pattern-image"], entry["style"].get("spacing","100"), entry["style"].get("allow-overlap","false"))
else:
xml += xml_linepatternsymbolizer(entry["style"]["pattern-image"])
sql.add(entry["sql"])
itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom))
xml += xml_rule_end()
xml += xml_style_end()
sql.discard("()")
if sql:
sql_g.update(sql)
xml_g += xml
itags_g.update(itags)
else:
xml_nosubstyle()
sql = sql_g
itags = itags_g
if sql:
mfile.write(xml_g)
sql = "(" + " OR ".join(sql) + ")" # and way &amp;&amp; !bbox!"
if zlayer == 0 and full_layering:
sql = "(" + sql + ') and ("layer" not in (' + ", ".join(['\'%s\'' % i for i in range(-5, 6) if i != 0]) + ") or \"layer\" is NULL)"
elif zlayer <= 5 and zlayer >= -5 and full_layering:
sql = "(" + sql + ') and "layer" = \'%s\'' % zlayer
oitags = itags
itags = add_numerics_to_itags(itags)
if layer_type == "polygon" and there_are_line_patterns:
itags = ", ".join(itags)
oitags = '"' + "\", \"".join(oitags) + '"'
sqlz = """SELECT %s, ST_ForceRHR(way) as way from %spolygon where (%s) and way &amp;&amp; !bbox! and ST_IsValid(way)""" % (itags, libkomapnik.table_prefix , sql)
mfile.write(xml_layer("postgis-process", layer_type, itags, sqlz, zoom=zoom))
#### FIXME: Performance degrades painfully on large lines ST_Union. Gotta find workaround :(
# if layer_type == "polygon" and there_are_dashed_lines:
# itags = ", ".join(itags)
# oitags = '"'+ "\", \"".join(oitags) +'"'
# sqlz = """select %s, ST_LineMerge(ST_Union(way)) as way from
#(SELECT %s, ST_Boundary(way) as way from planet_osm_polygon where (%s) and way &amp;&amp; !bbox! and ST_IsValid(way) ) tex
# group by %s
#"""%(itags,oitags,sql,oitags)
elif layer_type == "line" and there_are_dashed_lines and zoom < 10:
itags = ", ".join(itags) # FIXME: wrong when working with hstore
oitags = '"' + "\", \"".join(oitags) + '"'
sqlz = """select %s, ST_LineMerge(ST_Union(way)) as way from (SELECT %s, ST_SnapToGrid(way, %s) as way from %sline where way &amp;&amp; !bbox! and (%s)) as tex
group by %s
""" % (oitags, itags, pixel_size_at_zoom(zoom, 1.5), libkomapnik.table_prefix, sql, oitags)
mfile.write(xml_layer("postgis-process", layer_type, itags, sqlz, zoom=zoom))
else:
if roads:
layer_type = 'roads'
mfile.write(xml_layer("postgis", layer_type, itags, sql, zoom=zoom))
else:
xml_nolayer()
if not options.bgonly:
## icons pass
sql_g = set()
itags_g = set()
xml_g = ""
prevtype = ""
for zindex in ta:
for layer_type, entry_types in [("point", ("node", "point")), ("line", ("way", "line")), ("polygon", ("way", "area"))]:
sql = set()
itags = set()
style_started = False
for entry in zsheet[zindex]:
if entry["type"] in entry_types:
if "icon-image" in entry["style"]:
if not prevtype:
prevtype = layer_type
if prevtype != layer_type:
if sql_g:
mfile.write(xml_g)
sql_g = "(" + " OR ".join(sql_g) + ")" # and way &amp;&amp; !bbox!"
itags_g = add_numerics_to_itags(itags_g)
mfile.write(xml_layer("postgis", prevtype, itags_g, sql_g, zoom=zoom))
sql_g = set()
itags_g = set()
xml_g = ""
sql = set()
itags = set()
else:
xml_nolayer()
prevtype = layer_type
if not style_started:
xml = xml_style_start()
style_started = True
xml += xml_rule_start()
xml += x_scale
xml += xml_filter(entry["rulestring"])
xml += xml_pointsymbolizer(
path=entry["style"].get("icon-image", ""),
width=entry["style"].get("icon-width", ""),
height=entry["style"].get("icon-height", ""),
opacity=relaxedFloat(entry["style"].get("opacity", "1")))
if ("text" in entry["style"] and entry["style"].get("text-position", "center") == 'center'):
ttext = entry["style"]["text"].extract_tags().pop()
sql.add("((" + entry["sql"] + ") and " + escape_sql_column(ttext) + " is NULL)")
itags.add(ttext)
if ttext in columnmap:
itags.update(columnmap[ttext][1])
else:
sql.add(entry["sql"])
itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom))
xml += xml_rule_end()
if style_started:
xml += xml_style_end()
style_started = False
sql.discard("()")
if sql:
sql_g.update(sql)
xml_g += xml
itags_g.update(itags)
else:
xml_nosubstyle()
if sql_g:
mfile.write(xml_g)
sql_g = "(" + " OR ".join(sql_g) + ")" # and way &amp;&amp; !bbox!"
itags_g = add_numerics_to_itags(itags_g)
mfile.write(xml_layer("postgis", prevtype, itags_g, sql_g, zoom=zoom))
else:
xml_nolayer()
ta.reverse()
for zindex in ta:
for layer_type, entry_types in [("point", ("node", "point")), ("polygon", ("way", "area")), ("line", ("way", "line"))]:
for placement in ("center", "line"):
## text pass
collhere = set()
for entry in zsheet[zindex]:
if entry["type"] in entry_types: # , "node", "line", "point"):
if ("text" in entry["style"] or "shield-text" in entry["style"]) and entry["style"].get("text-position", "center") == placement:
csb = entry["style"].get("collision-sort-by", None)
cso = entry["style"].get("collision-sort-order", "desc")
collhere.add((csb, cso))
for snap_to_street in ('true', 'false'):
for (csb, cso) in collhere:
sql = set()
itags = set()
texttags = set()
xml = xml_style_start()
for entry in zsheet[zindex]:
if entry["type"] in entry_types and csb == entry["style"].get("collision-sort-by", None) and cso == entry["style"].get("collision-sort-order", "desc") and snap_to_street == entry["style"].get("-x-kot-snap-to-street", "false"):
if "shield-text" in entry["style"] and "shield-image" in entry["style"]:
ttext = entry["style"]["shield-text"].extract_tags().pop()
texttags.add(ttext)
tface = entry["style"].get("shield-font-family", libkomapnik.default_font_family)
tsize = entry["style"].get("shield-font-size", "10")
tcolor = entry["style"].get("shield-text-color", "#000000")
toverlap = entry["style"].get("text-allow-overlap", entry["style"].get("allow-overlap", "false"))
tdistance = relaxedFloat(entry["style"].get("-x-kot-min-distance", "20"))
twrap = relaxedFloat(entry["style"].get("shield-max-width", 25))
talign = entry["style"].get("shield-text-align", "center")
topacity = relaxedFloat(entry["style"].get("shield-text-opacity", entry["style"].get("opacity", "1")))
toffset = relaxedFloat(entry["style"].get("shield-text-offset", "0"))
ttransform = entry["style"].get("shield-text-transform", "none")
tspacing = entry["style"].get("shield-spacing", "500")
xml += xml_rule_start()
xml += x_scale
xml += xml_filter(entry["rulestring"])
xml += xml_shieldsymbolizer(
entry["style"].get("shield-image", ""),
"",
"",
ttext, tface, tsize, tcolor, "#000000", 0, "center",
toffset, toverlap, tdistance, twrap, talign, topacity, ttransform, "false", tspacing)
sql.add(entry["sql"])
itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom))
xml += xml_rule_end()
if "text" in entry["style"] and entry["style"].get("text-position", "center") == placement:
ttext = entry["style"]["text"].extract_tags().pop()
texttags.add(ttext)
tface = entry["style"].get("font-family", libkomapnik.default_font_family)
tsize = entry["style"].get("font-size", "10")
tcolor = entry["style"].get("text-color", "#000000")
thcolor = entry["style"].get("text-halo-color", "#ffffff")
thradius = relaxedFloat(entry["style"].get("text-halo-radius", "0"))
tplace = entry["style"].get("text-position", "center")
toffset = relaxedFloat(entry["style"].get("text-offset", "0"))
toverlap = entry["style"].get("text-allow-overlap", entry["style"].get("allow-overlap", "false"))
tdistance = relaxedFloat(entry["style"].get("-x-kot-min-distance", "20"))
twrap = relaxedFloat(entry["style"].get("max-width", 256))
talign = entry["style"].get("text-align", "center")
topacity = relaxedFloat(entry["style"].get("text-opacity", entry["style"].get("opacity", "1")))
tpos = entry["style"].get("text-placement", "X")
ttransform = entry["style"].get("text-transform", "none")
tspacing = entry["style"].get("text-spacing", "4096")
tangle = entry["style"].get("-x-kot-text-angle", libkomapnik.max_char_angle_delta)
tcharspacing = entry["style"].get("-x-kot-font-tracking", libkomapnik.font_tracking)
xml += xml_rule_start()
xml += x_scale
xml += xml_filter(entry["rulestring"])
if "icon-image" in entry["style"] and entry["style"].get("text-position", "center") == 'center':
xml += xml_shieldsymbolizer(
entry["style"].get("icon-image", ""),
entry["style"].get("icon-width", ""),
entry["style"].get("icon-height", ""),
ttext, tface, tsize, tcolor, thcolor, thradius, tplace,
toffset, toverlap, tdistance, twrap, talign, topacity, ttransform)
else:
xml += xml_textsymbolizer(ttext, tface, tsize, tcolor, thcolor, thradius, tcharspacing, tplace, toffset, toverlap, tdistance, twrap, talign, topacity, tpos, ttransform, tspacing, tangle)
sql.add(entry["sql"])
itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom))
xml += xml_rule_end()
xml += xml_style_end()
sql.discard("()")
if sql:
order = ""
if csb:
if cso != "desc":
cso = "asc"
itags.add(csb)
order = """ order by (CASE WHEN "%s" ~ E'^[[:digit:]]+([.][[:digit:]]+)?$' THEN to_char(CAST ("%s" AS FLOAT) ,'000000000000000.99999999999') else "%s" end) %s nulls last """ % (csb, csb, csb, cso)
mfile.write(xml)
add_tags = set()
for t in itags:
if t in columnmap:
add_tags.update(columnmap[t][1])
texttags.update(columnmap[t][1])
oitags = itags.union(add_tags) # SELECT: (tags->'mooring') as "mooring"
oitags = ", ".join([escape_sql_column(i, asname=True) for i in oitags])
goitags = itags.union(add_tags) # GROUP BY: (tags->'mooring')
goitags = ", ".join([escape_sql_column(i) for i in goitags])
fitags = [columnmap.get(i, (i,))[0] for i in itags]
# fitags = add_numerics_to_itags(itags)
itags = add_numerics_to_itags(fitags) # population => {population, population__num}
neitags = add_numerics_to_itags(fitags, escape=False) # for complex polygons, no escapng needed
del fitags
ttext = " OR ".join([escape_sql_column(i) + " is not NULL" for i in texttags])
if placement == "center" and layer_type == "polygon" and snap_to_street == 'false':
sqlz = " OR ".join(sql)
itags = ", ".join(itags)
neitags = ", ".join(neitags)
if not order:
order = "order by"
else:
order += ", "
if zoom > 11 or zoom < 6:
sqlz = """select %s, way
from %s%s
where (%s) and (%s) and (way_area > %s) and way &amp;&amp; ST_Expand(!bbox!,3000) %s way_area desc
""" % (itags, libkomapnik.table_prefix, layer_type, ttext, sqlz, pixel_size_at_zoom(zoom, 3) ** 2, order)
else:
sqlz = """select %s, way
from (
select (ST_Dump(ST_Multi(ST_Buffer(ST_Simplify(ST_Collect(p.way),%s),%s)))).geom as way, %s
from (
select *
from %s%s p
where (%s) and way_area > %s and p.way &amp;&amp; ST_Expand(!bbox!,%s) and (%s)) p
group by %s) p %s ST_Area(p.way) desc
""" % (neitags, pixel_size_at_zoom(zoom, 9), pixel_size_at_zoom(zoom, 10), oitags,
libkomapnik.table_prefix, layer_type, ttext, pixel_size_at_zoom(zoom, 5) ** 2, max(pixel_size_at_zoom(zoom, 20), 3000), sqlz, goitags, order)
mfile.write(xml_layer("postgis-process", layer_type, itags, sqlz, zoom))
elif layer_type == "line" and zoom < 16 and snap_to_street == 'false':
sqlz = " OR ".join(sql)
itags = ", ".join(itags)
if not order:
order = "order by"
else:
order += ", "
# itags = "\""+ itags+"\""
sqlz = """select * from (select %s, ST_Simplify(ST_LineMerge(ST_Union(way)),%s) as way from (SELECT * from %sline where way &amp;&amp; ST_Expand(!bbox!,%s) and (%s) and (%s)) as tex
group by %s) p
where ST_Length(p.way) > %s
%s ST_Length(p.way) desc
""" % (itags, pixel_size_at_zoom(zoom, 3), libkomapnik.table_prefix, max(pixel_size_at_zoom(zoom, 20), 3000), ttext, sqlz, goitags, pixel_size_at_zoom(zoom, 4), order)
mfile.write(xml_layer("postgis-process", layer_type, itags, sqlz, zoom=zoom))
elif snap_to_street == 'true':
sqlz = " OR ".join(sql)
itags = ", ".join(itags)
sqlz = """select %s,
coalesce(
(select
ST_Intersection(
ST_Translate(
ST_Rotate(
ST_GeomFromEWKT('SRID=%s;LINESTRING(-50 0, 50 0)'),
-1*ST_Azimuth(ST_PointN(ST_ShortestLine(l.way, ST_PointOnSurface(ST_Buffer(h.way,0.1))),1),
ST_PointN(ST_ShortestLine(l.way, ST_PointOnSurface(ST_Buffer(h.way,0.1))),2)
)
),
ST_X(ST_PointOnSurface(ST_Buffer(h.way,0.1))),
ST_Y(ST_PointOnSurface(ST_Buffer(h.way,0.1)))
),
ST_Buffer(h.way,20)
)
as way
from %sline l
where
l.way &amp;&amp; ST_Expand(h.way, 600) and
ST_IsValid(l.way) and
l."name" = h."addr:street" and
l.highway is not NULL and
l."name" is not NULL
order by ST_Distance(ST_PointOnSurface(ST_Buffer(h.way,0.1)), l.way) asc
limit 1
),
(select
ST_Intersection(
ST_Translate(
ST_Rotate(
ST_GeomFromEWKT('SRID=%s;LINESTRING(-50 0, 50 0)'),
-1*ST_Azimuth(ST_PointN(ST_ShortestLine(ST_Centroid(l.way), ST_PointOnSurface(ST_Buffer(h.way,0.1))),1),
ST_PointN(ST_ShortestLine(ST_Centroid(l.way), ST_PointOnSurface(ST_Buffer(h.way,0.1))),2)
)
),
ST_X(ST_PointOnSurface(ST_Buffer(h.way,0.1))),
ST_Y(ST_PointOnSurface(ST_Buffer(h.way,0.1)))
),
ST_Buffer(h.way,20)
)
as way
from %spolygon l
where
l.way &amp;&amp; ST_Expand(h.way, 600) and
ST_IsValid(l.way) and
l."name" = h."addr:street" and
l.highway is not NULL and
l."name" is not NULL
order by ST_Distance(ST_PointOnSurface(ST_Buffer(h.way,0.1)), l.way) asc
limit 1
),
ST_Intersection(
ST_MakeLine( ST_Translate(ST_PointOnSurface(ST_Buffer(h.way,0.1)),-50,0),
ST_Translate(ST_PointOnSurface(ST_Buffer(h.way,0.1)), 50,0)
),
ST_Buffer(h.way,20)
)
) as way
from %s%s h
where (%s) and (%s) and way &amp;&amp; ST_Expand(!bbox!,3000) %s
""" % (itags, libkomapnik.db_srid, libkomapnik.table_prefix, libkomapnik.db_srid, libkomapnik.table_prefix, libkomapnik.table_prefix, layer_type, ttext, sqlz, order)
mfile.write(xml_layer("postgis-process", layer_type, itags, sqlz, zoom))
else:
sql = "(" + " OR ".join(sql) + ") %s" % (order) # and way &amp;&amp; ST_Expand(!bbox!,%s), max(pixel_size_at_zoom(zoom,20),3000),
mfile.write(xml_layer("postgis", layer_type, itags, sql, zoom=zoom))
else:
xml_nolayer()
mfile.write(xml_end())

View file

@ -1,57 +0,0 @@
def komap_js(mfile, style):
subjs = {"canvas": ("canvas",), "way": ("Polygon", "LineString"), "line": ("Polygon", "LineString"), "area": ("Polygon",), "node": ("Point",), "*": ("Point", "Polygon", "LineString"), "": ("Point", "Polygon", "LineString"), }
mfile.write("function restyle (prop, zoom, type){")
mfile.write("style = new Object;")
mfile.write('style["default"] = new Object;')
for chooser in style.choosers:
condition = ""
subclass = "default"
for i in chooser.ruleChains:
if condition:
condition += "||"
rule = " zoom >= %s && zoom <= %s" % (i.minZoom, i.maxZoom)
for z in i.conditions:
t = z.type
params = z.params
if params[0] == "::class":
subclass = params[1][2:]
continue
if rule:
rule += " && "
if t == 'eq':
rule += 'prop["%s"] == "%s"' % (params[0], params[1])
if t == 'ne':
rule += 'prop["%s"] != "%s"' % (params[0], params[1])
if t == 'regex':
rule += 'prop["%s"].match(RegExp("%s"))' % (params[0], params[1])
if t == 'true':
rule += 'prop["%s"] == "yes"' % (params[0])
if t == 'untrue':
rule += 'prop["%s"] != "yes"' % (params[0])
if t == 'set':
rule += '"%s" in prop' % (params[0])
if t == 'unset':
rule += '!("%s"in prop)' % (params[0])
if t == '<':
rule += 'prop["%s"] < %s' % (params[0], params[1])
if t == '<=':
rule += 'prop["%s"] <= %s' % (params[0], params[1])
if t == '>':
rule += 'prop["%s"] > %s' % (params[0], params[1])
if t == '>=':
rule += 'prop["%s"] >= %s' % (params[0], params[1])
if rule:
rule = "&&" + rule
condition += "((" + "||".join(['type == "%s"' % z for z in subjs[i.subject]]) + ") " + rule + ")"
styles = ""
if subclass != "default":
styles = 'if(!("%s" in style)){style["%s"] = new Object;}' % (subclass, subclass)
for k, v in chooser.styles[0].iteritems():
if type(v) == str:
try:
v = str(float(v))
styles += 'style["' + subclass + '"]["' + k + '"] = ' + v + ';'
except:
styles += 'style["' + subclass + '"]["' + k + '"] = "' + v + '";'
mfile.write("if(%s) {%s};\n" % (condition, styles))
mfile.write("return style;}")

View file

@ -1,415 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
import os
import math
from debug import debug, Timer
from mapcss.webcolors.webcolors import whatever_to_hex as nicecolor
map_proj = ""
db_proj = ""
table_prefix = ""
db_user = ""
db_name = ""
db_srid = ""
icons_path = ""
world_bnd_path = ""
cleantopo_dem_path = ""
srtm_dem_path = ""
cleantopo_hs_path = ""
srtm_hs_path = ""
text_scale = 1
default_font_family = ""
max_char_angle_delta = ""
font_tracking = 0
substyles = []
last_id = 0
def get_id(i=0):
global last_id
last_id += i
return last_id
def zoom_to_scaledenom(z1, z2=False):
"""
Converts zoom level to mapnik's scaledenominator pair for EPSG:3857
"""
if not z2:
z2 = z1
s = 279541132.014
z1 = (s / (2 ** (z1 - 1)) + s / (2 ** (z1 - 2))) / 2
z2 = (s / (2 ** (z2 - 1)) + s / (2 ** z2)) / 2
# return 100000000000000, 1
return z1, z2
def pixel_size_at_zoom(z, l=1):
"""
Converts l pixels on tiles into length on zoom z
"""
return int(math.ceil(l * 20037508.342789244 / 256 * 2 / (2 ** z)))
def xml_fontset(name, unicode=True):
if unicode:
unicode = '<Font face-name="unifont Medium" />'
return """
<FontSet name="%s">
<Font face-name="%s" />
%s
</FontSet>""" % (name, name, unicode)
def xml_pointsymbolizer(path="", width="", height="", opacity=1, overlap="false"):
if width:
width = ' width="%s" ' % width
if height:
height = ' height="%s" ' % height
return """
<MarkersSymbolizer file="%s" %s %s opacity="%s" allow-overlap="%s" placement="point" />"""\
% (os.path.join(icons_path, path), width, height, opacity, overlap)
def xml_linesymbolizer(color="#000000", width="1", opacity="1", linecap="butt", linejoin="round", dashes="", smooth=0, zoom=200):
color = nicecolor(color)
linecap = {"none": "butt", }.get(linecap.lower(), linecap)
if dashes:
dashes = 'stroke-dasharray="' + str(dashes).strip('[]') + '"'
else:
dashes = ""
if smooth:
smooth = 'smooth="%s"' % (smooth)
else:
smooth = ""
rasterizer = ""
# if float(width) < 4 and not dashes and zoom < 6:
# rasterizer = ' rasterizer="fast"'
return """
<LineSymbolizer %s %s stroke="%s" stroke-width="%s" stroke-opacity="%s" stroke-linejoin="%s" stroke-linecap="%s" %s/>""" % (rasterizer, smooth, color, float(width), float(opacity), linejoin, linecap, dashes)
def xml_polygonsymbolizer(color="#000000", opacity="1", smooth='0'):
color = nicecolor(color)
if smooth:
smooth = 'smooth="%s"' % (smooth)
else:
smooth = ""
return """
<PolygonSymbolizer fill="%s" fill-opacity="%s" gamma="0.73" %s />""" % (color, float(opacity), smooth)
def xml_polygonpatternsymbolizer(file=""):
return """
<PolygonPatternSymbolizer file="%s"/>""" % (os.path.join(icons_path, file))
def xml_linepatternsymbolizer(file=""):
return """
<LinePatternSymbolizer file="%s" />""" % (os.path.join(icons_path, file))
def xml_linemarkerssymbolizer(file="", spacing="100", allow_overlap="false"):
return """
<MarkersSymbolizer file="%s" spacing="%s" allow-overlap="%s" placement="line"/>""" % (os.path.join(icons_path, file), spacing, allow_overlap)
def xml_textsymbolizer(
text="name", face=default_font_family, size="10", color="#000000", halo_color="#ffffff", halo_radius="0", character_spacing=font_tracking, placement="line", offset="0", overlap="false", distance="26", wrap_width=256, align="center", opacity="1", pos="X", transform="none", spacing="4096", angle=max_char_angle_delta):
color = nicecolor(color)
halo_color = nicecolor(halo_color)
pos = pos.replace("exact", "X").replace("any", "S, E, X, N, W, NE, SE, NW, SW").split(",")
pos.extend([str(int(float(x) * text_scale)) for x in size.split(",")])
pos = ",".join(pos)
size = str(float(size.split(",")[0]) * text_scale)
angle = str(int(angle))
placement = {"center": "interior"}.get(placement.lower(), placement)
align = {"center": "middle"}.get(align.lower(), align)
dy = int(float(offset))
dx = 0
if align in ("right", 'left'):
dx = dy
dy = 0
return """
<TextSymbolizer fontset-name="%s" size="%s" fill="%s" halo-fill= "%s" halo-radius="%s" halo-rasterizer="full" character-spacing="%s" placement="%s" dx="%s" dy="%s" max-char-angle-delta="%s" allow-overlap="%s" wrap-width="%s" minimum-distance="%s" vertical-alignment="middle" horizontal-alignment="%s" opacity="%s" placement-type="simple" placements="%s" text-transform="%s" minimum-path-length="5" clip="false" spacing="%s">[%s]</TextSymbolizer>
""" % (face, size, color, halo_color, halo_radius, character_spacing, placement, dx, dy, angle, overlap, wrap_width, distance, align, opacity, pos, transform, spacing, text)
def xml_shieldsymbolizer(path="", width="", height="",
text="name", face=default_font_family, size="10", color="#000000", halo_color="#ffffff", halo_radius="0", placement="line", offset="0", overlap="false", distance="26", wrap_width=256, align="center", opacity="1", transform="none", unlock_image='true', spacing='500'):
color = nicecolor(color)
halo_color = nicecolor(halo_color)
placement = {"center": "point"}.get(placement.lower(), placement)
align = {"center": "middle"}.get(align.lower(), align)
size = str(float(size.split(",")[0]) * text_scale)
if width:
width = ' width="%s" ' % width
if height:
height = ' height="%s" ' % height
return """
<ShieldSymbolizer file="%s%s" %s %s fontset-name="%s" size="%s" fill="%s" halo-fill= "%s" halo-radius="%s" placement="%s" dy="%s" allow-overlap="%s" wrap-width="%s" minimum-distance="%s" horizontal-alignment="%s" opacity="%s" text-transform="%s" unlock-image="%s" spacing="%s">[%s]</ShieldSymbolizer>
""" % (icons_path,
path, width, height, face, size, color, halo_color, halo_radius, placement, offset, overlap, wrap_width, distance, align, opacity, transform, unlock_image, spacing, text)
def xml_filter(string):
return """
<Filter>%s</Filter>""" % string
def xml_scaledenominator(z1, z2=False):
zz1, zz2 = zoom_to_scaledenom(z1, z2)
return """
<MaxScaleDenominator>%s</MaxScaleDenominator>
<MinScaleDenominator>%s</MinScaleDenominator><!-- z%s-%s -->""" % (zz1, zz2, z1, z2)
def xml_start(bgcolor="transparent"):
if bgcolor != "transparent":
bgcolor = nicecolor(bgcolor)
return """<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Map>
<Map background-color="%s" srs="%s" minimum-version="0.7.1" buffer-size="512" maximum-extent="-20037508.342789244,-20037508.342780735,20037508.342789244,20037508.342780709" >
""" % (bgcolor, map_proj)
def xml_end():
return """
</Map>"""
def xml_style_start():
global substyles
layer_id = get_id(1)
substyles.append(layer_id)
return """
<Style name="s%s">""" % (layer_id)
def xml_style_end():
return """
</Style>"""
def xml_rule_start():
return """
<Rule>"""
def xml_rule_end():
return """
</Rule>"""
def xml_cleantopo(zoom, x_scale, demramp):
return """
<Style name="elevation1z%s">
<Rule>%s
<RasterSymbolizer mesh-size="1">
<RasterColorizer default-mode="linear" epsilon="0.001">
%s
</RasterColorizer>
</RasterSymbolizer>
</Rule>
</Style>
<Layer name="ele-raster1z%s">
<StyleName>elevation1z%s</StyleName>
<Datasource>
<Parameter name="file">%s</Parameter>
<Parameter name="type">gdal</Parameter>
<Parameter name="band">1</Parameter>
<Parameter name="srid">3857</Parameter>
</Datasource>
</Layer>
""" % (zoom, x_scale, demramp, zoom, zoom, cleantopo_dem_path)
def xml_srtm(zoom, x_scale, demramp):
return """
<Style name="elevationz%s">
<Rule>%s
<RasterSymbolizer mesh-size="1">
<RasterColorizer default-mode="linear" epsilon="0.001">
%s
</RasterColorizer>
</RasterSymbolizer>
</Rule>
</Style>
<Layer name="ele-rasterz%s">
<StyleName>elevationz%s</StyleName>
<Datasource>
<Parameter name="file">%s</Parameter>
<Parameter name="type">gdal</Parameter>
<Parameter name="band">1</Parameter>
<Parameter name="srid">3857</Parameter>
</Datasource>
</Layer>
""" % (zoom, x_scale, demramp, zoom, zoom, srtm_dem_path)
def xml_hillshade(zoom, x_scale):
hs_path = cleantopo_hs_path
if zoom > 6:
hs_path = srtm_hs_path
return """
<Style name="hillshade%s">
<Rule>%s
<RasterSymbolizer opacity="0.3" mesh-size="1">
<RasterColorizer default-mode="linear">
<stop value="0" color="rgba(0,0,0,1)" />
<stop value="128" color="rgba(128,128,128,0.4)" />
<stop value="255" color="rgba(255,255,255,1)" />
</RasterColorizer>
</RasterSymbolizer>
</Rule>
</Style>
<Layer name="ele-hsz%s">
<StyleName>hillshade%s</StyleName>
<Datasource>
<Parameter name="file">%s</Parameter>
<Parameter name="type">gdal</Parameter>
<Parameter name="band">1</Parameter>
<Parameter name="srid">3857</Parameter>
</Datasource>
</Layer>
""" % (zoom, x_scale, zoom, zoom, hs_path)
def xml_hardcoded_arrows():
return """
<LineSymbolizer stroke="#6c70d5" stroke-width="1" stroke-linejoin="bevel" stroke-dasharray="0,12,10,152" />
<LineSymbolizer stroke="#6c70d5" stroke-width="2" stroke-linejoin="bevel" stroke-dasharray="0,12,9,153" />
<LineSymbolizer stroke="#6c70d5" stroke-width="3" stroke-linejoin="bevel" stroke-dasharray="0,18,2,154" />
<LineSymbolizer stroke="#6c70d5" stroke-width="4" stroke-linejoin="bevel" stroke-dasharray="0,18,1,155" />
"""
def xml_layer(type="postgis", geom="point", interesting_tags="*", sql="true", zoom=0):
layer_id = get_id(1)
global substyles
subs = "\n".join(["<StyleName>s%s</StyleName>" % i for i in substyles])
substyles = []
intersection_SQL = ""
if zoom < 5:
intersection_SQL = '<Parameter name="intersect_max_scale">1</Parameter>'
elif zoom > 16:
intersection_SQL = '<Parameter name="intersect_min_scale">500000000000</Parameter>'
if type == "postgis":
waystring = 'way'
if zoom < 10:
waystring = "ST_Simplify(way, %s) as way" % (pixel_size_at_zoom(zoom, 0.6))
if zoom >= 5:
sql = 'way &amp;&amp; !bbox! and ' + sql
if geom == "polygon":
sql = 'way_area &gt; %s and ' % (pixel_size_at_zoom(zoom, 0.1) ** 2) + sql
interesting_tags = list(interesting_tags)
if '"' not in "".join(interesting_tags) and "->" not in "".join(interesting_tags):
interesting_tags = "\", \"".join(interesting_tags)
interesting_tags = "\"" + interesting_tags + "\""
else:
interesting_tags = ", ".join(interesting_tags)
return """
<Layer name="l%s" status="on" srs="%s">
%s
<Datasource>
<Parameter name="table">
( -- zoom %s
select %s, %s
from %s%s
where %s
) as k_layer
</Parameter>
%s
<Parameter name="type">postgis</Parameter>
<Parameter name="st_prefix">true</Parameter>
<Parameter name="user">%s</Parameter>
<Parameter name="dbname">%s</Parameter>
<Parameter name="srid">%s</Parameter>
<Parameter name="geometry_field">way</Parameter>
<Parameter name="geometry_table">%s%s</Parameter>
<Parameter name="estimate_extent">false</Parameter>
<Parameter name="extent">-20037508.342789244, -20037508.342780735, 20037508.342789244, 20037508.342780709</Parameter>
</Datasource>
</Layer>""" % (layer_id, db_proj, subs, zoom, interesting_tags, waystring, table_prefix, geom, sql, intersection_SQL, db_user, db_name, db_srid, table_prefix, geom)
elif type == "postgis-process":
return """
<Layer name="l%s" status="on" srs="%s">
%s
<Datasource>
<Parameter name="table">
( -- zoom %s
%s
) as k_layer
</Parameter>
%s
<Parameter name="type">postgis</Parameter>
<Parameter name="st_prefix">true</Parameter>
<Parameter name="user">%s</Parameter>
<Parameter name="dbname">%s</Parameter>
<Parameter name="srid">%s</Parameter>
<Parameter name="geometry_field">way</Parameter>
<Parameter name="geometry_table">%s%s</Parameter>
<Parameter name="estimate_extent">false</Parameter>
<Parameter name="extent">-20037508.342789244, -20037508.342780735, 20037508.342789244, 20037508.342780709</Parameter>
</Datasource>
</Layer>""" % (layer_id, db_proj, subs, zoom, sql, intersection_SQL, db_user, db_name, db_srid, table_prefix, geom)
elif type == "coast":
if zoom < 9:
return """
<Layer name="l%s" status="on" srs="%s">
%s
<Datasource>
<Parameter name="type">shape</Parameter>
<Parameter name="file">%sshoreline_300</Parameter>
</Datasource>
</Layer>""" % (layer_id, db_proj, subs, world_bnd_path)
else:
return """
<Layer name="l%s" status="on" srs="%s">
%s
<Datasource>
<Parameter name="type">shape</Parameter>
<Parameter name="file">%sprocessed_p</Parameter>
</Datasource>
</Layer>""" % (layer_id, db_proj, subs, world_bnd_path)
def xml_nolayer():
global substyles
substyles = []
def xml_nosubstyle():
global substyles
substyles = substyles[:-1]

View file

@ -1,65 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
import sys
from debug import debug, Timer
from mapcss import MapCSS
langs = ['int_name', 'name:af', 'name:am', 'name:ar', 'name:be', 'name:bg', 'name:br', 'name:ca', 'name:cs', 'name:cy', 'name:de', 'name:el', 'name:en', 'name:eo', 'name:es', 'name:et', 'name:eu', 'name:fa', 'name:fi', 'name:fr', 'name:fur', 'name:fy', 'name:ga', 'name:gd', 'name:gsw', 'name:he', 'name:hi', 'name:hr', 'name:hsb', 'name:hu', 'name:hy', 'name:it', 'name:ja', 'name:ja_kana', 'name:ja_rm', 'name:ka', 'name:kk', 'name:kn', 'name:ko', 'name:ko_rm', 'name:ku', 'name:la', 'name:lb', 'name:lt', 'name:lv', 'name:mk', 'name:mn', 'name:nl', 'name:pl', 'name:pt', 'name:ro', 'name:ru', 'name:sk', 'name:sl', 'name:sq', 'name:sr', 'name:sv', 'name:th', 'name:tr', 'name:uk', 'name:vi', 'name:zh', 'name:zh_pinyin']
if len(sys.argv) < 2:
print "Usage: make_postgis_style.py [stylesheet] [additional_tag,tag2,tag3]"
exit()
style = MapCSS(1, 19) # zoom levels
style.parse(open(sys.argv[1], "r").read())
dct = {}
if len(sys.argv) >= 3:
langs.extend(sys.argv[2].split(","))
dct = dict([(k, set([("node", "linear"), ('way', 'linear')])) for k in langs])
t = {"node": ("node", "linear"), "line": ("way", "linear"), "area": ("way", "polygon")}
for a in t:
for tag in style.get_interesting_tags(type=a):
if tag not in dct:
dct[tag] = set()
dct[tag].add(t[a])
print """
# OsmType Tag DataType Flags"""
for t in ("z_order", "way_area", ":area"):
if t in dct:
del dct[t]
keys = dct.keys()
keys.sort()
for k in keys:
v = dct[k]
s = ",".join(set([i[0] for i in v]))
pol = "linear"
if "polygon" in set([i[1] for i in v]):
pol = "polygon"
print "%-10s %-20s %-13s %s" % (s, k, "text", pol)
print """
node,way z_order int4 linear # This is calculated during import
way way_area real # This is calculated during import"""

View file

@ -1,226 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
import os
import sqlite3
import sys
from lxml import etree
from twms import projections
from style import Styling
reload(sys)
sys.setdefaultencoding("utf-8") # a hack to support UTF-8
try:
import psyco
psyco.full()
except ImportError:
pass
MAXZOOM = 16
TEMPORARY_FILE_PATH = 'temp_file.bin'
proj = "EPSG:4326"
style = Styling()
# elsif($k eq 'highway' and $v eq 'footway' or $v eq 'path' or $v eq 'track'){
def tilelist_by_geometry(way, start_zoom=0, ispoly=False):
"""
Gives a number of (z,x,y) tile numbers that geometry crosses.
"""
ret = set([])
tiles_by_zooms = {} # zoom: set(tile,tile,tile...)
for t in xrange(0, MAXZOOM + 1):
tiles_by_zooms[t] = set([])
for point in way:
tile = projections.tile_by_coords(point, MAXZOOM, proj)
tile = (MAXZOOM, int(tile[0]), int(tile[1]))
tiles_by_zooms[MAXZOOM].add(tile)
for t in xrange(MAXZOOM - 1, start_zoom - 1, -1):
for tt in tiles_by_zooms[t + 1]:
tiles_by_zooms[t].add((t, int(tt[1] / 2), int(tt[2] / 2)))
for z in tiles_by_zooms.values():
ret.update(z)
return ret
def pix_distance(a, b, z):
"""
Calculates onscreen distance between 2 points on given zoom.
"""
return 2 ** z * 256 * (((a[0] - b[0]) / 360.) ** 2 + ((a[1] - b[1]) / 180.) ** 2) ** 0.5
def sanitize(string):
string = string.replace(" ", "_")
string = string.replace(";", ",")
string = string.replace("=", "###")
return string
print sanitize(" ;=")
def initDB(filename):
conn = sqlite3.connect(filename)
c = conn.cursor()
# create table with the osm element integer id being the primary index
# - according to the sqlite documentation this will equal the index with the
# built in rowid index, providing the same speedup as a separate index while
# saving space - win-win ! :)
# - brief testing shows that this makes the osm -> tiles operation about 5% faster
# but more importantly makes the temporary sqlite database 30% smaller! :)
c.execute('''CREATE TABLE nodes (id integer, lat real, lon real, PRIMARY KEY (id))''')
return conn
def storeNode(conn, id, lat, lon):
# conn.execute("INSERT INTO nodes VALUES ('%d', %f, %f)" % (id, lat, lon))
conn.execute("INSERT INTO nodes(id, lat, lon) values (?, ?, ?)", (id, lat, lon))
def getNode(conn, id):
# conn.execute("SELECT * FROM nodes WHERE id = '%s'" % id)
return conn.execute("SELECT lat, lon FROM nodes WHERE id = '%s'" % id).fetchone()
def main():
DROPPED_POINTS = 0
WAYS_WRITTEN = 0
NODES_READ = 0
WAYS_READ = 0
tilefiles = {}
tilefiles_hist = []
# osm_infile = open("minsk.osm", "rb")
osm_infile = sys.stdin
# remove any stale temporary files
if os.path.exists(TEMPORARY_FILE_PATH):
os.remove(TEMPORARY_FILE_PATH)
conn = initDB(TEMPORARY_FILE_PATH)
# nodes = {}
curway = []
tags = {}
context = etree.iterparse(osm_infile)
for action, elem in context:
items = dict(elem.items())
if elem.tag == "node":
NODES_READ += 1
if NODES_READ % 10000 == 0:
print "Nodes read:", NODES_READ
print len(curway), len(tags), len(tilefiles), len(tilefiles_hist)
if NODES_READ % 100000 == 0:
conn.commit()
print "flushing to temporary storage"
# nodes[str(items["id"])] = (float(items["lon"]), float(items["lat"]))
storeNode(conn, int(items["id"]), float(items["lon"]), float(items["lat"]))
tags = {}
elif elem.tag == "nd":
result = getNode(conn, int(items["ref"]))
if result:
curway.append(result)
# try:
# curway.append(nodes[str(items["ref"])])
# except KeyError:
# pass
elif elem.tag == "tag":
tags[sanitize(items["k"])] = sanitize(items["v"])
elif elem.tag == "way":
WAYS_READ += 1
if WAYS_READ % 1000 == 0:
print "Ways read:", WAYS_READ
mzoom = 1
# tags = style.filter_tags(tags)
if tags:
if True: # style.get_style("way", tags, True): # if way is stylized
towrite = ";".join(["%s=%s" % x for x in tags.iteritems()]) # TODO: sanitize keys and values
# print towrite
way_simplified = {MAXZOOM: curway}
for zoom in xrange(MAXZOOM - 1, -1, -1): # generalize a bit
# TODO: Douglas-Peucker
prev_point = curway[0]
way = [prev_point]
for point in way_simplified[zoom + 1]:
if pix_distance(point, prev_point, zoom) > 1.5:
way.append(point)
prev_point = point
else:
DROPPED_POINTS += 1
if len(way) == 1:
mzoom = zoom
# print zoom
break
if len(way) > 1:
way_simplified[zoom] = way
# print way
for tile in tilelist_by_geometry(curway, mzoom + 1):
z, x, y = tile
path = "tiles/z%s/%s/x%s/%s/" % (z, x / 1024, x, y / 1024)
if tile not in tilefiles:
if not os.path.exists(path):
os.makedirs(path)
tilefiles[tile] = open(path + "y" + str(y) + ".vtile", "wb")
tilefiles_hist.append(tile)
else:
if not tilefiles[tile]:
tilefiles[tile] = open(path + "y" + str(y) + ".vtile", "a")
tilefiles_hist.append(tile)
tilefiles_hist.remove(tile)
tilefiles_hist.append(tile)
print >>tilefiles[tile], "%s %s" % (towrite, items["id"]), " ".join([str(x[0]) + " " + str(x[1]) for x in way_simplified[tile[0]]])
if len(tilefiles_hist) > 400:
print "Cleaned up tiles. Wrote by now:", len(tilefiles), "active:", len(tilefiles_hist)
for tile in tilefiles_hist[0:len(tilefiles_hist) - 100]:
tilefiles_hist.remove(tile)
tilefiles[tile].flush()
tilefiles[tile].close()
tilefiles[tile] = None
# print >>corr, "%s %s %s %s %s %s"% (curway[0][0],curway[0][1],curway[1][0],curway[1][1], user, ts )
WAYS_WRITTEN += 1
if WAYS_WRITTEN % 10000 == 0:
print WAYS_WRITTEN
curway = []
tags = {}
elem.clear()
# extra insurance
del elem
# user = default_user
# ts = ""
print "Tiles generated:", len(tilefiles)
print "Nodes dropped when generalizing:", DROPPED_POINTS
# print "Nodes in memory:", len(nodes)
c = conn.cursor()
c.execute('SELECT * from nodes')
print "Nodes in memory:", len(c.fetchall())
# report temporary file size
print "Temporary file size:", os.path.getsize(TEMPORARY_FILE_PATH)
# remove temporary files
os.remove(TEMPORARY_FILE_PATH)
main()

View file

@ -1,31 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
"""
This is a module to substitute debug.py in porduction mode.
"""
debug = lambda st: None
class Timer:
def __init__(self, comment):
pass
def stop(self):
pass

View file

@ -1,544 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
from debug import debug, Timer
from twms import projections
import cairo
import math
import os as os_module
from copy import deepcopy
import pangocairo
import pango
def line(cr, c):
cr.move_to(*c[0])
for k in c:
cr.line_to(*k)
cr.stroke()
def poly(cr, c):
cr.move_to(*c[0])
for k in c:
cr.line_to(*k)
cr.fill()
def offset_line(line, offset):
a = []
prevcoord = line[0]
for coord in line:
if coord != prevcoord:
angle = - math.atan2(coord[1] - prevcoord[1], coord[0] - prevcoord[0])
dx = offset * math.sin(angle)
dy = offset * math.cos(angle)
a.append((prevcoord[0] + dx, prevcoord[1] + dy))
a.append((coord[0] + dx, coord[1] + dy))
prevcoord = coord
return a
class RasterTile:
def __init__(self, width, height, zoomlevel, data_backend, raster_proj="EPSG:3857"):
self.w = width
self.h = height
self.surface = cairo.ImageSurface(cairo.FORMAT_RGB24, self.w, self.h)
self.offset_x = 0
self.offset_y = 0
self.bbox = (0., 0., 0., 0.)
self.bbox_p = (0., 0., 0., 0.)
self.zoomlevel = zoomlevel
self.zoom = None
self.data = data_backend
self.proj = raster_proj
def __del__(self):
del self.surface
def screen2lonlat(self, x, y):
lo1, la1, lo2, la2 = self.bbox_p
debug("%s %s - %s %s" % (x, y, self.w, self.h))
debug(self.bbox_p)
return projections.to4326((1. * x / self.w * (lo2 - lo1) + lo1, la2 + (1. * y / (self.h) * (la1 - la2))), self.proj)
# return (x - self.w/2)/(math.cos(self.center_coord[1]*math.pi/180)*self.zoom) + self.center_coord[0], -(y - self.h/2)/self.zoom + self.center_coord[1]
def lonlat2screen(self, (lon, lat), epsg4326=False):
if epsg4326:
lon, lat = projections.from4326((lon, lat), self.proj)
lo1, la1, lo2, la2 = self.bbox_p
return ((lon - lo1) * (self.w - 1) / abs(lo2 - lo1), ((la2 - lat) * (self.h - 1) / (la2 - la1)))
# return (lon - self.center_coord[0])*self.lcc*self.zoom + self.w/2, -(lat - self.center_coord[1])*self.zoom + self.h/2
def update_surface_by_center(self, lonlat, zoom, style):
self.zoom = zoom
xy = projections.from4326(lonlat, self.proj)
xy1 = projections.to4326((xy[0] - 40075016 * 0.5 ** self.zoom / 256 * self.w, xy[1] - 40075016 * 0.5 ** self.zoom / 256 * self.h), self.proj)
xy2 = projections.to4326((xy[0] + 40075016 * 0.5 ** self.zoom / 256 * self.w, xy[1] + 40075016 * 0.5 ** self.zoom / 256 * self.h), self.proj)
bbox = (xy1[0], xy1[1], xy2[0], xy2[1])
debug(bbox)
return self.update_surface(bbox, zoom, style)
def update_surface(self, bbox, zoom, style, callback=lambda x=None: None):
rendertimer = Timer("Rendering image")
if "image" not in style.cache:
style.cache["image"] = ImageLoader()
timer = Timer("Getting data")
self.zoom = zoom
self.bbox = bbox
self.bbox_p = projections.from4326(bbox, self.proj)
print self.bbox_p
scale = abs(self.w / (self.bbox_p[0] - self.bbox_p[2]) / math.cos(math.pi * (self.bbox[1] + self.bbox[3]) / 2 / 180))
zscale = 0.5 * scale
cr = cairo.Context(self.surface)
# getting and setting canvas properties
bgs = style.get_style("canvas", {}, self.zoom, scale, zscale)
if not bgs:
bgs = [{}]
bgs = bgs[0]
cr.rectangle(0, 0, self.w, self.h)
# canvas color and opcity
color = bgs.get("fill-color", (0.7, 0.7, 0.7))
cr.set_source_rgba(color[0], color[1], color[2], bgs.get("fill-opacity", 1))
cr.fill()
callback()
# canvas antialiasing
antialias = bgs.get("antialias", "full")
if antialias == "none":
"no antialiasing enabled"
cr.set_antialias(1)
# cr.font_options_set_antialias(1)
elif antialias == "text":
"only text antialiased"
cr.set_antialias(1)
# cr.font_options_set_antialias(2)
else:
"full antialias"
cr.set_antialias(2)
# cr.font_options_set_antialias(2)
datatimer = Timer("Asking backend")
if "get_sql_hints" in dir(style):
hints = style.get_sql_hints('way', self.zoom)
else:
hints = None
if "get_interesting_tags" in dir(style):
itags = style.get_interesting_tags(zoom=self.zoom)
else:
itags = None
# enlarge bbox by 20% to each side. results in more vectors, but makes less artifaces.
span_x, span_y = bbox[2] - bbox[0], bbox[3] - bbox[1]
bbox_expand = [bbox[0] - 0.2 * span_x, bbox[1] - 0.2 * span_y, bbox[2] + 0.2 * span_x, bbox[3] + 0.2 * span_y]
vectors = self.data.get_vectors(bbox_expand, self.zoom, hints, itags).values()
datatimer.stop()
datatimer = Timer("Applying styles")
ww = []
for way in vectors:
type = "line"
if way.coords[0] == way.coords[-1]:
type == "area"
st = style.get_style("area", way.tags, self.zoom, scale, zscale)
if st:
for fpt in st:
# debug(fpt)
ww.append([way.copy(), fpt])
datatimer.stop()
debug("%s objects on screen (%s in dataset)" % (len(ww), len(vectors)))
er = Timer("Projecing data")
if self.data.proj != self.proj:
for w in ww:
w[0].cs = [self.lonlat2screen(coord) for coord in projections.transform(w[0].coords, self.data.proj, self.proj)]
else:
for w in ww:
w[0].cs = [self.lonlat2screen(coord) for coord in w[0].coords]
for w in ww:
if "offset" in w[1]:
offset = float(w[1]["offset"])
w[0] = w[0].copy()
w[0].cs = offset_line(w[0].cs, offset)
if "raise" in w[1] and not "extrude" in w[1]:
w[0] = w[0].copy()
offset = float(w[1]["raise"])
w[0].cs_real = w[0].cs
w[0].cs = [(x, y - offset) for x, y in w[0].cs]
if "extrude" in w[1]:
if w[1]["extrude"] < 2:
del w[1]["extrude"]
if "extrude" in w[1] and "fill-color" not in w[1] and "width" in w[1]:
w[1]["fill-color"] = w[1].get("color", (0, 0, 0))
w[1]["fill-opacity"] = w[1].get("opacity", 1)
w[0] = w[0].copy()
# print w[0].cs
w[0].cs = offset_line(w[0].cs, w[1]["width"] / 2)
# print w[0].cs
aa = offset_line(w[0].cs, -w[1]["width"])
del w[1]["width"]
aa.reverse()
w[0].cs.extend(aa)
er.stop()
ww.sort(key=lambda x: x[1]["layer"])
layers = list(set([int(x[1]["layer"] / 100.) for x in ww]))
layers.sort()
objs_by_layers = {}
for layer in layers:
objs_by_layers[layer] = []
for obj in ww:
objs_by_layers[int(obj[1]["layer"] / 100.)].append(obj)
del ww
timer.stop()
timer = Timer("Rasterizing image")
linecaps = {"butt": 0, "round": 1, "square": 2}
linejoin = {"miter": 0, "round": 1, "bevel": 2}
text_rendered_at = set([(-100, -100)])
for layer in layers:
data = objs_by_layers[layer]
# data.sort(lambda x,y:cmp(max([x1[1] for x1 in x[0].cs]), max([x1[1] for x1 in y[0].cs])))
# - fill polygons
for obj in data:
if ("fill-color" in obj[1] or "fill-image" in obj[1]) and not "extrude" in obj[1]: # TODO: fill-image
color = obj[1].get("fill-color", (0, 0, 0))
cr.set_source_rgba(color[0], color[1], color[2], obj[1].get("fill-opacity", 1))
if "fill-image" in obj[1]:
image = style.cache["image"][obj[1]["fill-image"]]
if image:
pattern = cairo.SurfacePattern(image)
pattern.set_extend(cairo.EXTEND_REPEAT)
cr.set_source(pattern)
poly(cr, obj[0].cs)
# - draw casings on layer
for obj in data:
### Extras: casing-linecap, casing-linejoin
if "casing-width" in obj[1] or "casing-color" in obj[1] and "extrude" not in obj[1]:
cr.set_dash(obj[1].get("casing-dashes", obj[1].get("dashes", [])))
cr.set_line_join(linejoin.get(obj[1].get("casing-linejoin", obj[1].get("linejoin", "round")), 1))
color = obj[1].get("casing-color", (0, 0, 0))
cr.set_source_rgba(color[0], color[1], color[2], obj[1].get("casing-opacity", 1))
## TODO: good combining of transparent lines and casing
## Probable solution: render casing, render way as mask and put casing with mask chopped out onto image
cr.set_line_width(obj[1].get("width", 0) + obj[1].get("casing-width", 1))
cr.set_line_cap(linecaps.get(obj[1].get("casing-linecap", obj[1].get("linecap", "butt")), 0))
line(cr, obj[0].cs)
# - draw line centers
for obj in data:
if ("width" in obj[1] or "color" in obj[1] or "image" in obj[1]) and "extrude" not in obj[1]:
cr.set_dash(obj[1].get("dashes", []))
cr.set_line_join(linejoin.get(obj[1].get("linejoin", "round"), 1))
color = obj[1].get("color", (0, 0, 0))
cr.set_source_rgba(color[0], color[1], color[2], obj[1].get("opacity", 1))
## TODO: better overlapping of transparent lines.
## Probable solution: render them (while they're of the same opacity and layer) on a temporary canvas that's merged into main later
cr.set_line_width(obj[1].get("width", 1))
cr.set_line_cap(linecaps.get(obj[1].get("linecap", "butt"), 0))
if "image" in obj[1]:
image = style.cache["image"][obj[1]["image"]]
if image:
pattern = cairo.SurfacePattern(image)
pattern.set_extend(cairo.EXTEND_REPEAT)
cr.set_source(pattern)
line(cr, obj[0].cs)
callback()
# - extruding polygons
# data.sort(lambda x,y:cmp(max([x1[1] for x1 in x[0].cs]), max([x1[1] for x1 in y[0].cs])))
# Pass 1. Creating list of extruded polygons
extlist = []
# fromat: (coords, ("h"/"v", y,z), real_obj)
for obj in data:
if "extrude" in obj[1]:
def face_to_poly(face, hgt):
"""
Converts a line into height-up extruded poly
"""
return [face[0], face[1], (face[1][0], face[1][1] - hgt), (face[0][0], face[0][1] - hgt), face[0]]
hgt = obj[1]["extrude"]
raised = float(obj[1].get("raise", 0))
excoords = [(a[0], a[1] - hgt - raised) for a in obj[0].cs]
faces = []
coord = obj[0].cs[-1]
# p_coord = (coord[0],coord[1]-raised)
p_coord = False
for coord in obj[0].cs:
c = (coord[0], coord[1] - raised)
if p_coord:
extlist.append((face_to_poly([c, p_coord], hgt), ("v", min(coord[1], p_coord[1]), hgt), obj))
p_coord = c
extlist.append((excoords, ("h", min(coord[1], p_coord[1]), hgt), obj))
# faces.sort(lambda x,y:cmp(max([x1[1] for x1 in x]), max([x1[1] for x1 in y])))
# Pass 2. Sorting
def compare_things(a, b):
"""
Custom comparator for extlist sorting.
Sorts back-to-front, bottom-to-top, | > \ > _, horizontal-to-vertical.
"""
t1, t2 = a[1], b[1]
if t1[1] > t2[1]: # back-to-front
return 1
if t1[1] < t2[1]:
return -1
if t1[2] > t2[2]: # bottom-to-top
return 1
if t1[2] < t2[2]:
return -1
if t1[0] < t2[0]: # h-to-v
return 1
if t1[0] > t2[0]:
return -1
return cmp(math.sin(math.atan2(a[0][0][0] - a[0][1][0], a[0][0][0] - a[0][1][0])), math.sin(math.atan2(b[0][0][0] - b[0][1][0], b[0][0][0] - b[0][1][0])))
print t1
print t2
extlist.sort(compare_things)
# Pass 3. Rendering using painter's algorythm
cr.set_dash([])
for ply, prop, obj in extlist:
if prop[0] == "v":
color = obj[1].get("extrude-face-color", obj[1].get("color", (0, 0, 0)))
cr.set_source_rgba(color[0], color[1], color[2], obj[1].get("extrude-face-opacity", obj[1].get("opacity", 1)))
poly(cr, ply)
color = obj[1].get("extrude-edge-color", obj[1].get("color", (0, 0, 0)))
cr.set_source_rgba(color[0], color[1], color[2], obj[1].get("extrude-edge-opacity", obj[1].get("opacity", 1)))
cr.set_line_width(.5)
line(cr, ply)
if prop[0] == "h":
if "fill-color" in obj[1]:
color = obj[1]["fill-color"]
cr.set_source_rgba(color[0], color[1], color[2], obj[1].get("fill-opacity", obj[1].get("opacity", 1)))
poly(cr, ply)
color = obj[1].get("extrude-edge-color", obj[1].get("color", (0, 0, 0)))
cr.set_source_rgba(color[0], color[1], color[2], obj[1].get("extrude-edge-opacity", obj[1].get("opacity", 1)))
cr.set_line_width(1)
line(cr, ply)
# cr.set_line_width (obj[1].get("width", 1))
# color = obj[1].get("color", (0,0,0) )
# cr.set_source_rgba(color[0], color[1], color[2], obj[1].get("extrude-edge-opacity", obj[1].get("opacity", 1)))
# line(cr,excoords)
# if "fill-color" in obj[1]:
# color = obj[1]["fill-color"]
# cr.set_source_rgba(color[0], color[1], color[2], obj[1].get("fill-opacity", 1))
# poly(cr,excoords)
for obj in data:
if "icon-image" in obj[1]:
image = style.cache["image"][obj[1]["icon-image"]]
if image:
dy = image.get_height() / 2
dx = image.get_width() / 2
where = self.lonlat2screen(projections.transform(obj[0].center, self.data.proj, self.proj))
cr.set_source_surface(image, where[0] - dx, where[1] - dy)
cr.paint()
callback()
# - render text labels
texttimer = Timer("Text rendering")
cr.set_line_join(1) # setting linejoin to "round" to get less artifacts on halo render
for obj in data:
if "text" in obj[1]:
text = obj[1]["text"]
# cr.set_line_width (obj[1].get("width", 1))
# cr.set_font_size(float(obj[1].get("font-size", 9)))
ft_desc = pango.FontDescription()
ft_desc.set_family(obj[1].get('font-family', 'sans'))
ft_desc.set_size(pango.SCALE * int(obj[1].get('font-size', 9)))
fontstyle = obj[1].get('font-style', 'normal')
if fontstyle == 'italic':
fontstyle = pango.STYLE_ITALIC
else:
fontstyle = pango.STYLE_NORMAL
ft_desc.set_style(fontstyle)
fontweight = obj[1].get('font-weight', 400)
try:
fontweight = int(fontweight)
except ValueError:
if fontweight == 'bold':
fontweight = 700
else:
fontweight = 400
ft_desc.set_weight(fontweight)
if obj[1].get('text-transform', None) == 'uppercase':
text = text.upper()
p_ctx = pangocairo.CairoContext(cr)
p_layout = p_ctx.create_layout()
p_layout.set_font_description(ft_desc)
p_layout.set_text(text)
p_attrs = pango.AttrList()
decoration = obj[1].get('text-decoration', 'none')
if decoration == 'underline':
p_attrs.insert(pango.AttrUnderline(pango.UNDERLINE_SINGLE, end_index=-1))
decoration = obj[1].get('font-variant', 'none')
if decoration == 'small-caps':
p_attrs.insert(pango.AttrVariant(pango.VARIANT_SMALL_CAPS, start_index=0, end_index=-1))
p_layout.set_attributes(p_attrs)
if obj[1].get("text-position", "center") == "center":
where = self.lonlat2screen(projections.transform(obj[0].center, self.data.proj, self.proj))
for t in text_rendered_at:
if ((t[0] - where[0]) ** 2 + (t[1] - where[1]) ** 2) < 15 * 15:
break
else:
text_rendered_at.add(where)
# debug ("drawing text: %s at %s"%(text, where))
if "text-halo-color" in obj[1] or "text-halo-radius" in obj[1]:
cr.new_path()
cr.move_to(where[0], where[1])
cr.set_line_width(obj[1].get("text-halo-radius", 1))
color = obj[1].get("text-halo-color", (1., 1., 1.))
cr.set_source_rgb(color[0], color[1], color[2])
cr.text_path(text)
cr.stroke()
cr.new_path()
cr.move_to(where[0], where[1])
cr.set_line_width(obj[1].get("text-halo-radius", 1))
color = obj[1].get("text-color", (0., 0., 0.))
cr.set_source_rgb(color[0], color[1], color[2])
cr.text_path(text)
cr.fill()
else: # render text along line
c = obj[0].cs
text = unicode(text, "utf-8")
# - calculate line length
length = reduce(lambda x, y: (x[0] + ((y[0] - x[1]) ** 2 + (y[1] - x[2]) ** 2) ** 0.5, y[0], y[1]), c, (0, c[0][0], c[0][1]))[0]
# print length, text, cr.text_extents(text)
if length > cr.text_extents(text)[2]:
# - function to get (x, y, normale) from (c, length_along_c)
def get_xy_from_len(c, length_along_c):
x0, y0 = c[0]
for x, y in c:
seg_len = ((x - x0) ** 2 + (y - y0) ** 2) ** 0.5
if length_along_c < seg_len:
normed = length_along_c / seg_len
return (x - x0) * normed + x0, (y - y0) * normed + y0, math.atan2(y - y0, x - x0)
else:
length_along_c -= seg_len
x0, y0 = x, y
else:
return None
da = 0
os = 1
z = length / 2 - cr.text_extents(text)[2] / 2
# print get_xy_from_len(c,z)
if c[0][0] < c[1][0] and get_xy_from_len(c, z)[2] < math.pi / 2 and get_xy_from_len(c, z)[2] > -math.pi / 2:
da = 0
os = 1
z = length / 2 - cr.text_extents(text)[2] / 2
else:
da = math.pi
os = -1
z = length / 2 + cr.text_extents(text)[2] / 2
z1 = z
if "text-halo-color" in obj[1] or "text-halo-radius" in obj[1]:
cr.set_line_width(obj[1].get("text-halo-radius", 1.5) * 2)
color = obj[1].get("text-halo-color", (1., 1., 1.))
cr.set_source_rgb(color[0], color[1], color[2])
xy = get_xy_from_len(c, z)
cr.save()
# cr.move_to(xy[0],xy[1])
p_ctx.translate(xy[0], xy[1])
cr.rotate(xy[2] + da)
# p_ctx.translate(x,y)
# p_ctx.show_layout(p_layout)
p_ctx.layout_path(p_layout)
cr.restore()
cr.stroke()
# for letter in text:
# cr.new_path()
# xy = get_xy_from_len(c,z)
# print letter, cr.text_extents(letter)
# cr.move_to(xy[0],xy[1])
# cr.save()
# cr.rotate(xy[2]+da)
# cr.text_path(letter)
# cr.restore()
# cr.stroke()
# z += os*cr.text_extents(letter)[4]
color = obj[1].get("text-color", (0., 0., 0.))
cr.set_source_rgb(color[0], color[1], color[2])
z = z1
xy = get_xy_from_len(c, z)
cr.save()
# cr.move_to(xy[0],xy[1])
p_ctx.translate(xy[0], xy[1])
cr.rotate(xy[2] + da)
# p_ctx.translate(x,y)
p_ctx.show_layout(p_layout)
cr.restore()
# for letter in text:
# cr.new_path()
# xy = get_xy_from_len(c,z)
# print letter, cr.text_extents(letter)
# cr.move_to(xy[0],xy[1])
# cr.save()
# cr.rotate(xy[2]+da)
# cr.text_path(letter)
# cr.restore()
# cr.fill()
# z += os*cr.text_extents(letter)[4]
texttimer.stop()
del data
del layers
timer.stop()
rendertimer.stop()
debug(self.bbox)
callback(True)
class ImageLoader:
def __init__(self):
self.cache = {}
def __getitem__(self, url):
if url in self.cache:
return self.cache[url]
else:
print url, os_module.path.exists(url)
if os_module.path.exists(url):
self.cache[url] = cairo.ImageSurface.create_from_png(url)
return self.cache[url]
else:
return False

View file

@ -1,106 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
from debug import debug, Timer
from backend.postgis import PostGisBackend as DataBackend
from mapcss import MapCSS
from twms import bbox, projections
from render import RasterTile
import web
import StringIO
style = MapCSS(1, 26) # zoom levels
style.parse(open("styles/landuses.mapcss", "r").read())
# bbox = (27.115768874532,53.740327031764,28.028320754378,54.067187302158)
# w,h = 630*4,364*4
# z = 17
db = DataBackend()
# style = Styling()
try:
import psyco
psyco.full()
except ImportError:
pass
OK = 200
ERROR = 500
def handler():
"""
A handler for web.py.
"""
data = web.input()
resp, ctype, content = twms_main(data)
web.header('Content-type', ctype)
return content
urls = (
'/(.*)', 'mainhandler'
)
class mainhandler:
def GET(self, crap):
return handler()
if __name__ == "__main__":
app = web.application(urls, globals())
app.run() # standalone run
def twms_main(req):
resp = ""
data = req
srs = data.get("srs", data.get("SRS", "EPSG:4326"))
content_type = "image/png"
# layer = data.get("layers",data.get("LAYERS", config.default_layers)).split(",")
width = 0
height = 0
req_bbox = ()
if data.get("bbox", data.get("BBOX", None)):
req_bbox = tuple(map(float, data.get("bbox", data.get("BBOX", req_bbox)).split(",")))
req_bbox = projections.to4326(req_bbox, srs)
req_bbox, flip_h = bbox.normalize(req_bbox)
box = req_bbox
height = int(data.get("height", data.get("HEIGHT", height)))
width = int(data.get("width", data.get("WIDTH", width)))
z = bbox.zoom_for_bbox(box, (height, width), {"proj": "EPSG:3857"}, min_zoom=1, max_zoom=25, max_size=(10000, 10000))
res = RasterTile(width, height, z, db)
res.update_surface(box, z, style)
image_content = StringIO.StringIO()
res.surface.write_to_png(image_content)
resp = image_content.getvalue()
return (OK, content_type, resp)

View file

@ -1,157 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of kothic, the realtime map renderer.
# kothic is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# kothic is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
### TODO: MapCSS loading and parsing
from debug import debug
from mapcss.webcolors.webcolors import whatever_to_cairo as colorparser
class Styling():
"""
Class used to choose the right way of rendering an object.
"""
def __init__(self, stylefile=None):
self.Selectors = {}
self.Selectors["way"] = []
self.Selectors["node"] = []
self.Selectors["relation"] = []
if not stylefile:
# self.Selectors["way"].append(StyleSelector( ( [ ( ("building",),(None) ) ] ),{"fill-color": "#00f"} ))
# if stylefile=="zzzz":
### using "builtin" styling
self.Selectors["way"].append(StyleSelector(([(("area",), ("yes"))]), {"fill-color": "#ff0000"}))
self.Selectors["way"].append(StyleSelector(([(("highway",), (None))]), {"width": 1, "color": "#ff0000", "text": "name", "text-position": "line", "text-halo-radius": 2, }))
self.Selectors["way"].append(StyleSelector(([(("barrier",), (None))]), {"casing-width": 1, }))
self.Selectors["way"].append(StyleSelector(([(("highway",), ("residential", "tertiary", "living_street"))]), {"width": 3, "color": "#ffffff", "casing-width": 5, "z-index": 10}))
self.Selectors["way"].append(StyleSelector(([(("highway",), ("service", "unclassified"))]), {"width": 2.5, "color": "#ccc", "casing-width": 4, "z-index": 9}))
self.Selectors["way"].append(StyleSelector(([(("highway",), ("primary", "motorway", "trunk"))]), {"width": 4, "color": "#ff0", "casing-width": 6, "z-index": 11}))
self.Selectors["way"].append(StyleSelector(([(("highway",), ("primary_link", "motorway_link", "trunk_link"))]), {"width": 3.5, "color": "#ff0", "casing-width": 6, "z-index": 11}))
self.Selectors["way"].append(StyleSelector(([(("highway",), ("secondary", ))]), {"width": 4, "color": "orange", "casing-width": 6, "z-index": 10}))
self.Selectors["way"].append(StyleSelector(([(("living_street",), ("yes"))]), {"width": 2, "casing-width": 3, "z-index": 0}))
self.Selectors["way"].append(StyleSelector(([(("landuse", "natural"), ("forest", "wood"))]), {"fill-color": "#020"}))
self.Selectors["way"].append(StyleSelector(([(("landuse",), ("industrial",))]), {"fill-color": "#855"}))
self.Selectors["way"].append(StyleSelector(([(("landuse",), ("military",))]), {"fill-color": "pink"}))
self.Selectors["way"].append(StyleSelector(([(("waterway", "natural"), ("riverbank", "water"))]), {"fill-color": "#002"}))
self.Selectors["way"].append(StyleSelector(([(("waterway", "natural"), ("river", "stream"))]), {"color": "#002"}))
self.Selectors["way"].append(StyleSelector(([(("landuse", "natural"), ("grass",))]), {"fill-color": "#050", }))
self.Selectors["way"].append(StyleSelector(([(("highway",), ("footway", "pedestrian", "path"))]), {"width": 2.5, "color": "#655", "dashes": [3, 1], "z-index": 3}))
self.Selectors["way"].append(StyleSelector(([(("bridge",), ("yes"))]), {"casing-width": 10}))
self.Selectors["way"].append(StyleSelector(([(("power",), ("line",))]), {"width": 1, "color": "#ccc", }))
self.Selectors["way"].append(StyleSelector(([(("building",), (None))]), {"fill-color": "#522", "text": "addr:housenumber", "text-halo-radius": 2, "z-index": 100})) # "extrude":10,
self.stylefile = stylefile
self.useful_keys = set(["layer"])
for objtype in self.Selectors.values(): # getting useful keys
for selector in objtype:
# debug(selector)
for tag in selector.tags:
self.useful_keys.update(set(tag[0]))
if "text" in selector.style:
self.useful_keys.update(set((selector.style["text"],)))
debug(self.useful_keys)
def get_style(self, objtype, tags, nodata=False):
"""
objtype is "node", "way" or "relation"
tags - object tags
nodata - we won't render that now, don't need exact styling
"""
resp = {}
for selector in self.Selectors[objtype]:
resp.update(selector.get_style(tags))
if nodata:
if resp:
return True
if not nodata and resp:
# debug((tags, tags.get("layer",0)), )
try:
resp["layer"] = int(tags.get("layer", 0)) * 100 + resp.get("z-index", 0) + 1000
except ValueError:
resp["layer"] = 1000000
if "text" in resp: # unpacking text
if resp["text"] in tags:
resp["text"] = tags[resp["text"]]
# debug("text: %s"%resp["text"])
else:
del resp["text"]
return resp
def filter_tags(self, tags):
"""
Returns only tags that are useful for rendering
"""
# resp = {}
# for k,v in tags.iteritems():
# if k in self.useful_keys:
# resp[k] = v
return tags
class StyleSelector():
def __init__(self, tags, style):
"""
Selector that decides if that style is right for the object
tags - list of tags [(("key","key"..), ("value", "value"...)), (("key","key"..), ("value", "value"...))]
style - MapCSS rules to apply
"""
self.tags = tags
self.style = {}
for key in style:
keyz = key.lower()
if "color" in keyz:
self.style[keyz] = colorparser(style[key])
debug((colorparser(style[key]), style[key]))
else:
self.style[keyz] = style[key]
def get_style(self, tags):
"""
Get actual styling for object.
"""
styled = False
# debug(self.tags)
for k, v in self.tags:
for j in k:
if j in tags:
if v:
if tags[j] in v:
styled = True
else:
styled = True
if styled:
return self.style
return {}
if __name__ == "__main__":
c = Styling()
print c.get_style("way", {"building": "yes"})
print c.get_style("way", {"highway": "residential"})
print c.get_style("way", {"highway": "road"})
print c.get_style("way", {"highway": "residential", "building": "yes"})
print c.get_style("way", {"highwadfgaay": "resifdgsdential", "builafgding": "yedfgs"})
print c.get_style("way", {"highwadfgaay": "resifdgsdential", "builafgding": "yedfgs"}, True)
print c.get_style("way", {"highway": "residential", "building": "yes"}, True)
print c.filter_tags({"highwadfgaay": "resifdgsdential", "builafgding": "yedfgs", "building": "residential"})

View file

@ -1,260 +0,0 @@
canvas{fill-color:#a0bc92}
/* ---------- DEFAULTS ---------- */
way {
/* text: name; */text-position: line; text-halo-radius:2;
linecap: round;
opacity: eval( min(1, (num(any(tag("layer"),1))+5)/6) );
casing-opacity: eval( min(1, (num(any(tag("layer"),1))+5)/6) );
}
/* ---------- ROADS ---------- */
way|z16-[highway] /*[!lanes]*/
{color:white;
/*casing-width: 1; */ }
/*way|z16-[highway][lanes]
{width: eval(cond(num(tag("lanes")) >= 1, metric("3.6m")-metric("10cm"), 0));
color:grey; linecap: round;
casing-width: eval(cond(num(tag("lanes")) >= 1, metric("10cm"), 0));
casing-color:white; casing-dashes: eval(str( metric("1m") ) +"," + str( metric("1m") )); casing-linecap:butt;
offset: eval(cond((num(tag("lanes"))/2-int(num(tag("lanes")))/2) != 0, metric("3.6m")/2, 0));
}
{width: eval(cond(num(tag("lanes")) >= 2, metric("3.6m")-metric("10cm"), 0));
color:grey; linecap: round;
casing-width: eval(cond(num(tag("lanes")) >= 2, metric("10cm"), 0));
casing-color:white;casing-dashes: eval(str( metric("1m") ) +"," + str( metric("1m") )); casing-linecap:butt;
offset: eval(cond((num(tag("lanes"))/2-int(num(tag("lanes")))/2) != 0, metric("3.6m")/2, 0)+(2-1)*metric("3.6m"));
}
{width: eval(cond(num(tag("lanes")) >= 3, metric("3.6m")-metric("10cm"), 0));
color:grey; linecap: round;
casing-width: eval(cond(num(tag("lanes")) >= 3, metric("10cm"), 0));
casing-color:white;casing-dashes: eval(str( metric("1m") ) +"," + str( metric("1m") )); casing-linecap:butt;
offset: eval((cond((num(tag("lanes"))/2-int(num(tag("lanes")))/2) != 0, metric("3.6m")/2, 0)-(2-1)*metric("3.6m")));
}
{width: eval(cond(num(tag("lanes")) >= 4, metric("3.6m")-metric("10cm"), 0));
color:grey; linecap: round;
casing-width: eval(cond(num(tag("lanes")) >= 4, metric("10cm"), 0));
casing-color:white;casing-dashes: eval(str( metric("1m") ) +"," + str( metric("1m") )); casing-linecap:butt;
offset: eval(cond((num(tag("lanes"))/2-int(num(tag("lanes")))/2) != 0, metric("3.6m")/2, 0)+(3-1)*metric("3.6m"));
}
{width: eval(cond(num(tag("lanes")) >= 5, metric("3.6m")-metric("10cm"), 0));
color:grey; linecap: round;
casing-width: eval(cond(num(tag("lanes")) >= 5, metric("10cm"), 0));
casing-color:white;casing-dashes: eval(str( metric("1m") ) +"," + str( metric("1m") )); casing-linecap:butt;
offset: eval((cond((num(tag("lanes"))/2-int(num(tag("lanes")))/2) != 0, metric("3.6m")/2, 0)-(3-1)*metric("3.6m")));
}*/
way|z16-[highway=motorway],
way|z16-[highway=trunk],
{width:eval(metric(4*4));}
way|z16-[highway=primary]
{width:eval(metric(3*4));}
way|z16-[highway=secondary],
way|z16-[highway=tertiary],
way|z16-[highway=residential],
way|z16-[highway=trunk_link],
way|z16-[highway=motorway_link],
way|z16-[highway=primary_link],
way|z16-[highway=secondary_link],
{width:eval(metric(2*4));}
way|z16-[highway=service],
way|z16-[highway=track],
{width:eval(metric(1.5*4));}
way|z16-[highway=footway],
way|z16-[highway=pedestrian],
way|z16-[highway=path],
way|z16-[highway=steps],
{width:eval(metric(1*4));
}
way[highway][lanes]{width:eval(metric( num(tag("lanes")) * 4));}
way[width]{width:eval(metric(tag("width")));}
way|z16-[highway=motorway],
way|z16-[highway=motorway_link],
way|z16-[highway=trunk],
way|z16-[highway=trunk_link],
way|z16-[highway=primary],
way|z16-[highway=primary_link],
way|z16-[highway=secondary],
way|z16-[highway=secondary_link],
way|z16-[highway=tertiary],
way|z16-[highway=tertiary_link],
way|z16-[highway=residential],
way|z16-[highway=service],
{image: "styles/default/asphalt.png";
z-index:5;
}
area|z16-[amenity=parking],
{fill-image: "styles/default/asphalt.png";
z-index:5; casing-width:1;
}
way|z16-[highway=footway],
way|z16-[highway=pedestrian],
{image: "styles/default/paving_stones6s.png";
z-index:4;}
way|z16-[highway=track],
{image: "styles/default/dirt.png";
z-index:3;}
way|z16-[highway=path],
{image: "styles/default/sand.png";z-index:2;}
way|z16-[layer<0],
{image: ""}
way|z16-[surface=asphalt] {image: "styles/default/asphalt.png"}
way|z16-[surface=grass] {image: eval("styles/default/"+tag("surface")+".png")}
way|z16-[surface=sand] {image: eval("styles/default/"+tag("surface")+".png")}
way|z16-[surface=dirt] {image: eval("styles/default/"+tag("surface")+".png")}
way|z16-[surface=granite] {color:#655}
way|z16-[surface=paving_stones] {image: styles/default/paving_stones6s.png}
way|z16-[landuse=field] {fill-image: styles/default/field.png}
way|z17-[barrier]
{casing-width:1; width: eval(metric(tag("width")))}
way|z-16[highway=residential],
way|z-16[highway=tertiary],
way|z-16[highway=living_street]
{width: 3; color:#ffffff; z-index:10;casing-width: 1;}
way|z15-16[highway=service][living_street!=yes],
way|z-16[highway=unclassified]
{width: 2.5; color:#ccc; z-index:9;casing-width: 1;}
way|z-16[highway=primary],
way|z-16[highway=motorway],
way|z-16[highway=trunk]
{width: 4; color: #ff0; z-index:11;casing-width: 1;}
way|z-16[highway=primary_link],
way|z-16[highway=motorway_link],
way|z-16[highway=trunk_link]
{width: 3.5; color: #ff0; z-index:11;casing-width: 1;}
way|z-16[highway=secondary]
{width: 4; color: orange; z-index:10;casing-width: 1;}
way|z15-16[highway=track]
{width: 3; color:#252; z-index:8;casing-width: 1;}
way|z15-16[living_street=yes]
{width: 2; z-index: 2;casing-width: 1;}
way|z15-16[highway=footway],
way|z15-16[highway=pedestrian],
way|z15-16[highway=path]
{width:eval(max(2, prop("width"))); color:#655; casing-dashes: 3,1; z-index:3;casing-width: 1;}
way|z15-[highway=steps]
{z-index:5; width:eval(max(2, prop("width"))); color:#655; casing-dashes: 1,0; linecap: butt;casing-width: 1;}
{z-index:6; width:eval(max(2, prop("width"))); dashes: eval("1," + str( max(num(any(num(metric(tag("step:length")))/100, num(metric("0.3m"))))-1, 1) ) ); color: black;casing-width: 1;}
way[bridge=yes] {casing-width:eval(min(3, num(prop("width"))/2 ));casing-linecap:butt}
area[highway][area=yes] {fill-color: eval(any(prop("fill-color"),prop("color"))); fill-image: eval(any(prop("fill-image"), prop("image")));}
/* ---------- FORESTS ---------- */
way[natural=forest],
way[natural=wood],
way[landuse=forest],
way[landuse=wood]
{fill-color: #020}
/* ---------- WATER ---------- */
way[waterway=riverbank],
way[landuse=reservoir],
way[natural=water] {fill-color: #009}
way[waterway=river],
way[waterway=stream]{color: #009;width: eval(max(3, metric(tag("width")) ))}
/* ---------- BUILDINGS ---------- */
way|z16-[building] {fill-color: #522;
/*text: addr:housenumber;*/
text-halo-radius:2; z-index:100; text-position: center;
opacity: 1;
fill-opacity: 1;
extrude: eval(zmetric("3m")*2);
extrude-face-color: #e2e2e2;
extrude-face-opacity: 1;
extrude-edge-width: 1;
extrude-edge-color: #404040;
}
way|z16-[barrier]{raise: eval(zmetric(tag("min_height")));extrude-face-opacity: 0.5}
way|z16-[barrier]{extrude: eval( zmetric(3) - num(prop("raise")) ); }
way|z16-[barrier][height]{extrude: eval( zmetric(tag("height")) - num(prop("raise")) ); }
way|z16-[building]{raise: eval( any( zmetric(tag("min_height")), zmetric ( num(tag("building:min_level")) * 3)));}
way|z16-[building][building:levels]{extrude: eval( zmetric(num(tag("building:levels"))*3) - num(prop("raise")) );}
way|z16-[building][height]{extrude: eval( zmetric(tag("height")) - num(prop("raise")) );}
/* ---------- INDUSTRY ---------- */
way|z17-[power=line] {width: 1; color:#ccc}
way|z10-[landuse=industrial] {fill-color: #855}
way|z10-[landuse=military] {fill-color: pink}
/* ---------- GARDENS&co ---------- */
way|z13-[landuse=allotments] {fill-color: #452; opacity: 0.8}
way|z10-[landuse=field] {fill-color: #CCCC4E; opacity: 0.8}
/* ---------- GRASS ---------- */
way|z16-[landuse=residential],
{fill-color: #cceecc; opacity: 0.8; fill-image: styles/default/grass.png; }
way|z16-[landuse=grass],
way|z16-[natural=grass]
{fill-color: #cceecc; opacity: 0.8; fill-image: styles/default/grass.png; z-index: 6}
/* ---------- AMENITIES ---------- */
way|z15-[amenity=parking] {icon-image: styles/default/parking.png; }
way[amenity=bench] {extrude: eval(zmetric("0.6m")); width:eval(metric("0.5m")); extrude-face-opacity:0;extrude-edge-color:black;color:brown;opacity:0.75}
{offset:eval(metric("0.25m")); extrude-face-color:brown;extrude:eval(zmetric("1.2m"));extrude-face-opacity: 0.5}
/* ---------- BORDERS ---------- */
/*line[boundary=administrative] {width: 2; color: red; dashes:5,3; z-index:15}
area|z-17[boundary=administrative] {text: name; text-position:center}*/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,246 +0,0 @@
/*
GisRussa style
by Hind, 2010
*/
canvas
{ antialiasing: none; fill-color: #F1FFFF; fill-opacity: 1.0; }
/* =============== Polygons =============== */
/* Defaults for all elements */
way { text-color: black; font-weight: normal; font-size: 8; }
node { text-color: black; font-weight: normal; font-size: 6; text-position: center; text-offset: 10; z-index: 1; }
/* Places on small zoomlevels */
area|z8-10[place]
{ fill-color : #FFFACD; text-position: center; text: name; }
/* Places on large zoomlevels */
area|z11-12[landuse=residential]
{ fill-color : #FFE4C4; text-position: center; text: name; }
/* Parkings */
area|z12-[amenity=parking]
{ fill-color : #F0F0F0; text-position: center; text: name; }
/* Retail area */
area|z12-[landuse=retail]
{ fill-color : #F8B880; text-position: center; text: name; }
/* Schools, colleges, universities */
area|z12-[amenity=school],
area|z12-[amenity=university]
{ fill-color : #F8B880; text-position: center; text: name; }
/* Hospitals */
area[amenity=doctors],area[amenity=hospital]
{ fill-color : #F8B880; text-position: center; text: name; }
/* Industrial area */
area|z11-[landuse=industrial]
{ fill-color : #E8E8E8; text-position: center; text: name; }
/* Buildings */
area|z13-[building][building!=garages]
{ fill-color : #969696; text-position: center; text: addr:housenumber; }
/* Garages */
area|z13-[building=garages]
{ fill-color : #E2E2E2; text-position: center; text: name; }
/* Parks */
area|z12-[leisure=park]
{ fill-color : #90BE00; text-position: center; text: name; }
/* Stadiums, leisures */
area|z12-[leisure]
{ fill-color : #F8B880; text-position: center; text: name; }
/* Water */
area|z9-[natural=water],way[waterway=riverbank]
{ fill-color : #0080FF; text-position: center; text: name; }
/* Forests and woods */
area|z9-[natural=wood],way[landuse=forest]
{ fill-color : #B7E999; text-position: center; text: name; }
/* Wetlands */
area|z10-[natural=wetland]
{ fill-color : #4ACA4A; text-position: center; text: name; }
/* =============== Ways =============== */
/* Trunks */
way[highway=trunk]
{ color: #C46442; width: 4; text-color: black; text-position: line; text: name; casing-width: 1; casing-color: black; text-offset: -8; shield-color: white; shield-frame-color: #C46442; shield-frame-width: 1; shield-shape: rectangular; shield-text: ref; }
/* Primaries */
way[highway=primary]
{ color: #DC7C5A; width: 3; text-color: black; text-position: line; text: name; casing-width: 1; casing-color: black; text-offset: -8; }
/* Secondaries, unclassified */
way[highway=secondary],way|z12-[highway=unclassified]
{ color: #E68664; width: 2; text-color: black; text-position: line; text: name; casing-width: 1; casing-color: black; text-offset: -8; }
/* Tertiaries */
way|z12-[highway=tertiary]
{ color: #E88866; width: 2; text-color: black; text-position: line; text: name; casing-width: 1; casing-color: black; text-offset: -8; }
/* Residentials */
way|z12-[highway=residential]
{ color: #EE8E6C; width: 1; text-color: black; text-position: line; text: name; casing-width: 1; casing-color: black; text-offset: -8; }
/* Services, pedestrians */
way|z12-[highway=service],way[highway=pedestrian]
{ color: #C46442; width: 1; text-color: black; text-position: line; text: name; text-offset: -8; }
/* Primary_links */
way|z11-[highway=primary_link]
{ color: #E88866; width: 2; text-color: black; text-position: line; text: name; casing-width: 1; casing-color: black; text-offset: -8; }
/* Tracks */
way|z12-[highway=track]
{ color: black; width: 1; text-color: black; text-position: line; text: name; dashes: 4; text-offset: -8; }
/* Trunk_links */
way|z11-[highway=trunk_link]
{ color: #C46442; width: 2; text-color: black; text-position: line; text: name; text-offset: -8; }
/* Unknown roads */
way|z12-[highway=road]
{ color: red; width: 1; text-color: black; text-position: line; text: name; text-offset: -8; }
/* Roundabouts */
way|z11-[highway][junction=roundabout]
{ color: #E88866; width: 2; text-color: black; text-position: line; text: name; casing-width: 1; casing-color: black; text-offset: -8; }
/* Railroads */
way|z11-[railway]
{ color: white; width: 1; text-color: black; text-position: line; text: name; dashes: 3; casing-width: 1; casing-color: black; }
/* Footways, paths */
way|z12-[highway=footway],way|z12-[highway=path]
{ color: black; width: 1; text-color: black; text-position: line; text: name; text-offset: -8; }
/* Streams */
way|z12-[waterway=stream]
{ color: black; width: 1; text-color: blue; text-position: line; text: name; text-offset: -8; }
/* Boundary=administrative, level 4 */
way[boundary=administrative][admin_level=4]
{ color: #00C864; width: 1; text-color: #00C864; text-position: line; text: name; }
/* { color: red; width: 1; dashes: 4; } */
/* Boundary=administrative, level 6 */
way[boundary=administrative][admin_level=6]
{ color: #00C864; width: 1; text-color: #00C864; text-position: line; text: name; }
/* { color: black; width: 1; dashes: 4; } */
/* Rivers */
way|z9-[waterway]
{ color: blue; width: 1; text-color: blue; text-position: line; text: name; text-offset: -8; }
/* Power lines */
way|z12-[power=line]
{ color: gray; width: 1; }
/* Fences, walls */
way|z12-[barrier=fence],way|z12-[barrier=wall]
{ color: #00C864; width: 1; text-color: #00C864; text-position: line; text: name; dashes: 4; }
/* =============== Nodes =============== */
/* Place names */
node[place] { z-index:10; }
node[place=city]
{ icon-image: icons/0001.png; font-size: 10; text: name; font-weight: 700; }
node[place=town]
{ icon-image: icons/0002.png; font-size: 10; text: name; font-weight: 700; }
node|z13-[place=village]
{ icon-image: icons/0003.png; font-size: 9; text: name; font-weight: 400; }
node|z13-[place=suburb],node|z13-[place=hamlet]
{ icon-image: icons/0004.png; font-size: 9; text: name; font-weight: 200; }
node|z13-[traffic_calming=bump],node|z12-[traffic_calming=hump]
{ icon-image: icons/1283.png; text: name; }
node|z13-[highway=bus_stop]
{ icon-image: icons/1240.png; text: name; }
node|z13-[amenity=post_office]
{ icon-image: icons/1077.png; text: name; }
node|z13-[natural=tree]
{ icon-image: icons/1040.png; text: name; }
node|z13-[shop=convenience],node|z13-[shop=mall],node|z13-[shop=supermarket]
{ icon-image: icons/1070.png; text: name; }
node|z13-[shop=alcohol]
{ icon-image: icons/1054.png; text: name; }
node|z13-[shop=clothes]
{ icon-image: icons/1071.png; text: name; }
node|z13-[amenity=restaurant],node|z13-[amenity=food_court],node|z13-[amenity=fast_food]
{ icon-image: icons/1031.png; text: name; }
node|z13-[tourism=hotel],node|z13-[tourism=hostel],node|z13-[tourism=motel]
{ icon-image: icons/1032.png; text: name; }
node|z13-[tourism=camp_site]
{ icon-image: icons/1033.png; text: name; }
node|z13-[historic]
{ icon-image: icons/1034.png; text: name; }
node|z13-[amenity=library]
{ icon-image: icons/1037.png; text: name; }
node|z13-[tourism=viewpoint]
{ icon-image: icons/1038.png; text: name; }
node|z13-[amenity=school]
{ icon-image: icons/1039.png; text: name; }
node|z13-[tourism=zoo]
{ icon-image: icons/1041.png; text: name; }
node|z13-[amenity=theatre]
{ icon-image: icons/1044.png; text: name; }
node|z13-[amenity=bar],node|z13-[amenity=pub]
{ icon-image: icons/1045.png; text: name; }
node|z13-[leisure=golf_course],node|z13-[sport=golf]
{ icon-image: icons/1048.png; text: name; }
node|z13-[leisure=ice_rink],node|z13-[sport=skating]
{ icon-image: icons/1051.png; text: name; }
node|z13-[sport=swimming]
{ icon-image: icons/1052.png; text: name; }
node|z13-[leisure=sports_centre][!sport]
{ icon-image: icons/1053.png; text: name; }
node|z13-[amenity=pharmacy]
{ icon-image: icons/1072.png; text: name; }
node|z13-[amenity=fuel]
{ icon-image: icons/1074.png; text: name; }
node|z13-[amenity=bank]
{ icon-image: icons/1078.png; text: name; }
node|z13-[amenity=parking]
{ icon-image: icons/1098.png; text: name; }
node|z13-[amenity=doctors],node|z13-[amenity=hospital]
{ icon-image: icons/1104.png; text: name; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

View file

@ -1,37 +0,0 @@
canvas{fill-color:#a0bc92}
way[landuse] {fill-color: red; }
way[landuse=garages] {fill-color: yellow; }
way[amenity=parking] {fill-color: #cccc00; }
way[landuse=military] {fill-color: pink; }
way[landuse=retail] {fill-color: blue; }
way[landuse=reservoir] {fill-color: lightblue; }
way[natural=water] {fill-color: lightblue; }
way[waterway=riverbank] {fill-color: lightblue; }
way[landuse=cemetery] {fill-color: black; }
way[landuse=industrial] {fill-color: gray; }
way[landuse=residential] {fill-color: white; }
way[landuse=allotments] {fill-color: #ccffcc; }
way[landuse=field] {fill-color: #ccffcc; }
way[landuse=farmland] {fill-color: #ccffcc; }
way[landuse=farm] {fill-color: #ccffcc; }
way[landuse=construction] {fill-color: #987654; }
way[landuse=greenfield] {fill-color: #987654; }
way[landuse=brownfield] {fill-color: #987654; }
way[landuse=quarry] {fill-color: lightgray; }
way[landuse=grass] {fill-color: lightgreen}
way[landuse=meadow] {fill-color: lightgreen}
way[landuse=forest] {fill-color: green}
way[natural=wood] {fill-color: green}
/*way[building] {fill-color: silver; }*/

File diff suppressed because it is too large Load diff

View file

@ -1,210 +0,0 @@
canvas{fill-color:#B5D0D0}
area[natural=ocean]{fill-color:#B5D0D0}
area[natural=coastline]{fill-color:#B5D0D0}
/*area[natural=coastline]{fill-color:#F1EEE8}*/
area|z10-[landuse=military]{fill-color:#F1EEE8; z-index:100}
line|z2-3[boundary=administrative][admin_level=2] {color:#B2B0AE; width:.3}
line|z4-6[boundary=administrative][admin_level=2] {color:#9d6c9d; width:.5}
line|z7-[boundary=administrative][admin_level=2] {color:#9d6c9d; width: 1}
line|z10-[boundary=administrative][admin_level=2]::halo {color:#9d6c9d; width: 6; opacity:0.3}
line|z4-6[boundary=administrative][admin_level=3] {color:#9d6c9d; width:.3}
line|z7-[boundary=administrative][admin_level=3] {color:#9d6c9d; width:.5}
line|z4-6[boundary=administrative][admin_level=4] {color:#9d6c9d; width:.2}
line|z7-[boundary=administrative][admin_level=4] {color:#9d6c9d; width:.3}
node|z2-4[place=country]{text-color:#9d6c9d;
text: name; collision-sort-by: population; font-size: 10,9,8,7;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 5; max-width: 20; z-index: 15
}
node|z5-6[place=country]{text-color:#9d6c9d;
text: name; collision-sort-by: population; font-size: 12,11,10,9,8,7;
text-halo-radius: 1.5; text-halo-color: white;
-x-mapnik-min-distance: 5; max-width: 20; z-index: 15
}
node|z4[place=state]{text-color:#9d6c9d;
font-family: "DejaVu Sans Oblique";
text: ref; collision-sort-by: population; font-size: 9,8,7;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 2; max-width: 20; z-index: 10
}
node|z5-6[place=state]{text-color:#9d6c9d;
font-family: "DejaVu Sans Oblique";
text: name; collision-sort-by: population; font-size: 9,8,7,6;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 3; max-width: 30; z-index: 10
}
node|z7-[place=state]{text-color:#9d6c9d;
font-family: "DejaVu Sans Oblique";
text: name; collision-sort-by: population; font-size: 11,10,9,8,7;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 2; max-width: 80; z-index: 10
}
node|z3-4[place=city]{text-color:grey;
text: name; collision-sort-by: population; font-size: 9,8,7;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 10; max-width: 20; z-index: 5
}
node|z5[place=city]{text-color:black;
text: name; collision-sort-by: population; font-size: 9,8,7;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 7; max-width: 20; z-index: 5
}
node|z6-8[place=city][capital?]
{text-color:black;
text: name; collision-sort-by: population; font-size: 13,12,11,10,9,8,7;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 2; max-width: 20; z-index: 7
}
node|z6-8[place=city][!capital?]
{text-color:black;
text: name; collision-sort-by: population; font-size: 9,8,7;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 1; max-width: 20; z-index: 5
}
node|z8-[place=town]
{text-color:black;
text: name; collision-sort-by: population; font-size: 8,7;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 5; max-width: 20; z-index: 5
}
node|z9-[place=city]
{text-color:black;
text: name; collision-sort-by: population; font-size: 12,11,10,9,8,7;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 2; max-width: 20; z-index: 7
}
node|z10-[place=village]
{text-color:black;
text: name; collision-sort-by: population; font-size: 7,6,5;
text-halo-radius: 1; text-halo-color: white;
-x-mapnik-min-distance: 2; max-width: 20; z-index: 7
}
line|z5-6[highway=motorway] {color: #d6dfea; width: 0.35}
line|z7[highway=motorway] {color: #809bc0; width: 1}
line|z8[highway=motorway] {color: #809bc0; width: 1}
line|z9-10[highway=motorway]{color: #809bc0; width: 1.5}
line|z11[highway=motorway] {color: #809bc0; width: 2}
line|z12-[highway=motorway] {color: #809bc0; width: 2.5}
area|z14-[area:highway=motorway] {fill-color: #809bc0}
line|z0[highway=trunk] {color: #cdeacd; width: 0.35}
line|z5-6[highway=trunk] {color: #cdeacd; width: 0.35}
line|z7[highway=trunk] {color: #a9dba9; width: 1; casing-width:.3; casing-color:#F1EEE8}
line|z8[highway=trunk] {color: #a9dba9; width: 1; casing-width:3; casing-color:#F1EEE8}
line|z9-10[highway=trunk] {color: #98D296; width: 1.5; casing-width:1; casing-color:#F1EEE8}
line|z10-[highway=trunk_link] {color: #98D296; width: 1.5; casing-width:1; casing-color:#F1EEE8}
line|z11[highway=trunk] {color: #98D296; width: 2; casing-width:1; casing-color:#F1EEE8}
line|z12-[highway=trunk] {color: #98D296; width: 2.5; casing-width:1; casing-color:#F1EEE8}
area|z14-[area:highway=trunk] {fill-color: #98D296}
line|z7[highway=primary] {color: #ec989a; width: 0.5}
line|z8[highway=primary] {color: #ec989a; width: 0.5; casing-width:1; casing-color:#F1EEE8}
line|z9-10[highway=primary] {color: #ec989a; width: 1.2}
line|z11-[highway=primary] {color: #ec989a; width: 2}
area|z14-[area:highway=primary] {fill-color: #ec989a}
line|z9-10[highway=secondary] {color: #fed7a5; width: 1.2}
line|z11-[highway=secondary] {color: #fed7a5; width: 2}
area|z14-[area:highway=secondary] {fill-color: #fed7a5}
area[area:highway]{z-index:100}
line|z10-[highway=tertiary],
line|z10-[highway=tertiary_link],
line|z10-[highway=residential],
line|z10-[highway=unclassified],
line|z10-[highway=living_street] {color: #BCBCBC; width: .7}
line|z11-[highway=trunk]
{text: name; text-position: line; font-size: 8;
text-halo-radius: 1; text-halo-color: #98D296; text-spacing: 256;}
line|z11-[highway=primary]
{text: name; text-position: line; font-size: 8;
text-halo-radius: 1; text-halo-color: #ec989a; text-spacing: 256;}
line|z11-[highway=motorway]
{text: name; text-position: line; font-size: 8;
text-halo-radius: 1; text-halo-color: #809bc0; text-spacing: 256;}
line|z11-[highway=secondary]
{text: name; text-position: line; font-size: 8;
text-halo-radius: 1; text-halo-color: #fed7a5; text-spacing: 256;}
line|z6-9[railway=rail] {color: grey; width: 0.27}
line|z10-[railway=rail] {color: #aaa; width: 1}
area|z6-[natural=water],
area|z6-[waterway=riverbank],
area|z8-[landuse=reservoir],
{fill-color:#B5D0D0}
line|z9-[waterway=river]{color:#B5D0D0; width:1.2}
area|z8-[landuse=forest],
area|z8-[natural=wood]
{fill-color:#AED0A0; fill-position: background; z-index:5}
area|z8-[landuse=residential],
area|z8-[place=town],
area|z8-[place=village],
area|z8-[place=hamlet]
{fill-color:#dddddd; fill-position: background}
area|z7-[boundary=national_park]{fill-color:#E5E8DD;fill-position:background; color:green; width:.3; dashes:2,2}
area|z8-[boundary=national_park]{text: name; font-family: DejaVu Sans Bold; font-size:8;
text-halo-radius: 1.5; text-halo-color: white; text-color: #9c9; z-index:6; max-width: 40}
line|z7-[route=ferry] {color:#66f; width:0.4; dashes:4,4; z-index:5}
area|z9-[landuse=farmland],
area|z9-[landuse=farm]
{fill-color:#E9D8BD;fill-position:background}
area|z9-[landuse=field],
{fill-color:#D5D2BA;fill-position:background}
area|z10-[landuse=construction],
area|z10-[landuse=brownfield]{fill-color:#B3B592;fill-position:background}
area|z10-[landuse=industrial]{fill-color:#DED1D5;fill-position:background}
area|z10-[landuse=grass]{fill-color:#CEEBA8;fill-position:background}
area|z10-[leisure=park]{fill-color:#CCF5C9;fill-position:background}
area|z12-[building][building!=no][building!=planned]{fill-color:#C1B0AE}
area|z15-[building]{text: "addr:housenumber";
font-size:8;
text-halo-radius: 1;
text-halo-color: white;
/* text-position:line; -x-mapnik-snap-to-street: true */
}

View file

@ -1,66 +0,0 @@
/*
Deja Vu MapCSS styles
OpenStreetInfo style
*/
canvas {fill-color: #ffffc8}
way[landuse=residential]
{fill-color: #daf4a4; color:#b8cd14 }
way[highway]
{width: eval( any( metric(tag("width")), metric ( num(tag("lanes")) * 4), metric("7m")));
color:#ffffff;
text: name; text-position: line; text-color:#0000ff;text-halo-radius:2;text-halo-color:#ffffc8}
way[highway]
{casing-width: eval(min(1, num(prop("width"))/5 ));}
way[highway][area=yes]{fill-color: #ffffff;width:0}
/* With this eval, if bridge is applied to invisible line, no bridge renders */
way[bridge=yes] {casing-width:eval(min(3, num(prop("width"))/2 ));}
way[natural=forest],
way[natural=wood],
way[landuse=forest],
way[landuse=wood]
{fill-color: #68ec80; color: #45a56b}
way|z15-[landuse=grass],
way[natural=grass]{fill-color: #e7ffd0; color: #45a56b}
way[landuse=garages]
{fill-color: #d2e8ed; color: #cad4e1}
way[waterway=riverbank],
way[natural=water] {fill-color: #5ba7ff; color: #0000a0}
way[waterway=river],
way[waterway=stream]{color: #5ba7ff;casing-width: 1}
way[leisure=stadium]{fill-color: #d0ffff; casing-width: 2; casing-color: #00ccff;z-index:10;}
way[railway=tram]{width: eval( any( metric(tag("width")), metric("1.52m")));color: #ffffff; casing-color: #000000}
{width: eval( metric("2.7m")); color: #000000; dashes: 1,10; z-index:1; object-id: "shpala"}
/*way[landuse=industrial] {fill-color: #855}*/
way[landuse=military] {fill-color: pink}
way[amenity=parking] {fill-color: #d2e8ed;color:cad4e1}
way|z16-[building] {
width: .5;
text: addr:housenumber; text-halo-radius:1; text-position: center;
fill-color: #EDEDED;
extrude: eval( any( metric(tag("height")), metric ( num(tag("building:levels")) * 3), metric("15m")));
extrude-face-color: #e2e2e2;
extrude-edge-width: 1;
extrude-edge-color: #404040;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,204 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from mapcss import MapCSS
import mapcss.webcolors
whatever_to_hex = mapcss.webcolors.webcolors.whatever_to_hex
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
minzoom = 0
maxzoom = 19
style = MapCSS(minzoom, maxzoom)
style.parse(filename=sys.argv[1], clamp=False)
TOTAL_TESTS = 0
FAILED_TESTS = 0
def get_color_lightness(c):
if c == 0:
return 0
return int((30. * c[0] + 15. * c[2] + 45. * c[1]) / 6.)
def renderable(a):
return any([any([y in ["width", "fill-color", "fill-image", "icon-image", "text", "extrude", "background-color", "pattern-image", "shield-text"] for y in x if x[y]]) for x in a])
def is_default(x):
return x.get('object-id') == '::default'
def compare_order(a, function, b):
"a is over b on all zooms"
global TOTAL_TESTS, FAILED_TESTS
z_offset = {"top": 10000, "bottom": -10000}
for zoom in range(minzoom, maxzoom + 1):
for typ1 in ['line', 'node', 'area']:
for typ2 in ['line', 'node', 'area']:
sa = [x.get('z-index', 0.) + z_offset.get(x.get('-x-kot-layer'), 0) for x in style.get_style(typ1, a, zoom) if renderable([x]) and is_default(x)]
sb = [x.get('z-index', 0.) + z_offset.get(x.get('-x-kot-layer'), 0) for x in style.get_style(typ2, b, zoom) if renderable([x]) and is_default(x)]
if sa and sb:
mia = min(sa)
mab = max(sb)
TOTAL_TESTS += 1
if (function == "over") and (mia <= mab):
print "ORDER: z%s\t[%s %s %s %s %s]\t[%s, %s], " % (zoom, typ1, mia, function, typ2, mab, repr(a), repr(b))
print style.get_style(typ1, a, zoom)
print style.get_style(typ2, b, zoom)
FAILED_TESTS += 1
def compare_line_lightness(a, function, b):
"a darker than b on all zooms"
global TOTAL_TESTS, FAILED_TESTS
for zoom in range(minzoom, maxzoom + 1):
for typ1 in ['line', 'node', 'area']:
for typ2 in ['line', 'node', 'area']:
sa = [get_color_lightness(x.get('color', 0.)) for x in style.get_style(typ1, a, zoom) if x.get("width", 0) > 0]
sb = [get_color_lightness(x.get('color', 0.)) for x in style.get_style(typ2, b, zoom) if x.get("width", 0) > 0]
if sa and sb:
mia = min(sa)
mab = max(sb)
TOTAL_TESTS += 1
if (function == "darker") and (mia >= mab):
print "LIGHT: z%s\t[%s %s %s %s %s]\t[%s, %s], " % (zoom, typ1, mia, function, typ2, mab, repr(a), repr(b))
FAILED_TESTS += 1
def compare_visibility(a, function, b):
"a is visible with b on all zooms"
global TOTAL_TESTS, FAILED_TESTS
for zoom in range(minzoom, maxzoom + 1):
for typ in ['line', 'node', 'area']:
sa = [x.get('z-index', 0.) for x in style.get_style(typ, a, zoom) if x]
sb = [x.get('z-index', 0.) for x in style.get_style(typ, b, zoom) if x]
if sa or sb:
TOTAL_TESTS += 1
if (function == "both") and not ((sa) and (sb)):
print "VISIBILITY: z%s\t[%s %s %s %s %s]\t[%s, %s], " % (zoom, typ, bool(sa), function, typ, bool(sb), repr(a), repr(b))
FAILED_TESTS += 1
def has_stable_labels(a):
"a has labels that don't appear-diasppear-appear on zoom-in"
global TOTAL_TESTS, FAILED_TESTS
prev = {"line": False, "node": False, "area": False}
for zoom in range(minzoom, maxzoom + 1):
for typ in ['line', 'node', 'area']:
sa = any(["text" in x for x in style.get_style(typ, a, zoom)])
sb = prev[typ]
if sa or sb:
TOTAL_TESTS += 1
if sb and not sa:
print "LABELS: %s|z%s\t[%s]" % (typ, zoom, repr(a))
FAILED_TESTS += 1
else:
prev[typ] = sa
def has_darker_casings(a):
"a has casings that are darker than the line itself"
global TOTAL_TESTS, FAILED_TESTS
for zoom in range(minzoom, maxzoom + 1):
for typ in ['line', 'node', 'area']:
sa = [x for x in style.get_style(typ, a, zoom) if ("width" in x and "casing-width" in x)]
if sa:
TOTAL_TESTS += 1
for x in sa:
light_color = get_color_lightness(x.get('color', 0.))
light_casing = get_color_lightness(x.get('casing-color', 0.))
if light_color != (light_casing + 2):
print "CASINGS: %s|z%s\t[%s], base: %x (%s) casing: %x (%s)" % (typ, zoom, repr(a), light_color, x.get('width'), light_casing, x.get('casing-width'))
FAILED_TESTS += 1
compare_order({'area:highway': 'primary'}, "over", {'highway': 'primary'})
compare_order({'highway': 'primary'}, "over", {'waterway': 'river'})
compare_order({'highway': 'primary'}, "over", {'waterway': 'canal'})
compare_order({'highway': 'path'}, "over", {'waterway': 'river'})
compare_order({"highway": "motorway"}, "over", {'highway': 'primary'})
compare_line_lightness({"highway": "motorway"}, "darker", {'highway': 'primary'})
compare_order({"highway": "motorway_link"}, "over", {'highway': 'primary_link'})
compare_line_lightness({"highway": "motorway_link"}, "darker", {'highway': 'primary_link'})
compare_order({"highway": "trunk"}, "over", {'highway': 'primary'})
compare_line_lightness({"highway": "trunk"}, "darker", {'highway': 'primary'})
compare_order({"highway": "trunk_link"}, "over", {'highway': 'primary_link'})
compare_order({'highway': 'primary'}, "over", {'highway': 'residential'})
compare_order({'highway': 'primary'}, "over", {'highway': 'secondary'})
compare_order({'highway': 'primary_link'}, "over", {'highway': 'secondary_link'})
compare_order({'highway': 'secondary'}, "over", {'highway': 'tertiary'})
compare_order({'highway': 'secondary_link'}, "over", {'highway': 'tertiary_link'})
compare_order({'highway': 'tertiary'}, "over", {'highway': 'residential'})
compare_order({'highway': 'tertiary'}, "over", {'highway': 'service'})
compare_order({'highway': 'tertiary'}, "over", {'highway': 'unclassified'})
compare_order({'highway': 'tertiary'}, "over", {"highway": "road"})
compare_order({'highway': 'residential'}, "over", {'highway': "track"})
compare_order({'highway': 'residential'}, "over", {'highway': "service"})
compare_order({'highway': 'residential'}, "over", {"highway": "living_street"})
compare_order({'highway': 'unclassified'}, "over", {'highway': "track"})
compare_order({'highway': 'unclassified'}, "over", {'highway': "construction"})
compare_order({'highway': 'residential'}, "over", {'highway': "path", "bicycle": "yes"})
compare_order({'highway': 'track'}, "over", {'highway': "path"})
compare_order({"highway": "steps"}, "over", {'highway': "pedestrian"})
compare_order({"highway": "steps"}, "over", {'highway': "cycleway"})
compare_order({"highway": "service"}, "over", {'highway': "footway"})
compare_order({"highway": "service"}, "over", {'highway': "path"})
compare_order({"highway": "service"}, "over", {'building': "yes"})
compare_order({"railway": "rail"}, "over", {"waterway": "riverbank"})
compare_order({"amenity": "cafe"}, "over", {'amenity': "parking"})
compare_order({"amenity": "bank"}, "over", {'amenity': "atm"})
compare_order({"amenity": "bank"}, "over", {'amenity': "atm"})
compare_order({"railway": "station"}, "over", {'leisure': "park"})
compare_order({"railway": "station"}, "over", {"highway": "bus_stop"})
compare_order({"highway": "tertiary"}, "over", {"highway": "bus_stop"})
compare_order({"highway": "secondary"}, "over", {"highway": "bus_stop"})
compare_order({"highway": "bus_stop"}, "over", {"amenity": "police"})
compare_order({"place": "suburb"}, "over", {'leisure': "park"})
compare_order({"highway": "path"}, "over", {'man_made': "cut_line"})
compare_order({"highway": "footway"}, "over", {'man_made': "cut_line"})
compare_order({"highway": "motorway"}, "over", {'man_made': "cut_line"})
compare_visibility({"highway": "primary"}, "both", {'highway': 'primary_link'})
compare_visibility({"highway": "primary"}, "both", {'highway': 'trunk_link'})
compare_visibility({"highway": "secondary"}, "both", {'highway': 'secondary_link'})
compare_visibility({"highway": "secondary"}, "both", {'highway': 'primary_link'})
compare_visibility({"highway": "tertiary"}, "both", {'highway': 'tertiary_link'})
has_stable_labels({"highway": "trunk", "name": "name", "int_name": "int_name"})
has_stable_labels({"highway": "motorway", "name": "name", "int_name": "int_name"})
has_stable_labels({"highway": "primary", "name": "name", "int_name": "int_name"})
has_stable_labels({"highway": "secondary", "name": "name", "int_name": "int_name"})
has_stable_labels({"highway": "tertiary", "name": "name", "int_name": "int_name"})
has_stable_labels({"highway": "residential", "name": "name", "int_name": "int_name"})
has_stable_labels({"highway": "unclassified", "name": "name", "int_name": "int_name"})
has_darker_casings({'highway': 'motorway'})
has_darker_casings({'highway': 'motorway_link'})
has_darker_casings({'highway': 'trunk'})
has_darker_casings({'highway': 'trunk_link'})
has_darker_casings({'highway': 'primary'})
has_darker_casings({'highway': 'primary_link'})
has_darker_casings({'highway': 'secondary'})
has_darker_casings({'highway': 'secondary_link'})
has_darker_casings({'highway': 'tertiary'})
has_darker_casings({'highway': 'tertiary_link'})
has_darker_casings({'highway': 'residential'})
has_darker_casings({'highway': 'unclassified'})
if TOTAL_TESTS > 0:
print "Failed tests: %s (%s%%)" % (FAILED_TESTS, 100 * FAILED_TESTS / TOTAL_TESTS)
print "Passed tests:", TOTAL_TESTS - FAILED_TESTS
print "Total tests:", TOTAL_TESTS

View file

@ -1,148 +0,0 @@
import os
import math
import pprint
import Image
import cairo
import StringIO
import rsvg
from xml.dom import minidom
def open_icon_as_image(icon, multiplier = 1.0, max_height = None):
fn = icon["file"]
original_multiplier = multiplier
max_height = max_height * multiplier
maki_resize = [
(18, 0.75, 12, 1),
(18, 1.5, 24, 1),
(18, 2, 24, 1.5),
(18, 3, 24, 2),
(12, 1.5, 18, 1),
(12, 2, 24, 1),
(12, 3, 24, 1.5),
(24, 0.75, 18, 1)
]
if "maki" in fn:
for (srcsize, srcmul, dstsize, dstmul) in maki_resize:
if str(srcsize) in fn and multiplier == srcmul:
fn = fn.replace(str(srcsize), str(dstsize))
multiplier = dstmul
break
try:
im = Image.open(fn)
im = im.resize((int(math.ceil(im.size[0] * multiplier)), int(math.ceil(im.size[1] * multiplier))), Image.NEAREST)
except IOError:
icon_dom = minidom.parse(fn)
if icon.get("fill-color"):
[a.setAttribute("fill", icon["fill-color"]) for a in icon_dom.getElementsByTagName("path") if a.getAttribute("fill")]
[a.setAttribute("fill", icon["fill-color"]) for a in icon_dom.getElementsByTagName("g") if a.getAttribute("fill")]
[a.setAttribute("fill", icon["fill-color"]) for a in icon_dom.getElementsByTagName("rect") if a.getAttribute("fill") not in ("none", "")]
if icon.get("color"):
[a.setAttribute("stroke", icon["color"]) for a in icon_dom.getElementsByTagName("path") if a.getAttribute("stroke")]
[a.setAttribute("stroke", icon["color"]) for a in icon_dom.getElementsByTagName("g") if a.getAttribute("stroke")]
[a.setAttribute("stroke", icon["color"]) for a in icon_dom.getElementsByTagName("rect") if a.getAttribute("stroke") not in ("none", "")]
tmpfile = StringIO.StringIO()
outfile = StringIO.StringIO()
svg = rsvg.Handle(data=icon_dom.toxml())
svgwidth = float(svg.get_property('width'))
svgheight = float(svg.get_property('height'))
iconheight = svgheight * multiplier
if max_height:
iconheight = min(iconheight, max_height)
iconwidth = svgwidth * iconheight / svgheight
reswidth, resheight = iconwidth, iconheight
if icon.get("symbol-file"):
bg_dom = minidom.parse(icon["symbol-file"])
if icon.get("symbol-fill-color"):
[a.setAttribute("fill", icon["symbol-fill-color"]) for a in bg_dom.getElementsByTagName("path") if a.getAttribute("fill")]
[a.setAttribute("fill", icon["symbol-fill-color"]) for a in bg_dom.getElementsByTagName("g") if a.getAttribute("fill")]
[a.setAttribute("fill", icon["symbol-fill-color"]) for a in bg_dom.getElementsByTagName("rect") if a.getAttribute("fill") not in ("none", "")]
if icon.get("symbol-color"):
[a.setAttribute("stroke", icon["symbol-color"]) for a in bg_dom.getElementsByTagName("path") if a.getAttribute("stroke")]
[a.setAttribute("stroke", icon["symbol-color"]) for a in bg_dom.getElementsByTagName("g") if a.getAttribute("stroke")]
[a.setAttribute("stroke", icon["symbol-color"]) for a in bg_dom.getElementsByTagName("rect") if a.getAttribute("stroke") not in ("none", "")]
bg_svg = rsvg.Handle(data=bg_dom.toxml())
bg_width = float(bg_svg.get_property('width'))
bg_height = float(bg_svg.get_property('height'))
reswidth = max(bg_width * original_multiplier, reswidth)
resheight = max(bg_height * original_multiplier, resheight)
svgsurface = cairo.SVGSurface(outfile, reswidth, resheight)
svgctx = cairo.Context(svgsurface)
if icon.get("symbol-file"):
svgctx.save()
svgctx.scale(original_multiplier, original_multiplier)
bg_svg.render_cairo(svgctx)
svgctx.restore()
svgctx.translate((reswidth - iconwidth) / 2., (resheight - iconheight) / 2.)
svgctx.scale(iconwidth / svgwidth, iconheight / svgheight)
svg.render_cairo(svgctx)
svgsurface.write_to_png(tmpfile)
svgsurface.finish()
tmpfile.seek(0)
im = Image.open(tmpfile)
bbox = im.getbbox()
if bbox:
dx, dy = min(bbox[0], im.size[0]-bbox[2]), min(bbox[1], im.size[1]-bbox[3])
bbox = (dx, dy, im.size[0] - dx, im.size[1] - dy)
im = im.crop(bbox)
return im
def pack_texture(icons=[], multiplier = 1.0, path = "", rasfilter = []):
images = {}
strips = []
area = 0
for (svg, icon, max_height) in icons:
if os.path.exists(icon["file"]):
images[svg] = open_icon_as_image(icon, multiplier, max_height)
area += images[svg].size[0] * images[svg].size[1]
else:
print "bad icon!", icon
width = 2 ** math.ceil(math.log(area ** 0.5, 2))
queue = images.keys()
queue.sort(key = lambda x: -images[x].size[1] * 10000 - images[x].size[0])
for img in queue:
for strip in strips:
if strip["len"] + images[img].size[0] <= width:
strip["len"] += images[img].size[0]
strip["height"] = max(images[img].size[1], strip["height"])
strip["list"].append(img)
break
else:
strips.append({"len": images[img].size[0], "height": images[img].size[1], "list": [img]})
height = 2 ** math.ceil(math.log(sum([i["height"] for i in strips]), 2))
page = Image.new("RGBA", (int(width), int(height)))
dx, dy = 0, 0
icon_id = 0
skin = open(os.path.join(path, 'basic.skn'), "w")
print >> skin, """<!DOCTYPE skin>
<skin>
<page width="%s" height="%s" file="symbols.png">"""%(int(width), int(height))
for strip in strips:
for img in strip["list"]:
page.paste(images[img], (dx, dy))
icon_id += 1
print >> skin,""" <symbolStyle id="%s" name="%s">
<resourceStyle x="%s" y="%s" width="%s" height="%s"/>
</symbolStyle>""" % (icon_id, img, dx, dy, images[img].size[0], images[img].size[1])
dx += images[img].size[0]
dy += strip["height"]
dx = 0
#pprint.pprint(strips)
print >>skin, """ </page>
</skin>"""
page.save(os.path.join(path,"symbols.png"))

View file

@ -1,125 +0,0 @@
# -*- coding: utf-8 -*-
# This file is part of tWMS.
# tWMS is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# tWMS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with tWMS. If not, see <http://www.gnu.org/licenses/>.
import StringIO
import Image
import os
import threading
import thread
from twms import projections
import config
# from vtiles_backend import QuadTileBackend as DataBackend
from backend.postgis import PostGisBackend as DataBackend
from mapcss import MapCSS
from render import RasterTile
from tempfile import NamedTemporaryFile
style = MapCSS(1, 19)
style.parse(open("/home/kom/osm/kothic/src/styles/default.mapcss", "r").read())
os.chdir("/home/kom/osm/kothic/src/")
metatiles_in_progress = {}
renderlock = threading.Lock()
def kothic_fetcher(z, x, y, this_layer):
if "max_zoom" in this_layer:
if z >= this_layer["max_zoom"]:
return None
bbox = projections.bbox_by_tile(z, x, y, "EPSG:3857")
db = DataBackend(path="/home/kom/osm/kothic/src/tiles")
res = RasterTile(256, 256, 1, db, "EPSG:3857")
res.update_surface(bbox, z, style)
f = NamedTemporaryFile()
f.close()
res.surface.write_to_png(f.name)
del res
del db
im = Image.open(f.name)
os.unlink(f.name)
im = im.convert("RGBA")
return im
def kothic_metatile(z, x, y, this_layer):
print z, x, y
global metatiles_in_progress
if "max_zoom" in this_layer:
if z >= this_layer["max_zoom"]:
return None
if z < 5:
return None
metatile_id = (z, int(x / 8), int(y / 8))
try:
metatiles_in_progress[metatile_id].join()
except KeyError:
metatiles_in_progress[metatile_id] = threading.Thread(None, gen_metatile, None, (metatile_id, this_layer))
metatiles_in_progress[metatile_id].start()
metatiles_in_progress[metatile_id].join()
except RuntimeError:
pass
local = config.tiles_cache + this_layer["prefix"] + "/z%s/%s/x%s/%s/y%s." % (z, x / 1024, x, y / 1024, y)
ext = this_layer["ext"]
if os.path.exists(local + ext): # First, look for tile in cache
try:
im1 = Image.open(local + ext)
del metatiles_in_progress[metatile_id]
return im1
except IOError:
os.remove(local + ext)
def gen_metatile(metatile_id, this_layer):
# renderlock.acquire()
z, x, y = metatile_id
z -= 3
wh = 2560
bb1 = projections.coords_by_tile(z, x - 0.125, y - 0.125, "EPSG:3857")
bb2 = projections.coords_by_tile(z, x + 1.125, y + 1.125, "EPSG:3857")
bbox = (bb1[0], bb2[1], bb2[0], bb1[1])
db = DataBackend()
res = RasterTile(wh, wh, 1, db, "EPSG:3857")
res.update_surface(bbox, z + 3, style)
f = NamedTemporaryFile()
f.close()
res.surface.write_to_png(f.name)
del res
del db
im = Image.open(f.name)
os.unlink(f.name)
im = im.convert("RGBA")
x *= 8
y *= 8
z += 3
ext = this_layer["ext"]
for i in range(x, x + 9):
for j in range(y, y + 9):
local = config.tiles_cache + this_layer["prefix"] + "/z%s/%s/x%s/%s/y%s." % (z, i / 1024, i, j / 1024, j)
box = (256 * (i - x + 1), 256 * (j - y + 1), 256 * (i - x + 2), 256 * (j - y + 2))
im1 = im.crop(box)
if not os.path.exists("/".join(local.split("/")[:-1])):
os.makedirs("/".join(local.split("/")[:-1]))
im1.save(local + ext)
del im1
# renderlock.release()