heavy profilign + autopep8
This commit is contained in:
parent
c82f301853
commit
506426b376
6 changed files with 856 additions and 851 deletions
|
@ -20,210 +20,210 @@ import re
|
|||
INVERSIONS = {"eq":"ne", "true":"false", "set":"unset", "<":">=", ">":"<="}
|
||||
in2 = {}
|
||||
for a,b in INVERSIONS.iteritems():
|
||||
in2[b] = a
|
||||
in2[b] = a
|
||||
INVERSIONS.update(in2)
|
||||
del in2
|
||||
|
||||
|
||||
class Condition:
|
||||
def __init__(self, typez, params):
|
||||
self.type=typez # eq, regex, lt, gt etc.
|
||||
if type(params) == type(str()):
|
||||
params = (params,)
|
||||
self.params=params # e.g. ('highway','primary')
|
||||
if typez == "regex":
|
||||
self.regex = re.compile(self.params[0], re.I)
|
||||
def __init__(self, typez, params):
|
||||
self.type=typez # eq, regex, lt, gt etc.
|
||||
if type(params) == type(str()):
|
||||
params = (params,)
|
||||
self.params=params # e.g. ('highway','primary')
|
||||
if typez == "regex":
|
||||
self.regex = re.compile(self.params[0], re.I)
|
||||
|
||||
self.compiled_regex = ""
|
||||
self.compiled_regex = ""
|
||||
|
||||
def get_interesting_tags(self):
|
||||
if self.params[0][:2] == "::":
|
||||
return []
|
||||
return set([self.params[0]])
|
||||
def get_interesting_tags(self):
|
||||
if self.params[0][:2] == "::":
|
||||
return []
|
||||
return set([self.params[0]])
|
||||
|
||||
def get_numerics(self):
|
||||
if self.type in ("<", ">", ">=", "<="):
|
||||
return self.params[0]
|
||||
else:
|
||||
return False
|
||||
def get_numerics(self):
|
||||
if self.type in ("<", ">", ">=", "<="):
|
||||
return self.params[0]
|
||||
else:
|
||||
return False
|
||||
|
||||
def test(self, tags):
|
||||
"""
|
||||
Test a hash against this condition
|
||||
"""
|
||||
t = self.type
|
||||
params = self.params
|
||||
if t == 'eq': # don't compare tags against sublayers
|
||||
if params[0][:2] == "::":
|
||||
return params[1]
|
||||
try:
|
||||
if t == 'eq':
|
||||
return tags[params[0]]==params[1]
|
||||
if t == 'ne':
|
||||
return tags.get(params[0], "")!=params[1]
|
||||
if t == 'regex':
|
||||
return bool(self.regex.match(tags[params[0]]))
|
||||
if t == 'true':
|
||||
return tags.get(params[0]) == 'yes'
|
||||
if t == 'untrue':
|
||||
return tags.get(params[0]) == 'no'
|
||||
if t == 'set':
|
||||
if params[0] in tags:
|
||||
return tags[params[0]] != ''
|
||||
return False
|
||||
if t == 'unset':
|
||||
if params[0] in tags:
|
||||
return tags[params[0]] == ''
|
||||
return True
|
||||
def test(self, tags):
|
||||
"""
|
||||
Test a hash against this condition
|
||||
"""
|
||||
t = self.type
|
||||
params = self.params
|
||||
if t == 'eq': # don't compare tags against sublayers
|
||||
if params[0][:2] == "::":
|
||||
return params[1]
|
||||
try:
|
||||
if t == 'eq':
|
||||
return tags[params[0]]==params[1]
|
||||
if t == 'ne':
|
||||
return tags.get(params[0], "")!=params[1]
|
||||
if t == 'regex':
|
||||
return bool(self.regex.match(tags[params[0]]))
|
||||
if t == 'true':
|
||||
return tags.get(params[0]) == 'yes'
|
||||
if t == 'untrue':
|
||||
return tags.get(params[0]) == 'no'
|
||||
if t == 'set':
|
||||
if params[0] in tags:
|
||||
return tags[params[0]] != ''
|
||||
return False
|
||||
if t == 'unset':
|
||||
if params[0] in tags:
|
||||
return tags[params[0]] == ''
|
||||
return True
|
||||
|
||||
if t == '<':
|
||||
return (Number(tags[params[0]])< Number(params[1]))
|
||||
if t == '<=':
|
||||
return (Number(tags[params[0]])<=Number(params[1]))
|
||||
if t == '>':
|
||||
return (Number(tags[params[0]])> Number(params[1]))
|
||||
if t == '>=':
|
||||
return (Number(tags[params[0]])>=Number(params[1]))
|
||||
except KeyError:
|
||||
pass
|
||||
return False;
|
||||
def inverse(self):
|
||||
"""
|
||||
Get a not-A for condition A
|
||||
"""
|
||||
t = self.type
|
||||
params = self.params
|
||||
try:
|
||||
return Condition(INVERSIONS[t], params)
|
||||
if t == 'regex':
|
||||
### FIXME: learn how to invert regexes
|
||||
return Condition("regex", params)
|
||||
except KeyError:
|
||||
pass
|
||||
return self;
|
||||
if t == '<':
|
||||
return (Number(tags[params[0]])< Number(params[1]))
|
||||
if t == '<=':
|
||||
return (Number(tags[params[0]])<=Number(params[1]))
|
||||
if t == '>':
|
||||
return (Number(tags[params[0]])> Number(params[1]))
|
||||
if t == '>=':
|
||||
return (Number(tags[params[0]])>=Number(params[1]))
|
||||
except KeyError:
|
||||
pass
|
||||
return False;
|
||||
def inverse(self):
|
||||
"""
|
||||
Get a not-A for condition A
|
||||
"""
|
||||
t = self.type
|
||||
params = self.params
|
||||
try:
|
||||
return Condition(INVERSIONS[t], params)
|
||||
if t == 'regex':
|
||||
### FIXME: learn how to invert regexes
|
||||
return Condition("regex", params)
|
||||
except KeyError:
|
||||
pass
|
||||
return self;
|
||||
|
||||
|
||||
|
||||
|
||||
def get_sql(self):
|
||||
#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 ("","")
|
||||
try:
|
||||
if t == 'eq':
|
||||
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])
|
||||
if t == 'regex':
|
||||
return params[0], '"%s" ~ \'%s\''%(params[0],params[1].replace("'","\\'"))
|
||||
if t == 'true':
|
||||
return params[0], '"%s" = \'yes\''%(params[0])
|
||||
if t == 'untrue':
|
||||
return params[0], '"%s" = \'no\''%(params[0])
|
||||
if t == 'set':
|
||||
return params[0], '"%s" IS NOT NULL'%(params[0])
|
||||
if t == 'unset':
|
||||
return params[0], '"%s" IS NULL'%(params[0])
|
||||
|
||||
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])
|
||||
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])
|
||||
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])
|
||||
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])
|
||||
except KeyError:
|
||||
pass
|
||||
def get_mapnik_filter(self):
|
||||
#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 ''
|
||||
try:
|
||||
if t == 'eq':
|
||||
return '[%s] = \'%s\''%(params[0], params[1])
|
||||
if t == 'ne':
|
||||
return 'not([%s] = \'%s\')'%(params[0], params[1])
|
||||
if t == 'regex':
|
||||
return '[%s].match(\'%s\')'%(params[0], params[1].replace("'","\\'"))
|
||||
if t == 'true':
|
||||
return '[%s] = \'yes\''%(params[0])
|
||||
if t == 'untrue':
|
||||
return '[%s] = \'no\''%(params[0])
|
||||
if t == 'set':
|
||||
return '[%s] != \'\''%(params[0])
|
||||
if t == 'unset':
|
||||
return 'not([%s] != \'\')'%(params[0])
|
||||
def get_sql(self):
|
||||
#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 ("","")
|
||||
try:
|
||||
if t == 'eq':
|
||||
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])
|
||||
if t == 'regex':
|
||||
return params[0], '"%s" ~ \'%s\''%(params[0],params[1].replace("'","\\'"))
|
||||
if t == 'true':
|
||||
return params[0], '"%s" = \'yes\''%(params[0])
|
||||
if t == 'untrue':
|
||||
return params[0], '"%s" = \'no\''%(params[0])
|
||||
if t == 'set':
|
||||
return params[0], '"%s" IS NOT NULL'%(params[0])
|
||||
if t == 'unset':
|
||||
return params[0], '"%s" IS NULL'%(params[0])
|
||||
|
||||
if t == '<':
|
||||
return '[%s__num] < %s'%(params[0], float(params[1]))
|
||||
if t == '<=':
|
||||
return '[%s__num] <= %s'%(params[0], float(params[1]))
|
||||
if t == '>':
|
||||
return '[%s__num] > %s'%(params[0], float(params[1]))
|
||||
if t == '>=':
|
||||
return '[%s__num] >= %s'%(params[0], float(params[1]))
|
||||
#return ""
|
||||
except KeyError:
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "%s %s "%(self.type, repr(self.params))
|
||||
def __eq__(self, a):
|
||||
return (self.params == a.params) and (self.type == a.type)
|
||||
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])
|
||||
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])
|
||||
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])
|
||||
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])
|
||||
except KeyError:
|
||||
pass
|
||||
def get_mapnik_filter(self):
|
||||
#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 ''
|
||||
try:
|
||||
if t == 'eq':
|
||||
return '[%s] = \'%s\''%(params[0], params[1])
|
||||
if t == 'ne':
|
||||
return 'not([%s] = \'%s\')'%(params[0], params[1])
|
||||
if t == 'regex':
|
||||
return '[%s].match(\'%s\')'%(params[0], params[1].replace("'","\\'"))
|
||||
if t == 'true':
|
||||
return '[%s] = \'yes\''%(params[0])
|
||||
if t == 'untrue':
|
||||
return '[%s] = \'no\''%(params[0])
|
||||
if t == 'set':
|
||||
return '[%s] != \'\''%(params[0])
|
||||
if t == 'unset':
|
||||
return 'not([%s] != \'\')'%(params[0])
|
||||
|
||||
def and_with(self, c2):
|
||||
"""
|
||||
merges two rules with AND.
|
||||
"""
|
||||
#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
|
||||
return False
|
||||
if c2.type == self.type:
|
||||
return (self,)
|
||||
if t == '<':
|
||||
return '[%s__num] < %s'%(params[0], float(params[1]))
|
||||
if t == '<=':
|
||||
return '[%s__num] <= %s'%(params[0], float(params[1]))
|
||||
if t == '>':
|
||||
return '[%s__num] > %s'%(params[0], float(params[1]))
|
||||
if t == '>=':
|
||||
return '[%s__num] >= %s'%(params[0], float(params[1]))
|
||||
#return ""
|
||||
except KeyError:
|
||||
pass
|
||||
def __repr__(self):
|
||||
return "%s %s "%(self.type, repr(self.params))
|
||||
def __eq__(self, a):
|
||||
return (self.params == a.params) and (self.type == a.type)
|
||||
|
||||
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),)
|
||||
if self.type == ">" and c2.type == "<":
|
||||
return False
|
||||
if self.type == "<" and c2.type == ">":
|
||||
return False
|
||||
def and_with(self, c2):
|
||||
"""
|
||||
merges two rules with AND.
|
||||
"""
|
||||
#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
|
||||
return False
|
||||
if c2.type == self.type:
|
||||
return (self,)
|
||||
|
||||
if c2.type == "eq" and self.type in ("ne", "<", ">"):
|
||||
if c2.params[1] != self.params[1]:
|
||||
return (c2,)
|
||||
if self.type == "eq" and c2.type in ("ne", "<", ">"):
|
||||
if c2.params[1] != self.params[1]:
|
||||
return (self,)
|
||||
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
|
||||
return (self,)
|
||||
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", "<", "<=", ">", ">="):
|
||||
return (c2,)
|
||||
if self.type == "unset" and c2.type in ("eq","ne","regex", "<", "<=", ">", ">="):
|
||||
return False
|
||||
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),)
|
||||
if self.type == ">" and c2.type == "<":
|
||||
return False
|
||||
if self.type == "<" and c2.type == ">":
|
||||
return False
|
||||
|
||||
if c2.type == "eq" and self.type in ("ne", "<", ">"):
|
||||
if c2.params[1] != self.params[1]:
|
||||
return (c2,)
|
||||
if self.type == "eq" and c2.type in ("ne", "<", ">"):
|
||||
if c2.params[1] != self.params[1]:
|
||||
return (self,)
|
||||
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
|
||||
return (self,)
|
||||
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", "<", "<=", ">", ">="):
|
||||
return (c2,)
|
||||
if self.type == "unset" and c2.type in ("eq","ne","regex", "<", "<=", ">", ">="):
|
||||
return False
|
||||
|
||||
|
||||
return self, c2
|
||||
return self, c2
|
||||
def Number(tt):
|
||||
"""
|
||||
Wrap float() not to produce exceptions
|
||||
"""
|
||||
|
||||
try:
|
||||
return float(tt)
|
||||
except ValueError:
|
||||
return 0
|
||||
"""
|
||||
Wrap float() not to produce exceptions
|
||||
"""
|
||||
|
||||
try:
|
||||
return float(tt)
|
||||
except ValueError:
|
||||
return 0
|
||||
|
|
|
@ -18,157 +18,157 @@
|
|||
NONE = ""
|
||||
|
||||
class Eval():
|
||||
def __init__(self, s='eval()'):
|
||||
"""
|
||||
Parse expression and convert it into Python
|
||||
"""
|
||||
s = s.strip()[5:-1].strip()
|
||||
self.expr_text = s
|
||||
try:
|
||||
self.expr = compile (s, "MapCSS expression", "eval")
|
||||
except:
|
||||
#print "Can't compile %s" % s
|
||||
self.expr = compile ("0", "MapCSS expression", "eval")
|
||||
def __init__(self, s='eval()'):
|
||||
"""
|
||||
Parse expression and convert it into Python
|
||||
"""
|
||||
s = s.strip()[5:-1].strip()
|
||||
self.expr_text = s
|
||||
try:
|
||||
self.expr = compile (s, "MapCSS expression", "eval")
|
||||
except:
|
||||
#print "Can't compile %s" % s
|
||||
self.expr = compile ("0", "MapCSS expression", "eval")
|
||||
|
||||
|
||||
def extract_tags(self):
|
||||
"""
|
||||
Extracts list of tags that might be used in calculation
|
||||
"""
|
||||
def fake_compute(*x):
|
||||
"""
|
||||
Perform a fake computation. Always computes all the parameters, always returns 0.
|
||||
WARNING: Might not cope with complex statements.
|
||||
"""
|
||||
for t in x:
|
||||
q = x
|
||||
return 0
|
||||
tags = set([])
|
||||
#print self.expr_text
|
||||
def extract_tags(self):
|
||||
"""
|
||||
Extracts list of tags that might be used in calculation
|
||||
"""
|
||||
def fake_compute(*x):
|
||||
"""
|
||||
Perform a fake computation. Always computes all the parameters, always returns 0.
|
||||
WARNING: Might not cope with complex statements.
|
||||
"""
|
||||
for t in x:
|
||||
q = x
|
||||
return 0
|
||||
tags = set([])
|
||||
#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
|
||||
return tags
|
||||
|
||||
|
||||
def compute(self, tags={}, props = {}, xscale = 1., zscale = 0.5 ):
|
||||
"""
|
||||
Compute this eval()
|
||||
"""
|
||||
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
|
||||
}))
|
||||
except:
|
||||
return ""
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "eval(%s)"%repr(self.expr)
|
||||
def compute(self, tags={}, props = {}, xscale = 1., zscale = 0.5 ):
|
||||
"""
|
||||
Compute this eval()
|
||||
"""
|
||||
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
|
||||
}))
|
||||
except:
|
||||
return ""
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "eval(%s)"%self.expr_text
|
||||
|
||||
def m_boolean(expr):
|
||||
expr = str(expr)
|
||||
if expr in ("", "0", "no", "false", "False"):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
expr = str(expr)
|
||||
if expr in ("", "0", "no", "false", "False"):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def m_cond(why, yes, no):
|
||||
if m_boolean(why):
|
||||
return yes
|
||||
else:
|
||||
return no
|
||||
if m_boolean(why):
|
||||
return yes
|
||||
else:
|
||||
return no
|
||||
|
||||
def m_min(*x):
|
||||
"""
|
||||
min() MapCSS Feature
|
||||
"""
|
||||
try:
|
||||
return min([m_num(t) for t in x])
|
||||
except:
|
||||
return 0
|
||||
"""
|
||||
min() MapCSS Feature
|
||||
"""
|
||||
try:
|
||||
return min([m_num(t) for t in x])
|
||||
except:
|
||||
return 0
|
||||
|
||||
def m_max(*x):
|
||||
"""
|
||||
max() MapCSS Feature
|
||||
"""
|
||||
try:
|
||||
return max([m_num(t) for t in x])
|
||||
except:
|
||||
return 0
|
||||
"""
|
||||
max() MapCSS Feature
|
||||
"""
|
||||
try:
|
||||
return max([m_num(t) for t in x])
|
||||
except:
|
||||
return 0
|
||||
|
||||
def m_any(*x):
|
||||
"""
|
||||
any() MapCSS feature
|
||||
"""
|
||||
for t in x:
|
||||
if t:
|
||||
return t
|
||||
else:
|
||||
return ""
|
||||
"""
|
||||
any() MapCSS feature
|
||||
"""
|
||||
for t in x:
|
||||
if t:
|
||||
return t
|
||||
else:
|
||||
return ""
|
||||
|
||||
def m_num(x):
|
||||
"""
|
||||
num() MapCSS feature
|
||||
"""
|
||||
try:
|
||||
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)
|
||||
except:
|
||||
"Heuristics."
|
||||
# FIXME: add ft, m and friends
|
||||
x = x.strip()
|
||||
"""
|
||||
num() MapCSS feature
|
||||
"""
|
||||
try:
|
||||
if x[-2:] in ("cm", "CM", "см"):
|
||||
return float(x[0:-2])*float(t)/100
|
||||
if x[-2:] in ("mm", "MM", "мм"):
|
||||
return float(x[0:-2])*float(t)/1000
|
||||
if x[-1] in ("m", "M", "м"):
|
||||
return float(x[0:-1])*float(t)
|
||||
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)
|
||||
except:
|
||||
return ""
|
||||
"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
|
||||
if x[-2:] in ("mm", "MM", "мм"):
|
||||
return float(x[0:-2])*float(t)/1000
|
||||
if x[-1] in ("m", "M", "м"):
|
||||
return float(x[0:-1])*float(t)
|
||||
except:
|
||||
return ""
|
||||
#def str(x):
|
||||
#"""
|
||||
#str() MapCSS feature
|
||||
#"""
|
||||
#return __builtins__.str(x)
|
||||
#"""
|
||||
#str() MapCSS feature
|
||||
#"""
|
||||
#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.extract_tags()
|
||||
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.extract_tags()
|
||||
|
|
|
@ -18,92 +18,92 @@
|
|||
|
||||
|
||||
class Rule():
|
||||
def __init__(self, s=''):
|
||||
self.conditions = []
|
||||
#self.isAnd = True
|
||||
self.minZoom = 0
|
||||
self.maxZoom = 19
|
||||
if s == "*":
|
||||
s = ""
|
||||
self.subject = s # "", "way", "node" or "relation"
|
||||
def __init__(self, s=''):
|
||||
self.conditions = []
|
||||
#self.isAnd = True
|
||||
self.minZoom = 0
|
||||
self.maxZoom = 19
|
||||
if s == "*":
|
||||
s = ""
|
||||
self.subject = s # "", "way", "node" or "relation"
|
||||
|
||||
def __repr__(self):
|
||||
return "%s|z%s-%s %s"%(self.subject, self.minZoom, self.maxZoom, self.conditions)
|
||||
def __repr__(self):
|
||||
return "%s|z%s-%s %s"%(self.subject, self.minZoom, self.maxZoom, self.conditions)
|
||||
|
||||
def test(self, obj, tags, zoom):
|
||||
if not self.test_zoom(zoom):
|
||||
return False
|
||||
if (self.subject != '') and not _test_feature_compatibility(obj, self.subject, tags):
|
||||
return False
|
||||
subpart = "::default"
|
||||
for condition in self.conditions:
|
||||
res = condition.test(tags)
|
||||
if not res:
|
||||
def test(self, obj, tags, zoom):
|
||||
if not ((zoom >= self.minZoom) and (zoom <= self.maxZoom)):
|
||||
return False
|
||||
if type(res) != bool:
|
||||
subpart = res
|
||||
return subpart
|
||||
if (self.subject != '') and not _test_feature_compatibility(obj, self.subject, tags):
|
||||
return False
|
||||
subpart = "::default"
|
||||
for condition in self.conditions:
|
||||
res = condition.test(tags)
|
||||
if not res:
|
||||
return False
|
||||
if type(res) != bool:
|
||||
subpart = res
|
||||
return subpart
|
||||
|
||||
def test_zoom(self, zoom):
|
||||
return (zoom >= self.minZoom) and (zoom <= self.maxZoom)
|
||||
def test_zoom(self, zoom):
|
||||
return (zoom >= self.minZoom) and (zoom <= self.maxZoom)
|
||||
|
||||
def get_interesting_tags(self, obj, zoom):
|
||||
if obj:
|
||||
if (self.subject != '') and not _test_feature_compatibility(obj, self.subject, {}):
|
||||
return set()
|
||||
def get_interesting_tags(self, obj, zoom):
|
||||
if obj:
|
||||
if (self.subject != '') and not _test_feature_compatibility(obj, self.subject, {}):
|
||||
return set()
|
||||
|
||||
if zoom and not self.test_zoom(zoom):
|
||||
return set()
|
||||
if zoom and not self.test_zoom(zoom):
|
||||
return set()
|
||||
|
||||
a = set()
|
||||
for condition in self.conditions:
|
||||
a.update(condition.get_interesting_tags())
|
||||
return a
|
||||
a = set()
|
||||
for condition in self.conditions:
|
||||
a.update(condition.get_interesting_tags())
|
||||
return a
|
||||
|
||||
def get_numerics(self):
|
||||
a = set()
|
||||
for condition in self.conditions:
|
||||
a.add(condition.get_numerics())
|
||||
a.discard(False)
|
||||
return a
|
||||
def get_numerics(self):
|
||||
a = set()
|
||||
for condition in self.conditions:
|
||||
a.add(condition.get_numerics())
|
||||
a.discard(False)
|
||||
return a
|
||||
|
||||
def get_sql_hints(self, obj, zoom):
|
||||
if obj:
|
||||
if (self.subject!='') and not _test_feature_compatibility(obj, self.subject, {":area":"yes"}):
|
||||
return set()
|
||||
if not self.test_zoom(zoom):
|
||||
return set()
|
||||
a = set()
|
||||
b = set()
|
||||
for condition in self.conditions:
|
||||
q = condition.get_sql()
|
||||
if q:
|
||||
if q[1]:
|
||||
a.add(q[0])
|
||||
b.add(q[1])
|
||||
b = " AND ".join(b)
|
||||
return a,b
|
||||
def get_sql_hints(self, obj, zoom):
|
||||
if obj:
|
||||
if (self.subject!='') and not _test_feature_compatibility(obj, self.subject, {":area":"yes"}):
|
||||
return set()
|
||||
if not self.test_zoom(zoom):
|
||||
return set()
|
||||
a = set()
|
||||
b = set()
|
||||
for condition in self.conditions:
|
||||
q = condition.get_sql()
|
||||
if q:
|
||||
if q[1]:
|
||||
a.add(q[0])
|
||||
b.add(q[1])
|
||||
b = " AND ".join(b)
|
||||
return a,b
|
||||
|
||||
def _test_feature_compatibility (f1, f2, tags={}):
|
||||
"""
|
||||
Checks if feature of type f1 is compatible with f2.
|
||||
"""
|
||||
if f2 == f1:
|
||||
return True
|
||||
return True
|
||||
if f2 not in ("way", "area", "line"):
|
||||
return False
|
||||
elif f2 == "way" and f1 == "line":
|
||||
return True
|
||||
return True
|
||||
elif f2 == "way" and f1 == "area":
|
||||
return True
|
||||
elif f2 == "area" and f1 in ("way", "area", "POLYGON"):
|
||||
return True
|
||||
elif f2 == "area" and f1 in ("way", "area"):
|
||||
# if ":area" in tags:
|
||||
return True
|
||||
# else:
|
||||
# return False
|
||||
elif f2 == "line" and f1 in ("way", "line", "LINESTRING"):
|
||||
return True
|
||||
elif f2 == "point" and f1 in ("node", "POINT"):
|
||||
return True
|
||||
elif f2 == "line" and f1 in ("way", "line"):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
#print f1, f2, True
|
||||
return True
|
||||
return True
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with kothic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
from Rule import Rule
|
||||
from webcolors.webcolors import whatever_to_cairo as colorparser
|
||||
|
@ -22,225 +22,233 @@ from webcolors.webcolors import cairo_to_hex
|
|||
from Eval import Eval
|
||||
|
||||
class StyleChooser:
|
||||
"""
|
||||
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.
|
||||
|
||||
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.
|
||||
"""
|
||||
def __repr__(self):
|
||||
return "{(%s) : [%s] }\n"%(self.ruleChains, self.styles)
|
||||
def __init__(self, scalepair):
|
||||
self.ruleChains = [[],]
|
||||
self.styles = []
|
||||
self.eval_type = type(Eval())
|
||||
self.scalepair = scalepair
|
||||
self.rcpos=0
|
||||
self.stylepos=0
|
||||
|
||||
|
||||
def get_numerics(self):
|
||||
"""
|
||||
Returns a set of number-compared values.
|
||||
"""
|
||||
a = set()
|
||||
for c in self.ruleChains:
|
||||
for r in c:
|
||||
a.update(r.get_numerics())
|
||||
a.discard(False)
|
||||
return a
|
||||
A StyleChooser object is equivalent to one CSS selector+declaration.
|
||||
|
||||
def get_interesting_tags(self, type, zoom):
|
||||
"""
|
||||
Returns a set of tags that were used in here.
|
||||
"""
|
||||
### FIXME
|
||||
a = set()
|
||||
for c in self.ruleChains:
|
||||
for r in c:
|
||||
a.update(r.get_interesting_tags(type, zoom))
|
||||
if a: ## FIXME: semi-illegal optimization, may wreck in future on tagless matches
|
||||
|
||||
for r in self.styles:
|
||||
for c,b in r.iteritems():
|
||||
if __builtins__["type"](b) == self.eval_type:
|
||||
a.update(b.extract_tags())
|
||||
return a
|
||||
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.
|
||||
|
||||
def get_sql_hints(self, type, zoom):
|
||||
"""
|
||||
Returns a set of tags that were used in here in form of SQL-hints.
|
||||
"""
|
||||
a = set()
|
||||
b = ""
|
||||
needed = set(["width", "casing-width", "fill-color", "fill-image", "icon-image", "text", "extrude", "background-image", "background-color", "pattern-image", "shield-text"])
|
||||
|
||||
if not needed.isdisjoint(set(self.styles[0].keys())):
|
||||
for c in self.ruleChains:
|
||||
for r in c:
|
||||
p = r.get_sql_hints(type, zoom)
|
||||
if p:
|
||||
q = "("+p[1] + ")"#[t[1] for t in p]
|
||||
if q == "()":
|
||||
q = ""
|
||||
if b and q:
|
||||
b += " OR "+ q
|
||||
else:
|
||||
b = q
|
||||
a.update(p[0])
|
||||
# no need to check for eval's
|
||||
return a,b
|
||||
|
||||
# // Update the current StyleList from this StyleChooser
|
||||
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
|
||||
|
||||
def updateStyles(self, sl, ftype, tags, zoom, scale, zscale):
|
||||
# Are any of the ruleChains fulfilled?
|
||||
object_id = False
|
||||
for c in self.ruleChains:
|
||||
object_id = self.testChain(c,ftype,tags,zoom)
|
||||
if object_id:
|
||||
break
|
||||
else:
|
||||
return sl
|
||||
w = 0
|
||||
for r in self.styles:
|
||||
ra = {}
|
||||
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():
|
||||
if "color" in p:
|
||||
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)
|
||||
def __init__(self, scalepair):
|
||||
self.ruleChains = [[],]
|
||||
self.styles = []
|
||||
self.eval_type = type(Eval())
|
||||
self.scalepair = scalepair
|
||||
self.selzooms = None
|
||||
self.rcpos=0
|
||||
self.stylepos=0
|
||||
|
||||
|
||||
def get_numerics(self):
|
||||
"""
|
||||
Returns a set of number-compared values.
|
||||
"""
|
||||
a = set()
|
||||
for c in self.ruleChains:
|
||||
for r in c:
|
||||
a.update(r.get_numerics())
|
||||
a.discard(False)
|
||||
return a
|
||||
|
||||
def get_interesting_tags(self, ztype, zoom):
|
||||
"""
|
||||
Returns a set of tags that were used in here.
|
||||
"""
|
||||
### FIXME
|
||||
a = set()
|
||||
for c in self.ruleChains:
|
||||
for r in c:
|
||||
a.update(r.get_interesting_tags(ztype, zoom))
|
||||
if a: ## FIXME: semi-illegal optimization, may wreck in future on tagless matches
|
||||
for r in self.styles:
|
||||
for c,b in r.iteritems():
|
||||
if type(b) == self.eval_type:
|
||||
a.update(b.extract_tags())
|
||||
return a
|
||||
|
||||
def get_sql_hints(self, type, zoom):
|
||||
"""
|
||||
Returns a set of tags that were used in here in form of SQL-hints.
|
||||
"""
|
||||
a = set()
|
||||
b = ""
|
||||
needed = set(["width", "casing-width", "fill-color", "fill-image", "icon-image", "text", "extrude", "background-image", "background-color", "pattern-image", "shield-text"])
|
||||
|
||||
if not needed.isdisjoint(set(self.styles[0].keys())):
|
||||
for c in self.ruleChains:
|
||||
for r in c:
|
||||
p = r.get_sql_hints(type, zoom)
|
||||
if p:
|
||||
q = "("+p[1] + ")"#[t[1] for t in p]
|
||||
if q == "()":
|
||||
q = ""
|
||||
if b and q:
|
||||
b += " OR "+ q
|
||||
else:
|
||||
b = q
|
||||
a.update(p[0])
|
||||
# no need to check for eval's
|
||||
return a,b
|
||||
|
||||
# // Update the current StyleList from this StyleChooser
|
||||
|
||||
def updateStyles(self, sl, ftype, tags, zoom, scale, zscale):
|
||||
# Are any of the ruleChains fulfilled?
|
||||
if self.selzooms:
|
||||
if zoom < self.selzooms[0] or zoom > self.selzooms[1]:
|
||||
return sl
|
||||
object_id = False
|
||||
for c in self.ruleChains:
|
||||
object_id = self.testChain(c,ftype,tags,zoom)
|
||||
if object_id:
|
||||
break
|
||||
else:
|
||||
return sl
|
||||
w = 0
|
||||
for r in self.styles:
|
||||
ra = {}
|
||||
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():
|
||||
if "color" in p:
|
||||
combined_style[p] = cairo_to_hex(q)
|
||||
b = b.compute(tags, combined_style, scale, zscale)
|
||||
ra[a] = b
|
||||
r = ra
|
||||
ra = {}
|
||||
for a, b in r.iteritems():
|
||||
"checking and nicifying style table"
|
||||
if "color" in a:
|
||||
"parsing color value to 3-tuple"
|
||||
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"
|
||||
b = b.compute(tags, combined_style, scale, zscale)
|
||||
ra[a] = b
|
||||
r = ra
|
||||
ra = {}
|
||||
for a, b in r.iteritems():
|
||||
"checking and nicifying style table"
|
||||
if "color" in a:
|
||||
"parsing color value to 3-tuple"
|
||||
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"
|
||||
try:
|
||||
ra[a] = float(b)
|
||||
except ValueError:
|
||||
pass
|
||||
elif "dashes" in a:
|
||||
"these things are arrays of float's or not in table at all"
|
||||
try:
|
||||
b = b.split(",")
|
||||
b = [float(x) for x in b]
|
||||
ra[a] = b
|
||||
except ValueError:
|
||||
ra[a] = []
|
||||
else:
|
||||
ra[a]=b
|
||||
ra["layer"] = float(tags.get("layer",0))*2000+ra.get("z-index",1) # calculating z-index
|
||||
#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)
|
||||
hasall = False
|
||||
allinit = {}
|
||||
for x in sl:
|
||||
if x.get("object-id") == "::*":
|
||||
allinit = x.copy()
|
||||
if ra["object-id"] == "::*":
|
||||
oid = x.get("object-id")
|
||||
x.update(ra)
|
||||
x["object-id"] = oid
|
||||
if oid == "::*":
|
||||
hasall = True
|
||||
if x.get("object-id") == ra["object-id"]:
|
||||
x.update(ra)
|
||||
break
|
||||
else:
|
||||
if not hasall:
|
||||
allinit.update(ra)
|
||||
sl.append(allinit)
|
||||
#
|
||||
return sl
|
||||
|
||||
def testChain(self,chain, obj, tags, zoom):
|
||||
"""
|
||||
Tests an object against a chain
|
||||
"""
|
||||
for r in chain:
|
||||
tt = r.test(obj,tags,zoom)
|
||||
if tt:
|
||||
return tt
|
||||
return False
|
||||
|
||||
|
||||
def newGroup(self):
|
||||
"""
|
||||
starts a new ruleChain in this.ruleChains
|
||||
"""
|
||||
if self.ruleChains[self.rcpos]:
|
||||
self.ruleChains.append([])
|
||||
|
||||
|
||||
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])
|
||||
self.ruleChains[self.rcpos].append(rule)
|
||||
|
||||
def addZoom(self,z):
|
||||
"""
|
||||
adds into the current ruleChain (existing Rule)
|
||||
"""
|
||||
|
||||
self.ruleChains[self.rcpos][-1].minZoom=float(z[0])
|
||||
self.ruleChains[self.rcpos][-1].maxZoom=float(z[1])
|
||||
if not self.selzooms:
|
||||
self.selzooms = list(z)
|
||||
else:
|
||||
self.selzooms[0] = min(self.selzooms[0], z[0])
|
||||
self.selzooms[1] = min(self.selzooms[1], z[1])
|
||||
|
||||
def addCondition(self,c):
|
||||
"""
|
||||
adds into the current ruleChain (existing Rule)
|
||||
"""
|
||||
self.ruleChains[self.rcpos][-1].conditions.append(c)
|
||||
|
||||
|
||||
def addStyles(self, a):
|
||||
"""
|
||||
adds to this.styles
|
||||
"""
|
||||
rb = []
|
||||
for r in a:
|
||||
ra = {}
|
||||
for a,b in r.iteritems():
|
||||
a = a.strip()
|
||||
b = b.strip()
|
||||
if a == "casing-width":
|
||||
"josm support"
|
||||
if b[0] == "+":
|
||||
try:
|
||||
ra[a] = float(b)
|
||||
except ValueError:
|
||||
pass
|
||||
elif "dashes" in a:
|
||||
"these things are arrays of float's or not in table at all"
|
||||
try:
|
||||
b = b.split(",")
|
||||
b = [float(x) for x in b]
|
||||
ra[a]= b
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
ra[a]=b
|
||||
ra["layer"] = float(tags.get("layer",0))*2000+ra.get("z-index",1) # calculating z-index
|
||||
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)
|
||||
hasall = False
|
||||
allinit = {}
|
||||
for x in sl:
|
||||
if x.get("object-id") == "::*":
|
||||
allinit = x.copy()
|
||||
if ra["object-id"] == "::*":
|
||||
oid = x.get("object-id")
|
||||
x.update(ra)
|
||||
x["object-id"] = oid
|
||||
if oid == "::*":
|
||||
hasall = True
|
||||
if x.get("object-id") == ra["object-id"]:
|
||||
x.update(ra)
|
||||
break
|
||||
else:
|
||||
if not hasall:
|
||||
allinit.update(ra)
|
||||
sl.append(allinit)
|
||||
#
|
||||
return sl
|
||||
|
||||
def testChain(self,chain, obj, tags, zoom):
|
||||
"""
|
||||
Tests an object against a chain
|
||||
"""
|
||||
### FIXME: total MapCSS misreading
|
||||
for r in chain:
|
||||
return r.test(obj,tags,zoom)
|
||||
return False
|
||||
|
||||
|
||||
def newGroup(self):
|
||||
"""
|
||||
starts a new ruleChain in this.ruleChains
|
||||
"""
|
||||
if self.ruleChains[self.rcpos]:
|
||||
self.ruleChains.append([])
|
||||
|
||||
|
||||
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])
|
||||
self.ruleChains[self.rcpos].append(rule)
|
||||
|
||||
def addZoom(self,z):
|
||||
"""
|
||||
adds into the current ruleChain (existing Rule)
|
||||
"""
|
||||
|
||||
self.ruleChains[self.rcpos][-1].minZoom=float(z[0])
|
||||
self.ruleChains[self.rcpos][-1].maxZoom=float(z[1])
|
||||
|
||||
|
||||
def addCondition(self,c):
|
||||
"""
|
||||
adds into the current ruleChain (existing Rule)
|
||||
"""
|
||||
self.ruleChains[self.rcpos][-1].conditions.append(c)
|
||||
|
||||
|
||||
def addStyles(self, a):
|
||||
"""
|
||||
adds to this.styles
|
||||
"""
|
||||
rb = []
|
||||
for r in a:
|
||||
ra = {}
|
||||
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)
|
||||
except:
|
||||
pass
|
||||
if "text" == a[-4:]:
|
||||
if b[:5] != "eval(":
|
||||
b = "eval(tag(\""+b+"\"))"
|
||||
if b[:5] == "eval(":
|
||||
b = Eval(b)
|
||||
ra[a] = b
|
||||
rb.append(ra)
|
||||
# print rb
|
||||
self.styles = self.styles + rb
|
||||
b = str(float(b)/2)
|
||||
except:
|
||||
pass
|
||||
if "text" == a[-4:]:
|
||||
if b[:5] != "eval(":
|
||||
b = "eval(tag(\""+b+"\"))"
|
||||
if b[:5] == "eval(":
|
||||
b = Eval(b)
|
||||
ra[a] = b
|
||||
rb.append(ra)
|
||||
# print rb
|
||||
self.styles = self.styles + rb
|
||||
|
|
|
@ -90,33 +90,33 @@ way {width: 1; casing-width:1; casing-color: white}
|
|||
|
||||
class MapCSS():
|
||||
def __init__(self,minscale=0,maxscale=19):
|
||||
"""
|
||||
"""
|
||||
self.cache = {}
|
||||
self.cache["style"] = {}
|
||||
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.cache = {}
|
||||
self.cache["style"] = {}
|
||||
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
|
||||
|
||||
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])
|
||||
elif ZOOM_SINGLE.match(s):
|
||||
return float(ZOOM_SINGLE.match(s).groups()[0]),float(ZOOM_SINGLE.match(s).groups()[0])
|
||||
else:
|
||||
logging.error("unparsed zoom: %s" %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])
|
||||
elif ZOOM_SINGLE.match(s):
|
||||
return float(ZOOM_SINGLE.match(s).groups()[0]),float(ZOOM_SINGLE.match(s).groups()[0])
|
||||
else:
|
||||
logging.error("unparsed zoom: %s" %s)
|
||||
|
||||
def precompile_style (self):
|
||||
# TODO: styleshees precompilation
|
||||
# TODO: styleshees precompilation
|
||||
subjs = {"canvas": ("canvas",),"way": ("Polygon","LineString"), "line":("Polygon","LineString"), "area": ("Polygon",), "node": ("Point",), "*":("Point","Polygon","LineString") }
|
||||
mfile.write("function restyle (prop, zoom, type){")
|
||||
mfile.write("style = new Object;")
|
||||
|
@ -166,7 +166,7 @@ class MapCSS():
|
|||
#if subclass != "default":
|
||||
#styles = 'if(!("%s" in style)){style["%s"] = new Object;}'%(subclass,subclass)
|
||||
#for k, v in chooser.styles[0].iteritems():
|
||||
|
||||
|
||||
if type(v) == str:
|
||||
try:
|
||||
v = str(float(v))
|
||||
|
@ -178,73 +178,70 @@ class MapCSS():
|
|||
mfile.write("return style;}")
|
||||
|
||||
def get_style (self, type, tags={}, zoom=0, scale=1, zscale=.5):
|
||||
"""
|
||||
Kothic styling API
|
||||
"""
|
||||
shash = md5(repr(type)+repr(tags)+repr(zoom)).digest()
|
||||
if shash in self.cache["style"]:
|
||||
return self.cache["style"][shash]
|
||||
style = []
|
||||
dbg = False
|
||||
if tags.get('highway') == 'footway' and zoom == 17:
|
||||
dbg = True
|
||||
for chooser in self.choosers:
|
||||
style = chooser.updateStyles(style, type, tags, zoom, scale, zscale)
|
||||
style = [x for x in style if x["object-id"] != "::*"]
|
||||
self.cache["style"][shash] = style
|
||||
return style
|
||||
"""
|
||||
Kothic styling API
|
||||
"""
|
||||
shash = md5(repr(type)+repr(tags)+repr(zoom)).digest()
|
||||
if shash in self.cache["style"]:
|
||||
return self.cache["style"][shash]
|
||||
style = []
|
||||
for chooser in self.choosers:
|
||||
style = chooser.updateStyles(style, type, tags, zoom, scale, zscale)
|
||||
style = [x for x in style if x["object-id"] != "::*"]
|
||||
self.cache["style"][shash] = style
|
||||
return style
|
||||
|
||||
def get_interesting_tags(self, type=None, zoom=None):
|
||||
"""
|
||||
Get set of interesting tags.
|
||||
"""
|
||||
tags = set()
|
||||
for chooser in self.choosers:
|
||||
tags.update(chooser.get_interesting_tags(type, zoom))
|
||||
return tags
|
||||
"""
|
||||
Get set of interesting tags.
|
||||
"""
|
||||
tags = set()
|
||||
for chooser in self.choosers:
|
||||
tags.update(chooser.get_interesting_tags(type, zoom))
|
||||
return tags
|
||||
|
||||
def get_sql_hints(self, type=None, zoom=None):
|
||||
"""
|
||||
Get set of interesting tags.
|
||||
"""
|
||||
hints = []
|
||||
for chooser in self.choosers:
|
||||
p = chooser.get_sql_hints(type, zoom)
|
||||
if p:
|
||||
if p[0] and p[1]:
|
||||
hints.append(p)
|
||||
return hints
|
||||
"""
|
||||
Get set of interesting tags.
|
||||
"""
|
||||
hints = []
|
||||
for chooser in self.choosers:
|
||||
p = chooser.get_sql_hints(type, zoom)
|
||||
if p:
|
||||
if p[0] and p[1]:
|
||||
hints.append(p)
|
||||
return hints
|
||||
|
||||
|
||||
def parse(self, css):
|
||||
"""
|
||||
Parses MapCSS given as string
|
||||
"""
|
||||
if not self.style_loaded:
|
||||
self.choosers = []
|
||||
log = logging.getLogger('mapcss.parser')
|
||||
previous = 0 # what was the previous CSS word?
|
||||
sc=StyleChooser(self.scalepair) #currently being assembled
|
||||
#choosers=[]
|
||||
#o = []
|
||||
while (css):
|
||||
"""
|
||||
Parses MapCSS given as string
|
||||
"""
|
||||
if not self.style_loaded:
|
||||
self.choosers = []
|
||||
log = logging.getLogger('mapcss.parser')
|
||||
previous = 0 # what was the previous CSS word?
|
||||
sc=StyleChooser(self.scalepair) #currently being assembled
|
||||
#choosers=[]
|
||||
#o = []
|
||||
while (css):
|
||||
|
||||
# CSS comment
|
||||
if COMMENT.match(css):
|
||||
# CSS comment
|
||||
if COMMENT.match(css):
|
||||
log.debug("comment found")
|
||||
css=COMMENT.sub("", css)
|
||||
|
||||
#// Whitespace (probably only at beginning of file)
|
||||
elif WHITESPACE.match(css):
|
||||
#// Whitespace (probably only at beginning of file)
|
||||
elif WHITESPACE.match(css):
|
||||
log.debug("whitespace found")
|
||||
css=WHITESPACE.sub("",css)
|
||||
|
||||
#// Class - .motorway, .builtup, :hover
|
||||
elif CLASS.match(css):
|
||||
#// Class - .motorway, .builtup, :hover
|
||||
elif CLASS.match(css):
|
||||
if previous==oDECLARATION:
|
||||
self.choosers.append(sc)
|
||||
sc = StyleChooser(self.scalepair)
|
||||
|
||||
self.choosers.append(sc)
|
||||
sc = StyleChooser(self.scalepair)
|
||||
|
||||
cond = CLASS.match(css).groups()[0]
|
||||
log.debug("class found: %s"% (cond))
|
||||
css = CLASS.sub("", css)
|
||||
|
@ -252,11 +249,11 @@ class MapCSS():
|
|||
sc.addCondition(Condition('eq',("::class",cond)))
|
||||
previous=oCONDITION;
|
||||
|
||||
#// Not class - !.motorway, !.builtup, !:hover
|
||||
elif NOT_CLASS.match(css):
|
||||
#// Not class - !.motorway, !.builtup, !:hover
|
||||
elif NOT_CLASS.match(css):
|
||||
if (previous==oDECLARATION):
|
||||
self.choosers.append(sc)
|
||||
sc = StyleChooser(self.scalepair)
|
||||
self.choosers.append(sc)
|
||||
sc = StyleChooser(self.scalepair)
|
||||
|
||||
cond = NOT_CLASS.match(css).groups()[0]
|
||||
log.debug("not_class found: %s"% (cond))
|
||||
|
@ -267,10 +264,10 @@ class MapCSS():
|
|||
#sc.addCondition(new Condition('unset',o[1]));
|
||||
#previous=oCONDITION;
|
||||
|
||||
#// Zoom
|
||||
elif ZOOM.match(css):
|
||||
#// Zoom
|
||||
elif ZOOM.match(css):
|
||||
if (previous!=oOBJECT & previous!=oCONDITION):
|
||||
sc.newObject()
|
||||
sc.newObject()
|
||||
|
||||
cond = ZOOM.match(css).groups()[0]
|
||||
log.debug("zoom found: %s"% (cond))
|
||||
|
@ -278,144 +275,144 @@ class MapCSS():
|
|||
sc.addZoom(self.parseZoom(cond))
|
||||
previous=oZOOM;
|
||||
|
||||
#// Grouping - just a comma
|
||||
elif GROUP.match(css):
|
||||
#// Grouping - just a comma
|
||||
elif GROUP.match(css):
|
||||
css=GROUP.sub("",css)
|
||||
sc.newGroup()
|
||||
previous=oGROUP
|
||||
|
||||
#// Condition - [highway=primary]
|
||||
elif CONDITION.match(css):
|
||||
#// Condition - [highway=primary]
|
||||
elif CONDITION.match(css):
|
||||
if (previous==oDECLARATION):
|
||||
self.choosers.append(sc)
|
||||
sc = StyleChooser(self.scalepair)
|
||||
self.choosers.append(sc)
|
||||
sc = StyleChooser(self.scalepair)
|
||||
if (previous!=oOBJECT) and (previous!=oZOOM) and (previous!=oCONDITION):
|
||||
sc.newObject()
|
||||
sc.newObject()
|
||||
cond = CONDITION.match(css).groups()[0]
|
||||
log.debug("condition found: %s"% (cond))
|
||||
css=CONDITION.sub("",css)
|
||||
sc.addCondition(parseCondition(cond))
|
||||
previous=oCONDITION;
|
||||
|
||||
#// Object - way, node, relation
|
||||
elif OBJECT.match(css):
|
||||
#// Object - way, node, relation
|
||||
elif OBJECT.match(css):
|
||||
if (previous==oDECLARATION):
|
||||
self.choosers.append(sc)
|
||||
sc = StyleChooser(self.scalepair)
|
||||
self.choosers.append(sc)
|
||||
sc = StyleChooser(self.scalepair)
|
||||
obj = OBJECT.match(css).groups()[0]
|
||||
log.debug("object found: %s"% (obj))
|
||||
css=OBJECT.sub("",css)
|
||||
sc.newObject(obj)
|
||||
previous=oOBJECT
|
||||
|
||||
#// Declaration - {...}
|
||||
elif DECLARATION.match(css):
|
||||
#// Declaration - {...}
|
||||
elif DECLARATION.match(css):
|
||||
decl = DECLARATION.match(css).groups()[0]
|
||||
log.debug("declaration found: %s"% (decl))
|
||||
sc.addStyles(parseDeclaration(decl))
|
||||
css=DECLARATION.sub("",css)
|
||||
previous=oDECLARATION
|
||||
|
||||
#// Unknown pattern
|
||||
elif UNKNOWN.match(css):
|
||||
#// Unknown pattern
|
||||
elif UNKNOWN.match(css):
|
||||
log.warning("unknown thing found: %s"%(UNKNOWN.match(css).group()))
|
||||
css=UNKNOWN.sub("",css)
|
||||
|
||||
else:
|
||||
else:
|
||||
log.warning("choked on: %s"%(css))
|
||||
return
|
||||
return
|
||||
|
||||
if (previous==oDECLARATION):
|
||||
self.choosers.append(sc)
|
||||
sc= StyleChooser(self.scalepair)
|
||||
if (previous==oDECLARATION):
|
||||
self.choosers.append(sc)
|
||||
sc= StyleChooser(self.scalepair)
|
||||
|
||||
|
||||
|
||||
|
||||
def parseCondition(s):
|
||||
log = logging.getLogger('mapcss.parser.condition')
|
||||
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):
|
||||
a = CONDITION_invTRUE.match(s).groups()
|
||||
log.debug("condition invtrue: %s"%(a[0]))
|
||||
return Condition('ne' ,(a[0],"yes"))
|
||||
log = logging.getLogger('mapcss.parser.condition')
|
||||
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):
|
||||
a = CONDITION_invTRUE.match(s).groups()
|
||||
log.debug("condition invtrue: %s"%(a[0]))
|
||||
return Condition('ne' ,(a[0],"yes"))
|
||||
|
||||
if CONDITION_FALSE.match(s):
|
||||
a = CONDITION_FALSE.match(s).groups()
|
||||
log.debug("condition false: %s"%(a[0]))
|
||||
return Condition('false' ,a)
|
||||
if CONDITION_FALSE.match(s):
|
||||
a = CONDITION_FALSE.match(s).groups()
|
||||
log.debug("condition false: %s"%(a[0]))
|
||||
return Condition('false' ,a)
|
||||
|
||||
if CONDITION_SET.match(s):
|
||||
a = CONDITION_SET.match(s).groups()
|
||||
log.debug("condition set: %s"%(a))
|
||||
return Condition('set' ,a)
|
||||
if CONDITION_SET.match(s):
|
||||
a = CONDITION_SET.match(s).groups()
|
||||
log.debug("condition set: %s"%(a))
|
||||
return Condition('set' ,a)
|
||||
|
||||
if CONDITION_UNSET.match(s):
|
||||
a = CONDITION_UNSET.match(s).groups()
|
||||
log.debug("condition unset: %s"%(a))
|
||||
return Condition('unset' ,a)
|
||||
if CONDITION_UNSET.match(s):
|
||||
a = CONDITION_UNSET.match(s).groups()
|
||||
log.debug("condition unset: %s"%(a))
|
||||
return Condition('unset' ,a)
|
||||
|
||||
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)
|
||||
## FIXME: convert other conditions to python
|
||||
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)
|
||||
## FIXME: convert other conditions to python
|
||||
|
||||
if CONDITION_LE.match(s):
|
||||
a = CONDITION_LE.match(s).groups()
|
||||
log.debug("condition LE: %s <= %s"%(a[0], a[1]))
|
||||
return Condition('<=' ,a)
|
||||
if CONDITION_LE.match(s):
|
||||
a = CONDITION_LE.match(s).groups()
|
||||
log.debug("condition LE: %s <= %s"%(a[0], a[1]))
|
||||
return Condition('<=' ,a)
|
||||
|
||||
if CONDITION_GE.match(s):
|
||||
a = CONDITION_GE.match(s).groups()
|
||||
log.debug("condition GE: %s >= %s"%(a[0], a[1]))
|
||||
return Condition('>=' ,a)
|
||||
if CONDITION_GE.match(s):
|
||||
a = CONDITION_GE.match(s).groups()
|
||||
log.debug("condition GE: %s >= %s"%(a[0], a[1]))
|
||||
return Condition('>=' ,a)
|
||||
|
||||
if CONDITION_LT.match(s):
|
||||
a = CONDITION_LT.match(s).groups()
|
||||
log.debug("condition LT: %s < %s"%(a[0], a[1]))
|
||||
return Condition('<' ,a)
|
||||
if CONDITION_LT.match(s):
|
||||
a = CONDITION_LT.match(s).groups()
|
||||
log.debug("condition LT: %s < %s"%(a[0], a[1]))
|
||||
return Condition('<' ,a)
|
||||
|
||||
if CONDITION_GT.match(s):
|
||||
a = CONDITION_GT.match(s).groups()
|
||||
log.debug("condition GT: %s > %s"%(a[0], a[1]))
|
||||
return Condition('>' ,a)
|
||||
if CONDITION_GT.match(s):
|
||||
a = CONDITION_GT.match(s).groups()
|
||||
log.debug("condition GT: %s > %s"%(a[0], a[1]))
|
||||
return Condition('>' ,a)
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
else:
|
||||
log.warning("condition UNKNOWN: %s"%(s))
|
||||
else:
|
||||
log.warning("condition UNKNOWN: %s"%(s))
|
||||
|
||||
|
||||
def parseDeclaration(s):
|
||||
"""
|
||||
Parse declaration string into list of styles
|
||||
"""
|
||||
styles=[]
|
||||
t = {}
|
||||
"""
|
||||
Parse declaration string into list of styles
|
||||
"""
|
||||
styles=[]
|
||||
t = {}
|
||||
|
||||
for a in s.split(';'):
|
||||
#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]) )
|
||||
else:
|
||||
logging.debug("unknown %s" % (a) )
|
||||
return [t]
|
||||
for a in s.split(';'):
|
||||
#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]) )
|
||||
else:
|
||||
logging.debug("unknown %s" % (a) )
|
||||
return [t]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
mc = MapCSS(0,19)
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
mc = MapCSS(0,19)
|
||||
|
|
|
@ -196,7 +196,7 @@ def _reversedict(d):
|
|||
"""
|
||||
Internal helper for generating reverse mappings; given a
|
||||
dictionary, returns a new dictionary with keys and values swapped.
|
||||
|
||||
|
||||
"""
|
||||
return dict(zip(d.values(), d.keys()))
|
||||
|
||||
|
@ -407,22 +407,22 @@ def normalize_hex(hex_value):
|
|||
"""
|
||||
Normalize a hexadecimal color value to the following form and
|
||||
return the result::
|
||||
|
||||
|
||||
#[a-f0-9]{6}
|
||||
|
||||
|
||||
In other words, the following transformations are applied as
|
||||
needed:
|
||||
|
||||
|
||||
* If the value contains only three hexadecimal digits, it is
|
||||
expanded to six.
|
||||
|
||||
|
||||
* The value is normalized to lower-case.
|
||||
|
||||
|
||||
If the supplied value cannot be interpreted as a hexadecimal color
|
||||
value, ``ValueError`` is raised.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> normalize_hex('#09c')
|
||||
'#0099cc'
|
||||
>>> normalize_hex('#0099cc')
|
||||
|
@ -447,7 +447,7 @@ def normalize_hex(hex_value):
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: '#0' is not a valid hexadecimal color value.
|
||||
|
||||
|
||||
"""
|
||||
try:
|
||||
hex_digits = HEX_COLOR_RE.match(hex_value).groups()[0]
|
||||
|
@ -466,18 +466,18 @@ def normalize_hex(hex_value):
|
|||
def name_to_hex(name, spec='css3'):
|
||||
"""
|
||||
Convert a color name to a normalized hexadecimal color value.
|
||||
|
||||
|
||||
The optional keyword argument ``spec`` determines which
|
||||
specification's list of color names will be used; valid values are
|
||||
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
|
||||
``css3``.
|
||||
|
||||
|
||||
The color name will be normalized to lower-case before being
|
||||
looked up, and when no color of that name exists in the given
|
||||
specification, ``ValueError`` is raised.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> name_to_hex('deepskyblue')
|
||||
'#00bfff'
|
||||
>>> name_to_hex('DeepSkyBlue')
|
||||
|
@ -498,7 +498,7 @@ def name_to_hex(name, spec='css3'):
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: 'deepskyblue' is not defined as a named color in css2.
|
||||
|
||||
|
||||
"""
|
||||
if spec not in SUPPORTED_SPECIFICATIONS:
|
||||
raise TypeError("'%s' is not a supported specification for color name lookups; supported specifications are: %s." % (spec,
|
||||
|
@ -514,18 +514,18 @@ def name_to_rgb(name, spec='css3'):
|
|||
"""
|
||||
Convert a color name to a 3-tuple of integers suitable for use in
|
||||
an ``rgb()`` triplet specifying that color.
|
||||
|
||||
|
||||
The optional keyword argument ``spec`` determines which
|
||||
specification's list of color names will be used; valid values are
|
||||
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
|
||||
``css3``.
|
||||
|
||||
|
||||
The color name will be normalized to lower-case before being
|
||||
looked up, and when no color of that name exists in the given
|
||||
specification, ``ValueError`` is raised.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> name_to_rgb('navy')
|
||||
(0, 0, 128)
|
||||
>>> name_to_rgb('cadetblue')
|
||||
|
@ -534,7 +534,7 @@ def name_to_rgb(name, spec='css3'):
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: 'cadetblue' is not defined as a named color in html4.
|
||||
|
||||
|
||||
"""
|
||||
return hex_to_rgb(name_to_hex(name, spec=spec))
|
||||
|
||||
|
@ -542,25 +542,25 @@ def name_to_rgb_percent(name, spec='css3'):
|
|||
"""
|
||||
Convert a color name to a 3-tuple of percentages suitable for use
|
||||
in an ``rgb()`` triplet specifying that color.
|
||||
|
||||
|
||||
The optional keyword argument ``spec`` determines which
|
||||
specification's list of color names will be used; valid values are
|
||||
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
|
||||
``css3``.
|
||||
|
||||
|
||||
The color name will be normalized to lower-case before being
|
||||
looked up, and when no color of that name exists in the given
|
||||
specification, ``ValueError`` is raised.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> name_to_rgb_percent('white')
|
||||
('100%', '100%', '100%')
|
||||
>>> name_to_rgb_percent('navy')
|
||||
('0%', '0%', '50%')
|
||||
>>> name_to_rgb_percent('goldenrod')
|
||||
('85.49%', '64.71%', '12.5%')
|
||||
|
||||
|
||||
"""
|
||||
return rgb_to_rgb_percent(name_to_rgb(name, spec=spec))
|
||||
|
||||
|
@ -569,23 +569,23 @@ def name_to_rgb_percent(name, spec='css3'):
|
|||
# Conversions from hexadecimal color values to various formats.
|
||||
######################################################################
|
||||
|
||||
|
||||
|
||||
def hex_to_name(hex_value, spec='css3'):
|
||||
"""
|
||||
Convert a hexadecimal color value to its corresponding normalized
|
||||
color name, if any such name exists.
|
||||
|
||||
|
||||
The optional keyword argument ``spec`` determines which
|
||||
specification's list of color names will be used; valid values are
|
||||
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
|
||||
``css3``.
|
||||
|
||||
|
||||
The hexadecimal value will be normalized before being looked up,
|
||||
and when no color name for the value is found in the given
|
||||
specification, ``ValueError`` is raised.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> hex_to_name('#000080')
|
||||
'navy'
|
||||
>>> hex_to_name('#000080', spec='html4')
|
||||
|
@ -604,7 +604,7 @@ def hex_to_name(hex_value, spec='css3'):
|
|||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: 'css4' is not a supported specification for color name lookups; supported specifications are: html4, css2, css21, css3.
|
||||
|
||||
|
||||
"""
|
||||
if spec not in SUPPORTED_SPECIFICATIONS:
|
||||
raise TypeError("'%s' is not a supported specification for color name lookups; supported specifications are: %s." % (spec,
|
||||
|
@ -627,11 +627,11 @@ def hex_to_rgb(hex_value):
|
|||
"""
|
||||
Convert a hexadecimal color value to a 3-tuple of integers
|
||||
suitable for use in an ``rgb()`` triplet specifying that color.
|
||||
|
||||
|
||||
The hexadecimal value will be normalized before being converted.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> hex_to_rgb('#000080')
|
||||
(0, 0, 128)
|
||||
>>> hex_to_rgb('#ffff00')
|
||||
|
@ -640,7 +640,7 @@ def hex_to_rgb(hex_value):
|
|||
(255, 0, 0)
|
||||
>>> hex_to_rgb('#deb887')
|
||||
(222, 184, 135)
|
||||
|
||||
|
||||
"""
|
||||
hex_digits = normalize_hex(hex_value)
|
||||
return tuple(map(lambda s: int(s, 16),
|
||||
|
@ -650,16 +650,16 @@ def hex_to_rgb_percent(hex_value):
|
|||
"""
|
||||
Convert a hexadecimal color value to a 3-tuple of percentages
|
||||
suitable for use in an ``rgb()`` triplet representing that color.
|
||||
|
||||
|
||||
The hexadecimal value will be normalized before converting.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
>>> hex_to_rgb_percent('#ffffff')
|
||||
('100%', '100%', '100%')
|
||||
>>> hex_to_rgb_percent('#000080')
|
||||
('0%', '0%', '50%')
|
||||
|
||||
|
||||
"""
|
||||
return rgb_to_rgb_percent(hex_to_rgb(hex_value))
|
||||
|
||||
|
@ -674,23 +674,23 @@ def rgb_to_name(rgb_triplet, spec='css3'):
|
|||
Convert a 3-tuple of integers, suitable for use in an ``rgb()``
|
||||
color triplet, to its corresponding normalized color name, if any
|
||||
such name exists.
|
||||
|
||||
|
||||
The optional keyword argument ``spec`` determines which
|
||||
specification's list of color names will be used; valid values are
|
||||
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
|
||||
``css3``.
|
||||
|
||||
|
||||
If there is no matching name, ``ValueError`` is raised.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> rgb_to_name((0, 0, 0))
|
||||
'black'
|
||||
>>> rgb_to_name((0, 0, 128))
|
||||
'navy'
|
||||
>>> rgb_to_name((95, 158, 160))
|
||||
'cadetblue'
|
||||
|
||||
|
||||
"""
|
||||
return hex_to_name(rgb_to_hex(rgb_triplet), spec=spec)
|
||||
|
||||
|
@ -698,16 +698,16 @@ def rgb_to_hex(rgb_triplet):
|
|||
"""
|
||||
Convert a 3-tuple of integers, suitable for use in an ``rgb()``
|
||||
color triplet, to a normalized hexadecimal value for that color.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> rgb_to_hex((255, 255, 255))
|
||||
'#ffffff'
|
||||
>>> rgb_to_hex((0, 0, 128))
|
||||
'#000080'
|
||||
>>> rgb_to_hex((33, 56, 192))
|
||||
'#2138c0'
|
||||
|
||||
|
||||
"""
|
||||
return '#%02x%02x%02x' % rgb_triplet
|
||||
|
||||
|
@ -716,7 +716,7 @@ def rgb_to_rgb_percent(rgb_triplet):
|
|||
Convert a 3-tuple of integers, suitable for use in an ``rgb()``
|
||||
color triplet, to a 3-tuple of percentages suitable for use in
|
||||
representing that color.
|
||||
|
||||
|
||||
This function makes some trade-offs in terms of the accuracy of
|
||||
the final representation; for some common integer values,
|
||||
special-case logic is used to ensure a precise result (e.g.,
|
||||
|
@ -724,9 +724,9 @@ def rgb_to_rgb_percent(rgb_triplet):
|
|||
convert to '12.5%'), but for all other values a standard Python
|
||||
``float`` is used and rounded to two decimal places, which may
|
||||
result in a loss of precision for some values.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> rgb_to_rgb_percent((255, 255, 255))
|
||||
('100%', '100%', '100%')
|
||||
>>> rgb_to_rgb_percent((0, 0, 128))
|
||||
|
@ -735,7 +735,7 @@ def rgb_to_rgb_percent(rgb_triplet):
|
|||
('12.94%', '21.96%', '75.29%')
|
||||
>>> rgb_to_rgb_percent((64, 32, 16))
|
||||
('25%', '12.5%', '6.25%')
|
||||
|
||||
|
||||
"""
|
||||
# In order to maintain precision for common values,
|
||||
# 256 / 2**n is special-cased for values of n
|
||||
|
@ -756,23 +756,23 @@ def rgb_percent_to_name(rgb_percent_triplet, spec='css3'):
|
|||
Convert a 3-tuple of percentages, suitable for use in an ``rgb()``
|
||||
color triplet, to its corresponding normalized color name, if any
|
||||
such name exists.
|
||||
|
||||
|
||||
The optional keyword argument ``spec`` determines which
|
||||
specification's list of color names will be used; valid values are
|
||||
``html4``, ``css2``, ``css21`` and ``css3``, and the default is
|
||||
``css3``.
|
||||
|
||||
|
||||
If there is no matching name, ``ValueError`` is raised.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> rgb_percent_to_name(('0%', '0%', '0%'))
|
||||
'black'
|
||||
>>> rgb_percent_to_name(('0%', '0%', '50%'))
|
||||
'navy'
|
||||
>>> rgb_percent_to_name(('85.49%', '64.71%', '12.5%'))
|
||||
'goldenrod'
|
||||
|
||||
|
||||
"""
|
||||
return rgb_to_name(rgb_percent_to_rgb(rgb_percent_triplet), spec=spec)
|
||||
|
||||
|
@ -781,7 +781,7 @@ def rgb_percent_to_hex(rgb_percent_triplet):
|
|||
Convert a 3-tuple of percentages, suitable for use in an ``rgb()``
|
||||
color triplet, to a normalized hexadecimal color value for that
|
||||
color.
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
>>> rgb_percent_to_hex(('100%', '100%', '0%'))
|
||||
|
@ -790,7 +790,7 @@ def rgb_percent_to_hex(rgb_percent_triplet):
|
|||
'#000080'
|
||||
>>> rgb_percent_to_hex(('85.49%', '64.71%', '12.5%'))
|
||||
'#daa520'
|
||||
|
||||
|
||||
"""
|
||||
return rgb_to_hex(rgb_percent_to_rgb(rgb_percent_triplet))
|
||||
|
||||
|
@ -798,7 +798,7 @@ def _percent_to_integer(percent):
|
|||
"""
|
||||
Internal helper for converting a percentage value to an integer
|
||||
between 0 and 255 inclusive.
|
||||
|
||||
|
||||
"""
|
||||
num = float(percent.split('%')[0]) / 100.0 * 255
|
||||
e = num - math.floor(num)
|
||||
|
@ -809,16 +809,16 @@ def rgb_percent_to_rgb(rgb_percent_triplet):
|
|||
Convert a 3-tuple of percentages, suitable for use in an ``rgb()``
|
||||
color triplet, to a 3-tuple of integers suitable for use in
|
||||
representing that color.
|
||||
|
||||
|
||||
Some precision may be lost in this conversion. See the note
|
||||
regarding precision for ``rgb_to_rgb_percent()`` for details;
|
||||
generally speaking, the following is true for any 3-tuple ``t`` of
|
||||
integers in the range 0...255 inclusive::
|
||||
|
||||
|
||||
t == rgb_percent_to_rgb(rgb_to_rgb_percent(t))
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
>>> rgb_percent_to_rgb(('100%', '100%', '100%'))
|
||||
(255, 255, 255)
|
||||
>>> rgb_percent_to_rgb(('0%', '0%', '50%'))
|
||||
|
@ -827,39 +827,39 @@ def rgb_percent_to_rgb(rgb_percent_triplet):
|
|||
(64, 32, 16)
|
||||
>>> rgb_percent_to_rgb(('12.94%', '21.96%', '75.29%'))
|
||||
(33, 56, 192)
|
||||
|
||||
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
string = string.strip().lower()
|
||||
try:
|
||||
return name_to_rgb(string)
|
||||
except ValueError:
|
||||
"""
|
||||
Converts CSS3 color or a hex into rgb triplet; hash of string if fails.
|
||||
"""
|
||||
string = string.strip().lower()
|
||||
try:
|
||||
return hex_to_rgb(string)
|
||||
return name_to_rgb(string)
|
||||
except ValueError:
|
||||
try:
|
||||
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])
|
||||
try:
|
||||
return hex_to_rgb(string)
|
||||
except ValueError:
|
||||
try:
|
||||
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])
|
||||
|
||||
def whatever_to_hex(string):
|
||||
if type(string) == tuple:
|
||||
return cairo_to_hex(string).upper()
|
||||
return rgb_to_hex(whatever_to_rgb(string)).upper()
|
||||
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.,
|
||||
a = whatever_to_rgb(string)
|
||||
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,))
|
||||
|
||||
return rgb_to_hex((cairo[0]*255,cairo[1]*255,cairo[2]*255,))
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue