User coloring.

This commit is contained in:
Sergey Vartanov 2015-12-20 17:08:23 +03:00
parent 75aa8e4996
commit edef3a69f2
9 changed files with 465 additions and 327 deletions

View file

@ -1,4 +1,7 @@
Röntgen project focuses on displaying every [OpenStreetMap](http://openstreetmap.org) data tag on the map. <!-- PLEASE DO NOT EDIT THIS FILE.
IT WAS GENERATED BY MOIRE. -->
Röntgen project focuses on displaying every \[OpenStreetMap\](http://openstreetmap.org) data tag on the map.
Why do we need yet another map style? Why do we need yet another map style?
------------------------------------- -------------------------------------
@ -8,7 +11,7 @@ It is actually not just another map style since it is **not** *a map for users*
Map generation Map generation
-------------- --------------
![Sample map](doc/map.png) !\[Sample map\](doc/map.png)
**Requirements**: Python 2.7. **Requirements**: Python 2.7.
@ -28,13 +31,13 @@ There are simple Python renderer that generates SVG map from OpenStreetMap data.
</td></tr><tr><td><tt>-bbox</tt>, <tt>--boundary-box</tt> </td></tr><tr><td><tt>-bbox</tt>, <tt>--boundary-box</tt>
</td><td><tt>&lt;longitude 1&gt;,&lt;longitude 2&gt;,&lt;latitude 1&gt;,&lt;latitude 2&gt;</tt> (decimal float) </td><td><tt>,,,</tt> (decimal float)
</td><td>Boundary box to draw </td><td>Boundary box to draw
</td></tr><tr><td><tt>-s</tt>, <tt>--size</tt> </td></tr><tr><td><tt>-s</tt>, <tt>--size</tt>
</td><td><tt>&lt;width&gt;,&lt;height&gt;</tt> (pixels) </td><td><tt>,</tt> (pixels)
</td><td>Result image size </td><td>Result image size
@ -45,11 +48,13 @@ Icon set
If tag is drawable it is displayed using icon combination and colors. If tag is drawable it is displayed using icon combination and colors.
All icons are under [CC BY 4.0](http://creativecommons.org/licenses/by/4.0/) license. So, do whatever you want but give appropriate credit. All icons are under \[CC BY 4.0\](http://creativecommons.org/licenses/by/4.0/) license. So, do whatever you want but give appropriate credit.
Double size: Double size:
![Icons](doc/grid.png) !\[Icons\](doc/grid.png)
Feel free to request new icons via issues for whatever you want to see on the map. No matter how frequently the tag is used in OpenStreetMap since final goal is to cover all tags. However, common used tags have priority, other things being equal. Feel free to request new icons via issues for whatever you want to see on the map. No matter how frequently the tag is used in OpenStreetMap since final goal is to cover all tags. However, common used tags have priority, other things being equal.

View file

@ -220,12 +220,21 @@ tags:
color: deciduous color: deciduous
- tags: {natural: tree, leaf_cycle: evergreen} - tags: {natural: tree, leaf_cycle: evergreen}
color: evergreen color: evergreen
# Tree genus
- tags: {natural: tree, genus: Betula}
icon: [betula]
color: tree
# Tree over icons
- tags: {natural: tree, denotation: urban} - tags: {natural: tree, denotation: urban}
over_icon: [urban_tree_pot] over_icon: [urban_tree_pot]
under_icon: [tree, broadleaved, needleleaved] under_icon: [tree, broadleaved, needleleaved, betula]
- tags: {natural: tree, denotation: avenue} - tags: {natural: tree, denotation: avenue}
over_icon: [avenue_tree] over_icon: [avenue_tree]
under_icon: [tree, broadleaved, needleleaved] under_icon: [tree, broadleaved, needleleaved, betula]
# Entrance # Entrance

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 92 KiB

View file

@ -1,6 +1,6 @@
Röntgen project focuses on displaying every \href {http://openstreetmap.org} {OpenStreetMap} data tag on the map. Röntgen project focuses on displaying every \href {http://openstreetmap.org} {OpenStreetMap} data tag on the map.
\2 {Why do we need yet another map style?} \2 {Why do we need yet another map style?} {map_style}
It is actually not just another map style since it is \b {not} \i {a map for users} but \i {map for OpenStreetMap contributors}. Suppose, you spent time adding colors for building walls, benches and shelters for bus stops but they do not represented on the map. Röntgen helps to display all changes you made. It is actually not just another map style since it is \b {not} \i {a map for users} but \i {map for OpenStreetMap contributors}. Suppose, you spent time adding colors for building walls, benches and shelters for bus stops but they do not represented on the map. Röntgen helps to display all changes you made.
@ -15,7 +15,7 @@ There are simple Python renderer that generates SVG map from OpenStreetMap data.
\code \code
{python mapper.py -i <input OSM XML file name> -o <output SVG file name>} {python mapper.py -i <input OSM XML file name> -o <output SVG file name>}
\3 {Options} \3 {Options} {options}
\table \table
{ {
@ -32,7 +32,7 @@ There are simple Python renderer that generates SVG map from OpenStreetMap data.
} }
} }
\2 {Icon set} \2 {Icon set} {icons}
If tag is drawable it is displayed using icon combination and colors. If tag is drawable it is displayed using icon combination and colors.
@ -43,3 +43,4 @@ Double size:
\image {doc/grid.png} {Icons} \image {doc/grid.png} {Icons}
Feel free to request new icons via issues for whatever you want to see on the map. No matter how frequently the tag is used in OpenStreetMap since final goal is to cover all tags. However, common used tags have priority, other things being equal. Feel free to request new icons via issues for whatever you want to see on the map. No matter how frequently the tag is used in OpenStreetMap since final goal is to cover all tags. However, common used tags have priority, other things being equal.

View file

@ -27,7 +27,8 @@ sys.path.append('../lib')
import svg import svg
from vector import Vector from vector import Vector
background_color = 'DDDDDD' background_color = 'DDDDDD' # 'DDDDDD'
outline_color = 'FFFFFF'
beach_color = 'F0E0C0' beach_color = 'F0E0C0'
building_color = 'EEEEEE' # 'D0D0C0' building_color = 'EEEEEE' # 'D0D0C0'
building_border_color = 'C4C4C4' # 'AAAAAA' building_border_color = 'C4C4C4' # 'AAAAAA'
@ -86,8 +87,10 @@ prefix_to_write = set(['addr', 'contact', 'name', 'operator', 'wikipedia',
# To draw # To draw
'species', 'taxon', 'genus']) 'species', 'taxon', 'genus'])
tags_to_skip = set(['note', 'layer', 'source', 'building:part', 'fixme', 'comment', tags_to_skip = set(['note', 'layer', 'source', 'building:part', 'fixme',
'FIXME', 'source_ref', 'naptan:verified:note', 'building:levels']) 'comment', 'FIXME', 'source_ref', 'naptan:verified:note',
'building:levels', 'ref:opendataparis:adresse',
'ref:opendataparis:geo_point_2d', 'created_by'])
prefix_to_skip = set(['source']) prefix_to_skip = set(['source'])
@ -144,7 +147,6 @@ def draw_point_shape(name, x, y, fill):
def draw_point_outline(shape, x, y, fill, size=16, xx=0, yy=0): def draw_point_outline(shape, x, y, fill, size=16, xx=0, yy=0):
x = int(float(x)) x = int(float(x))
y = int(float(y)) y = int(float(y))
outline_fill = 'FFFFFF'
opacity = 0.5 opacity = 0.5
r = int(fill[0:2], 16) r = int(fill[0:2], 16)
g = int(fill[2:4], 16) g = int(fill[2:4], 16)
@ -154,8 +156,8 @@ def draw_point_outline(shape, x, y, fill, size=16, xx=0, yy=0):
outline_fill = '000000' outline_fill = '000000'
opacity = 0.3 opacity = 0.3
output_file.write('<path d="' + shape + \ output_file.write('<path d="' + shape + \
'" style="fill:#' + outline_fill + ';opacity:' + str(opacity) + ';' + \ '" style="fill:#' + outline_color + ';opacity:' + str(opacity) + ';' + \
'stroke:#' + outline_fill + ';stroke-width:3;stroke-linejoin:round;" ' + \ 'stroke:#' + outline_color + ';stroke-width:3;stroke-linejoin:round;" ' + \
'transform="translate(' + \ 'transform="translate(' + \
str(x - size / 2.0 - xx * 16) + ',' + str(y - size / 2.0 - yy * 16) + ')" />\n') str(x - size / 2.0 - xx * 16) + ',' + str(y - size / 2.0 - yy * 16) + ')" />\n')
@ -181,7 +183,7 @@ def point(k, v, x, y, fill, text_y):
text = text.encode('utf-8') text = text.encode('utf-8')
draw_text(text, x, float(y) + text_y + 18, '734A08') draw_text(text, x, float(y) + text_y + 18, '734A08')
def construct_text(tags): def construct_text(tags, processed):
for key in tags: for key in tags:
tags[key] = tags[key].replace('&quot;', '"') tags[key] = tags[key].replace('&quot;', '"')
texts = [] texts = []
@ -193,13 +195,13 @@ def construct_text(tags):
tags.pop('name', None) tags.pop('name', None)
if 'name:ru' in tags: if 'name:ru' in tags:
if not name: if not name:
name = tags['name'] name = tags['name:ru']
tags.pop('name', None) tags.pop('name:ru', None)
tags.pop('name:ru', None) tags.pop('name:ru', None)
if 'name:en' in tags: if 'name:en' in tags:
if not name: if not name:
name = tags['name'] name = tags['name:en']
tags.pop('name', None) tags.pop('name:en', None)
tags.pop('name:en', None) tags.pop('name:en', None)
if 'alt_name' in tags: if 'alt_name' in tags:
if alt_name: if alt_name:
@ -239,8 +241,8 @@ def construct_text(tags):
else: else:
addr = '' addr = ''
street = tags['addr:street'] street = tags['addr:street']
if street[:6] == 'улица ': if street.startswith('улица '):
street = 'ул. ' + street[6:] street = 'ул. ' + street[len('улица '):]
addr += street addr += street
tags.pop('addr:street', None) tags.pop('addr:street', None)
if 'addr:housenumber' in tags: if 'addr:housenumber' in tags:
@ -280,7 +282,7 @@ def construct_text(tags):
texts.append({'text': tags[k], 'fill': '444444'}) texts.append({'text': tags[k], 'fill': '444444'})
tags.pop(k) tags.pop(k)
for tag in tags: for tag in tags:
if to_write(tag): if to_write(tag) and not (tag in processed):
#texts.append({'text': tag + ': ' + tags[tag]}) #texts.append({'text': tag + ': ' + tags[tag]})
texts.append({'text': tags[tag]}) texts.append({'text': tags[tag]})
return texts return texts
@ -298,6 +300,7 @@ def draw_raw_ways():
way = way_map[way_id] way = way_map[way_id]
draw_path(way['nodes'], 'stroke:#FFFFFF;fill:none;stroke-width:0.2;') draw_path(way['nodes'], 'stroke:#FFFFFF;fill:none;stroke-width:0.2;')
def line_center(node_ids): def line_center(node_ids):
ma = Vector() ma = Vector()
mi = Vector(10000, 10000) mi = Vector(10000, 10000)
@ -311,244 +314,276 @@ def line_center(node_ids):
return Vector((ma.x + mi.x) / 2.0, (ma.y + mi.y) / 2.0) return Vector((ma.x + mi.x) / 2.0, (ma.y + mi.y) / 2.0)
def get_float(string):
try:
return float(string)
except ValueError:
return 0
def get_user_color(user):
if user == '':
return '000000'
rgb = hex(abs(hash(options.seed + user)))[-6:]
r = int(rgb[0:2], 16)
g = int(rgb[2:4], 16)
b = int(rgb[4:6], 16)
c = (r + g + b) / 3.
cc = 0
r = r * (1 - cc) + c * cc
g = g * (1 - cc) + c * cc
b = b * (1 - cc) + c * cc
h = hex(int(r))[2:] + hex(int(g))[2:] + hex(int(b))[2:]
return '0' * (6 - len(h)) + h
def construct_ways(drawing): def construct_ways(drawing):
for way_id in way_map: for way_id in way_map:
way = way_map[way_id] way = way_map[way_id]
construct_way(drawing, way['nodes'], way['tags'], None) user = way['user'] if 'user' in way else ''
construct_way(drawing, way['nodes'], way['tags'], None, user)
def construct_way(drawing, nodes, tags, path):
is_area = None def construct_way(drawing, nodes, tags, path, user):
is_area = None
if nodes:
is_area = nodes[0] == nodes[-1]
layer = 0
if 'layer' in tags:
layer = get_float(tags['layer'])
if nodes:
c = line_center(nodes)
user_color = get_user_color(user)
if options.user_coloring:
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'path': path,
'style': 'fill:none;stroke:#' + user_color + ';stroke-width:1.5;'})
return
if 'natural' in tags:
v = tags['natural']
style = 'stroke:none;'
if v == 'wood':
style += 'fill:#' + wood_color + ';'
layer += 0.2
elif v == 'scrub':
style += 'fill:#' + wood_color + ';'
layer += 0.2
elif v == 'sand':
style += 'fill:#' + sand_color + ';'
layer += 0.1
elif v == 'beach':
style += 'fill:#' + beach_color + ';'
layer += 0.1
elif v == 'desert':
style += 'fill:#' + desert_color + ';'
layer += 0.1
elif v == 'forest':
style += 'fill:#' + wood_color + ';'
layer += 0.2
elif v == 'tree_row':
style += 'fill:none;stroke:#' + wood_color + ';stroke-width:5;'
layer += 0.2
elif v == 'water':
style = 'fill:#' + water_color + ';stroke:#' + \
water_border_color + ';stroke-width:1.0;'
layer += 0.2
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
'priority': 50, 'style': style, 'path': path})
if 'landuse' in tags:
style = 'fill:none;stroke:none;'
if tags['landuse'] == 'grass':
style = 'fill:#' + grass_color + ';stroke:#' + grass_border_color + ';'
layer += 0.1
elif tags['landuse'] == 'conservation':
style = 'fill:#' + grass_color + ';stroke:none;'
layer += 0.1
elif tags['landuse'] == 'forest':
style = 'fill:#' + wood_color + ';stroke:none;'
layer += 0.2
elif tags['landuse'] == 'garages':
style = 'fill:#' + parking_color + ';stroke:none;'
layer += 0.2
shapes, fill, processed = \
process.get_icon(tags, scheme, '444444')
if nodes:
drawing['nodes'].append({'shapes': shapes, 'tags': tags,
'x': c.x, 'y': c.y, 'color': fill, 'path': path,
'processed': processed})
elif tags['landuse'] == 'construction':
layer += 0.1
style = 'fill:#' + construction_color + ';stroke:none;'
elif tags['landuse'] in ['residential', 'commercial']:
return
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
'priority': 50, 'style': style, 'path': path})
if 'building' in tags:
style = 'fill:none;stroke:none;'
text_y = 0
layer += 0.6
style = 'fill:#' + building_color + ';stroke:#' + \
building_border_color + ';opacity:1.0;'
shapes, fill, processed = process.get_icon(tags, scheme, '444444')
if 'height' in tags:
layer += float(tags['height'])
if nodes: if nodes:
is_area = nodes[0] == nodes[-1] drawing['nodes'].append({'shapes': shapes, 'x': c.x, 'y': c.y,
layer = float(tags['layer']) if ('layer' in tags) else 0 'color': fill, 'priority': 1, 'processed': processed,
if nodes: 'tags': tags, 'path': path})
c = line_center(nodes) drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
if 'natural' in tags: 'priority': 50, 'style': style, 'path': path})
v = tags['natural'] if 'amenity' in tags:
style = 'stroke:none;' style = 'fill:none;stroke:none;'
if v == 'wood': layer += 0.2
style += 'fill:#' + wood_color + ';' if tags['amenity'] == 'parking':
layer += 0.2 style = 'fill:#' + parking_color + ';stroke:none;opacity:0.5;'
elif v == 'scrub':
style += 'fill:#' + wood_color + ';'
layer += 0.2
elif v == 'sand':
style += 'fill:#' + sand_color + ';'
layer += 0.1
elif v == 'beach':
style += 'fill:#' + beach_color + ';'
layer += 0.1
elif v == 'desert':
style += 'fill:#' + desert_color + ';'
layer += 0.1
elif v == 'forest':
style += 'fill:#' + wood_color + ';'
layer += 0.2
elif v == 'tree_row':
style += 'fill:none;stroke:#' + wood_color + ';stroke-width:5;'
layer += 0.2
elif v == 'water':
style = 'fill:#' + water_color + ';stroke:#' + \
water_border_color + ';stroke-width:1.0;'
layer += 0.2
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
'priority': 50, 'style': style, 'path': path})
if 'landuse' in tags:
style = 'fill:none;stroke:none;'
if tags['landuse'] == 'grass':
style = 'fill:#' + grass_color + ';stroke:#' + grass_border_color + ';'
layer += 0.1
elif tags['landuse'] == 'conservation':
style = 'fill:#' + grass_color + ';stroke:none;'
layer += 0.1
elif tags['landuse'] == 'forest':
style = 'fill:#' + wood_color + ';stroke:none;'
layer += 0.2
elif tags['landuse'] == 'garages':
style = 'fill:#' + parking_color + ';stroke:none;'
layer += 0.2
shapes, fill, processed = \
process.get_icon(tags, scheme, '444444')
if nodes:
drawing['nodes'].append({'shapes': shapes, 'tags': tags,
'x': c.x, 'y': c.y, 'color': fill, 'path': path,
'processed': processed})
elif tags['landuse'] == 'construction':
layer += 0.1
style = 'fill:#' + construction_color + ';stroke:none;'
elif tags['landuse'] in ['residential', 'commercial']:
return
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
'priority': 50, 'style': style, 'path': path})
if 'building' in tags:
style = 'fill:none;stroke:none;'
text_y = 0
layer += 0.6
style = 'fill:#' + building_color + ';stroke:#' + \
building_border_color + ';opacity:1.0;'
shapes, fill, processed = process.get_icon(tags, scheme, '444444') shapes, fill, processed = process.get_icon(tags, scheme, '444444')
if 'height' in tags:
layer += float(tags['height'])
if nodes: if nodes:
drawing['nodes'].append({'shapes': shapes, 'x': c.x, 'y': c.y, drawing['nodes'].append({'shapes': shapes, 'x': c.x, 'y': c.y,
'color': fill, 'priority': 1, 'processed': processed, 'color': fill, 'priority': 1, 'processed': processed,
'tags': tags, 'path': path}) 'tags': tags, 'path': path})
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
'priority': 50, 'style': style, 'path': path}) 'priority': 50, 'style': style, 'path': path})
if 'amenity' in tags: if 'waterway' in tags:
style = 'fill:none;stroke:none;' style = 'fill:none;stroke:none;'
layer += 0.2 layer += 0.2
if tags['amenity'] == 'parking': if tags['waterway'] == 'riverbank':
style = 'fill:#' + parking_color + ';stroke:none;opacity:0.5;' style = 'fill:#' + water_color + ';stroke:#' + \
shapes, fill, processed = process.get_icon(tags, scheme, '444444') water_border_color + ';stroke-width:1.0;'
if nodes: elif tags['waterway'] == 'river':
drawing['nodes'].append({'shapes': shapes, 'x': c.x, 'y': c.y, style = 'fill:none;stroke:#' + water_color + ';stroke-width:10.0;'
'color': fill, 'priority': 1, 'processed': processed, drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
'tags': tags, 'path': path}) 'priority': 50, 'style': style, 'path': path})
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, if 'railway' in tags:
'priority': 50, 'style': style, 'path': path}) style = 'fill:none;stroke:none;'
if 'waterway' in tags: layer += 0.45
style = 'fill:none;stroke:none;' v = tags['railway']
layer += 0.2 style = 'fill:none;stroke-dasharray:none;stroke-linejoin:round;' + \
if tags['waterway'] == 'riverbank': 'stroke-linecap:round;stroke-width:'
style = 'fill:#' + water_color + ';stroke:#' + \ if v == 'subway': style += '10;stroke:#DDDDDD;'
water_border_color + ';stroke-width:1.0;' if v in ['narrow_gauge', 'tram']:
elif tags['waterway'] == 'river': style += '2;stroke:#000000;'
style = 'fill:none;stroke:#' + water_color + ';stroke-width:10.0;' else:
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, return
'priority': 50, 'style': style, 'path': path}) drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
if 'railway' in tags: 'priority': 50, 'style': style, 'path': path})
style = 'fill:none;stroke:none;' if 'highway' in tags:
layer += 0.45 style = 'fill:none;stroke:none;'
v = tags['railway'] layer += 0.4
style = 'fill:none;stroke-dasharray:none;stroke-linejoin:round;' + \ v = tags['highway']
'stroke-linecap:round;stroke-width:' if 'tunnel' in tags and tags['tunnel'] == 'yes':
if v == 'subway': style += '10;stroke:#DDDDDD;' style = 'fill:none;stroke:#FFFFFF;stroke-dasharray:none;' + \
if v in ['narrow_gauge', 'tram']: 'stroke-linejoin:round;stroke-linecap:round;stroke-width:10;'
style += '2;stroke:#000000;' drawing['ways'].append({'kind': 'way', 'nodes': nodes,
'layer': layer - 100, 'priority': 50, 'style': style,
'path': path})
style = 'fill:none;stroke:#' + road_border_color + \
';stroke-dasharray:none;' + \
'stroke-linejoin:round;stroke-linecap:round;stroke-width:'
if v == 'motorway': style += '30'
elif v == 'trunk': style += '25'
elif v == 'primary': style += '20;stroke:#' + primary_border_color
elif v == 'secondary': style += '13'
elif v == 'tertiary': style += '25'
elif v == 'unclassified': style += '17'
elif v == 'residential': style += '17'
elif v == 'service':
if 'service' in tags and tags['service'] == 'parking_aisle':
style += '7'
else: else:
return style += '11'
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, elif v == 'track': style += '3'
'priority': 50, 'style': style, 'path': path}) elif v in ['footway', 'pedestrian', 'cycleway']: style += '3;stroke:#' + foot_border_color
if 'highway' in tags: else: style = None
style = 'fill:none;stroke:none;' if style:
layer += 0.4
v = tags['highway']
if 'tunnel' in tags and tags['tunnel'] == 'yes':
style = 'fill:none;stroke:#FFFFFF;stroke-dasharray:none;' + \
'stroke-linejoin:round;stroke-linecap:round;stroke-width:10;'
drawing['ways'].append({'kind': 'way', 'nodes': nodes,
'layer': layer - 100, 'priority': 50, 'style': style,
'path': path})
style = 'fill:none;stroke:#' + road_border_color + \
';stroke-dasharray:none;' + \
'stroke-linejoin:round;stroke-linecap:round;stroke-width:'
if v == 'motorway': style += '30'
elif v == 'trunk': style += '25'
elif v == 'primary': style += '20;stroke:#' + primary_border_color
elif v == 'secondary': style += '13'
elif v == 'tertiary': style += '25'
elif v == 'unclassified': style += '17'
elif v == 'residential': style += '17'
elif v == 'service':
if 'service' in tags and tags['service'] == 'parking_aisle':
style += '7'
else:
style += '11'
elif v == 'track': style += '3'
elif v in ['footway', 'pedestrian', 'cycleway']: style += '3;stroke:#' + foot_border_color
else: style = None
if style:
style += ';'
drawing['ways'].append({'kind': 'way', 'nodes': nodes,
'layer': layer - 0.1, 'priority': 50, 'style': style,
'path': path})
style = 'fill:none;stroke:#FFFFFF;stroke-linecap:round;' + \
'stroke-linejoin:round;stroke-width:'
if v == 'motorway': style += '28'
elif v == 'trunk': style += '23'
elif v == 'primary': style += '19;stroke:#' + primary_color
elif v == 'secondary': style += '11'
elif v == 'tertiary': style += '23'
elif v == 'unclassified': style += '15'
elif v == 'residential': style += '15'
elif v == 'service':
if 'service' in tags and tags['service'] == 'parking_aisle':
style += '5'
else:
style += '9'
elif v == 'cycleway':
style += '1;stroke-dasharray:8,2;istroke-linecap:butt;' + \
'stroke:#' + cycle_color
elif v in ['footway', 'pedestrian']:
if 'area' in tags and tags['area'] == 'yes':
style += '1;stroke:none;fill:#DDDDDD'
else:
style += '1.5;stroke-dasharray:8,2;stroke-linecap:butt;' + \
'stroke:#' + foot_color
elif v == 'steps':
style += '5;stroke-dasharray:1,2;stroke-linecap:butt;' + \
'stroke:#' + foot_color
elif v == 'path':
style += '1;stroke-dasharray:5,5;stroke-linecap:butt;' + \
'stroke:#' + foot_color
style += ';' style += ';'
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, drawing['ways'].append({'kind': 'way', 'nodes': nodes,
'priority': 50, 'style': style, 'path': path}) 'layer': layer - 0.1, 'priority': 50, 'style': style,
if 'access' in tags and tags['access'] == 'private': 'path': path})
drawing['ways'].append({'kind': 'way', 'nodes': nodes,
'layer': layer + 0.1, 'priority': 50, 'path': path, style = 'fill:none;stroke:#FFFFFF;stroke-linecap:round;' + \
'style': 'fill:none;' + \ 'stroke-linejoin:round;stroke-width:'
'stroke:#' + private_access_color + ';' + \ if v == 'motorway': style += '28'
'stroke-linecap:butt;' + \ elif v == 'trunk': style += '23'
'stroke-width:10;stroke-dasharray:1,5;' + \ elif v == 'primary': style += '19;stroke:#' + primary_color
'opacity:0.4;'}) elif v == 'secondary': style += '11'
if 'leisure' in tags: elif v == 'tertiary': style += '23'
style = 'fill:none;stroke:none;' elif v == 'unclassified': style += '15'
layer += 0.2 elif v == 'residential': style += '15'
if tags['leisure'] == 'playground': elif v == 'service':
style = 'fill:#' + playground_color + ';opacity:0.2;' if 'service' in tags and tags['service'] == 'parking_aisle':
if nodes: style += '5'
draw_point_shape('toy_horse', c.x, c.y, '444444')
elif tags['leisure'] == 'garden':
style = 'fill:#' + grass_color + ';'
elif tags['leisure'] == 'pitch':
style = 'fill:#' + playground_color + ';opacity:0.2;'
elif tags['leisure'] == 'park':
return
else: else:
style = 'fill:#FF0000;opacity:0.2;' style += '9'
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, elif v == 'cycleway':
'priority': 50, 'style': style, 'path': path}) style += '1;stroke-dasharray:8,2;istroke-linecap:butt;' + \
if 'barrier' in tags: 'stroke:#' + cycle_color
style = 'fill:none;stroke:none;' elif v in ['footway', 'pedestrian']:
layer += 0.5 if 'area' in tags and tags['area'] == 'yes':
if tags['barrier'] == 'hedge': style += '1;stroke:none;fill:#DDDDDD'
style += 'fill:none;stroke:#' + wood_color + ';stroke-width:4;'
elif tags['barrier'] == 'fense':
style += 'fill:none;stroke:#000000;stroke-width:1;opacity:0.4;'
elif tags['barrier'] == 'kerb':
style += 'fill:none;stroke:#000000;stroke-width:1;opacity:0.2;'
else: else:
style += 'fill:none;stroke:#000000;stroke-width:1;opacity:0.3;' style += '1.5;stroke-dasharray:8,2;stroke-linecap:butt;' + \
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, 'stroke:#' + foot_color
'priority': 50, 'style': style, 'path': path}) elif v == 'steps':
if 'border' in tags: style += '5;stroke-dasharray:1,2;stroke-linecap:butt;' + \
style = 'fill:none;stroke:none;' 'stroke:#' + foot_color
style += 'fill:none;stroke:#FF0000;stroke-width:0.5;' + \ elif v == 'path':
'stroke-dahsarray:10,20;' style += '1;stroke-dasharray:5,5;stroke-linecap:butt;' + \
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, 'stroke:#' + foot_color
'priority': 50, 'style': style, 'path': path}) style += ';'
if 'area:highway' in tags: drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
style = 'fill:none;stroke:none;' 'priority': 50, 'style': style, 'path': path})
if tags['area:highway'] == 'yes': if 'access' in tags and tags['access'] == 'private':
style += 'fill:#FFFFFF;stroke:#DDDDDD;stroke-width:1;' drawing['ways'].append({'kind': 'way', 'nodes': nodes,
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, 'layer': layer + 0.1, 'priority': 50, 'path': path,
'priority': 50, 'style': style, 'path': path}) 'style': 'fill:none;' + \
#drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, 'stroke:#' + private_access_color + ';' + \
# 'priority': 50, 'style': style, 'path': path}) 'stroke-linecap:butt;' + \
'stroke-width:10;stroke-dasharray:1,5;' + \
'opacity:0.4;'})
if 'leisure' in tags:
style = 'fill:none;stroke:none;'
layer += 0.2
if tags['leisure'] == 'playground':
style = 'fill:#' + playground_color + ';opacity:0.2;'
if nodes:
draw_point_shape('toy_horse', c.x, c.y, '444444')
elif tags['leisure'] == 'garden':
style = 'fill:#' + grass_color + ';'
elif tags['leisure'] == 'pitch':
style = 'fill:#' + playground_color + ';opacity:0.2;'
elif tags['leisure'] == 'park':
return
else:
style = 'fill:#FF0000;opacity:0.2;'
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
'priority': 50, 'style': style, 'path': path})
if 'barrier' in tags:
style = 'fill:none;stroke:none;'
layer += 0.5
if tags['barrier'] == 'hedge':
style += 'fill:none;stroke:#' + wood_color + ';stroke-width:4;'
elif tags['barrier'] == 'fense':
style += 'fill:none;stroke:#000000;stroke-width:1;opacity:0.4;'
elif tags['barrier'] == 'kerb':
style += 'fill:none;stroke:#000000;stroke-width:1;opacity:0.2;'
else:
style += 'fill:none;stroke:#000000;stroke-width:1;opacity:0.3;'
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
'priority': 50, 'style': style, 'path': path})
if 'border' in tags:
style = 'fill:none;stroke:none;'
style += 'fill:none;stroke:#FF0000;stroke-width:0.5;' + \
'stroke-dahsarray:10,20;'
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
'priority': 50, 'style': style, 'path': path})
if 'area:highway' in tags:
style = 'fill:none;stroke:none;'
if tags['area:highway'] == 'yes':
style += 'fill:#FFFFFF;stroke:#DDDDDD;stroke-width:1;'
drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
'priority': 50, 'style': style, 'path': path})
#drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer,
# 'priority': 50, 'style': style, 'path': path})
def glue_ways(ways): def glue_ways(ways):
@ -616,7 +651,7 @@ def construct_relations(drawing):
way.reverse() way.reverse()
path = get_path(way) path = get_path(way)
p += path + ' ' p += path + ' '
construct_way(drawing, None, tags, p) construct_way(drawing, None, tags, p, '')
# Nodes drawing # Nodes drawing
@ -636,6 +671,8 @@ def no_draw(key):
return False return False
def to_write(key): def to_write(key):
if key in tags_to_skip:
return False
if key in tags_to_write: if key in tags_to_write:
return True return True
for prefix in prefix_to_write: for prefix in prefix_to_write:
@ -665,21 +702,25 @@ def draw_shapes(shapes, overlap, points, x, y, fill, show_missed_tags, tags,
draw_point_shape(shape, x + xxx, y, fill) draw_point_shape(shape, x + xxx, y, fill)
xxx += 16 xxx += 16
write_tags = construct_text(tags) if options.draw_captions:
write_tags = construct_text(tags, processed)
for text_struct in write_tags: for text_struct in write_tags:
fill = text_struct['fill'] if 'fill' in text_struct else '444444' fill = text_struct['fill'] if 'fill' in text_struct else '444444'
size = text_struct['size'] if 'size' in text_struct else 10 size = text_struct['size'] if 'size' in text_struct else 10
text_y += size + 1 text_y += size + 1
wr(text_struct['text'], x, y, fill, text_y, size=size) wr(text_struct['text'], x, y, fill, text_y, size=size)
if show_missed_tags: if show_missed_tags:
for k in tags: for k in tags:
if not no_draw(k) and not k in processed: if not no_draw(k) and not k in processed:
point(k, tags[k], x, y, fill, text_y) point(k, tags[k], x, y, fill, text_y)
text_y += 10 text_y += 10
def construct_nodes(drawing): def construct_nodes(drawing):
"""
Draw nodes.
"""
print 'Draw nodes...' print 'Draw nodes...'
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
@ -704,6 +745,9 @@ def construct_nodes(drawing):
shapes, fill, processed = process.get_icon(tags, scheme) shapes, fill, processed = process.get_icon(tags, scheme)
if options.user_coloring:
fill = get_user_color(node['user'])
for k in tags: for k in tags:
if k in processed or no_draw(k): if k in processed or no_draw(k):
processed_tags += 1 processed_tags += 1
@ -772,22 +816,27 @@ options = ui.parse_options(sys.argv)
if not options: if not options:
sys.exit(1) sys.exit(1)
input_file_name = options['input_file_name'] input_file_name = options.input_file_name
if not os.path.isfile(input_file_name): if not os.path.isfile(input_file_name):
print 'Fatal: no such file: ' + input_file_name + '.' print 'Fatal: no such file: ' + input_file_name + '.'
sys.exit(1) sys.exit(1)
node_map, way_map, relation_map = osm_reader.parse_osm_file(input_file_name, full = False # Full keys getting
parse_ways=options['draw_ways'], parse_relations=options['draw_ways'])
output_file = svg.SVG(open(options['output_file_name'], 'w+')) if options.user_coloring:
full = True
node_map, way_map, relation_map = osm_reader.parse_osm_file(input_file_name,
parse_ways=options.draw_ways, parse_relations=options.draw_ways, full=full)
output_file = svg.SVG(open(options.output_file_name, 'w+'))
w, h = 2650, 2650 w, h = 2650, 2650
if 'size' in options: if 'size' in options:
w = options['size'][0] w = options.size[0]
h = options['size'][1] h = options.size[1]
output_file.begin(w, h) output_file.begin(w, h)
output_file.rect(0, 0, w, h, color=background_color) output_file.rect(0, 0, w, h, color=background_color)
@ -796,7 +845,7 @@ minimum = Geo(180, 180)
maximum = Geo(-180, -180) maximum = Geo(-180, -180)
if 'boundary_box' in options: if 'boundary_box' in options:
bb = options['boundary_box'] bb = options.boundary_box
min1 = Geo(bb[2], bb[0]) min1 = Geo(bb[2], bb[0])
max1 = Geo(bb[3], bb[1]) max1 = Geo(bb[3], bb[1])
@ -823,20 +872,20 @@ icons = extract_icon.IconExtractor(icons_file_name)
drawing = {'nodes': [], 'ways': []} drawing = {'nodes': [], 'ways': []}
if options['draw_ways']: if options.draw_ways:
construct_ways(drawing) construct_ways(drawing)
construct_relations(drawing) construct_relations(drawing)
construct_nodes(drawing) construct_nodes(drawing)
draw(drawing, show_missed_tags=options['show_missed_tags'], draw(drawing, show_missed_tags=options.show_missed_tags,
overlap=options['overlap'], draw=options['draw_nodes']) overlap=options.overlap, draw=options.draw_nodes)
if flinger.space.x == 0: if flinger.space.x == 0:
output_file.rect(0, 0, w, flinger.space.y, color='FFFFFF') output_file.rect(0, 0, w, flinger.space.y, color='FFFFFF')
output_file.rect(0, h - flinger.space.y, w, flinger.space.y, color='FFFFFF') output_file.rect(0, h - flinger.space.y, w, flinger.space.y, color='FFFFFF')
if options['show_index']: if options.show_index:
print min1.lon, max1.lon print min1.lon, max1.lon
print min1.lat, max1.lat print min1.lat, max1.lat

View file

@ -6,10 +6,11 @@ Author: Sergey Vartanov
import datetime import datetime
import ui import ui
import re
import sys import sys
def parse_node_full(node_datae): def parse_node_full(node_data):
""" """
Parse full node parameters using regular expressions: id, visible, version, Parse full node parameters using regular expressions: id, visible, version,
etc. For faster parsing use parse_node(). etc. For faster parsing use parse_node().
@ -19,9 +20,10 @@ def parse_node_full(node_datae):
'lat="(.*)" lon="(.*)"', node_data) 'lat="(.*)" lon="(.*)"', node_data)
if m: if m:
return {'id': int(m.group(1)), 'visible': m.group(2), return {'id': int(m.group(1)), 'visible': m.group(2),
'changeset': m.group(3), 'timestamp': m.group(4), 'version': m.group(3),
'user': m.group(5), 'uid': m.group(6), 'changeset': m.group(4), 'timestamp': m.group(5),
'lat': float(m.group(7)), 'lon': float(m.group(8))} 'user': m.group(6), 'uid': m.group(7),
'lat': float(m.group(8)), 'lon': float(m.group(9))}
else: else:
print 'Error: cannot parse node data: ' + node_data + '.' print 'Error: cannot parse node data: ' + node_data + '.'
return None return None
@ -46,8 +48,8 @@ def parse_way_full(way_data):
'timestamp="(.*)" user="(.*)" uid="(.*)"', way_data) 'timestamp="(.*)" user="(.*)" uid="(.*)"', way_data)
if m: if m:
return {'id': m.group(1), 'visible': m.group(2), return {'id': m.group(1), 'visible': m.group(2),
'changeset': m.group(3), 'timestamp': m.group(4), 'changeset': m.group(4), 'timestamp': m.group(5),
'user': m.group(5), 'uid': m.group(6)} 'user': m.group(6), 'uid': m.group(7)}
else: else:
print 'Error: cannot parse way data: ' + way_data + '.' print 'Error: cannot parse way data: ' + way_data + '.'
return None return None
@ -87,12 +89,12 @@ def parse_tag(text):
return k, v return k, v
def parse_osm_file(file_name, parse_nodes=True, parse_ways=True, def parse_osm_file(file_name, parse_nodes=True, parse_ways=True,
parse_relations=True): parse_relations=True, full=False):
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
try: try:
node_map, way_map, relation_map = parse_osm_file_fast(file_name, node_map, way_map, relation_map = parse_osm_file_fast(file_name,
parse_nodes=parse_nodes, parse_ways=parse_ways, parse_nodes=parse_nodes, parse_ways=parse_ways,
parse_relations=parse_relations) parse_relations=parse_relations, full=full)
except Exception as e: except Exception as e:
print e print e
print '\033[31mFast parsing failed.\033[0m' print '\033[31mFast parsing failed.\033[0m'
@ -107,7 +109,7 @@ def parse_osm_file(file_name, parse_nodes=True, parse_ways=True,
input_file.close() input_file.close()
print 'Done.' print 'Done.'
else: else:
return None, None, None sys.exit(0)
print 'File readed in ' + \ print 'File readed in ' + \
str(datetime.datetime.now() - start_time) + '.' str(datetime.datetime.now() - start_time) + '.'
print 'Nodes: ' + str(len(node_map)) + ', ways: ' + \ print 'Nodes: ' + str(len(node_map)) + ', ways: ' + \
@ -115,7 +117,7 @@ def parse_osm_file(file_name, parse_nodes=True, parse_ways=True,
return node_map, way_map, relation_map return node_map, way_map, relation_map
def parse_osm_file_fast(file_name, parse_nodes=True, parse_ways=True, def parse_osm_file_fast(file_name, parse_nodes=True, parse_ways=True,
parse_relations=True): parse_relations=True, full=False):
node_map = {} node_map = {}
way_map = {} way_map = {}
relation_map = {} relation_map = {}
@ -141,10 +143,16 @@ def parse_osm_file_fast(file_name, parse_nodes=True, parse_ways=True,
else: else:
break break
if line[-3] == '/': if line[-3] == '/':
node = parse_node(line[7:-3]) if not full:
node = parse_node(line[7:-3])
else:
node = parse_node_full(line[7:-3])
node_map[node['id']] = node node_map[node['id']] = node
else: else:
element = parse_node(line[7:-2]) if not full:
element = parse_node(line[7:-2])
else:
element = parse_node_full(line[7:-2])
element['tags'] = {} element['tags'] = {}
elif line in [' </node>\n', '\t</node>\n']: elif line in [' </node>\n', '\t</node>\n']:
node_map[element['id']] = element node_map[element['id']] = element
@ -158,10 +166,16 @@ def parse_osm_file_fast(file_name, parse_nodes=True, parse_ways=True,
else: else:
break break
if line[-3] == '/': if line[-3] == '/':
way = parse_way(line[6:-3]) if not full:
way = parse_way(line[6:-3])
else:
way = parse_way_full(line[6:-3])
way_map[node['id']] = way way_map[node['id']] = way
else: else:
element = parse_way(line[6:-2]) if not full:
element = parse_way(line[6:-2])
else:
element = parse_way_full(line[6:-2])
element['tags'] = {} element['tags'] = {}
element['nodes'] = [] element['nodes'] = []
elif line in [' </way>\n', '\t</way>\n']: elif line in [' </way>\n', '\t</way>\n']:

View file

@ -4,45 +4,47 @@
Author: Sergey Vartanov (me@enzet.ru). Author: Sergey Vartanov (me@enzet.ru).
""" """
import argparse
import sys import sys
def parse_options(args): def parse_options(args):
options = {'draw_nodes': True, 'draw_ways': False, 'overlap': 12,
'show_missed_tags': False, 'show_index': False} parser = argparse.ArgumentParser()
args = iter(args[1:])
for arg in args: parser.add_argument('-i', '--input', dest='input_file_name',
if arg in ['-i', '--input']: required=True)
options['input_file_name'] = next(args) parser.add_argument('-o', '--output', dest='output_file_name',
elif arg in ['-o', '--output']: required=True)
options['output_file_name'] = next(args) parser.add_argument('-bbox', '--boundary-box', dest='boundary_box',
elif arg in ['-bbox', '--boundary-box']: required=True)
arg = next(args) parser.add_argument('-nn', '--no-draw-nodes', dest='draw_nodes',
options['boundary_box'] = map(lambda x: float(x), arg.split(',')) action='store_false', default=True)
elif arg in ['-n', '--draw-nodes']: parser.add_argument('-nw', '--no-draw-ways', dest='draw_ways',
options['draw_nodes'] = True action='store_false', default=True)
elif arg in ['-w', '--draw-ways']: parser.add_argument('-nc', '--no-draw-captions', dest='draw_captions',
options['draw_ways'] = True action='store_false', default=True)
elif arg in ['-nn', '--no-draw-nodes']: parser.add_argument('--show-missed-tags', dest='show_missed_tags',
options['draw_nodes'] = False action='store_true')
elif arg in ['-nw', '--no-draw-ways']: parser.add_argument('--no-show-missed-tags', dest='show_missed_tags',
options['draw_ways'] = False action='store_false')
elif arg in ['--show-missed-tags']: parser.add_argument('--overlap', dest='overlap', default=12, type=int)
options['show_missed_tags'] = True parser.add_argument('-s', '--size', dest='size')
elif arg in ['--no-show-missed-tags']: parser.add_argument('--show-index', dest='show_index',
options['show_missed_tags'] = False action='store_true')
elif arg in ['--overlap']: parser.add_argument('--no-show-index', dest='show_index',
options['overlap'] = int(next(args)) action='store_false')
elif arg in ['-s', '--size']: parser.add_argument('--user-coloring', dest='user_coloring',
options['size'] = map(lambda x: float(x), next(args).split(',')) action='store_true', default=False)
elif arg in ['--show-index']: parser.add_argument('--seed', dest='seed', default='')
options['show_index'] = True
elif arg in ['--no-show-index']: arguments = parser.parse_args(args[1:])
options['show_index'] = False
else: arguments.boundary_box = \
print 'Unknown option: ' + arg map(lambda x: float(x), arguments.boundary_box.split(','))
return None arguments.size = map(lambda x: float(x), arguments.size.split(','))
return options
return arguments
def write_line(number, total): def write_line(number, total):

View file

@ -24,9 +24,9 @@
borderopacity="1.0" borderopacity="1.0"
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="16" inkscape:zoom="5.656854"
inkscape:cx="191.13126" inkscape:cx="330.04973"
inkscape:cy="368.67156" inkscape:cy="498.87454"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
inkscape:document-units="px" inkscape:document-units="px"
showgrid="true" showgrid="true"
@ -36,8 +36,8 @@
inkscape:snap-bbox="true" inkscape:snap-bbox="true"
inkscape:window-width="1425" inkscape:window-width="1425"
inkscape:window-height="995" inkscape:window-height="995"
inkscape:window-x="67" inkscape:window-x="66"
inkscape:window-y="18" inkscape:window-y="24"
inkscape:window-maximized="0"> inkscape:window-maximized="0">
<inkscape:grid <inkscape:grid
type="xygrid" type="xygrid"
@ -3492,7 +3492,7 @@
rx="1" /> rx="1" />
<path <path
style="fill:#000000;stroke:none" style="fill:#000000;stroke:none"
d="m 388,99 0,11 7,0 0,-2 0.90625,0 0.0937,0 0,-0.0312 c 0.54727,0.0521 1.06536,-0.1396 1.40625,-0.5 C 397.76971,107.08444 398,106.55159 398,106 l 0,-3 c 0,-1.09865 -1.01734,-1.50867 -2,-2 l -1,0 0,-2 z m 1.5,1 1,0 3,0 c 0.277,0 0.5,0.223 0.5,0.5 0,0.277 -0.223,0.5 -0.5,0.5 l -1.5,0 c -0.55228,0 -1,0.44772 -1,1 l 0,2.5 c 0,0.277 -0.223,0.5 -0.5,0.5 -0.277,0 -0.5,-0.223 -0.5,-0.5 l 0,-0.9375 c 0.003,-0.0216 0,-0.0401 0,-0.0625 0,-0.24069 -0.17967,-0.42115 -0.40625,-0.46875 C 389.56115,103.01055 389.5346,103 389.5,103 c -0.277,0 -0.5,-0.223 -0.5,-0.5 l 0,-2 c 0,-0.277 0.223,-0.5 0.5,-0.5 z m 5.5,2 1,0 c 0.55821,0 1,0.44179 1,1 l 0,3 c 0,0.27684 -0.13025,0.58857 -0.3125,0.78125 -0.18225,0.19268 -0.36556,0.25678 -0.59375,0.21875 l -0.0625,0 -0.0312,0 -1,0 z" d="m 388,99 0,11 7,0 0,-2 0.90625,0 0.0937,0 0,-0.0312 c 0.54727,0.0521 1.06536,-0.1396 1.40625,-0.5 C 397.76971,107.08444 398,106.55159 398,106 l 0,-3 c 0,-1.09865 -0.84338,-2 -2,-2 l -1,0 0,-2 z m 1.5,1 1,0 3,0 c 0.277,0 0.5,0.223 0.5,0.5 0,0.277 -0.223,0.5 -0.5,0.5 l -1.5,0 c -0.55228,0 -1,0.44772 -1,1 l 0,2.5 c 0,0.277 -0.223,0.5 -0.5,0.5 -0.277,0 -0.5,-0.223 -0.5,-0.5 l 0,-0.9375 c 0.003,-0.0216 0,-0.0401 0,-0.0625 0,-0.24069 -0.17967,-0.42115 -0.40625,-0.46875 C 389.56115,103.01055 389.5346,103 389.5,103 c -0.277,0 -0.5,-0.223 -0.5,-0.5 l 0,-2 c 0,-0.277 0.223,-0.5 0.5,-0.5 z m 5.5,2 1,0 c 0.55821,0 1,0.44179 1,1 l 0,3 c 0,0.27684 -0.13025,0.58857 -0.3125,0.78125 -0.18225,0.19268 -0.36556,0.25678 -0.59375,0.21875 l -0.0625,0 -0.0312,0 -1,0 z"
id="beer" id="beer"
inkscape:label="#rect4413" inkscape:label="#rect4413"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
@ -5395,5 +5395,63 @@
style="fill:#000000;fill-opacity:1;stroke:none" style="fill:#000000;fill-opacity:1;stroke:none"
d="M 231 226 L 231 228 L 228 232 L 228 239 L 235 239 L 235 232 L 232 228 L 232 226 L 231 226 z M 231.5 229.03125 L 233.71875 232 L 229.28125 232 L 231.5 229.03125 z " d="M 231 226 L 231 228 L 228 232 L 228 239 L 235 239 L 235 232 L 232 228 L 232 226 L 231 226 z M 231.5 229.03125 L 233.71875 232 L 229.28125 232 L 231.5 229.03125 z "
id="milk" /> id="milk" />
<path
sodipodi:nodetypes="cccccccccccccccccsscscsscscsscc"
inkscape:connector-curvature="0"
inkscape:label="#rect4452"
id="betula"
d="m 245,233 c 0,0.554 0.446,1 1,1 l 1,0 0,3 1,0 0,1 -1,0 0,1 2,0 0,-3 -1,0 0,-1 1,0 0,-1 1,0 c 0.554,0 1,-0.446 1,-1 l 0,-1 c 0.554,0 1,-0.446 1,-1 l 0,-2 c 0,-0.554 -0.446,-1 -1,-1 l 0,-1 c 0,-0.554 -0.446,-1 -1,-1 0,-0.554 -0.446,-1 -1,-1 l -2,0 c -0.554,0 -1,0.446 -1,1 -0.554,0 -1,0.446 -1,1 l 0,1 c -0.554,0 -1,0.446 -1,1 l 0,2 c 0,0.554 0.446,1 1,1 z"
style="fill:#000000;stroke:none" />
<rect
ry="1"
rx="1"
y="209"
x="246"
height="6"
width="4"
id="rect3794"
style="fill:#808080;stroke:none" />
<rect
ry="1"
rx="1"
y="210"
x="245"
height="8"
width="6"
id="rect3796"
style="fill:#808080;stroke:none" />
<rect
ry="1"
rx="1"
y="212"
x="244"
height="4"
width="8"
id="rect3798"
style="fill:#808080;stroke:none" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3800"
d="m 249,216 0,6 -2,0 0,-6 z"
style="fill:#808080;stroke:none" />
<rect
ry="0.5"
rx="0.5"
y="219"
x="248"
height="1"
width="3"
id="rect3802"
style="fill:#ffd5d5;stroke:none" />
<rect
style="fill:#ffd5d5;stroke:none"
id="rect3804"
width="3"
height="1"
x="245"
y="220"
rx="0.5"
ry="0.5" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 278 KiB