autopep8 for all the source code

This commit is contained in:
Darafei Praliaskouski 2013-09-24 14:29:44 +03:00
parent bc1b41042a
commit af75b8cf57
28 changed files with 1495 additions and 1449 deletions

View file

@ -15,10 +15,12 @@
# 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 debug import debug
from twms import projections
import psycopg2
import shapely.wkb
class Empty:
def copy(self):
a = Empty()
@ -33,18 +35,18 @@ class Way:
def __init__(self, tags, geom):
self.cs = []
#print [x.split("=") for x in tags.split(";")]
# 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):
# 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)
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()
@ -54,17 +56,16 @@ class Way:
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", ):
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.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
@ -73,16 +74,16 @@ class PostGisBackend:
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):
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))
bbox = tuple(projections.from4326(bbox, self.proj))
### FIXME: hardcoded EPSG:3857 in database
tables = ("planet_osm_line","planet_osm_polygon") # FIXME: points
tables = ("planet_osm_line", "planet_osm_polygon") # FIXME: points
resp = {}
for table in tables:
add = ""
@ -92,7 +93,7 @@ class PostGisBackend:
for tp in sql_hint:
add = []
b.execute("SELECT * FROM %s LIMIT 1;"%table)
b.execute("SELECT * FROM %s LIMIT 1;" % table)
names = [q[0] for q in b.description]
for j in tp[0]:
@ -102,25 +103,23 @@ class PostGisBackend:
add.append(tp[1])
if add:
add = " OR ".join(add)
add = "("+add+")"
add = "(" + add + ")"
adp.append(add)
if tags_hint:
taghint = ", ".join(['"'+j+'"' for j in tags_hint if j in names])+ ", way, osm_id"
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])
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():
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'))
@ -138,12 +137,12 @@ class PostGisBackend:
continue
### FIXME
#geom = projections.to4326(geom, self.proj)
# 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
# print row_dict
resp[oid] = w
a.close()
del a

View file

@ -19,6 +19,7 @@
from twms import projections
import twms.bbox
class Empty:
def copy(self):
a = Empty()
@ -29,23 +30,25 @@ class Empty:
a.bbox = self.bbox
return a
class Way:
def __init__(self, tags, coords):
self.cs = []
#print [x.split("=") for x in tags.split(";")]
# 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])]
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)
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()
@ -61,9 +64,7 @@ class QuadTileBackend:
A class that gives out vector data on demand.
"""
def __init__(self,max_zoom = 16,proj = "EPSG:4326", path = "tiles", lang = "ru"):
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
@ -73,52 +74,53 @@ class QuadTileBackend:
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)):
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)
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,))
# debug("loading tile: %s"% (k,))
try:
f = open(self.filename(k))
except IOError:
print ( "Failed open: '%s'" % self.filename(k) )
print ("Failed open: '%s'" % self.filename(k))
return {}
t = {}
for line in f:
#debug(line)
# 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]:
# 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,))
# debug ("killed tile: %s" % (tile,))
except KeyError, ValueError:
pass
#debug ("tile killed not by us: %s" % (tile,))
# debug ("tile killed not by us: %s" % (tile,))
def get_vectors (self, bbox, zoom, sql_hint = None, itags = None):
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)]
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)]):
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]
@ -135,7 +137,7 @@ class QuadTileBackend:
"filling response with interesting-tagged objects"
need = False
for tag in ti[obj].tags:
#if tag in hint:
# if tag in hint:
need = True
break
if need:

View file

@ -17,16 +17,16 @@
import datetime
import sys
def debug(st):
"""
Debug write to stderr
"""
sys.stderr.write(str(st)+"\n")
sys.stderr.write(str(st) + "\n")
sys.stderr.flush()
class Timer:
"""
A small timer for debugging
@ -35,5 +35,6 @@ class Timer:
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

@ -7,61 +7,60 @@ from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
DESCRIPTOR = descriptor.FileDescriptor(
name='drules_struct.proto',
package='',
serialized_pb='\n\x13\x64rules_struct.proto\"*\n\x0c\x44\x61shDotProto\x12\n\n\x02\x64\x64\x18\x01 \x03(\x01\x12\x0e\n\x06offset\x18\x02 \x01(\x01\":\n\x0cPathSymProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04step\x18\x02 \x02(\x01\x12\x0e\n\x06offset\x18\x03 \x01(\x01\"\xaf\x01\n\rLineRuleProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\x12\x1e\n\x07pathsym\x18\x05 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"\x9c\x01\n\x0cLineDefProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x1e\n\x07pathsym\x18\x04 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"O\n\rAreaRuleProto\x12\r\n\x05\x63olor\x18\x01 \x02(\r\x12\x1d\n\x06\x62order\x18\x02 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"I\n\x0fSymbolRuleProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x16\n\x0e\x61pply_for_type\x18\x02 \x01(\x05\x12\x10\n\x08priority\x18\x03 \x02(\x05\"j\n\x0f\x43\x61ptionDefProto\x12\x0e\n\x06height\x18\x01 \x02(\x05\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x14\n\x0cstroke_color\x18\x03 \x01(\r\x12\x10\n\x08offset_x\x18\x04 \x01(\x05\x12\x10\n\x08offset_y\x18\x05 \x01(\x05\"l\n\x10\x43\x61ptionRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"a\n\x0f\x43ircleRuleProto\x12\x0e\n\x06radius\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1d\n\x06\x62order\x18\x03 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\"m\n\x11PathTextRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"\xed\x01\n\x10\x44rawElementProto\x12\r\n\x05scale\x18\x01 \x02(\x05\x12\x1d\n\x05lines\x18\x02 \x03(\x0b\x32\x0e.LineRuleProto\x12\x1c\n\x04\x61rea\x18\x03 \x01(\x0b\x32\x0e.AreaRuleProto\x12 \n\x06symbol\x18\x04 \x01(\x0b\x32\x10.SymbolRuleProto\x12\"\n\x07\x63\x61ption\x18\x05 \x01(\x0b\x32\x11.CaptionRuleProto\x12 \n\x06\x63ircle\x18\x06 \x01(\x0b\x32\x10.CircleRuleProto\x12%\n\tpath_text\x18\x07 \x01(\x0b\x32\x12.PathTextRuleProto\"G\n\x13\x43lassifElementProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\"\n\x07\x65lement\x18\x02 \x03(\x0b\x32\x11.DrawElementProto\"4\n\x0e\x43ontainerProto\x12\"\n\x04\x63ont\x18\x01 \x03(\x0b\x32\x14.ClassifElementProto*4\n\x08LineJoin\x12\r\n\tROUNDJOIN\x10\x00\x12\r\n\tBEVELJOIN\x10\x01\x12\n\n\x06NOJOIN\x10\x02*3\n\x07LineCap\x12\x0c\n\x08ROUNDCAP\x10\x00\x12\x0b\n\x07\x42UTTCAP\x10\x01\x12\r\n\tSQUARECAP\x10\x02\x42\x02H\x03')
name='drules_struct.proto',
package='',
serialized_pb='\n\x13\x64rules_struct.proto\"*\n\x0c\x44\x61shDotProto\x12\n\n\x02\x64\x64\x18\x01 \x03(\x01\x12\x0e\n\x06offset\x18\x02 \x01(\x01\":\n\x0cPathSymProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04step\x18\x02 \x02(\x01\x12\x0e\n\x06offset\x18\x03 \x01(\x01\"\xaf\x01\n\rLineRuleProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\x12\x1e\n\x07pathsym\x18\x05 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"\x9c\x01\n\x0cLineDefProto\x12\r\n\x05width\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1e\n\x07\x64\x61shdot\x18\x03 \x01(\x0b\x32\r.DashDotProto\x12\x1e\n\x07pathsym\x18\x04 \x01(\x0b\x32\r.PathSymProto\x12\x17\n\x04join\x18\x06 \x01(\x0e\x32\t.LineJoin\x12\x15\n\x03\x63\x61p\x18\x07 \x01(\x0e\x32\x08.LineCap\"O\n\rAreaRuleProto\x12\r\n\x05\x63olor\x18\x01 \x02(\r\x12\x1d\n\x06\x62order\x18\x02 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"I\n\x0fSymbolRuleProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x16\n\x0e\x61pply_for_type\x18\x02 \x01(\x05\x12\x10\n\x08priority\x18\x03 \x02(\x05\"j\n\x0f\x43\x61ptionDefProto\x12\x0e\n\x06height\x18\x01 \x02(\x05\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x14\n\x0cstroke_color\x18\x03 \x01(\r\x12\x10\n\x08offset_x\x18\x04 \x01(\x05\x12\x10\n\x08offset_y\x18\x05 \x01(\x05\"l\n\x10\x43\x61ptionRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"a\n\x0f\x43ircleRuleProto\x12\x0e\n\x06radius\x18\x01 \x02(\x01\x12\r\n\x05\x63olor\x18\x02 \x02(\r\x12\x1d\n\x06\x62order\x18\x03 \x01(\x0b\x32\r.LineDefProto\x12\x10\n\x08priority\x18\x04 \x02(\x05\"m\n\x11PathTextRuleProto\x12!\n\x07primary\x18\x01 \x02(\x0b\x32\x10.CaptionDefProto\x12#\n\tsecondary\x18\x02 \x01(\x0b\x32\x10.CaptionDefProto\x12\x10\n\x08priority\x18\x03 \x02(\x05\"\xed\x01\n\x10\x44rawElementProto\x12\r\n\x05scale\x18\x01 \x02(\x05\x12\x1d\n\x05lines\x18\x02 \x03(\x0b\x32\x0e.LineRuleProto\x12\x1c\n\x04\x61rea\x18\x03 \x01(\x0b\x32\x0e.AreaRuleProto\x12 \n\x06symbol\x18\x04 \x01(\x0b\x32\x10.SymbolRuleProto\x12\"\n\x07\x63\x61ption\x18\x05 \x01(\x0b\x32\x11.CaptionRuleProto\x12 \n\x06\x63ircle\x18\x06 \x01(\x0b\x32\x10.CircleRuleProto\x12%\n\tpath_text\x18\x07 \x01(\x0b\x32\x12.PathTextRuleProto\"G\n\x13\x43lassifElementProto\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\"\n\x07\x65lement\x18\x02 \x03(\x0b\x32\x11.DrawElementProto\"4\n\x0e\x43ontainerProto\x12\"\n\x04\x63ont\x18\x01 \x03(\x0b\x32\x14.ClassifElementProto*4\n\x08LineJoin\x12\r\n\tROUNDJOIN\x10\x00\x12\r\n\tBEVELJOIN\x10\x01\x12\n\n\x06NOJOIN\x10\x02*3\n\x07LineCap\x12\x0c\n\x08ROUNDCAP\x10\x00\x12\x0b\n\x07\x42UTTCAP\x10\x01\x12\r\n\tSQUARECAP\x10\x02\x42\x02H\x03')
_LINEJOIN = descriptor.EnumDescriptor(
name='LineJoin',
full_name='LineJoin',
filename=None,
file=DESCRIPTOR,
values=[
descriptor.EnumValueDescriptor(
name='ROUNDJOIN', index=0, number=0,
options=None,
type=None),
descriptor.EnumValueDescriptor(
name='BEVELJOIN', index=1, number=1,
options=None,
type=None),
descriptor.EnumValueDescriptor(
name='NOJOIN', index=2, number=2,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=1415,
serialized_end=1467,
name='LineJoin',
full_name='LineJoin',
filename=None,
file=DESCRIPTOR,
values=[
descriptor.EnumValueDescriptor(
name='ROUNDJOIN', index=0, number=0,
options=None,
type=None),
descriptor.EnumValueDescriptor(
name='BEVELJOIN', index=1, number=1,
options=None,
type=None),
descriptor.EnumValueDescriptor(
name='NOJOIN', index=2, number=2,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=1415,
serialized_end=1467,
)
_LINECAP = descriptor.EnumDescriptor(
name='LineCap',
full_name='LineCap',
filename=None,
file=DESCRIPTOR,
values=[
descriptor.EnumValueDescriptor(
name='ROUNDCAP', index=0, number=0,
options=None,
type=None),
descriptor.EnumValueDescriptor(
name='BUTTCAP', index=1, number=1,
options=None,
type=None),
descriptor.EnumValueDescriptor(
name='SQUARECAP', index=2, number=2,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=1469,
serialized_end=1520,
name='LineCap',
full_name='LineCap',
filename=None,
file=DESCRIPTOR,
values=[
descriptor.EnumValueDescriptor(
name='ROUNDCAP', index=0, number=0,
options=None,
type=None),
descriptor.EnumValueDescriptor(
name='BUTTCAP', index=1, number=1,
options=None,
type=None),
descriptor.EnumValueDescriptor(
name='SQUARECAP', index=2, number=2,
options=None,
type=None),
],
containing_type=None,
options=None,
serialized_start=1469,
serialized_end=1520,
)
@ -73,59 +72,58 @@ BUTTCAP = 1
SQUARECAP = 2
_DASHDOTPROTO = descriptor.Descriptor(
name='DashDotProto',
full_name='DashDotProto',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
descriptor.FieldDescriptor(
name='dd', full_name='DashDotProto.dd', index=0,
number=1, type=1, cpp_type=5, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
descriptor.FieldDescriptor(
name='offset', full_name='DashDotProto.offset', index=1,
number=2, type=1, cpp_type=5, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
extension_ranges=[],
serialized_start=23,
serialized_end=65,
name='DashDotProto',
full_name='DashDotProto',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
descriptor.FieldDescriptor(
name='dd', full_name='DashDotProto.dd', index=0,
number=1, type=1, cpp_type=5, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
descriptor.FieldDescriptor(
name='offset', full_name='DashDotProto.offset', index=1,
number=2, type=1, cpp_type=5, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
extension_ranges=[],
serialized_start=23,
serialized_end=65,
)
_PATHSYMPROTO = descriptor.Descriptor(
name='PathSymProto',
full_name='PathSymProto',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
descriptor.FieldDescriptor(
name='name', full_name='PathSymProto.name', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=unicode("", "utf-8"),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
descriptor.FieldDescriptor(
name='step', full_name='PathSymProto.step', index=1,
number=2, type=1, cpp_type=5, label=2,
name='PathSymProto',
full_name='PathSymProto',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
descriptor.FieldDescriptor(
name='name', full_name='PathSymProto.name', index=0,
number=1, type=9, cpp_type=9, label=2,
has_default_value=False, default_value=unicode("", "utf-8"),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
descriptor.FieldDescriptor(
name='step', full_name='PathSymProto.step', index=1,
number=2, type=1, cpp_type=5, label=2,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
@ -725,82 +723,95 @@ DESCRIPTOR.message_types_by_name['DrawElementProto'] = _DRAWELEMENTPROTO
DESCRIPTOR.message_types_by_name['ClassifElementProto'] = _CLASSIFELEMENTPROTO
DESCRIPTOR.message_types_by_name['ContainerProto'] = _CONTAINERPROTO
class DashDotProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _DASHDOTPROTO
# @@protoc_insertion_point(class_scope:DashDotProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _DASHDOTPROTO
# @@protoc_insertion_point(class_scope:DashDotProto)
class PathSymProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _PATHSYMPROTO
# @@protoc_insertion_point(class_scope:PathSymProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _PATHSYMPROTO
# @@protoc_insertion_point(class_scope:PathSymProto)
class LineRuleProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _LINERULEPROTO
# @@protoc_insertion_point(class_scope:LineRuleProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _LINERULEPROTO
# @@protoc_insertion_point(class_scope:LineRuleProto)
class LineDefProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _LINEDEFPROTO
# @@protoc_insertion_point(class_scope:LineDefProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _LINEDEFPROTO
# @@protoc_insertion_point(class_scope:LineDefProto)
class AreaRuleProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _AREARULEPROTO
# @@protoc_insertion_point(class_scope:AreaRuleProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _AREARULEPROTO
# @@protoc_insertion_point(class_scope:AreaRuleProto)
class SymbolRuleProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _SYMBOLRULEPROTO
# @@protoc_insertion_point(class_scope:SymbolRuleProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _SYMBOLRULEPROTO
# @@protoc_insertion_point(class_scope:SymbolRuleProto)
class CaptionDefProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _CAPTIONDEFPROTO
# @@protoc_insertion_point(class_scope:CaptionDefProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _CAPTIONDEFPROTO
# @@protoc_insertion_point(class_scope:CaptionDefProto)
class CaptionRuleProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _CAPTIONRULEPROTO
# @@protoc_insertion_point(class_scope:CaptionRuleProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _CAPTIONRULEPROTO
# @@protoc_insertion_point(class_scope:CaptionRuleProto)
class CircleRuleProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _CIRCLERULEPROTO
# @@protoc_insertion_point(class_scope:CircleRuleProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _CIRCLERULEPROTO
# @@protoc_insertion_point(class_scope:CircleRuleProto)
class PathTextRuleProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _PATHTEXTRULEPROTO
# @@protoc_insertion_point(class_scope:PathTextRuleProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _PATHTEXTRULEPROTO
# @@protoc_insertion_point(class_scope:PathTextRuleProto)
class DrawElementProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _DRAWELEMENTPROTO
# @@protoc_insertion_point(class_scope:DrawElementProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _DRAWELEMENTPROTO
# @@protoc_insertion_point(class_scope:DrawElementProto)
class ClassifElementProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _CLASSIFELEMENTPROTO
# @@protoc_insertion_point(class_scope:ClassifElementProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _CLASSIFELEMENTPROTO
# @@protoc_insertion_point(class_scope:ClassifElementProto)
class ContainerProto(message.Message):
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _CONTAINERPROTO
# @@protoc_insertion_point(class_scope:ContainerProto)
__metaclass__ = reflection.GeneratedProtocolMessageType
DESCRIPTOR = _CONTAINERPROTO
# @@protoc_insertion_point(class_scope:ContainerProto)
# @@protoc_insertion_point(module_scope)

View file

@ -18,8 +18,8 @@
from debug import debug, Timer
from backend.vtile import QuadTileBackend as DataBackend
#from backend.postgis import PostGisBackend as DataBackend
#from style import Styling
# from backend.postgis import PostGisBackend as DataBackend
# from style import Styling
from mapcss import MapCSS
from render import RasterTile
@ -30,22 +30,22 @@ if svg:
import cairo
style = MapCSS(1, 19) #zoom levels
style.parse(open("styles/default.mapcss","r").read())
style = MapCSS(1, 19) # zoom levels
style.parse(open("styles/default.mapcss", "r").read())
bbox = (27.115768874532,53.740327031764,28.028320754378,54.067187302158)
bbox = (27.115768874532, 53.740327031764, 28.028320754378, 54.067187302158)
w,h = 630*4,364*4
w, h = 630 * 4, 364 * 4
z = 10
db = DataBackend()
#style = Styling()
# style = Styling()
res = RasterTile(w, h, z, db)
if svg:
file = open("test.svg", "wb")
res.surface = cairo.SVGSurface(file.name, w,h)
res.surface = cairo.SVGSurface(file.name, w, h)
res.update_surface(bbox, z, style)

View file

@ -19,88 +19,87 @@ maxzoom = 18
sample_width = 80
style = MapCSS(minzoom, maxzoom)
style.parse(open(sys.argv[1],"r").read(), clamp=False)
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))
# a = cairo.PDFSurface("legend.pdf",100,100*len(tags))
maxzoom += 1
a = cairo.ImageSurface (cairo.FORMAT_ARGB32, maxzoom*sample_width, 50*len(tags))
a = cairo.ImageSurface(cairo.FORMAT_ARGB32, maxzoom * sample_width, 50 * len(tags))
cr = cairo.Context(a)
cr.translate(0,0.5)
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()])+']')
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())
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))
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:
text = '[' + ']['.join([ k+"="+v for k,v in tag.iteritems()])+']'
cr.move_to(10, 20+50*i)
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_line_width(1)
cr.set_dash([])
cr.move_to(0, 60+50*i)
cr.line_to(maxzoom*sample_width, 60+50*i)
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")
# 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, "<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")
a.write_to_png("legend.png")

View file

@ -26,14 +26,12 @@ import Queue
import os
#from backend.postgis import PostGisBackend as DataBackend
# 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()
@ -52,12 +50,9 @@ class KothicApp:
self.data = DataBackend()
self.load_style()
self.request_d = (0,0)
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)
@ -75,7 +70,7 @@ class KothicApp:
stylemenu = gtk.Menu()
stylem = gtk.MenuItem("Style")
stylem.set_submenu(stylemenu)
styles = [name for name in os.listdir("styles") if ".mapcss" in name]
styles = [name for name in os.listdir("styles") if ".mapcss" in name]
for style in styles:
i = gtk.MenuItem(style)
i.StyleName = style
@ -90,29 +85,26 @@ class KothicApp:
menu.append(stylem)
vbox = gtk.VBox(False, 2)
vbox.pack_start(menu,False,False,0)
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.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()

View file

@ -31,13 +31,14 @@ 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.request_d = (0, 0)
self.tiles = TileSource(data, style, callback=self.redraw)
self.dx = 0
self.dy = 0
self.drag_x = 0
@ -50,145 +51,146 @@ class KothicWidget(gtk.DrawingArea):
self.max_zoom = 25
self.zoom = 0
self.center_coord = (0.0,0.0)
self.center_coord = (0.0, 0.0)
self.old_zoom = 1
self.old_center_coord = (0.0,0.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.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
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)
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((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")
# 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")
# 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")
# debug("Stop drag")
self.drag = False
self.timer.stop()
#debug("dd: %s,%s "%(self.dx, self.dy))
# 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+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.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:
if self.zoom + 0.5 <= self.max_zoom:
self.zoom += 0.5
#debug("Zoom in")
# debug("Zoom in")
elif event.direction == gtk.gdk.SCROLL_DOWN:
if self.zoom >= 0: ## negative zooms are nonsense
if self.zoom >= 0: # negative zooms are nonsense
self.zoom -= 0.5
# debug("Zoom out")
#self.redraw()
debug("new zoom: %s"%(self.zoom))
# 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
# 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!")
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])
# 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
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))
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))
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)
# 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()
# self.comm[3].release()
class TileSource:
def __init__(self,data,style, callback = lambda: None):
def __init__(self, data, style, callback=lambda: None):
self.tiles = {}
self.tilewidth = 2048
self.tileheight = 2048
@ -199,79 +201,82 @@ class TileSource:
self.onscreen = set()
self._singlethread = False
self._prerender = True
def __getitem__(self,(z,x,y),wait=False):
def __getitem__(self, (z, x, y), wait=False):
try:
#if "surface" in self.tiles[(z,x,y)] and not wait:
# 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"]
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()
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))
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"]
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()
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:
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)
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"]
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"]
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:
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"])
cand.sort(lambda i, j: self.tiles[i]["finish_time"] < self.tiles[i]["finish_time"])
while cand:
if (len(self.tiles)> self.max_tiles):
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"])
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
@ -279,7 +284,6 @@ class TileSource:
break
if __name__ == "__main__":
gtk.gdk.threads_init()

View file

@ -15,9 +15,10 @@ try:
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."
# 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"):
def get_vectors(bbox, zoom, style, vec="polygon"):
bbox_p = projections.from4326(bbox, "EPSG:3857")
geomcolumn = "way"
@ -25,7 +26,7 @@ def get_vectors(bbox, zoom, style, vec = "polygon"):
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"}
table = {"polygon": "planet_osm_polygon", "line": "planet_osm_line", "point": "planet_osm_point", "coastline": "coastlines"}
a = psycopg2.connect(database)
b = a.cursor()
@ -35,11 +36,10 @@ def get_vectors(bbox, zoom, style, vec = "polygon"):
for i in ignore_columns:
if i in names:
names.remove(i)
names = ",".join(['"'+i+'"' for i in names])
names = ",".join(['"' + i + '"' for i in names])
taghint = "*"
types = {"line":"line","polygon":"area", "point":"node"}
types = {"line": "line", "polygon": "area", "point": "node"}
adp = ""
if "get_sql_hints" in dir(style):
sql_hint = style.get_sql_hints(types[vec], zoom)
@ -53,14 +53,13 @@ def get_vectors(bbox, zoom, style, vec = "polygon"):
add.append(tp[1])
if add:
add = " OR ".join(add)
add = "("+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
@ -77,23 +76,23 @@ def get_vectors(bbox, zoom, style, vec = "polygon"):
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
)
""" % (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
@ -106,33 +105,33 @@ def get_vectors(bbox, zoom, style, vec = "polygon"):
) 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],
""" % (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,
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],
""" % (
-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
@ -145,19 +144,19 @@ def get_vectors(bbox, zoom, style, vec = "polygon"):
) 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
""" % (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)
@ -168,7 +167,7 @@ def get_vectors(bbox, zoom, style, vec = "polygon"):
for row in b.fetchall():
ROWS_FETCHED += 1
geom = dict(map(None,names,row))
geom = dict(map(None, names, row))
for t in geom.keys():
if not geom[t]:
del geom[t]
@ -180,7 +179,7 @@ def get_vectors(bbox, zoom, style, vec = "polygon"):
geojson["reprpoint"] = json.loads(geom["reprpoint"])["coordinates"]
del geom["reprpoint"]
prop = {}
for k,v in geom.iteritems():
for k, v in geom.iteritems():
prop[k] = v
try:
if int(v) == float(v):
@ -193,9 +192,7 @@ def get_vectors(bbox, zoom, style, vec = "polygon"):
pass
geojson["properties"] = prop
polygons.append(geojson)
return {"bbox": bbox, "granularity":intscalefactor, "features":polygons}
return {"bbox": bbox, "granularity": intscalefactor, "features": polygons}
print "Content-Type: text/html"
@ -214,25 +211,25 @@ if "y" not in form:
z = int(form["z"].value)
x = int(form["x"].value)
y = int(form["y"].value)
if z>22:
if z > 22:
exit()
callback = "onKothicDataResponse"
bbox = projections.bbox_by_tile(z+1,x,y,"EPSG:3857")
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"])
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)
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
dir = "/var/www/vtile/%s/%s/" % (z, x)
file = "%s.js" % y
try:
if not os.path.exists(dir):
@ -240,7 +237,7 @@ try:
except:
pass
file = open(dir+file,"w")
file = open(dir + file, "w")
file.write(aaaa)
file.flush()
file.close()

View file

@ -40,6 +40,7 @@ import math
config = ConfigParser.ConfigParser()
def relaxedFloat(x):
try:
return float(x) if int(float(x)) != float(x) else int(x)
@ -49,45 +50,46 @@ def relaxedFloat(x):
parser = OptionParser()
parser.add_option("-r", "--renderer", dest="renderer", default="mapnik",
help="which renderer stylesheet to generate", metavar="ENGINE")
help="which renderer stylesheet to generate", metavar="ENGINE")
parser.add_option("-s", "--stylesheet", dest="filename",
help="read MapCSS stylesheet from FILE", metavar="FILE")
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")
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")
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")
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")
help="output filename (defaults to stdout)", metavar="FILE")
parser.add_option("-p", "--osm2pgsql-style", dest="osm2pgsqlstyle", default="-",
help="osm2pgsql stylesheet filename", metavar="FILE")
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")
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")
help="text size scale", metavar="SCALE")
parser.add_option("-c", "--config", dest="conffile", default="komap.conf",
help="config file name", metavar="FILE")
help="config file name", metavar="FILE")
(options, args) = parser.parse_args()
if (options.filename == None):
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(open(options.filename,"r").read())
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(open(options.filename, "r").read())
if options.renderer == "mapswithme":
from libkomwm import *
@ -97,7 +99,7 @@ if options.renderer == "mapswithme":
if options.outfile == "-":
mfile = sys.stdout
else:
mfile = open(options.outfile,"w")
mfile = open(options.outfile, "w")
if options.renderer == "js":
from libkojs import *
@ -121,19 +123,16 @@ if options.renderer == "mapnik":
libkomapnik.srtm_hs_path = config.get("mapnik", "srtm_hs_path")
libkomapnik.text_scale = options.textscale
from libkomapnik import *
osm2pgsql_avail_keys = {} # "column" : ["node", "way"]
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")
osm2pgsql_avail_keys["tags"] = ("node", "way")
columnmap = {}
@ -154,7 +153,7 @@ if options.renderer == "mapnik":
'', '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'))
replace(replace(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",
@ -162,11 +161,11 @@ if options.renderer == "mapnik":
"int_name",
"name:en",
"name"
) AS name"""%(table_prefix,table_prefix,table_prefix),('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,))
) AS name""" % (table_prefix, table_prefix, table_prefix), ('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',))
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
@ -176,21 +175,21 @@ if options.renderer == "mapnik":
coast = {}
fonts = set()
demhack = False
for zoom in xrange (options.minzoom, options.maxzoom+1):
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")
# 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)
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 = "(" + chooser.get_sql_hints(chooser.ruleChains[0].subject, zoom)[1] + ")"
sql = sql.split('"')
sq = ""
odd = True
@ -203,12 +202,12 @@ if options.renderer == "mapnik":
chooser_entry["sql"] = sq
chooser_entry["style"] = styles
fonts.add(styles.get("font-family","DejaVu Sans Book"))
fonts.add(styles.get("font-family", "DejaVu Sans Book"))
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"]])
# 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":
@ -220,10 +219,10 @@ if options.renderer == "mapnik":
che["type"] = ttype
zsheet[zindex].append(che)
#sys.stderr.write(str(numerics)+"\n")
#print mapniksheet
# sys.stderr.write(str(numerics)+"\n")
# print mapniksheet
def add_numerics_to_itags(itags, escape = True):
def add_numerics_to_itags(itags, escape=True):
tt = set()
nitags = set()
if escape:
@ -231,30 +230,26 @@ if options.renderer == "mapnik":
else:
def escape(i, asname=False):
if i in mapped_cols:
return i # already escaped
return '"'+i+'"'
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))
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)
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'
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))
@ -264,20 +259,20 @@ if options.renderer == "mapnik":
ta = zsheet.keys()
ta.sort(key=float)
demcolors = {}
demramp = {"ground":"", "ocean":""}
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])
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)
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"])
@ -287,7 +282,7 @@ if options.renderer == "mapnik":
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")))
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()
@ -314,12 +309,12 @@ if options.renderer == "mapnik":
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"):
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")))
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"])
@ -337,9 +332,9 @@ if options.renderer == "mapnik":
itags = itags_g
if sql:
mfile.write(xml_g)
sql = "(" + " OR ".join(sql) + ")"# and way &amp;&amp; !bbox!"
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 ))
mfile.write(xml_layer("postgis", "polygon", itags, sql, zoom=zoom))
else:
xml_nolayer()
@ -347,36 +342,37 @@ if options.renderer == "mapnik":
xml = xml_hillshade(zoom, x_scale)
mfile.write(xml)
index_range = range(-6,7)
index_range = range(-6, 7)
full_layering = conf_full_layering
if (zoom < 9) or not conf_full_layering :
index_range = (-6,0,6)
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] "
])
"[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"))]:
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
roads = (layer_type == 'line') # whether to use planet_osm_roads
## casings pass
for zindex in ta:
sql = set()
@ -389,7 +385,7 @@ if options.renderer == "mapnik":
continue
if zlayer != 6 and entry["style"]["-x-kot-layer"] == "top":
continue
elif zlayer not in range(-5,6):
elif zlayer not in range(-5, 6):
continue
if "casing-width" in entry["style"]:
xml += xml_rule_start()
@ -397,18 +393,18 @@ if options.renderer == "mapnik":
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));
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)
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))
@ -427,26 +423,26 @@ if options.renderer == "mapnik":
itags = itags_g
if sql:
mfile.write(xml_g)
sql = "(" + " OR ".join(sql) + ")"# and way &amp;&amp; !bbox!"
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
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 ))
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"))]:
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
roads = (layer_type == 'line') # whether to use planet_osm_roads
xml_g = ""
sql = set()
@ -459,17 +455,17 @@ if options.renderer == "mapnik":
continue
if zlayer != 6 and entry["style"]["-x-kot-layer"] == "top":
continue
elif zlayer not in range(-5,6):
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")):
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 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")))
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"]:
@ -488,16 +484,16 @@ if options.renderer == "mapnik":
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)
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!!!"
# print "dashes!!!"
if "pattern-image" in entry["style"]:
there_are_line_patterns = True
if entry["style"]["pattern-image"] == "arrows":
@ -507,27 +503,27 @@ if options.renderer == "mapnik":
fname = entry["style"]["pattern-image"]
try:
im = Image.open(icons_path + fname).convert("RGBA")
fname = "f"+fname
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
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))
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
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))
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)
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
print >> sys.stderr, "Error writing to ", icons_path + "komap/" + fname
else:
xml += xml_linepatternsymbolizer(entry["style"]["pattern-image"])
sql.add(entry["sql"])
@ -546,38 +542,38 @@ if options.renderer == "mapnik":
itags = itags_g
if sql:
mfile.write(xml_g)
sql = "(" + " OR ".join(sql) + ")"# and way &amp;&amp; !bbox!"
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
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)
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
# 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
# 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) +'"'
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 ))
""" % (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 ))
mfile.write(xml_layer("postgis", layer_type, itags, sql, zoom=zoom))
else:
xml_nolayer()
@ -588,7 +584,7 @@ if options.renderer == "mapnik":
xml_g = ""
prevtype = ""
for zindex in ta:
for layer_type, entry_types in [("point", ("node", "point")),("line",("way", "line")), ("polygon",("way","area"))]:
for layer_type, entry_types in [("point", ("node", "point")), ("line", ("way", "line")), ("polygon", ("way", "area"))]:
sql = set()
itags = set()
style_started = False
@ -600,9 +596,9 @@ if options.renderer == "mapnik":
if prevtype != layer_type:
if sql_g:
mfile.write(xml_g)
sql_g = "(" + " OR ".join(sql_g) + ")"# and way &amp;&amp; !bbox!"
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 ))
mfile.write(xml_layer("postgis", prevtype, itags_g, sql_g, zoom=zoom))
sql_g = set()
itags_g = set()
xml_g = ""
@ -618,13 +614,13 @@ if options.renderer == "mapnik":
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'):
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)")
sql.add("((" + entry["sql"] + ") and " + escape_sql_column(ttext) + " is NULL)")
itags.add(ttext)
if ttext in columnmap:
itags.update(columnmap[ttext][1])
@ -645,24 +641,24 @@ if options.renderer == "mapnik":
xml_nosubstyle()
if sql_g:
mfile.write(xml_g)
sql_g = "(" + " OR ".join(sql_g) + ")"# and way &amp;&amp; !bbox!"
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 ))
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"):
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))
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()
@ -670,68 +666,68 @@ if options.renderer == "mapnik":
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 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","DejaVu Sans Book")
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")
tface = entry["style"].get("shield-font-family", "DejaVu Sans Book")
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)
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:
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","DejaVu Sans Book")
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")
tface = entry["style"].get("font-family", "DejaVu Sans Book")
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")
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':
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)
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, tplace, toffset,toverlap,tdistance,twrap,talign,topacity,tpos,ttransform,tspacing)
xml += xml_textsymbolizer(ttext, tface, tsize, tcolor, thcolor, thradius, tplace, toffset, toverlap, tdistance, twrap, talign, topacity, tpos, ttransform, tspacing)
sql.add(entry["sql"])
itags.update(entry["chooser"].get_interesting_tags(entry["type"], zoom))
xml += xml_rule_end()
@ -744,7 +740,7 @@ if options.renderer == "mapnik":
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)
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)
@ -754,20 +750,20 @@ if options.renderer == "mapnik":
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])
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])
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
# 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])
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)
@ -781,7 +777,7 @@ if options.renderer == "mapnik":
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)
""" % (itags, libkomapnik.table_prefix, layer_type, ttext, sqlz, pixel_size_at_zoom(zoom, 3) ** 2, order)
else:
sqlz = """select %s, way
from (
@ -791,10 +787,10 @@ if options.renderer == "mapnik":
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)
""" % (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 ))
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)
@ -802,14 +798,13 @@ if options.renderer == "mapnik":
order = "order by"
else:
order += ", "
#itags = "\""+ itags+"\""
# 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 ))
""" % (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)
@ -878,13 +873,12 @@ if options.renderer == "mapnik":
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 ))
""" % (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 ))
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()

View file

@ -1,5 +1,5 @@
def komap_js(mfile, style):
subjs = {"canvas": ("canvas",),"way": ("Polygon","LineString"), "line":("Polygon","LineString"), "area": ("Polygon",), "node": ("Point",), "*":("Point","Polygon","LineString"), "":("Point","Polygon","LineString"), }
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;')
@ -9,8 +9,8 @@ def komap_js(mfile, style):
for i in chooser.ruleChains:
if condition:
condition += "||"
rule = " zoom >= %s && zoom <= %s"%(i.minZoom, i.maxZoom)
for z in i.conditions:
rule = " zoom >= %s && zoom <= %s" % (i.minZoom, i.maxZoom)
for z in i.conditions:
t = z.type
params = z.params
if params[0] == "::class":
@ -19,39 +19,39 @@ def komap_js(mfile, style):
if rule:
rule += " && "
if t == 'eq':
rule += 'prop["%s"] == "%s"'%(params[0], params[1])
rule += 'prop["%s"] == "%s"' % (params[0], params[1])
if t == 'ne':
rule += 'prop["%s"] != "%s"'%(params[0], params[1])
rule += 'prop["%s"] != "%s"' % (params[0], params[1])
if t == 'regex':
rule += 'prop["%s"].match(RegExp("%s"))'%(params[0], params[1])
rule += 'prop["%s"].match(RegExp("%s"))' % (params[0], params[1])
if t == 'true':
rule += 'prop["%s"] == "yes"'%(params[0])
rule += 'prop["%s"] == "yes"' % (params[0])
if t == 'untrue':
rule += 'prop["%s"] != "yes"'%(params[0])
rule += 'prop["%s"] != "yes"' % (params[0])
if t == 'set':
rule += '"%s" in prop'%(params[0])
rule += '"%s" in prop' % (params[0])
if t == 'unset':
rule += '!("%s"in prop)'%(params[0])
rule += '!("%s"in prop)' % (params[0])
if t == '<':
rule += 'prop["%s"] < %s'%(params[0], params[1])
rule += 'prop["%s"] < %s' % (params[0], params[1])
if t == '<=':
rule += 'prop["%s"] <= %s'%(params[0], params[1])
rule += 'prop["%s"] <= %s' % (params[0], params[1])
if t == '>':
rule += 'prop["%s"] > %s'%(params[0], params[1])
rule += 'prop["%s"] > %s' % (params[0], params[1])
if t == '>=':
rule += 'prop["%s"] >= %s'%(params[0], params[1])
rule += 'prop["%s"] >= %s' % (params[0], params[1])
if rule:
rule = "&&" + rule
condition += "(("+"||".join(['type == "%s"'%z for z in subjs[i.subject]])+") "+ 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)
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 + ';'
styles += 'style["' + subclass + '"]["' + k + '"] = ' + v + ';'
except:
styles += 'style["'+subclass+'"]["'+k+'"] = "' + v + '";'
mfile.write("if(%s) {%s};\n"%(condition,styles))
styles += 'style["' + subclass + '"]["' + k + '"] = "' + v + '";'
mfile.write("if(%s) {%s};\n" % (condition, styles))
mfile.write("return style;}")

View file

@ -42,29 +42,31 @@ substyles = []
last_id = 0
def get_id(i = 0):
def get_id(i=0):
global last_id
last_id += i
return last_id
def zoom_to_scaledenom(z1,z2=False):
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
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)))
return int(math.ceil(l * 20037508.342789244 / 256 * 2 / (2 ** z)))
def xml_fontset(name, unicode=True):
@ -74,30 +76,30 @@ def xml_fontset(name, unicode=True):
<FontSet name="%s">
<Font face-name="%s" />
%s
</FontSet>"""%(name, name, unicode)
</FontSet>""" % (name, name, unicode)
def xml_pointsymbolizer(path="", width="", height="", opacity=1, overlap="false"):
if width:
width =' width="%s" '%width
width = ' width="%s" ' % width
if height:
height =' height="%s" '%height
height = ' height="%s" ' % height
return """
<PointSymbolizer file="%s" %s %s opacity="%s" allow-overlap="%s" />"""\
%(os.path.join(icons_path, path), width, height, opacity, overlap)
% (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)
linecap = {"none": "butt", }.get(linecap.lower(), linecap)
if dashes:
dashes = 'stroke-dasharray="%s"'%(dashes)
dashes = 'stroke-dasharray="%s"' % (dashes)
else:
dashes = ""
if smooth:
smooth = 'smooth="%s"'%(smooth)
smooth = 'smooth="%s"' % (smooth)
else:
smooth = ""
@ -106,75 +108,79 @@ def xml_linesymbolizer(color="#000000", width="1", opacity="1", linecap="butt",
# 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)
<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)
smooth = 'smooth="%s"' % (smooth)
else:
smooth = ""
return """
<PolygonSymbolizer fill="%s" fill-opacity="%s" gamma="0.73" %s />"""%(color, float(opacity), smooth)
<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))
<PolygonPatternSymbolizer file="%s"/>""" % (os.path.join(icons_path, file))
def xml_linepatternsymbolizer(file=""):
return """
<LinePatternSymbolizer file="%s"/>"""%(os.path.join(icons_path,file))
<LinePatternSymbolizer file="%s"/>""" % (os.path.join(icons_path, file))
def xml_textsymbolizer(
text="name",face="DejaVu Sans Book",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", pos="X", transform = "none", spacing="4096"):
text="name", face="DejaVu Sans Book", 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", pos="X", transform="none", spacing="4096"):
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 = 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(int(float(size.split(",")[0])*text_scale))
size = str(int(float(size.split(",")[0]) * text_scale))
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'):
if align in ("right", 'left'):
dx = dy
dy = 0
return """
<TextSymbolizer fontset-name="%s" size="%s" fill="%s" halo-fill= "%s" halo-radius="%s" placement="%s" dx="%s" dy="%s" max-char-angle-delta="17" 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" spacing="%s">[%s]</TextSymbolizer>
"""%(face,int(float(size)),color,halo_color,halo_radius,placement,dx,dy,overlap,wrap_width,distance,align,opacity,pos, transform, spacing,text)
""" % (face, int(float(size)), color, halo_color, halo_radius, placement, dx, dy, overlap, wrap_width, distance, align, opacity, pos, transform, spacing, text)
def xml_shieldsymbolizer(path="", width="", height="",
text="name",face="DejaVu Sans Book",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'):
text="name", face="DejaVu Sans Book", 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 = size.split(",")[0]
if width:
width =' width="%s" '%width
width = ' width="%s" ' % width
if height:
height =' height="%s" '%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,int(float(size)*text_scale),color,halo_color,halo_radius,placement,offset,overlap,wrap_width,distance,align,opacity, transform, unlock_image, spacing,text )
""" % (icons_path,
path, width, height, face, int(float(size) * text_scale), 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
<Filter>%s</Filter>""" % string
def xml_scaledenominator(z1, z2=False):
zz1, zz2 = zoom_to_scaledenom(z1,z2)
zz1, zz2 = zoom_to_scaledenom(z1, z2)
return """
<MaxScaleDenominator>%s</MaxScaleDenominator>
<MinScaleDenominator>%s</MinScaleDenominator><!-- z%s-%s -->"""%(zz1,zz2,z1,z2)
<MinScaleDenominator>%s</MinScaleDenominator><!-- z%s-%s -->""" % (zz1, zz2, z1, z2)
def xml_start(bgcolor="transparent"):
if bgcolor != "transparent":
@ -182,7 +188,8 @@ def xml_start(bgcolor="transparent"):
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)
""" % (bgcolor, map_proj)
def xml_end():
return """
@ -194,20 +201,24 @@ def xml_style_start():
layer_id = get_id(1)
substyles.append(layer_id)
return """
<Style name="s%s">"""%(layer_id)
<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">
@ -231,6 +242,7 @@ def xml_cleantopo(zoom, x_scale, demramp):
</Layer>
""" % (zoom, x_scale, demramp, zoom, zoom, cleantopo_dem_path)
def xml_srtm(zoom, x_scale, demramp):
return """
<Style name="elevationz%s">
@ -257,7 +269,7 @@ def xml_srtm(zoom, x_scale, demramp):
def xml_hillshade(zoom, x_scale):
hs_path = cleantopo_hs_path
if zoom>6:
if zoom > 6:
hs_path = srtm_hs_path
return """
<Style name="hillshade%s">
@ -292,10 +304,11 @@ def xml_hardcoded_arrows():
<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 ):
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])
subs = "\n".join(["<StyleName>s%s</StyleName>" % i for i in substyles])
substyles = []
intersection_SQL = ""
if zoom < 5:
@ -303,19 +316,18 @@ def xml_layer(type="postgis", geom="point", interesting_tags = "*", sql = "true"
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))
waystring = "ST_Simplify(way, %s) as way" % (pixel_size_at_zoom(zoom, 0.6))
if zoom >= 5:
sql = 'way &amp;&amp; !bbox! and '+ sql
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
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+"\""
interesting_tags = "\"" + interesting_tags + "\""
else:
interesting_tags = ", ".join(interesting_tags)
@ -341,7 +353,7 @@ def xml_layer(type="postgis", geom="point", interesting_tags = "*", sql = "true"
<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)
</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">
@ -363,7 +375,7 @@ def xml_layer(type="postgis", geom="point", interesting_tags = "*", sql = "true"
<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)
</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 """
@ -373,7 +385,7 @@ def xml_layer(type="postgis", geom="point", interesting_tags = "*", sql = "true"
<Parameter name="type">shape</Parameter>
<Parameter name="file">%sshoreline_300</Parameter>
</Datasource>
</Layer>"""%(layer_id, db_proj, subs, world_bnd_path)
</Layer>""" % (layer_id, db_proj, subs, world_bnd_path)
else:
return """
<Layer name="l%s" status="on" srs="%s">
@ -382,10 +394,14 @@ def xml_layer(type="postgis", geom="point", interesting_tags = "*", sql = "true"
<Parameter name="type">shape</Parameter>
<Parameter name="file">%sprocessed_p</Parameter>
</Datasource>
</Layer>"""%(layer_id, db_proj, subs, world_bnd_path)
</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

@ -9,6 +9,7 @@ whatever_to_cairo = mapcss.webcolors.webcolors.whatever_to_cairo
WIDTH_SCALE = 1.0
def komap_mapswithme(options, style):
if options.outfile == "-":
print "Please specify base output path."
@ -28,7 +29,7 @@ def komap_mapswithme(options, style):
class_tree = {}
visibility = {}
for row in csv.reader(open(os.path.join(ddir,'mapcss-mapping.csv')), delimiter=';'):
for row in csv.reader(open(os.path.join(ddir, 'mapcss-mapping.csv')), delimiter=';'):
pairs = [i.strip(']').split("=") for i in row[1].split(',')[0].split('[')]
kv = {}
for i in pairs:
@ -47,9 +48,9 @@ def komap_mapswithme(options, style):
else:
# compatibility mode
if row[6]:
print >> types_file, row[6]
print >> types_file, row[6]
else:
print >> types_file, "mapswithme"
print >> types_file, "mapswithme"
class_tree[row[0].replace("|", "-")] = row[0]
class_order.sort()
@ -59,8 +60,8 @@ def komap_mapswithme(options, style):
opacity = hex(255 - int(255 * float(st.get(prefix + "opacity", 1))))
if opacity == "0x0":
opacity = "0x"
color = whatever_to_hex(st.get(prefix+'color', default))
color = color[1]+color[1]+color[3]+color[3]+color[5]+color[5]
color = whatever_to_hex(st.get(prefix + 'color', default))
color = color[1] + color[1] + color[3] + color[3] + color[5] + color[5]
return int(opacity + color, 16)
bgpos = 0
@ -73,7 +74,7 @@ def komap_mapswithme(options, style):
dr_cont = ClassifElementProto()
dr_cont.name = cl
for zoom in xrange(options.minzoom, options.maxzoom+1):
for zoom in xrange(options.minzoom, options.maxzoom + 1):
txclass = classificator[cl]
txclass["name"] = "name"
txclass["addr:housenumber"] = "addr:housenumber"
@ -83,21 +84,21 @@ def komap_mapswithme(options, style):
zstyle = {}
if "area" not in txclass:
zstyle = style.get_style_dict("line", txclass, zoom, olddict = zstyle)
#for st in zstyle:
zstyle = style.get_style_dict("line", txclass, zoom, olddict=zstyle)
# for st in zstyle:
# if "fill-color" in st:
# del st["fill-color"]
if True:
areastyle = style.get_style_dict("area", txclass, zoom, olddict = zstyle)
areastyle = style.get_style_dict("area", txclass, zoom, olddict=zstyle)
for st in areastyle.values():
if "icon-image" in st or 'symbol-shape' in st:
has_icons_for_areas = True
zstyle = areastyle
if "area" not in txclass:
nodestyle = style.get_style_dict("node", txclass, zoom, olddict = zstyle)
#for st in nodestyle:
nodestyle = style.get_style_dict("node", txclass, zoom, olddict=zstyle)
# for st in nodestyle:
# if "fill-color" in st:
# del st["fill-color"]
zstyle = nodestyle
@ -107,7 +108,7 @@ def komap_mapswithme(options, style):
has_icons = False
has_fills = False
for st in zstyle:
st = dict([(k,v) for k,v in st.iteritems() if str(v).strip(" 0.")])
st = dict([(k, v) for k, v in st.iteritems() if str(v).strip(" 0.")])
if 'width' in st or 'pattern-image' in st:
has_lines = True
if 'icon-image' in st or 'symbol-shape' in st:
@ -127,11 +128,11 @@ def komap_mapswithme(options, style):
for st in zstyle:
if st.get('-x-kot-layer') == 'top':
st['z-index'] = float(st.get('z-index',0)) + 15001.
st['z-index'] = float(st.get('z-index', 0)) + 15001.
if st.get('-x-kot-layer') == 'bottom':
st['z-index'] = float(st.get('z-index',0)) - 15001.
st['z-index'] = float(st.get('z-index', 0)) - 15001.
if st.get('casing-width') not in (None, 0): # and (st.get('width') or st.get('fill-color')):
if st.get('casing-width') not in (None, 0): # and (st.get('width') or st.get('fill-color')):
dr_line = LineRuleProto()
dr_line.width = (st.get('width', 0) * WIDTH_SCALE) + (st.get('casing-width') * WIDTH_SCALE * 2)
dr_line.color = mwm_encode_color(st, "casing")
@ -144,22 +145,22 @@ def komap_mapswithme(options, style):
if st.get('width'):
dr_line = LineRuleProto()
dr_line.width = (st.get('width',0) * WIDTH_SCALE)
dr_line.width = (st.get('width', 0) * WIDTH_SCALE)
dr_line.color = mwm_encode_color(st)
for i in st.get('dashes',[]):
for i in st.get('dashes', []):
dr_line.dashdot.dd.extend([max(float(i), 1) * WIDTH_SCALE])
dr_line.cap = dr_linecaps.get(st.get('linecap', 'butt'), BUTTCAP)
dr_line.join = dr_linejoins.get(st.get('linejoin', 'round'), ROUNDJOIN)
dr_line.priority = min((int(st.get('z-index', 0))+1000), 20000)
dr_line.priority = min((int(st.get('z-index', 0)) + 1000), 20000)
dr_element.lines.extend([dr_line])
if st.get('pattern-image'):
dr_line = LineRuleProto()
dr_line.width = 0
dr_line.color = 0
dr_line.pathsym.name = st.get('pattern-image',"").replace(".svg","")
dr_line.pathsym.step = float(st.get('pattern-spacing',0)) - 16
dr_line.pathsym.offset = st.get('pattern-offset',0)
dr_line.pathsym.name = st.get('pattern-image', "").replace(".svg", "")
dr_line.pathsym.step = float(st.get('pattern-spacing', 0)) - 16
dr_line.pathsym.offset = st.get('pattern-offset', 0)
dr_line.priority = int(st.get('z-index', 0)) + 1000
dr_element.lines.extend([dr_line])
@ -168,12 +169,12 @@ def komap_mapswithme(options, style):
if not has_icons_for_areas:
dr_element.symbol.apply_for_type = 1
dr_element.symbol.name = st.get('icon-image', "").replace(".svg", "")
dr_element.symbol.priority = min(19100,(16000+int(st.get('z-index', 0))))
dr_element.symbol.priority = min(19100, (16000 + int(st.get('z-index', 0))))
has_icons = False
if st.get('symbol-shape'):
dr_element.circle.radius = float(st.get('symbol-size'))
dr_element.circle.color = mwm_encode_color(st, 'symbol-fill')
dr_element.circle.priority = min(19000, (15000+int(st.get('z-index', 0))))
dr_element.circle.priority = min(19000, (15000 + int(st.get('z-index', 0))))
has_icons = False
if has_text and st.get('text'):
@ -190,16 +191,16 @@ def komap_mapswithme(options, style):
dr_cur_subtext = dr_text.primary
if len(has_text) == 2:
dr_cur_subtext = dr_text.secondary
dr_cur_subtext.height = int(float(sp.get('font-size',"10").split(",")[0]))
dr_cur_subtext.height = int(float(sp.get('font-size', "10").split(",")[0]))
dr_cur_subtext.color = mwm_encode_color(sp, "text")
if st.get('text-halo-radius', 0) != 0:
dr_cur_subtext.stroke_color = mwm_encode_color(sp, "text-halo", "white")
if 'text-offset' in sp or 'text-offset-y' in sp:
dr_cur_subtext.offset_y = int(sp.get('text-offset-y',sp.get('text-offset',0)))
dr_cur_subtext.offset_y = int(sp.get('text-offset-y', sp.get('text-offset', 0)))
if 'text-offset-x' in sp:
dr_cur_subtext.offset_x = int(sp.get('text-offset-x',0))
dr_cur_subtext.offset_x = int(sp.get('text-offset-x', 0))
has_text.pop()
dr_text.priority = min(19000,(base_z + int(st.get('z-index', 0))))
dr_text.priority = min(19000, (base_z + int(st.get('z-index', 0))))
has_text = False
if has_fills:
@ -208,30 +209,31 @@ def komap_mapswithme(options, style):
if st.get('fill-position', 'foreground') == 'background':
if 'z-index' not in st:
bgpos -= 1
dr_element.area.priority = (int(st.get('z-index', bgpos))-16000)
dr_element.area.priority = (int(st.get('z-index', bgpos)) - 16000)
else:
dr_element.area.priority = (int(st.get('z-index', 0))+1+1000)
dr_element.area.priority = (int(st.get('z-index', 0)) + 1 + 1000)
has_fills = False
dr_cont.element.extend([dr_element])
if dr_cont.element:
drules.cont.extend([dr_cont])
visibility["world|"+class_tree[cl]+"|"] = "".join(visstring)
visibility["world|" + class_tree[cl] + "|"] = "".join(visstring)
prevvis = []
visnodes = set()
drules_bin.write(drules.SerializeToString())
drules_txt.write(unicode(drules))
for k,v in visibility.iteritems():
for k, v in visibility.iteritems():
vis = k.split("|")
for i in range(1,len(vis)-1):
visnodes.add("|".join(vis[0:i])+"|")
for i in range(1, len(vis) - 1):
visnodes.add("|".join(vis[0:i]) + "|")
viskeys = list(set(visibility.keys() + list(visnodes)))
def cmprepl(a,b):
def cmprepl(a, b):
if a == b:
return 0
a = a.replace("|","-")
b = b.replace("|","-")
a = a.replace("|", "-")
b = b.replace("|", "-")
if a > b:
return 1
return -1
@ -239,17 +241,17 @@ def komap_mapswithme(options, style):
oldoffset = ""
for k in viskeys:
offset = " " * (k.count("|")-1)
for i in range(len(oldoffset)/4,len(offset)/4,-1):
print >>visibility_file, " "*i+"{}"
print >>classificator_file, " "*i+"{}"
offset = " " * (k.count("|") - 1)
for i in range(len(oldoffset) / 4, len(offset) / 4, -1):
print >>visibility_file, " " * i + "{}"
print >>classificator_file, " " * i + "{}"
oldoffset = offset
end = "-"
if k in visnodes:
end = "+"
print >>visibility_file, offset+k.split("|")[-2] + " " + visibility.get(k, "0"*(options.maxzoom+1))+ " " + end
print >>classificator_file, offset+k.split("|")[-2] + " " + end
for i in range(len(offset)/4,0,-1):
print >>visibility_file, " "*i+"{}"
print >>classificator_file, " "*i+"{}"
print >>visibility_file, offset + k.split("|")[-2] + " " + visibility.get(k, "0" * (options.maxzoom + 1)) + " " + end
print >>classificator_file, offset + k.split("|")[-2] + " " + end
for i in range(len(offset) / 4, 0, -1):
print >>visibility_file, " " * i + "{}"
print >>classificator_file, " " * i + "{}"

View file

@ -27,16 +27,16 @@ 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())
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])
dct = dict([(k, set([("node", "linear"), ('way', 'linear')])) for k in langs])
t = {"node":("node", "linear"), "line":("way", "linear"), "area":("way", "polygon")}
t = {"node": ("node", "linear"), "line": ("way", "linear"), "area": ("way", "polygon")}
for a in t:
for tag in style.get_interesting_tags(type=a):
@ -46,7 +46,7 @@ for a in t:
print """
# OsmType Tag DataType Flags"""
for t in ("z_order","way_area",":area"):
for t in ("z_order", "way_area", ":area"):
if t in dct:
del dct[t]
@ -59,7 +59,7 @@ for k in keys:
pol = "linear"
if "polygon" in set([i[1] for i in v]):
pol = "polygon"
print "%-10s %-20s %-13s %s"%(s, k, "text", pol)
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

@ -17,9 +17,9 @@
import re
INVERSIONS = {"eq":"ne", "true":"false", "set":"unset", "<":">=", ">":"<="}
INVERSIONS = {"eq": "ne", "true": "false", "set": "unset", "<": ">=", ">": "<="}
in2 = {}
for a,b in INVERSIONS.iteritems():
for a, b in INVERSIONS.iteritems():
in2[b] = a
INVERSIONS.update(in2)
del in2
@ -27,10 +27,10 @@ del in2
class Condition:
def __init__(self, typez, params):
self.type=typez # eq, regex, lt, gt etc.
self.type = typez # eq, regex, lt, gt etc.
if type(params) == type(str()):
params = (params,)
self.params=params # e.g. ('highway','primary')
self.params = params # e.g. ('highway','primary')
if typez == "regex":
self.regex = re.compile(self.params[0], re.I)
@ -58,9 +58,9 @@ class Condition:
return params[1]
try:
if t == 'eq':
return tags[params[0]]==params[1]
return tags[params[0]] == params[1]
if t == 'ne':
return tags.get(params[0], "")!=params[1]
return tags.get(params[0], "") != params[1]
if t == 'regex':
return bool(self.regex.match(tags[params[0]]))
if t == 'true':
@ -77,16 +77,17 @@ class Condition:
return True
if t == '<':
return (Number(tags[params[0]])< Number(params[1]))
return (Number(tags[params[0]]) < Number(params[1]))
if t == '<=':
return (Number(tags[params[0]])<=Number(params[1]))
return (Number(tags[params[0]]) <= Number(params[1]))
if t == '>':
return (Number(tags[params[0]])> Number(params[1]))
return (Number(tags[params[0]]) > Number(params[1]))
if t == '>=':
return (Number(tags[params[0]])>=Number(params[1]))
return (Number(tags[params[0]]) >= Number(params[1]))
except KeyError:
pass
return False;
return False
def inverse(self):
"""
Get a not-A for condition A
@ -100,46 +101,44 @@ class Condition:
return Condition("regex", params)
except KeyError:
pass
return self;
return self
def get_sql(self):
#params = [re.escape(x) for x in self.params]
# params = [re.escape(x) for x in self.params]
params = self.params
t = self.type
if t == 'eq': # don't compare tags against sublayers
if params[0][:2] == "::":
return ("","")
return ("", "")
try:
if t == 'eq':
return params[0], '"%s" = \'%s\''%(params[0], params[1])
return params[0], '"%s" = \'%s\'' % (params[0], params[1])
if t == 'ne':
return params[0], '("%s" != \'%s\' or "%s" IS NULL)'%(params[0], params[1],params[0])
return params[0], '("%s" != \'%s\' or "%s" IS NULL)' % (params[0], params[1], params[0])
if t == 'regex':
return params[0], '"%s" ~ \'%s\''%(params[0],params[1].replace("'","\\'"))
return params[0], '"%s" ~ \'%s\'' % (params[0], params[1].replace("'", "\\'"))
if t == 'true':
return params[0], '"%s" = \'yes\''%(params[0])
return params[0], '"%s" = \'yes\'' % (params[0])
if t == 'untrue':
return params[0], '"%s" = \'no\''%(params[0])
return params[0], '"%s" = \'no\'' % (params[0])
if t == 'set':
return params[0], '"%s" IS NOT NULL'%(params[0])
return params[0], '"%s" IS NOT NULL' % (params[0])
if t == 'unset':
return params[0], '"%s" IS NULL'%(params[0])
return params[0], '"%s" IS NULL' % (params[0])
if t == '<':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) &lt; %s ELSE false END) """%(params[0],params[0],params[1])
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) &lt; %s ELSE false END) """ % (params[0], params[0], params[1])
if t == '<=':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) &lt;= %s ELSE false END)"""%(params[0],params[0],params[1])
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) &lt;= %s ELSE false END)""" % (params[0], params[0], params[1])
if t == '>':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) > %s ELSE false END) """%(params[0],params[0],params[1])
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) > %s ELSE false END) """ % (params[0], params[0], params[1])
if t == '>=':
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) >= %s ELSE false END) """%(params[0],params[0],params[1])
return params[0], """(CASE WHEN "%s" ~ E'^[-]?[[:digit:]]+([.][[:digit:]]+)?$' THEN CAST ("%s" AS FLOAT) >= %s ELSE false END) """ % (params[0], params[0], params[1])
except KeyError:
pass
def get_mapnik_filter(self):
#params = [re.escape(x) for x in self.params]
# params = [re.escape(x) for x in self.params]
params = self.params
t = self.type
if t == 'eq': # don't compare tags against sublayers
@ -147,33 +146,35 @@ class Condition:
return ''
try:
if t == 'eq':
return '[%s] = \'%s\''%(params[0], params[1])
return '[%s] = \'%s\'' % (params[0], params[1])
if t == 'ne':
return 'not([%s] = \'%s\')'%(params[0], params[1])
return 'not([%s] = \'%s\')' % (params[0], params[1])
if t == 'regex':
return '[%s].match(\'%s\')'%(params[0], params[1].replace("'","\\'"))
return '[%s].match(\'%s\')' % (params[0], params[1].replace("'", "\\'"))
if t == 'true':
return '[%s] = \'yes\''%(params[0])
return '[%s] = \'yes\'' % (params[0])
if t == 'untrue':
return '[%s] = \'no\''%(params[0])
return '[%s] = \'no\'' % (params[0])
if t == 'set':
return '[%s] != \'\''%(params[0])
return '[%s] != \'\'' % (params[0])
if t == 'unset':
return 'not([%s] != \'\')'%(params[0])
return 'not([%s] != \'\')' % (params[0])
if t == '<':
return '[%s__num] &lt; %s'%(params[0], float(params[1]))
return '[%s__num] &lt; %s' % (params[0], float(params[1]))
if t == '<=':
return '[%s__num] &lt;= %s'%(params[0], float(params[1]))
return '[%s__num] &lt;= %s' % (params[0], float(params[1]))
if t == '>':
return '[%s__num] &gt; %s'%(params[0], float(params[1]))
return '[%s__num] &gt; %s' % (params[0], float(params[1]))
if t == '>=':
return '[%s__num] &gt;= %s'%(params[0], float(params[1]))
#return ""
return '[%s__num] &gt;= %s' % (params[0], float(params[1]))
# return ""
except KeyError:
pass
def __repr__(self):
return "%s %s "%(self.type, repr(self.params))
return "%s %s " % (self.type, repr(self.params))
def __eq__(self, a):
return (self.params == a.params) and (self.type == a.type)
@ -181,7 +182,7 @@ class Condition:
"""
merges two rules with AND.
"""
#TODO: possible other minimizations
# TODO: possible other minimizations
if c2.params[0] == self.params[0]:
if c2.params == self.params:
if c2.type == INVERSIONS[self.type]: # for example, eq AND ne = 0
@ -189,10 +190,10 @@ class Condition:
if c2.type == self.type:
return (self,)
if self.type == ">=" and c2.type == "<=": # a<=2 and a>=2 --> a=2
return (Condition ("eq", self.params),)
if self.type == ">=" and c2.type == "<=": # a<=2 and a>=2 --> a=2
return (Condition("eq", self.params),)
if self.type == "<=" and c2.type == ">=":
return (Condition ("eq", self.params),)
return (Condition("eq", self.params),)
if self.type == ">" and c2.type == "<":
return False
if self.type == "<" and c2.type == ">":
@ -207,17 +208,18 @@ class Condition:
if self.type == "eq" and c2.type == "eq":
if c2.params[1] != self.params[1]:
return False
if c2.type == "set" and self.type in ("eq","ne","regex", "<", "<=", ">", ">="): # a is set and a == b -> a == b
if c2.type == "set" and self.type in ("eq", "ne", "regex", "<", "<=", ">", ">="): # a is set and a == b -> a == b
return (self,)
if c2.type == "unset" and self.type in ("eq","ne","regex", "<", "<=", ">", ">="): # a is unset and a == b -> impossible
if c2.type == "unset" and self.type in ("eq", "ne", "regex", "<", "<=", ">", ">="): # a is unset and a == b -> impossible
return False
if self.type == "set" and c2.type in ("eq","ne","regex", "<", "<=", ">", ">="):
if self.type == "set" and c2.type in ("eq", "ne", "regex", "<", "<=", ">", ">="):
return (c2,)
if self.type == "unset" and c2.type in ("eq","ne","regex", "<", "<=", ">", ">="):
if self.type == "unset" and c2.type in ("eq", "ne", "regex", "<", "<=", ">", ">="):
return False
return self, c2
def Number(tt):
"""
Wrap float() not to produce exceptions

View file

@ -17,6 +17,7 @@
NONE = ""
class Eval():
def __init__(self, s='eval()'):
"""
@ -25,11 +26,10 @@ class Eval():
s = s.strip()[5:-1].strip()
self.expr_text = s
try:
self.expr = compile (s, "MapCSS expression", "eval")
self.expr = compile(s, "MapCSS expression", "eval")
except:
#print "Can't compile %s" % s
self.expr = compile ("0", "MapCSS expression", "eval")
# print "Can't compile %s" % s
self.expr = compile("0", "MapCSS expression", "eval")
def extract_tags(self):
"""
@ -44,50 +44,50 @@ class Eval():
q = x
return 0
tags = set([])
#print self.expr_text
# print self.expr_text
a = eval(self.expr,{},{
"tag":lambda x: max([tags.add(x), " "]),
"prop": lambda x: "",
"num": lambda x: 0,
"metric": fake_compute,
"zmetric": fake_compute,
"str": lambda x: "",
"any": fake_compute,
"min": fake_compute,
"max": fake_compute,
})
a = eval(self.expr, {}, {
"tag": lambda x: max([tags.add(x), " "]),
"prop": lambda x: "",
"num": lambda x: 0,
"metric": fake_compute,
"zmetric": fake_compute,
"str": lambda x: "",
"any": fake_compute,
"min": fake_compute,
"max": fake_compute,
})
return tags
def compute(self, tags={}, props = {}, xscale = 1., zscale = 0.5 ):
def compute(self, tags={}, props={}, xscale=1., zscale=0.5):
"""
Compute this eval()
"""
for k,v in tags.iteritems():
for k, v in tags.iteritems():
try:
tag[k] = float(v)
except:
pass
try:
return str(eval(self.expr, {}, {
"tag":lambda x: tags.get(x,""),
"prop":lambda x: props.get(x,""),
"num": m_num,
"metric": lambda x: m_metric(x, xscale),
"zmetric": lambda x: m_metric(x, zscale),
"str": str,
"any": m_any,
"min": m_min,
"max": m_max,
"cond": m_cond,
"boolean": m_boolean
}))
"tag": lambda x: tags.get(x, ""),
"prop": lambda x: props.get(x, ""),
"num": m_num,
"metric": lambda x: m_metric(x, xscale),
"zmetric": lambda x: m_metric(x, zscale),
"str": str,
"any": m_any,
"min": m_min,
"max": m_max,
"cond": m_cond,
"boolean": m_boolean
}))
except:
return ""
def __repr__(self):
return "eval(%s)"%self.expr_text
return "eval(%s)" % self.expr_text
def m_boolean(expr):
expr = str(expr)
@ -96,12 +96,14 @@ def m_boolean(expr):
else:
return True
def m_cond(why, yes, no):
if m_boolean(why):
return yes
else:
return no
def m_min(*x):
"""
min() MapCSS Feature
@ -111,6 +113,7 @@ def m_min(*x):
except:
return 0
def m_max(*x):
"""
max() MapCSS Feature
@ -120,6 +123,7 @@ def m_max(*x):
except:
return 0
def m_any(*x):
"""
any() MapCSS feature
@ -130,6 +134,7 @@ def m_any(*x):
else:
return ""
def m_num(x):
"""
num() MapCSS feature
@ -138,35 +143,37 @@ def m_num(x):
return float(str(x))
except ValueError:
return 0
def m_metric(x, t):
"""
metric() and zmetric() function.
"""
x = str(x)
try:
return float(x)*float(t)
return float(x) * float(t)
except:
"Heuristics."
# FIXME: add ft, m and friends
x = x.strip()
try:
if x[-2:] in ("cm", "CM", "см"):
return float(x[0:-2])*float(t)/100
return float(x[0:-2]) * float(t) / 100
if x[-2:] in ("mm", "MM", "мм"):
return float(x[0:-2])*float(t)/1000
return float(x[0:-2]) * float(t) / 1000
if x[-1] in ("m", "M", "м"):
return float(x[0:-1])*float(t)
return float(x[0:-1]) * float(t)
except:
return ""
#def str(x):
# def str(x):
#"""
#str() MapCSS feature
# str() MapCSS feature
#"""
#return __builtins__.str(x)
# return __builtins__.str(x)
if __name__ == "__main__":
a = Eval(""" eval( any( metric(tag("height")), metric ( num(tag("building:levels")) * 3), metric("1m"))) """)
print repr(a)
print a.compute({"building:levels":"3"})
print a.compute({"building:levels": "3"})
print a.extract_tags()

View file

@ -16,11 +16,10 @@
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
class Rule():
def __init__(self, s=''):
self.conditions = []
#self.isAnd = True
# self.isAnd = True
self.minZoom = 0
self.maxZoom = 19
if s == "*":
@ -28,7 +27,7 @@ class Rule():
self.subject = s # "", "way", "node" or "relation"
def __repr__(self):
return "%s|z%s-%s %s"%(self.subject, self.minZoom, self.maxZoom, self.conditions)
return "%s|z%s-%s %s" % (self.subject, self.minZoom, self.maxZoom, self.conditions)
def test(self, obj, tags, zoom):
if (zoom < self.minZoom) or (zoom > self.maxZoom):
@ -72,7 +71,7 @@ class Rule():
def get_sql_hints(self, obj, zoom):
if obj:
if (self.subject!='') and not _test_feature_compatibility(obj, self.subject, {":area":"yes"}):
if (self.subject != '') and not _test_feature_compatibility(obj, self.subject, {":area": "yes"}):
return set()
if not self.test_zoom(zoom):
return set()
@ -85,9 +84,10 @@ class Rule():
a.add(q[0])
b.add(q[1])
b = " AND ".join(b)
return a,b
return a, b
def _test_feature_compatibility (f1, f2, tags={}):
def _test_feature_compatibility(f1, f2, tags={}):
"""
Checks if feature of type f1 is compatible with f2.
"""
@ -95,9 +95,9 @@ def _test_feature_compatibility (f1, f2, tags={}):
return True
if f2 not in ("way", "area", "line"):
return False
elif f2 == "way" and f1 == "line":
elif f2 == "way" and f1 == "line":
return True
elif f2 == "way" and f1 == "area":
elif f2 == "way" and f1 == "area":
return True
elif f2 == "area" and f1 in ("way", "area"):
# if ":area" in tags:
@ -108,5 +108,5 @@ def _test_feature_compatibility (f1, f2, tags={}):
return True
else:
return False
#print f1, f2, True
# print f1, f2, True
return True

View file

@ -21,25 +21,26 @@ from webcolors.webcolors import whatever_to_cairo as colorparser
from webcolors.webcolors import cairo_to_hex
from Eval import Eval
class StyleChooser:
"""
A StyleChooser object is equivalent to one CSS selector+declaration.
A StyleChooser object is equivalent to one CSS selector+declaration.
Its ruleChains property is an array of all the selectors, which would
traditionally be comma-separated. For example:
h1, h2, h3 em
is three ruleChains.
Its ruleChains property is an array of all the selectors, which would
traditionally be comma-separated. For example:
h1, h2, h3 em
is three ruleChains.
Each ruleChain is itself an array of nested selectors. So the above
example would roughly be encoded as:
[[h1],[h2],[h3,em]]
^^ ^^ ^^ ^^ each of these is a Rule
Each ruleChain is itself an array of nested selectors. So the above
example would roughly be encoded as:
[[h1],[h2],[h3,em]]
^^ ^^ ^^ ^^ each of these is a Rule
The styles property is an array of all the style objects to be drawn
if any of the ruleChains evaluate to true.
The styles property is an array of all the style objects to be drawn
if any of the ruleChains evaluate to true.
"""
def __repr__(self):
return "{(%s) : [%s] }\n"%(self.ruleChains, self.styles)
return "{(%s) : [%s] }\n" % (self.ruleChains, self.styles)
def __init__(self, scalepair):
self.ruleChains = []
@ -66,9 +67,9 @@ class StyleChooser:
a = set()
for r in self.ruleChains:
a.update(r.get_interesting_tags(ztype, zoom))
if a: ## FIXME: semi-illegal optimization, may wreck in future on tagless matches
if a: # FIXME: semi-illegal optimization, may wreck in future on tagless matches
for r in self.styles:
for c,b in r.iteritems():
for c, b in r.iteritems():
if type(b) == self.eval_type:
a.update(b.extract_tags())
return a
@ -85,16 +86,16 @@ class StyleChooser:
for r in self.ruleChains:
p = r.get_sql_hints(type, zoom)
if p:
q = "("+p[1] + ")"#[t[1] for t in p]
q = "(" + p[1] + ")" # [t[1] for t in p]
if q == "()":
q = ""
if b and q:
b += " OR "+ q
b += " OR " + q
else:
b = q
a.update(p[0])
# no need to check for eval's
return a,b
return a, b
def updateStyles(self, sl, ftype, tags, zoom, scale, zscale):
# Are any of the ruleChains fulfilled?
@ -102,7 +103,7 @@ class StyleChooser:
if zoom < self.selzooms[0] or zoom > self.selzooms[1]:
return sl
object_id = self.testChain(self.ruleChains,ftype,tags,zoom)
object_id = self.testChain(self.ruleChains, ftype, tags, zoom)
if not object_id:
return sl
@ -111,13 +112,13 @@ class StyleChooser:
for r in self.styles:
ra = {}
for a,b in r.iteritems():
for a, b in r.iteritems():
"calculating eval()'s"
if type(b) == self.eval_type:
combined_style = {}
for t in sl:
combined_style.update(t)
for p,q in combined_style.iteritems():
for p, q in combined_style.iteritems():
if "color" in p:
combined_style[p] = cairo_to_hex(q)
b = b.compute(tags, combined_style, scale, zscale)
@ -129,11 +130,11 @@ class StyleChooser:
"checking and nicifying style table"
if "color" in a:
"parsing color value to 3-tuple"
#print "res:", b
# print "res:", b
if b:
#if not b:
# if not b:
# print sl, ftype, tags, zoom, scale, zscale
#else:
# else:
ra[a] = colorparser(b)
elif any(x in a for x in ("width", "z-index", "opacity", "offset", "radius", "extrude")):
"these things are float's or not in table at all"
@ -150,8 +151,8 @@ class StyleChooser:
except ValueError:
ra[a] = []
else:
ra[a]=b
#for k,v in ra.items(): # if a value is empty, we don't need it - renderer will do as default.
ra[a] = b
# for k,v in ra.items(): # if a value is empty, we don't need it - renderer will do as default.
# if not v:
# del ra[k]
ra["object-id"] = str(object_id)
@ -185,30 +186,29 @@ class StyleChooser:
return tt
return False
def newGroup(self):
"""
starts a new ruleChain in this.ruleChains
"""
pass
def newObject(self,e=''):
def newObject(self, e=''):
"""
adds into the current ruleChain (starting a new Rule)
"""
rule = Rule(e)
rule.minZoom=float(self.scalepair[0])
rule.maxZoom=float(self.scalepair[1])
rule.minZoom = float(self.scalepair[0])
rule.maxZoom = float(self.scalepair[1])
self.ruleChains.append(rule)
def addZoom(self,z):
def addZoom(self, z):
"""
adds into the current ruleChain (existing Rule)
"""
self.ruleChains[-1].minZoom=float(z[0])
self.ruleChains[-1].maxZoom=float(z[1])
self.ruleChains[-1].minZoom = float(z[0])
self.ruleChains[-1].maxZoom = float(z[1])
def addCondition(self,c):
def addCondition(self, c):
"""
adds into the current ruleChain (existing Rule)
"""
@ -227,19 +227,19 @@ class StyleChooser:
rb = []
for r in a:
ra = {}
for a,b in r.iteritems():
for a, b in r.iteritems():
a = a.strip()
b = b.strip()
if a == "casing-width":
"josm support"
if b[0] == "+":
try:
b = str(float(b)/2)
b = str(float(b) / 2)
except:
pass
if "text" == a[-4:]:
if b[:5] != "eval(":
b = "eval(tag(\""+b+"\"))"
b = "eval(tag(\"" + b + "\"))"
if b[:5] == "eval(":
b = Eval(b)
ra[a] = b

View file

