MapCSS initial support.
- TODO: MapCSS loading and parsing - TODO: better default stylesheet
This commit is contained in:
parent
df2643ef96
commit
3453083473
4 changed files with 115 additions and 93 deletions
105
src/kothic.py
105
src/kothic.py
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
42
src/style.py
42
src/style.py
|
@ -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"})
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue