From 5153bb4385bfb9c15c353c33686f3413ce8d7a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kom=D1=8Fpa?= Date: Sun, 17 Oct 2010 14:37:03 +0300 Subject: [PATCH] * enhanced postgres support * FIX: lines for polygons (thanks Hind) --- src/komap.py | 181 +++++++++++++++++------------- src/libkomapnik.py | 2 + src/make_postgis_style.py | 2 +- src/mapcss/Condition.py | 8 +- src/mapcss/StyleChooser.py | 13 ++- src/styles/osmosnimki-maps.mapcss | 4 +- 6 files changed, 121 insertions(+), 89 deletions(-) diff --git a/src/komap.py b/src/komap.py index 6e48299..0d5a435 100644 --- a/src/komap.py +++ b/src/komap.py @@ -43,14 +43,15 @@ for zoom in range (minzoom, maxzoom): mapniksheet[zoom] = {} zsheet = mapniksheet[zoom] for chooser in style.choosers: - if chooser.get_sql_hints(chooser.ruleChains[0][0].subject, zoom): + if chooser.get_sql_hints(chooser.ruleChains[0][0].subject, zoom)[0]: + sys.stderr.write(str(chooser.get_sql_hints(chooser.ruleChains[0][0].subject, zoom)[0])+"\n") styles = chooser.styles[0] zindex = styles.get("z-index",0) if zindex not in zsheet: zsheet[zindex] = [] chooser_entry = {} zsheet[zindex].append(chooser_entry) - chooser_entry["sql"] = chooser.get_sql_hints(chooser.ruleChains[0][0].subject, zoom) + chooser_entry["sql"] = "("+ chooser.get_sql_hints(chooser.ruleChains[0][0].subject,zoom)[1] +")" chooser_entry["style"] = styles chooser_entry["type"] = chooser.ruleChains[0][0].subject chooser_entry["rule"] = [i.conditions for i in chooser.ruleChains[0]] @@ -84,94 +85,112 @@ for zoom, zsheet in mapniksheet.iteritems(): xml += xml_polygonsymbolizer(entry["style"].get("fill-color", "black"), entry["style"].get("fill-opacity", "1")) if "fill-image" in entry["style"]: xml += xml_polygonpatternsymbolizer(entry["style"].get("fill-image", "")) - sql.update(entry["sql"]) + sql.add(entry["sql"]) itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom)) xml += xml_rule_end() - sql = [i[1] for i in sql] + xml += xml_style_end() + sql.discard("()") if sql: mfile.write(xml) sql = " OR ".join(sql) mfile.write(xml_layer("postgis", "polygon", itags, sql )) else: xml_nolayer() - for zlayer in range(-5,6): - for zindex in ta: - ## casings pass - sql = set() - itags = set() - xml = xml_style_start() - for entry in zsheet[zindex]: - if entry["type"] in ("way", "line"): - if "casing-width" in entry["style"]: - xml += xml_rule_start() - xml += x_scale - rulestring = " or ".join([ "("+ " and ".join([i.get_mapnik_filter() for i in rule]) + ")" for rule in entry["rule"]]) - xml += xml_filter(rulestring) - xml += xml_linesymbolizer(color=entry["style"].get("casing-color", "black"), - width=2*float(entry["style"].get("casing-width", 1))+float(entry["style"].get("width", 0)), - opacity=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", ""))) + for layer_type, entry_types in {"line":("way", "line"), "polygon":("way","area")}.iteritems(): + for zlayer in range(-6,7): + for zindex in ta: + ## casings pass + sql = set() + itags = set() + xml = xml_style_start() + for entry in zsheet[zindex]: + if entry["type"] in entry_types: + if "-x-mapnik-layer" in entry["style"]: + if zlayer != -6 and entry["style"]["-x-mapnik-layer"] == "bottom": + continue + if zlayer != 6 and entry["style"]["-x-mapnik-layer"] == "top": + continue + elif zlayer not in range(-5,6): + continue + if "casing-width" in entry["style"]: + xml += xml_rule_start() + xml += x_scale + rulestring = " or ".join([ "("+ " and ".join([i.get_mapnik_filter() for i in rule]) + ")" for rule in entry["rule"]]) + xml += xml_filter(rulestring) + xml += xml_linesymbolizer(color=entry["style"].get("casing-color", "black"), + width=2*float(entry["style"].get("casing-width", 1))+float(entry["style"].get("width", 0)), + opacity=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", ""))) - sql.update(entry["sql"]) - itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom)) - xml += xml_rule_end() - sql = [i[1] for i in sql] - xml += xml_style_end() - if sql: - mfile.write(xml) - sql = " OR ".join(sql) - if zlayer != 0: - sql = "("+ sql +') and "layer" = \'%s\''%zlayer - else: - sql = "("+ sql +') and ("layer" not in ('+ ", ".join(['\'%s\''%i for i in range(-5,6) if i != 0])+") or \"layer\" is NULL)" - mfile.write(xml_layer("postgis", "line", itags, sql )) - else: - xml_nolayer() + sql.add(entry["sql"]) + itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom)) + xml += xml_rule_end() - for zindex in ta: - ## lines pass - sql = set() - itags = set() - xml = xml_style_start() - for entry in zsheet[zindex]: - if entry["type"] in ("way", "line"): - if "width" in entry["style"] or "line-style" in entry["style"]: - xml += xml_rule_start() - xml += x_scale - rulestring = " or ".join([ "("+ " and ".join([i.get_mapnik_filter() for i in rule]) + ")" for rule in entry["rule"]]) - xml += xml_filter(rulestring) - if "width" in entry["style"]: - xml += xml_linesymbolizer(color=entry["style"].get("color", "black"), - width=entry["style"].get("width", "1"), - opacity=entry["style"].get("opacity", "1"), - linecap=entry["style"].get("linecap", "butt"), - linejoin=entry["style"].get("linejoin", "round"), - dashes=entry["style"].get("dashes", "")) - if "line-style" in entry["style"]: - if entry["style"]["line-style"] == "arrows": - xml += xml_hardcoded_arrows() - else: - xml += xml_linepatternsymbolizer(entry["style"]["line-style"]) - sql.update(entry["sql"]) - itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom)) - xml += xml_rule_end() - sql = [i[1] for i in sql] - xml += xml_style_end() - if sql: - mfile.write(xml) - sql = " OR ".join(sql) - if zlayer != 0: - sql = "("+ sql +') and "layer" = \'%s\''%zlayer + xml += xml_style_end() + sql.discard("()") + if sql: + mfile.write(xml) + sql = " OR ".join(sql) + if zlayer == 0: + 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: + sql = "("+ sql +') and "layer" = \'%s\''%zlayer + mfile.write(xml_layer("postgis", layer_type, itags, sql )) else: - sql = "("+ sql +') and ("layer" not in ('+ ", ".join(['\'%s\''%i for i in range(-5,6) if i != 0])+") or \"layer\" is NULL)" - mfile.write(xml_layer("postgis", "line", itags, sql )) - else: - xml_nolayer() + xml_nolayer() + + for zindex in ta: + ## lines pass + sql = set() + itags = set() + xml = xml_style_start() + for entry in zsheet[zindex]: + if entry["type"] in entry_types: + if "-x-mapnik-layer" in entry["style"]: + if zlayer != -6 and entry["style"]["-x-mapnik-layer"] == "bottom": + continue + if zlayer != 6 and entry["style"]["-x-mapnik-layer"] == "top": + continue + elif zlayer not in range(-5,6): + continue + if "width" in entry["style"] or "line-style" in entry["style"]: + xml += xml_rule_start() + xml += x_scale + rulestring = " or ".join([ "("+ " and ".join([i.get_mapnik_filter() for i in rule]) + ")" for rule in entry["rule"]]) + xml += xml_filter(rulestring) + if "width" in entry["style"]: + xml += xml_linesymbolizer(color=entry["style"].get("color", "black"), + width=entry["style"].get("width", "1"), + opacity=entry["style"].get("opacity", "1"), + linecap=entry["style"].get("linecap", "round"), + linejoin=entry["style"].get("linejoin", "round"), + dashes=entry["style"].get("dashes", "")) + if "line-style" in entry["style"]: + if entry["style"]["line-style"] == "arrows": + xml += xml_hardcoded_arrows() + else: + xml += xml_linepatternsymbolizer(entry["style"]["line-style"]) + 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: + mfile.write(xml) + sql = " OR ".join(sql) + if zlayer == 0: + 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: + sql = "("+ sql +') and "layer" = \'%s\''%zlayer + mfile.write(xml_layer("postgis", layer_type, itags, sql )) + else: + xml_nolayer() for layer_type, entry_types in {"line":("way", "line"), "polygon":("way","area"), "point": ("node", "point")}.iteritems(): for zindex in ta: ## icons pass @@ -192,11 +211,12 @@ for zoom, zsheet in mapniksheet.iteritems(): opacity=entry["style"].get("opacity", "1")) - sql.update(entry["sql"]) + sql.add(entry["sql"]) itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom)) xml += xml_rule_end() - sql = [i[1] for i in sql] + xml += xml_style_end() + sql.discard("()") if sql: mfile.write(xml) sql = " OR ".join(sql) @@ -228,11 +248,12 @@ for zoom, zsheet in mapniksheet.iteritems(): rulestring = " or ".join([ "("+ " and ".join([i.get_mapnik_filter() for i in rule]) + ")" for rule in entry["rule"]]) xml += xml_filter(rulestring) xml += xml_textsymbolizer(ttext,tface,tsize,tcolor, thcolor, thradius, tplace, toffset,toverlap) - sql.update(entry["sql"]) + sql.add(entry["sql"]) itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom)) xml += xml_rule_end() - sql = [i[1] for i in sql] + xml += xml_style_end() + sql.discard("()") if sql: mfile.write(xml) if layer_type == "line": diff --git a/src/libkomapnik.py b/src/libkomapnik.py index 6538a80..10b716a 100644 --- a/src/libkomapnik.py +++ b/src/libkomapnik.py @@ -205,6 +205,7 @@ def xml_layer(type="postgis", geom="point", interesting_tags = "*", sql = "true" %s way %s%s + false -20037508.342789244, -20037508.342780735, 20037508.342789244, 20037508.342780709 """%(layer_id, db_proj, subs, interesting_tags, table_prefix, geom, sql, db_user, db_name, db_srid, table_prefix, geom) @@ -223,6 +224,7 @@ def xml_layer(type="postgis", geom="point", interesting_tags = "*", sql = "true" %s way %s%s + false -20037508.342789244, -20037508.342780735, 20037508.342789244, 20037508.342780709 """%(layer_id, db_proj, subs, sql, db_user, db_name, db_srid, table_prefix, geom) diff --git a/src/make_postgis_style.py b/src/make_postgis_style.py index 5b19416..8f07e26 100644 --- a/src/make_postgis_style.py +++ b/src/make_postgis_style.py @@ -20,7 +20,7 @@ from debug import debug, Timer from mapcss import MapCSS style = MapCSS(1, 19) #zoom levels -style.parse(open("styles/default.mapcss","r").read()) +style.parse(open("styles/osmosnimki-maps.mapcss","r").read()) t = ("way", "node") dct = {} diff --git a/src/mapcss/Condition.py b/src/mapcss/Condition.py index fa7119c..9f63244 100644 --- a/src/mapcss/Condition.py +++ b/src/mapcss/Condition.py @@ -93,13 +93,13 @@ class Condition: return params[0], '"%s" IS NULL'%(params[0]) if t == '<': - return params[0], '"%s" IS NOT NULL'%(params[0]) + return params[0], """(CASE WHEN "%s" ~ E'^[[:digit:]]+(\.[[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) ELSE 0 END) < %s"""%(params[0],params[0],params[1]) if t == '<=': - return params[0], '"%s" IS NOT NULL'%(params[0]) + return params[0], """(CASE WHEN "%s" ~ E'^[[:digit:]]+(\.[[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) ELSE 0 END) <= %s"""%(params[0],params[0],params[1]) if t == '>': - return params[0], '"%s" IS NOT NULL'%(params[0]) + return params[0], """(CASE WHEN "%s" ~ E'^[[:digit:]]+(\.[[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) ELSE 0 END) > %s"""%(params[0],params[0],params[1]) if t == '>=': - return params[0], '"%s" IS NOT NULL'%(params[0]) + return params[0], """(CASE WHEN "%s" ~ E'^[[:digit:]]+(\.[[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) ELSE 0 END) >= %s"""%(params[0],params[0],params[1]) except KeyError: pass def get_mapnik_filter(self): diff --git a/src/mapcss/StyleChooser.py b/src/mapcss/StyleChooser.py index c872670..8e4857a 100644 --- a/src/mapcss/StyleChooser.py +++ b/src/mapcss/StyleChooser.py @@ -71,11 +71,20 @@ class StyleChooser: Returns a set of tags that were used in here in form of SQL-hints. """ a = set() + b = "" for c in self.ruleChains: for r in c: - a.update(r.get_sql_hints(type, zoom)) + p = r.get_sql_hints(type, zoom) + q = "("+") AND (".join([t[1] for t in p]) + ")" + if q == "()": + q = "" + if b and q: + b += " OR "+ q + else: + b = q + a.update(p) # no need to check for eval's - return a + return a,b # // Update the current StyleList from this StyleChooser def updateStyles(self,sl,type, tags, zoom, scale, zscale): diff --git a/src/styles/osmosnimki-maps.mapcss b/src/styles/osmosnimki-maps.mapcss index 3bd5f88..06ca0b5 100644 --- a/src/styles/osmosnimki-maps.mapcss +++ b/src/styles/osmosnimki-maps.mapcss @@ -364,7 +364,7 @@ way[railway=rail]::ticks {width:1; color: #ffffff; dashes: 6,6;z-index:15} way|z12-[railway=subway] -{width:3; color: #072889;z-index:15; dashes:3,3; opacity:0.3} +{width:3; color: #072889;z-index:15; dashes:3,3; opacity:0.3; linecap: butt;} node|z15-[amenity=fuel] {icon-image:tankstelle1_10x11.png} @@ -409,7 +409,7 @@ text:name; text-offset:7; font-size:9; font-family: DejaVu Sans Mono Book; text- } node|z12-[railway=station][transport=subway] {icon-image:metro_others6.png; -text:name; text-offset:11; font-size:9; font-family: DejaVu Sans Book; text-halo-radius:2; text-color:#1300bb;text-halo-color:#ffffff; text-allow-overlap: false;z-index:17; linecap: butt; +text:name; text-offset:11; font-size:9; font-family: DejaVu Sans Book; text-halo-radius:2; text-color:#1300bb;text-halo-color:#ffffff; text-allow-overlap: false;z-index:17; }