@ -66,12 +66,12 @@ SET_TAG = re.compile(r'^ \s* set \s+(\S+)\s* = \s* (.+?) \s*
SET_TAG_TRUE = re.compile(r'^ \s* set \s+(\S+)\s* $', re.I | re.S | re.X)
EXIT = re.compile(r'^ \s* exit \s* $', re.I | re.S | re.X)
oZOOM=2
oGROUP=3
oCONDITION=4
oOBJECT=5
oDECLARATION=6
oSUBPART=7
oZOOM = 2
oGROUP = 3
oCONDITION = 4
oOBJECT = 5
oDECLARATION = 6
oSUBPART = 7
DASH = re.compile(r'\-/g')
COLOR = re.compile(r'color$/')
@ -93,37 +93,36 @@ way {width: 1; casing-width:1; casing-color: white}
## ** also needs to support @import rules
class MapCSS():
def __init__(self,minscale=0,maxscale=19):
def __init__(self, minscale=0, maxscale=19):
"""
"""
self.cache = {}
self.cache["style"] = {}
self.minscale=minscale
self.maxscale=maxscale
self.minscale = minscale
self.maxscale = maxscale
self.scalepair = (minscale, maxscale)
self.choosers = []
self.style_loaded = False
self.parse(builtin_style)
self.style_loaded = False #override one after loading
self.style_loaded = False # override one after loading
def parseZoom(self, s):
if ZOOM_MINMAX.match(s):
return tuple([float(i) for i in ZOOM_MINMAX.match(s).groups()])
elif ZOOM_MIN.match(s):
return float(ZOOM_MIN.match(s).groups()[0]), self.maxscale
elif ZOOM_MAX.match(s):
return float(self.minscale),float(ZOOM_MAX.match(s).groups()[0])
return float(self.minscale), float(ZOOM_MAX.match(s).groups()[0])
elif ZOOM_SINGLE.match(s):
return float(ZOOM_SINGLE.match(s).groups()[0]),float(ZOOM_SINGLE.match(s).groups()[0])
return float(ZOOM_SINGLE.match(s).groups()[0]), float(ZOOM_SINGLE.match(s).groups()[0])
else:
logging.error("unparsed zoom: %s" %s)
logging.error("unparsed zoom: %s" % s)
def get_style (self, type, tags={}, zoom=0, scale=1, zscale=.5):
def get_style(self, type, tags={}, zoom=0, scale=1, zscale=.5):
"""
Kothic styling API
"""
shash = md5(repr(type)+repr(tags)+repr(zoom)).digest()
shash = md5(repr(type) + repr(tags) + repr(zoom)).digest()
if shash in self.cache["style"]:
return deepcopy(self.cache["style"][shash])
style = []
@ -132,7 +131,7 @@ class MapCSS():
style = [x for x in style if x["object-id"] != "::*"]
st = []
for x in style:
for k,v in [('width',0), ('casing-width',0)]:
for k, v in [('width', 0), ('casing-width', 0)]:
if k in x:
if x[k] == v:
del x[k]
@ -141,17 +140,17 @@ class MapCSS():
if not NEEDED_KEYS.isdisjoint(x):
st.append(x)
style = st
self.cache["style"][shash] = style
return deepcopy(style)
def get_style_dict (self, type, tags={}, zoom=0, scale=1, zscale=.5, olddict = {}):
def get_style_dict(self, type, tags={}, zoom=0, scale=1, zscale=.5, olddict={}):
r = self.get_style(type, tags, zoom, scale, zscale)
d = olddict
for x in r:
if x.get('object-id','') not in d:
d[x.get('object-id','')] = {}
d[x.get('object-id','')].update(x)
if x.get('object-id', '') not in d:
d[x.get('object-id', '')] = {}
d[x.get('object-id', '')].update(x)
return d
def get_interesting_tags(self, type=None, zoom=None):
@ -175,7 +174,6 @@ class MapCSS():
hints.append(p)
return hints
def parse(self, css, clamp=True, stretch=1000):
"""
Parses MapCSS given as string
@ -184,212 +182,213 @@ class MapCSS():
self.choosers = []
log = logging.getLogger('mapcss.parser')
previous = 0 # what was the previous CSS word?
sc=StyleChooser(self.scalepair) #currently being assembled
#choosers=[]
#o = []
sc = StyleChooser(self.scalepair) # currently being assembled
# choosers=[]
# o = []
css_orig = css
while (css):
# CSS comment
if COMMENT.match(css):
log.debug("comment found")
css=COMMENT.sub("", css)
css = COMMENT.sub("", css)
#// Whitespace (probably only at beginning of file)
elif WHITESPACE.match(css):
log.debug("whitespace found")
css=WHITESPACE.sub("",css)
css = WHITESPACE.sub("", css)
#// Class - .motorway, .builtup, :hover
elif CLASS.match(css):
if previous==oDECLARATION:
if previous == oDECLARATION:
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
cond = CLASS.match(css).groups()[0]
log.debug("class found: %s"% (cond))
log.debug("class found: %s" % (cond))
css = CLASS.sub("", css)
sc.addCondition(Condition('eq',("::class",cond)))
previous=oCONDITION;
sc.addCondition(Condition('eq', ("::class", cond)))
previous = oCONDITION
#// Not class - !.motorway, !.builtup, !:hover
elif NOT_CLASS.match(css):
if (previous==oDECLARATION):
if (previous == oDECLARATION):
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
cond = NOT_CLASS.match(css).groups()[0]
log.debug("not_class found: %s"% (cond))
log.debug("not_class found: %s" % (cond))
css = NOT_CLASS.sub("", css)
sc.addCondition(Condition('ne',("::class",cond)))
previous=oCONDITION;
sc.addCondition(Condition('ne', ("::class", cond)))
previous = oCONDITION
#// Zoom
elif ZOOM.match(css):
if (previous!=oOBJECT & previous!=oCONDITION):
if (previous != oOBJECT & previous != oCONDITION):
sc.newObject()
cond = ZOOM.match(css).groups()[0]
log.debug("zoom found: %s"% (cond))
css=ZOOM.sub("",css)
log.debug("zoom found: %s" % (cond))
css = ZOOM.sub("", css)
sc.addZoom(self.parseZoom(cond))
previous=oZOOM;
previous = oZOOM
#// Grouping - just a comma
elif GROUP.match(css):
css=GROUP.sub("",css)
css = GROUP.sub("", css)
sc.newGroup()
previous=oGROUP
previous = oGROUP
#// Condition - [highway=primary]
elif CONDITION.match(css):
if (previous==oDECLARATION):
if (previous == oDECLARATION):
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
if (previous!=oOBJECT) and (previous!=oZOOM) and (previous!=oCONDITION):
if (previous != oOBJECT) and (previous != oZOOM) and (previous != oCONDITION):
sc.newObject()
cond = CONDITION.match(css).groups()[0]
log.debug("condition found: %s"% (cond))
css=CONDITION.sub("",css)
log.debug("condition found: %s" % (cond))
css = CONDITION.sub("", css)
sc.addCondition(parseCondition(cond))
previous=oCONDITION;
previous = oCONDITION
#// Object - way, node, relation
elif OBJECT.match(css):
if (previous==oDECLARATION):
if (previous == oDECLARATION):
self.choosers.append(sc)
sc = StyleChooser(self.scalepair)
obj = OBJECT.match(css).groups()[0]
log.debug("object found: %s"% (obj))
css=OBJECT.sub("",css)
log.debug("object found: %s" % (obj))
css = OBJECT.sub("", css)
sc.newObject(obj)
previous=oOBJECT
previous = oOBJECT
#// Declaration - {...}
elif DECLARATION.match(css):
decl = DECLARATION.match(css).groups()[0]
log.debug("declaration found: %s"% (decl))
log.debug("declaration found: %s" % (decl))
sc.addStyles(parseDeclaration(decl))
css=DECLARATION.sub("",css)
previous=oDECLARATION
css = DECLARATION.sub("", css)
previous = oDECLARATION
#// Unknown pattern
elif UNKNOWN.match(css):
log.warning("unknown thing found on line %s: %s"%(unicode(css_orig[:-len(unicode(css))]).count("\n")+1, UNKNOWN.match(css).group()))
css=UNKNOWN.sub("",css)
log.warning("unknown thing found on line %s: %s" % (unicode(css_orig[:-len(unicode(css))]).count("\n") + 1, UNKNOWN.match(css).group()))
css = UNKNOWN.sub("", css)
else:
log.warning("choked on: %s"%(css))
log.warning("choked on: %s" % (css))
return
if (previous==oDECLARATION):
if (previous == oDECLARATION):
self.choosers.append(sc)
sc= StyleChooser(self.scalepair)
sc = StyleChooser(self.scalepair)
try:
if clamp:
"clamp z-indexes, so they're tightly following integers"
zindex = set()
for chooser in self.choosers:
for stylez in chooser.styles:
zindex.add(float(stylez.get('z-index',0)))
zindex.add(float(stylez.get('z-index', 0)))
zindex = list(zindex)
zindex.sort()
for chooser in self.choosers:
for stylez in chooser.styles:
if 'z-index' in stylez:
if stretch:
stylez['z-index'] = 1.*zindex.index(float(stylez.get('z-index',0)))/len(zindex)*stretch
stylez['z-index'] = 1. * zindex.index(float(stylez.get('z-index', 0))) / len(zindex) * stretch
else:
stylez['z-index'] = zindex.index(float(stylez.get('z-index',0)))
stylez['z-index'] = zindex.index(float(stylez.get('z-index', 0)))
except TypeError:
pass
def parseCondition(s):
log = logging.getLogger('mapcss.parser.condition')
if CONDITION_TRUE.match(s):
if CONDITION_TRUE.match(s):
a = CONDITION_TRUE.match(s).groups()
log.debug("condition true: %s"%(a[0]))
return Condition('true' ,a)
if CONDITION_invTRUE.match(s):
log.debug("condition true: %s" % (a[0]))
return Condition('true', a)
if CONDITION_invTRUE.match(s):
a = CONDITION_invTRUE.match(s).groups()
log.debug("condition invtrue: %s"%(a[0]))
return Condition('ne' ,(a[0],"yes"))
log.debug("condition invtrue: %s" % (a[0]))
return Condition('ne', (a[0], "yes"))
if CONDITION_FALSE.match(s):
if CONDITION_FALSE.match(s):
a = CONDITION_FALSE.match(s).groups()
log.debug("condition false: %s"%(a[0]))
return Condition('false' ,a)
log.debug("condition false: %s" % (a[0]))
return Condition('false', a)
if CONDITION_SET.match(s):
if CONDITION_SET.match(s):
a = CONDITION_SET.match(s).groups()
log.debug("condition set: %s"%(a))
return Condition('set' ,a)
log.debug("condition set: %s" % (a))
return Condition('set', a)
if CONDITION_UNSET.match(s):
if CONDITION_UNSET.match(s):
a = CONDITION_UNSET.match(s).groups()
log.debug("condition unset: %s"%(a))
return Condition('unset' ,a)
log.debug("condition unset: %s" % (a))
return Condition('unset', a)
if CONDITION_NE.match(s):
if CONDITION_NE.match(s):
a = CONDITION_NE.match(s).groups()
log.debug("condition NE: %s = %s"%(a[0], a[1]))
return Condition('ne' ,a)
log.debug("condition NE: %s = %s" % (a[0], a[1]))
return Condition('ne', a)
## FIXME: convert other conditions to python
if CONDITION_LE.match(s):
if CONDITION_LE.match(s):
a = CONDITION_LE.match(s).groups()
log.debug("condition LE: %s <= %s"%(a[0], a[1]))
return Condition('<=' ,a)
log.debug("condition LE: %s <= %s" % (a[0], a[1]))
return Condition('<=', a)
if CONDITION_GE.match(s):
if CONDITION_GE.match(s):
a = CONDITION_GE.match(s).groups()
log.debug("condition GE: %s >= %s"%(a[0], a[1]))
return Condition('>=' ,a)
log.debug("condition GE: %s >= %s" % (a[0], a[1]))
return Condition('>=', a)
if CONDITION_LT.match(s):
if CONDITION_LT.match(s):
a = CONDITION_LT.match(s).groups()
log.debug("condition LT: %s < %s"%(a[0], a[1]))
return Condition('<' ,a)
log.debug("condition LT: %s < %s" % (a[0], a[1]))
return Condition('<', a)
if CONDITION_GT.match(s):
if CONDITION_GT.match(s):
a = CONDITION_GT.match(s).groups()
log.debug("condition GT: %s > %s"%(a[0], a[1]))
return Condition('>' ,a)
log.debug("condition GT: %s > %s" % (a[0], a[1]))
return Condition('>', a)
if CONDITION_REGEX.match(s):
if CONDITION_REGEX.match(s):
a = CONDITION_REGEX.match(s).groups()
log.debug("condition REGEX: %s = %s"%(a[0], a[1]))
return Condition('regex' ,a)
log.debug("condition REGEX: %s = %s" % (a[0], a[1]))
return Condition('regex', a)
if CONDITION_EQ.match(s):
if CONDITION_EQ.match(s):
a = CONDITION_EQ.match(s).groups()
log.debug("condition EQ: %s = %s"%(a[0], a[1]))
return Condition('eq' ,a)
log.debug("condition EQ: %s = %s" % (a[0], a[1]))
return Condition('eq', a)
else:
log.warning("condition UNKNOWN: %s"%(s))
log.warning("condition UNKNOWN: %s" % (s))
def parseDeclaration(s):
"""
Parse declaration string into list of styles
"""
styles=[]
styles = []
t = {}
for a in s.split(';'):
#if ((o=ASSIGNMENT_EVAL.exec(a))) { t[o[1].replace(DASH,'_')]=new Eval(o[2]); }
# if ((o=ASSIGNMENT_EVAL.exec(a))) { t[o[1].replace(DASH,'_')]=new Eval(o[2]); }
if ASSIGNMENT.match(a):
tzz = ASSIGNMENT.match(a).groups()
t[tzz[0]]=tzz[1].strip().strip('"')
logging.debug("%s == %s" % (tzz[0],tzz[1]) )
t[tzz[0]] = tzz[1].strip().strip('"')
logging.debug("%s == %s" % (tzz[0], tzz[1]))
else:
logging.debug("unknown %s" % (a) )
logging.debug("unknown %s" % (a))
return [t]
if __name__ == "__main__":
logging.basicConfig(level=logging.WARNING)
mc = MapCSS(0,19)
mc = MapCSS(0, 19)

View file

@ -512,6 +512,7 @@ def name_to_hex(name, spec='css3'):
raise ValueError("'%s' is not defined as a named color in %s." % (name, spec))
return hex_value
def name_to_rgb(name, spec='css3'):
"""
Convert a color name to a 3-tuple of integers suitable for use in
@ -540,6 +541,7 @@ def name_to_rgb(name, spec='css3'):
"""
return hex_to_rgb(name_to_hex(name, spec=spec))
def name_to_rgb_percent(name, spec='css3'):
"""
Convert a color name to a 3-tuple of percentages suitable for use
@ -618,6 +620,7 @@ def hex_to_name(hex_value, spec='css3'):
raise ValueError("'%s' has no defined color name in %s." % (hex_value, spec))
return name
def any_hex_to_name(hex_value):
try:
return hex_to_name(hex_value)
@ -648,6 +651,7 @@ def hex_to_rgb(hex_value):
return tuple(map(lambda s: int(s, 16),
(hex_digits[1:3], hex_digits[3:5], hex_digits[5:7])))
def hex_to_rgb_percent(hex_value):
"""
Convert a hexadecimal color value to a 3-tuple of percentages
@ -696,6 +700,7 @@ def rgb_to_name(rgb_triplet, spec='css3'):
"""
return hex_to_name(rgb_to_hex(rgb_triplet), spec=spec)
def rgb_to_hex(rgb_triplet):
"""
Convert a 3-tuple of integers, suitable for use in an ``rgb()``
@ -713,6 +718,7 @@ def rgb_to_hex(rgb_triplet):
"""
return '#%02x%02x%02x' % rgb_triplet
def rgb_to_rgb_percent(rgb_triplet):
"""
Convert a 3-tuple of integers, suitable for use in an ``rgb()``
@ -742,8 +748,8 @@ def rgb_to_rgb_percent(rgb_triplet):
# In order to maintain precision for common values,
# 256 / 2**n is special-cased for values of n
# from 0 through 4, as well as 0 itself.
specials = { 255: '100%', 128: '50%', 64: '25%',
32: '12.5%', 16: '6.25%', 0: '0%' }
specials = {255: '100%', 128: '50%', 64: '25%',
32: '12.5%', 16: '6.25%', 0: '0%'}
return tuple(map(lambda d: specials.get(d, '%.02f%%' % ((d / 255.0) * 100)),
rgb_triplet))
@ -778,6 +784,7 @@ def rgb_percent_to_name(rgb_percent_triplet, spec='css3'):
"""
return rgb_to_name(rgb_percent_to_rgb(rgb_percent_triplet), spec=spec)
def rgb_percent_to_hex(rgb_percent_triplet):
"""
Convert a 3-tuple of percentages, suitable for use in an ``rgb()``
@ -796,6 +803,7 @@ def rgb_percent_to_hex(rgb_percent_triplet):
"""
return rgb_to_hex(rgb_percent_to_rgb(rgb_percent_triplet))
def _percent_to_integer(percent):
"""
Internal helper for converting a percentage value to an integer
@ -806,6 +814,7 @@ def _percent_to_integer(percent):
e = num - math.floor(num)
return e < 0.5 and int(math.floor(num)) or int(math.ceil(num))
def rgb_percent_to_rgb(rgb_percent_triplet):
"""
Convert a 3-tuple of percentages, suitable for use in an ``rgb()``
@ -833,6 +842,7 @@ def rgb_percent_to_rgb(rgb_percent_triplet):
"""
return tuple(map(_percent_to_integer, rgb_percent_triplet))
def whatever_to_rgb(string):
"""
Converts CSS3 color or a hex into rgb triplet; hash of string if fails.
@ -848,19 +858,22 @@ def whatever_to_rgb(string):
if string[:3] == "rgb":
return tuple([float(i) for i in string[4:-1].split(",")][0:3])
except:
return hex_to_rgb("#"+md5(string).hexdigest()[:6])
return hex_to_rgb("#" + md5(string).hexdigest()[:6])
def whatever_to_hex(string):
if type(string) == tuple:
return cairo_to_hex(string).upper()
return rgb_to_hex(whatever_to_rgb(string)).upper()
def whatever_to_cairo(string):
a = whatever_to_rgb(string)
return a[0]/255.,a[1]/255.,a[2]/255.
return a[0] / 255., a[1] / 255., a[2] / 255.
def cairo_to_hex (cairo):
return rgb_to_hex((cairo[0]*255.,cairo[1]*255.,cairo[2]*255.))
def cairo_to_hex(cairo):
return rgb_to_hex((cairo[0] * 255., cairo[1] * 255., cairo[2] * 255.))
if __name__ == '__main__':
import doctest

View file

@ -40,38 +40,42 @@ 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):
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):
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]))
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 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):
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
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("=", "###")
string = string.replace(" ", "_")
string = string.replace(";", ",")
string = string.replace("=", "###")
return string
print sanitize (" ;=")
print sanitize(" ;=")
def initDB(filename):
conn = sqlite3.connect(filename)
@ -83,22 +87,25 @@ def initDB(filename):
c.execute('''CREATE INDEX id_idx ON nodes(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 ():
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 = open("minsk.osm", "rb")
osm_infile = sys.stdin
# remove any stale temporary files
@ -140,18 +147,18 @@ def main ():
print "Ways read:", WAYS_READ
mzoom = 1
#tags = style.filter_tags(tags)
# 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
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
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]:
for point in way_simplified[zoom + 1]:
if pix_distance(point, prev_point, zoom) > 1.5:
way.append(point)
prev_point = point
@ -160,39 +167,37 @@ def main ():
if len(way) == 1:
mzoom = zoom
#print zoom
# print zoom
break
if len(way) > 1:
way_simplified[zoom] = way
#print way
for tile in tilelist_by_geometry(curway, mzoom+1):
# 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):
os.makedirs(path)
tilefiles[tile] = open(path+"y"+str(y)+".vtile","wb")
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[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]]])
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]:
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 )
# 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
@ -201,9 +206,9 @@ def main ():
elem.clear()
# extra insurance
del elem
#user = default_user
#ts = ""
print "Tiles generated:",len(tilefiles)
# 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()

View file

@ -16,14 +16,16 @@
# 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

@ -24,33 +24,35 @@ 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):
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))
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
@ -58,50 +60,52 @@ class RasterTile:
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.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("%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 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)
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 - 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)
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):
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)
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
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)
@ -110,27 +114,25 @@ class RasterTile:
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))
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":
if antialias == "none":
"no antialiasing enabled"
cr.set_antialias(1)
#cr.font_options_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)
# cr.font_options_set_antialias(2)
else:
"full antialias"
cr.set_antialias(2)
#cr.font_options_set_antialias(2)
# cr.font_options_set_antialias(2)
datatimer = Timer("Asking backend")
if "get_sql_hints" in dir(style):
@ -143,9 +145,9 @@ class RasterTile:
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()
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 = []
@ -157,11 +159,11 @@ class RasterTile:
st = style.get_style("area", way.tags, self.zoom, scale, zscale)
if st:
for fpt in st:
#debug(fpt)
# debug(fpt)
ww.append([way.copy(), fpt])
datatimer.stop()
debug( "%s objects on screen (%s in dataset)"%(len(ww),len(vectors)) )
debug("%s objects on screen (%s in dataset)" % (len(ww), len(vectors)))
er = Timer("Projecing data")
if self.data.proj != self.proj:
@ -179,53 +181,48 @@ class RasterTile:
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]
w[0].cs = [(x, y - offset) for x, y in w[0].cs]
if "extrude" in w[1]:
if w[1]["extrude"]<2:
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-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
# 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 = 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)
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}
linecaps = {"butt": 0, "round": 1, "square": 2}
linejoin = {"miter": 0, "round": 1, "bevel": 2}
text_rendered_at = set([(-100,-100)])
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])))
# 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))
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]:
@ -240,29 +237,28 @@ class RasterTile:
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_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))
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_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))
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:
@ -271,11 +267,10 @@ class RasterTile:
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])))
# 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)
@ -285,46 +280,45 @@ class RasterTile:
"""
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]]
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]
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 = (coord[0],coord[1]-raised)
p_coord = False
for coord in obj[0].cs:
c = (coord[0],coord[1]-raised)
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 ))
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])))
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):
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
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
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
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])))
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
@ -334,43 +328,42 @@ class RasterTile:
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) ))
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) ))
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)
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) ))
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)
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)
# 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
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)
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")
@ -379,12 +372,12 @@ class RasterTile:
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)))
# 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)))
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
@ -409,122 +402,121 @@ class RasterTile:
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))
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))
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:
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))
# 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_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_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
else: # render text along line
c = obj[0].cs
text = unicode(text,"utf-8")
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)
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):
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
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)
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
x0, y0 = x, y
else:
return None
da = 0
os = 1
z = length/2-cr.text_extents(text)[2]/2
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:
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
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
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_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)
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.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]
# 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.))
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)
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)
# 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]
# 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
@ -539,13 +531,14 @@ class RasterTile:
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)
self.cache[url] = cairo.ImageSurface.create_from_png(url)
return self.cache[url]
else:
return False

View file

@ -24,19 +24,17 @@ from render import RasterTile
import web
import StringIO
style = MapCSS(1, 26) #zoom levels
style.parse(open("styles/landuses.mapcss","r").read())
style = MapCSS(1, 26) # zoom levels
style.parse(open("styles/landuses.mapcss", "r").read())
#bbox = (27.115768874532,53.740327031764,28.028320754378,54.067187302158)
# bbox = (27.115768874532,53.740327031764,28.028320754378,54.067187302158)
#w,h = 630*4,364*4
#z = 17
# w,h = 630*4,364*4
# z = 17
db = DataBackend()
#style = Styling()
# style = Styling()
try:
@ -48,6 +46,7 @@ except ImportError:
OK = 200
ERROR = 500
def handler():
"""
A handler for web.py.
@ -58,16 +57,16 @@ def handler():
return content
urls = (
'/(.*)', 'mainhandler'
'/(.*)', 'mainhandler'
)
class mainhandler:
def GET(self, crap):
return handler()
if __name__ == "__main__":
app = web.application(urls, globals())
@ -79,33 +78,29 @@ def twms_main(req):
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(",")
# layer = data.get("layers",data.get("LAYERS", config.default_layers)).split(",")
width=0
height=0
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(",")))
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)))
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))
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

@ -22,11 +22,12 @@ 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):
def __init__(self, stylefile=None):
self.Selectors = {}
self.Selectors["way"] = []
self.Selectors["node"] = []
@ -34,44 +35,42 @@ class Styling():
if not stylefile:
# self.Selectors["way"].append(StyleSelector( ( [ ( ("building",),(None) ) ] ),{"fill-color": "#00f"} ))
#if stylefile=="zzzz":
# 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(([(("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(([(("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.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)
# 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):
def get_style(self, objtype, tags, nodata=False):
"""
objtype is "node", "way" or "relation"
tags - object tags
@ -84,31 +83,31 @@ class Styling():
if resp:
return True
if not nodata and resp:
#debug((tags, tags.get("layer",0)), )
# debug((tags, tags.get("layer",0)), )
try:
resp["layer"] = int(tags.get("layer",0))*100+resp.get("z-index",0)+1000
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"])
# 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():
# 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):
"""
@ -124,7 +123,7 @@ class StyleSelector():
if "color" in keyz:
self.style[keyz] = colorparser(style[key])
debug((colorparser(style[key]),style[key]))
debug((colorparser(style[key]), style[key]))
else:
self.style[keyz] = style[key]
@ -133,8 +132,8 @@ class StyleSelector():
Get actual styling for object.
"""
styled = False
#debug(self.tags)
for k,v in self.tags:
# debug(self.tags)
for k, v in self.tags:
for j in k:
if j in tags:
if v:
@ -148,11 +147,11 @@ class StyleSelector():
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"})
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,7 +1,8 @@
canvas{fill-color:#B5D0D0}
area[natural=ocean]{fill-color:#B5D0D0}
area[natural=coastline]{fill-color:#F1EEE8}
area[natural=coastline]{fill-color:#B5D0D0}
/*area[natural=coastline]{fill-color:#F1EEE8}*/
area|z10-[landuse=military]{fill-color:#F1EEE8; z-index:100}
@ -108,6 +109,7 @@ 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}
@ -128,6 +130,8 @@ 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],
@ -198,6 +202,9 @@ 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;
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}
text-halo-radius: 1;
text-halo-color: white;
/* text-position:line; -x-mapnik-snap-to-street: true */
}

View file

@ -12,60 +12,66 @@ minzoom = 0
maxzoom = 19
style = MapCSS(minzoom, maxzoom)
style.parse(open(sys.argv[1],"r").read(), clamp=False)
style.parse(open(sys.argv[1], "r").read(), 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.)
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])
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 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
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 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
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 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]
@ -75,11 +81,12 @@ def compare_visibility(a, function, b):
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):
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]
@ -91,10 +98,11 @@ def has_stable_labels(a):
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 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)]
@ -103,96 +111,93 @@ def has_darker_casings(a):
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) :
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({'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': '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": "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': '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({"highway": "service"}, "over", {'building': "yes"})
compare_order( {"railway": "rail"}, "over", {"waterway": "riverbank"})
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({"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_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'})
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_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'})
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'})
print "Failed tests: %s (%s%%)" % (FAILED_TESTS, 100*FAILED_TESTS/TOTAL_TESTS)
print "Failed tests: %s (%s%%)" % (FAILED_TESTS, 100 * FAILED_TESTS / TOTAL_TESTS)
print "Passed tests:", TOTAL_TESTS - FAILED_TESTS
print "Total tests:", TOTAL_TESTS
print "Total tests:", TOTAL_TESTS

View file

@ -17,30 +17,32 @@
import StringIO
import Image
import os
import threading, thread
import threading
import thread
from twms import projections
import config
#from vtiles_backend import QuadTileBackend as DataBackend
# 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())
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):
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")
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)
@ -63,10 +65,10 @@ def kothic_metatile(z, x, y, this_layer):
if "max_zoom" in this_layer:
if z >= this_layer["max_zoom"]:
return None
if z<5:
if z < 5:
return None
metatile_id = (z,int(x/8), int(y/8))
metatile_id = (z, int(x / 8), int(y / 8))
try:
metatiles_in_progress[metatile_id].join()
@ -77,28 +79,28 @@ def kothic_metatile(z, x, y, this_layer):
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)
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
if os.path.exists(local + ext): # First, look for tile in cache
try:
im1 = Image.open(local+ext)
im1 = Image.open(local + ext)
del metatiles_in_progress[metatile_id]
return im1
except IOError:
os.remove(local+ext)
os.remove(local + ext)
def gen_metatile(metatile_id, this_layer):
#renderlock.acquire()
# 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])
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)
res.update_surface(bbox, z + 3, style)
f = NamedTemporaryFile()
f.close()
res.surface.write_to_png(f.name)
@ -107,17 +109,17 @@ def gen_metatile(metatile_id, this_layer):
im = Image.open(f.name)
os.unlink(f.name)
im = im.convert("RGBA")
x*=8
y*=8
z+=3
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))
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)
im1.save(local + ext)
del im1
#renderlock.release()
# renderlock.release()