MapCSS initial support.

- TODO: MapCSS loading and parsing
 - TODO: better default stylesheet
This commit is contained in:
Komяpa 2010-05-02 15:14:12 +03:00
parent df2643ef96
commit 3453083473
4 changed files with 115 additions and 93 deletions

View file

@ -28,6 +28,7 @@ import Queue
from debug import debug, Timer
from vtiles_backend import QuadTileBackend as DataBackend
from style import Styling
@ -80,24 +81,8 @@ class Navigator:
self.rastertile = None
self.f = True
undef = None
self.style = [
[None, None, None, 0],
[undef, [6.0, [0,0,0]], [4.0, [1, 1, .7]], 1],
[undef, [4.5, [0,0,0]], [2.5, [1, 1, .7]], 2],
[undef, [3.5, [0,0,0]], [2.5, [1, 1, .7]], 3],
[undef, [2.8, [0,0,0]], [2.0, [1, 1, 1]], 4],
[undef, undef, [1.0, [1, 1, 1]], 5],
[undef, [0, [0.7, 0.4, 0.4]], undef, 6],
[[1, [0.30, 0.5, 0.30]], undef, undef, 7],
[undef, undef, [2, [1, 0.3, 0.3]], 8],
[[0, [0.7, 0.6, 0.6]], undef, undef, 9],
[[0, [0.4, 0.4, 1.0]], undef, undef, 10],
[[0, [0.6, 0.6, 0.6]], undef, undef, 11],
[undef, [3.5, [0.4, 0.4, 1.0]], undef, 12],
[undef, [2, [0.4, 0.4, 1.0]], undef, 13],
[[0, [0.72, 0.51, 0.32]], undef, undef, 14],
[[0, [1, 0.0, 0.0]], undef, undef, 0] #unknown landuse
]
self.style = Styling()
da = gtk.DrawingArea()
da.add_events(gtk.gdk.BUTTON1_MOTION_MASK)
da.add_events(gtk.gdk.POINTER_MOTION_MASK)
@ -273,35 +258,79 @@ class RasterTile:
#FIXME add time2
#ww = ways(tilecache)
#debug("ways: %s" % len(ww))
ww = self.data.get_vectors((lonmin,latmin,lonmax,latmax),self.zoomlevel).values()
ww = [ (x, style.get_style("way", x.tags)) for x in self.data.get_vectors((lonmin,latmin,lonmax,latmax),self.zoomlevel).values()]
ww1 = []
for way in ww:
if way[1]:
ww1.append(way)
ww = ww1
if lock is not None:
lock.acquire()
lock.release()
self.lcc = math.cos(self.center_coord[1]*math.pi/180)
ww.sort(key=lambda x: style[x.style][3])
#ww = dict([(int(x[1]["layer"]/100), x) for x in ww])
#debug(objs_by_layers)
#ww = [x[0] for x in ww]
lcc = math.cos(self.center_coord[1]*math.pi/180)
for w in ww:
cs = []
for k in range(0, len(w.coords), 2):
x, y = self.lonlat2screen((w.coords[k], w.coords[k+1]));
for k in range(0, len(w[0].coords), 2):
x, y = self.lonlat2screen((w[0].coords[k], w[0].coords[k+1]));
cs.append(x)
cs.append(y)
w.cs = cs
for passn in range(1, 4):
debug("pass %s" % passn)
for w in ww:
stn = w.style
if lock is not None:
lock.acquire()
lock.release()
if stn < len(style) and style[stn] is not None and style[stn][passn-1] is not None:
st = style[w.style][passn-1]
cr.set_line_width(st[0])
cr.set_source_rgb(st[1][0], st[1][1], st[1][2])
if w.type == "L":
line(cr, w.cs)
elif w.type == "P":
poly(cr, w.cs)
w[0].cs = cs
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:
# debug(obj)
objs_by_layers[int(obj[1]["layer"]/100)].append(obj)
del ww
for layer in layers:
data = objs_by_layers[layer]
# - fill polygons
for obj in data:
#debug(obj[1])
if "fill-color" in obj[1]:
color = gtk.gdk.Color(obj[1]["fill-color"])
cr.set_source_rgb(color.red, color.green, color.blue)
cr.set_line_width (0)
#debug("poly!")
poly(cr, obj[0].cs)
# - draw casings on layer
for obj in data:
if "casing-width" in obj[1] or "casing-color" in obj[1]:
color = gtk.gdk.Color(obj[1].get("casing-color", "#000"))
cr.set_source_rgb(color.red, color.green, color.blue)
cr.set_line_width (obj[1].get("casing-width", obj[1].get("width",0)+1 ))
line(cr, obj[0].cs)
# - draw line centers
for obj in data:
if "width" in obj[1] or "color" in obj[1]:
color = gtk.gdk.Color(obj[1].get("color", "#000"))
cr.set_source_rgb(color.red, color.green, color.blue)
cr.set_line_width (obj[1].get("width", 1))
line(cr, obj[0].cs)
#debug("pass %s" % passn)
#for w in ww:
#stn = w.style
#if lock is not None:
#lock.acquire()
#lock.release()
#if stn < len(style) and style[stn] is not None and style[stn][passn-1] is not None:
#st = style[w.style][passn-1]
#cr.set_line_width(st[0])
#cr.set_source_rgb(st[1][0], st[1][1], st[1][2])
#if w.type == "L":
#line(cr, w.cs)
#elif w.type == "P":
#poly(cr, w.cs)

View file

@ -19,6 +19,7 @@ import os
import sys
from lxml import etree
from twms import projections
from style import Styling
try:
import psyco
@ -29,26 +30,7 @@ except ImportError:
MAXZOOM = 16
proj = "EPSG:4326"
style = {}
style["L"] = {
1: set([("highway",("primary", "motorway", "trunk"))]),
2: set([("highway",("primary_link", "motorway_link", "trunk_link"))]),
3: set([("highway",("secondary"))]),
4: set([("highway",("residential", "tertiary", "living_street"))]),
5: set([("highway",("service", "unclassified"))]),
# 8: set([("highway", None)]),
12: set([("waterway", ("river"))]),
13: set([("waterway", ("stream"))]),
}
style["P"] = {
6: set([("building",None)]),
7: set([("natural",("wood")), ("landuse",("forest")), ("leisure", ("park"))]),
9: set([("landuse",("industrial"))]),
10: set([("natural",("water")),("waterway",("riverbank"))]),
11: set([("landuse",("residential"))]),
14: set([("landuse", ("allotments"))]),
# 13: set([("landuse", None)]),
}
style = Styling()
# elsif($k eq 'highway' and $v eq 'footway' or $v eq 'path' or $v eq 'track'){
@ -77,15 +59,6 @@ def pix_distance(a,b,z):
"""
return 2**z*256*(((a[0]-b[0])/360.)**2+((a[1]-b[1])/180.)**2)**0.5
needed_ways_tags = set(['highway','building','landuse'])
def way_interesting(tags):
res = {}
for k,v in tags.iteritems():
if k in needed_ways_tags:
res[k] = v
return res
def main ():
DROPPED_POINTS = 0
@ -106,20 +79,10 @@ def main ():
elif elem.tag == "way":
mzoom = 1
waytype, waynum = 0, 0
for objtype, tagset in style.iteritems():
for tid, tagz in tagset.iteritems():
for k, v in tagz:
if k in tags:
if v:
if tags[k] not in v:
continue
#print k, v
waytype = objtype
waynum = tid
if waytype is not 0:
if style.get_style("way", tags, True): # if way is stylized
tags = style.filter_tags(tags)
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
@ -141,7 +104,7 @@ def main ():
#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)
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):
@ -149,7 +112,7 @@ def main ():
tilefiles[tile] = "aaa"
tilefile = open(path+"y"+str(y)+".vtile","wb")
tilefile = open(path+"y"+str(y)+".vtile","a")
print >>tilefile, "%s %s %s" % (waytype, items["id"], waynum), " ".join([str(x[0])+" "+str(x[1]) for x in way_simplified[tile[0]]])
print >>tilefile, "%s %s" % (towrite, items["id"]), " ".join([str(x[0])+" "+str(x[1]) for x in way_simplified[tile[0]]])
tilefile.flush()
tilefile.close()

View file

@ -31,20 +31,44 @@ class Styling():
self.Selectors["relation"] = []
if not stylefile:
### using "builtin" styling
self.Selectors["way"].append(StyleSelector( ( [ ( ("highway",),("residential", "tertiary", "living_street")) ] ),{"width": 5, "color":"#ffffff"} ))
self.Selectors["way"].append(StyleSelector( ( [ ( ("building",),(None) ) ] ),{"width": 1, "fill-color":"#ff0000"} ))
self.Selectors["way"].append(StyleSelector( ( [ ( ("highway",),("residential", "tertiary", "living_street")) ] ),{"width": 3, "color":"#ffffff", "casing-width": 5, "z-index":100} ))
self.Selectors["way"].append(StyleSelector( ( [ ( ("building",),(None) ) ] ),{"fill-color":"#ff0000"} ))
self.stylefile = stylefile
self.useful_keys = set()
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]))
def get_style(self, objtype, tags):
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:
resp["layer"] = int(tags.get("layer",0))*100+resp.get("z-index",0)+1000
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 resp
class StyleSelector():
def __init__(self, tags, style):
"""
@ -66,7 +90,8 @@ class StyleSelector():
if v:
if tags[j] in v:
styled = True
styled = True
else:
styled = True
if styled:
return self.style
return {}
@ -75,4 +100,9 @@ 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":"residential", "building": "yes"})
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

@ -19,11 +19,11 @@ from debug import debug
from twms import projections
class Way:
def __init__(self, type, style, coords):
self.type = type
def __init__(self, tags, coords):
self.coords = coords
self.style = style
self.cs = None
#print [x.split("=") for x in tags.split(";")]
self.tags = dict((x.split("=") for x in tags.split(";")))
class QuadTileBackend:
"""
@ -54,7 +54,7 @@ class QuadTileBackend:
t = {}
for line in f:
a = line.split(" ")
w = Way(a[0], int(a[2]), [float(x) for x in a[3:]])
w = Way(a[0], [float(x) for x in a[2:]])
t[int(a[1])] = w
f.close()
return t