diff --git a/README.md b/README.md index c26b3e6..c4df0a5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -Röntgen project focuses on displaying every [OpenStreetMap](http://openstreetmap.org) data tag on the map. + + +Röntgen project focuses on displaying every \[OpenStreetMap\](http://openstreetmap.org) data tag on the map. 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 -------------- -![Sample map](doc/map.png) +!\[Sample map\](doc/map.png) **Requirements**: Python 2.7. @@ -28,13 +31,13 @@ There are simple Python renderer that generates SVG map from OpenStreetMap data. -bbox, --boundary-box -<longitude 1>,<longitude 2>,<latitude 1>,<latitude 2> (decimal float) +,,, (decimal float) Boundary box to draw -s, --size -<width>,<height> (pixels) +, (pixels) Result image size @@ -45,11 +48,13 @@ Icon set 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: -![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. + + diff --git a/data/tags.yml b/data/tags.yml index c398b91..898bd89 100644 --- a/data/tags.yml +++ b/data/tags.yml @@ -220,12 +220,21 @@ tags: color: deciduous - tags: {natural: tree, leaf_cycle: evergreen} color: evergreen + + # Tree genus + +- tags: {natural: tree, genus: Betula} + icon: [betula] + color: tree + + # Tree over icons + - tags: {natural: tree, denotation: urban} over_icon: [urban_tree_pot] - under_icon: [tree, broadleaved, needleleaved] + under_icon: [tree, broadleaved, needleleaved, betula] - tags: {natural: tree, denotation: avenue} over_icon: [avenue_tree] - under_icon: [tree, broadleaved, needleleaved] + under_icon: [tree, broadleaved, needleleaved, betula] # Entrance diff --git a/doc/grid.png b/doc/grid.png index 4df3688..ed9327c 100644 Binary files a/doc/grid.png and b/doc/grid.png differ diff --git a/doc/map.png b/doc/map.png index 5610a67..8859df8 100644 Binary files a/doc/map.png and b/doc/map.png differ diff --git a/doc/readme.moi b/doc/readme.moi index 0d0b21b..80338ee 100644 --- a/doc/readme.moi +++ b/doc/readme.moi @@ -1,6 +1,6 @@ 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. @@ -15,7 +15,7 @@ There are simple Python renderer that generates SVG map from OpenStreetMap data. \code {python mapper.py -i -o } -\3 {Options} +\3 {Options} {options} \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. @@ -43,3 +43,4 @@ Double size: \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. + diff --git a/engine/mapper.py b/engine/mapper.py index 22e696d..108ba3a 100644 --- a/engine/mapper.py +++ b/engine/mapper.py @@ -27,7 +27,8 @@ sys.path.append('../lib') import svg from vector import Vector -background_color = 'DDDDDD' +background_color = 'DDDDDD' # 'DDDDDD' +outline_color = 'FFFFFF' beach_color = 'F0E0C0' building_color = 'EEEEEE' # 'D0D0C0' building_border_color = 'C4C4C4' # 'AAAAAA' @@ -86,8 +87,10 @@ prefix_to_write = set(['addr', 'contact', 'name', 'operator', 'wikipedia', # To draw 'species', 'taxon', 'genus']) -tags_to_skip = set(['note', 'layer', 'source', 'building:part', 'fixme', 'comment', - 'FIXME', 'source_ref', 'naptan:verified:note', 'building:levels']) +tags_to_skip = set(['note', 'layer', 'source', 'building:part', 'fixme', + 'comment', 'FIXME', 'source_ref', 'naptan:verified:note', + 'building:levels', 'ref:opendataparis:adresse', + 'ref:opendataparis:geo_point_2d', 'created_by']) 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): x = int(float(x)) y = int(float(y)) - outline_fill = 'FFFFFF' opacity = 0.5 r = int(fill[0:2], 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' opacity = 0.3 output_file.write('\n') @@ -181,7 +183,7 @@ def point(k, v, x, y, fill, text_y): text = text.encode('utf-8') draw_text(text, x, float(y) + text_y + 18, '734A08') -def construct_text(tags): +def construct_text(tags, processed): for key in tags: tags[key] = tags[key].replace('"', '"') texts = [] @@ -193,13 +195,13 @@ def construct_text(tags): tags.pop('name', None) if 'name:ru' in tags: if not name: - name = tags['name'] - tags.pop('name', None) + name = tags['name:ru'] + tags.pop('name:ru', None) tags.pop('name:ru', None) if 'name:en' in tags: if not name: - name = tags['name'] - tags.pop('name', None) + name = tags['name:en'] + tags.pop('name:en', None) tags.pop('name:en', None) if 'alt_name' in tags: if alt_name: @@ -239,8 +241,8 @@ def construct_text(tags): else: addr = '' street = tags['addr:street'] - if street[:6] == 'улица ': - street = 'ул. ' + street[6:] + if street.startswith('улица '): + street = 'ул. ' + street[len('улица '):] addr += street tags.pop('addr:street', None) if 'addr:housenumber' in tags: @@ -280,7 +282,7 @@ def construct_text(tags): texts.append({'text': tags[k], 'fill': '444444'}) tags.pop(k) 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': tags[tag]}) return texts @@ -298,6 +300,7 @@ def draw_raw_ways(): way = way_map[way_id] draw_path(way['nodes'], 'stroke:#FFFFFF;fill:none;stroke-width:0.2;') + def line_center(node_ids): ma = Vector() 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) +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): for way_id in way_map: 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: - is_area = nodes[0] == nodes[-1] - layer = float(tags['layer']) if ('layer' in tags) else 0 - if nodes: - c = line_center(nodes) - 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;' + drawing['nodes'].append({'shapes': shapes, 'x': c.x, 'y': c.y, + 'color': fill, 'priority': 1, 'processed': processed, + 'tags': tags, 'path': path}) + drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, + 'priority': 50, 'style': style, 'path': path}) + if 'amenity' in tags: + style = 'fill:none;stroke:none;' + layer += 0.2 + if tags['amenity'] == 'parking': + style = 'fill:#' + parking_color + ';stroke:none;opacity:0.5;' shapes, fill, processed = process.get_icon(tags, scheme, '444444') - if 'height' in tags: - layer += float(tags['height']) if nodes: drawing['nodes'].append({'shapes': shapes, 'x': c.x, 'y': c.y, 'color': fill, 'priority': 1, 'processed': processed, 'tags': tags, 'path': path}) - drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, - 'priority': 50, 'style': style, 'path': path}) - if 'amenity' in tags: - style = 'fill:none;stroke:none;' - layer += 0.2 - if tags['amenity'] == 'parking': - style = 'fill:#' + parking_color + ';stroke:none;opacity:0.5;' - shapes, fill, processed = process.get_icon(tags, scheme, '444444') - if nodes: - drawing['nodes'].append({'shapes': shapes, 'x': c.x, 'y': c.y, - 'color': fill, 'priority': 1, 'processed': processed, - 'tags': tags, 'path': path}) - drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, - 'priority': 50, 'style': style, 'path': path}) - if 'waterway' in tags: - style = 'fill:none;stroke:none;' - layer += 0.2 - if tags['waterway'] == 'riverbank': - style = 'fill:#' + water_color + ';stroke:#' + \ - water_border_color + ';stroke-width:1.0;' - elif tags['waterway'] == 'river': - style = 'fill:none;stroke:#' + water_color + ';stroke-width:10.0;' - drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, - 'priority': 50, 'style': style, 'path': path}) - if 'railway' in tags: - style = 'fill:none;stroke:none;' - layer += 0.45 - v = tags['railway'] - style = 'fill:none;stroke-dasharray:none;stroke-linejoin:round;' + \ - 'stroke-linecap:round;stroke-width:' - if v == 'subway': style += '10;stroke:#DDDDDD;' - if v in ['narrow_gauge', 'tram']: - style += '2;stroke:#000000;' + drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, + 'priority': 50, 'style': style, 'path': path}) + if 'waterway' in tags: + style = 'fill:none;stroke:none;' + layer += 0.2 + if tags['waterway'] == 'riverbank': + style = 'fill:#' + water_color + ';stroke:#' + \ + water_border_color + ';stroke-width:1.0;' + elif tags['waterway'] == 'river': + style = 'fill:none;stroke:#' + water_color + ';stroke-width:10.0;' + drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, + 'priority': 50, 'style': style, 'path': path}) + if 'railway' in tags: + style = 'fill:none;stroke:none;' + layer += 0.45 + v = tags['railway'] + style = 'fill:none;stroke-dasharray:none;stroke-linejoin:round;' + \ + 'stroke-linecap:round;stroke-width:' + if v == 'subway': style += '10;stroke:#DDDDDD;' + if v in ['narrow_gauge', 'tram']: + style += '2;stroke:#000000;' + else: + return + drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, + 'priority': 50, 'style': style, 'path': path}) + if 'highway' in tags: + style = 'fill:none;stroke:none;' + 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: - return - drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, - 'priority': 50, 'style': style, 'path': path}) - if 'highway' in tags: - style = 'fill:none;stroke:none;' - 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 += '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, - 'priority': 50, 'style': style, 'path': path}) - if 'access' in tags and tags['access'] == 'private': - drawing['ways'].append({'kind': 'way', 'nodes': nodes, - 'layer': layer + 0.1, 'priority': 50, 'path': path, - 'style': 'fill:none;' + \ - 'stroke:#' + private_access_color + ';' + \ - '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 + 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 = '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;' + 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 += '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}) + 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 += ';' + drawing['ways'].append({'kind': 'way', 'nodes': nodes, 'layer': layer, + 'priority': 50, 'style': style, 'path': path}) + if 'access' in tags and tags['access'] == 'private': + drawing['ways'].append({'kind': 'way', 'nodes': nodes, + 'layer': layer + 0.1, 'priority': 50, 'path': path, + 'style': 'fill:none;' + \ + 'stroke:#' + private_access_color + ';' + \ + '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): @@ -616,7 +651,7 @@ def construct_relations(drawing): way.reverse() path = get_path(way) p += path + ' ' - construct_way(drawing, None, tags, p) + construct_way(drawing, None, tags, p, '') # Nodes drawing @@ -636,6 +671,8 @@ def no_draw(key): return False def to_write(key): + if key in tags_to_skip: + return False if key in tags_to_write: return True 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) xxx += 16 - write_tags = construct_text(tags) + if options.draw_captions: + write_tags = construct_text(tags, processed) - for text_struct in write_tags: - fill = text_struct['fill'] if 'fill' in text_struct else '444444' - size = text_struct['size'] if 'size' in text_struct else 10 - text_y += size + 1 - wr(text_struct['text'], x, y, fill, text_y, size=size) + for text_struct in write_tags: + fill = text_struct['fill'] if 'fill' in text_struct else '444444' + size = text_struct['size'] if 'size' in text_struct else 10 + text_y += size + 1 + wr(text_struct['text'], x, y, fill, text_y, size=size) - if show_missed_tags: - for k in tags: - if not no_draw(k) and not k in processed: - point(k, tags[k], x, y, fill, text_y) - text_y += 10 + if show_missed_tags: + for k in tags: + if not no_draw(k) and not k in processed: + point(k, tags[k], x, y, fill, text_y) + text_y += 10 def construct_nodes(drawing): + """ + Draw nodes. + """ print 'Draw nodes...' start_time = datetime.datetime.now() @@ -704,6 +745,9 @@ def construct_nodes(drawing): shapes, fill, processed = process.get_icon(tags, scheme) + if options.user_coloring: + fill = get_user_color(node['user']) + for k in tags: if k in processed or no_draw(k): processed_tags += 1 @@ -772,22 +816,27 @@ options = ui.parse_options(sys.argv) if not options: 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): print 'Fatal: no such file: ' + input_file_name + '.' sys.exit(1) -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 = False # Full keys getting -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 if 'size' in options: - w = options['size'][0] - h = options['size'][1] + w = options.size[0] + h = options.size[1] output_file.begin(w, h) output_file.rect(0, 0, w, h, color=background_color) @@ -796,7 +845,7 @@ minimum = Geo(180, 180) maximum = Geo(-180, -180) if 'boundary_box' in options: - bb = options['boundary_box'] + bb = options.boundary_box min1 = Geo(bb[2], bb[0]) max1 = Geo(bb[3], bb[1]) @@ -823,20 +872,20 @@ icons = extract_icon.IconExtractor(icons_file_name) drawing = {'nodes': [], 'ways': []} -if options['draw_ways']: +if options.draw_ways: construct_ways(drawing) construct_relations(drawing) construct_nodes(drawing) -draw(drawing, show_missed_tags=options['show_missed_tags'], - overlap=options['overlap'], draw=options['draw_nodes']) +draw(drawing, show_missed_tags=options.show_missed_tags, + overlap=options.overlap, draw=options.draw_nodes) if flinger.space.x == 0: 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') -if options['show_index']: +if options.show_index: print min1.lon, max1.lon print min1.lat, max1.lat diff --git a/engine/osm_reader.py b/engine/osm_reader.py index 07ebf09..d8f6456 100644 --- a/engine/osm_reader.py +++ b/engine/osm_reader.py @@ -6,10 +6,11 @@ Author: Sergey Vartanov import datetime import ui +import re import sys -def parse_node_full(node_datae): +def parse_node_full(node_data): """ Parse full node parameters using regular expressions: id, visible, version, etc. For faster parsing use parse_node(). @@ -19,9 +20,10 @@ def parse_node_full(node_datae): 'lat="(.*)" lon="(.*)"', node_data) if m: return {'id': int(m.group(1)), 'visible': m.group(2), - 'changeset': m.group(3), 'timestamp': m.group(4), - 'user': m.group(5), 'uid': m.group(6), - 'lat': float(m.group(7)), 'lon': float(m.group(8))} + 'version': m.group(3), + 'changeset': m.group(4), 'timestamp': m.group(5), + 'user': m.group(6), 'uid': m.group(7), + 'lat': float(m.group(8)), 'lon': float(m.group(9))} else: print 'Error: cannot parse node data: ' + node_data + '.' return None @@ -46,8 +48,8 @@ def parse_way_full(way_data): 'timestamp="(.*)" user="(.*)" uid="(.*)"', way_data) if m: return {'id': m.group(1), 'visible': m.group(2), - 'changeset': m.group(3), 'timestamp': m.group(4), - 'user': m.group(5), 'uid': m.group(6)} + 'changeset': m.group(4), 'timestamp': m.group(5), + 'user': m.group(6), 'uid': m.group(7)} else: print 'Error: cannot parse way data: ' + way_data + '.' return None @@ -87,12 +89,12 @@ def parse_tag(text): return k, v 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() try: node_map, way_map, relation_map = parse_osm_file_fast(file_name, parse_nodes=parse_nodes, parse_ways=parse_ways, - parse_relations=parse_relations) + parse_relations=parse_relations, full=full) except Exception as e: print e 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() print 'Done.' else: - return None, None, None + sys.exit(0) print 'File readed in ' + \ str(datetime.datetime.now() - start_time) + '.' 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 def parse_osm_file_fast(file_name, parse_nodes=True, parse_ways=True, - parse_relations=True): + parse_relations=True, full=False): node_map = {} way_map = {} relation_map = {} @@ -141,10 +143,16 @@ def parse_osm_file_fast(file_name, parse_nodes=True, parse_ways=True, else: break 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 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'] = {} elif line in [' \n', '\t\n']: node_map[element['id']] = element @@ -158,10 +166,16 @@ def parse_osm_file_fast(file_name, parse_nodes=True, parse_ways=True, else: break 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 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['nodes'] = [] elif line in [' \n', '\t\n']: diff --git a/engine/ui.py b/engine/ui.py index 1249cee..1d51cad 100644 --- a/engine/ui.py +++ b/engine/ui.py @@ -4,45 +4,47 @@ Author: Sergey Vartanov (me@enzet.ru). """ +import argparse import sys def parse_options(args): - options = {'draw_nodes': True, 'draw_ways': False, 'overlap': 12, - 'show_missed_tags': False, 'show_index': False} - args = iter(args[1:]) - for arg in args: - if arg in ['-i', '--input']: - options['input_file_name'] = next(args) - elif arg in ['-o', '--output']: - options['output_file_name'] = next(args) - elif arg in ['-bbox', '--boundary-box']: - arg = next(args) - options['boundary_box'] = map(lambda x: float(x), arg.split(',')) - elif arg in ['-n', '--draw-nodes']: - options['draw_nodes'] = True - elif arg in ['-w', '--draw-ways']: - options['draw_ways'] = True - elif arg in ['-nn', '--no-draw-nodes']: - options['draw_nodes'] = False - elif arg in ['-nw', '--no-draw-ways']: - options['draw_ways'] = False - elif arg in ['--show-missed-tags']: - options['show_missed_tags'] = True - elif arg in ['--no-show-missed-tags']: - options['show_missed_tags'] = False - elif arg in ['--overlap']: - options['overlap'] = int(next(args)) - elif arg in ['-s', '--size']: - options['size'] = map(lambda x: float(x), next(args).split(',')) - elif arg in ['--show-index']: - options['show_index'] = True - elif arg in ['--no-show-index']: - options['show_index'] = False - else: - print 'Unknown option: ' + arg - return None - return options + + parser = argparse.ArgumentParser() + + parser.add_argument('-i', '--input', dest='input_file_name', + required=True) + parser.add_argument('-o', '--output', dest='output_file_name', + required=True) + parser.add_argument('-bbox', '--boundary-box', dest='boundary_box', + required=True) + parser.add_argument('-nn', '--no-draw-nodes', dest='draw_nodes', + action='store_false', default=True) + parser.add_argument('-nw', '--no-draw-ways', dest='draw_ways', + action='store_false', default=True) + parser.add_argument('-nc', '--no-draw-captions', dest='draw_captions', + action='store_false', default=True) + parser.add_argument('--show-missed-tags', dest='show_missed_tags', + action='store_true') + parser.add_argument('--no-show-missed-tags', dest='show_missed_tags', + action='store_false') + parser.add_argument('--overlap', dest='overlap', default=12, type=int) + parser.add_argument('-s', '--size', dest='size') + parser.add_argument('--show-index', dest='show_index', + action='store_true') + parser.add_argument('--no-show-index', dest='show_index', + action='store_false') + parser.add_argument('--user-coloring', dest='user_coloring', + action='store_true', default=False) + parser.add_argument('--seed', dest='seed', default='') + + arguments = parser.parse_args(args[1:]) + + arguments.boundary_box = \ + map(lambda x: float(x), arguments.boundary_box.split(',')) + arguments.size = map(lambda x: float(x), arguments.size.split(',')) + + return arguments def write_line(number, total): diff --git a/icons/icons.svg b/icons/icons.svg index 8a42e94..8e2dc6f 100644 --- a/icons/icons.svg +++ b/icons/icons.svg @@ -24,9 +24,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="16" - inkscape:cx="191.13126" - inkscape:cy="368.67156" + inkscape:zoom="5.656854" + inkscape:cx="330.04973" + inkscape:cy="498.87454" inkscape:current-layer="layer1" inkscape:document-units="px" showgrid="true" @@ -36,8 +36,8 @@ inkscape:snap-bbox="true" inkscape:window-width="1425" inkscape:window-height="995" - inkscape:window-x="67" - inkscape:window-y="18" + inkscape:window-x="66" + inkscape:window-y="24" inkscape:window-maximized="0"> + + + + + + +