Faster parsing; new drawing rules.

This commit is contained in:
Sergey Vartanov 2015-07-28 23:06:57 +03:00
parent aa6720f30e
commit 3e10d9c1eb
2 changed files with 358 additions and 287 deletions

407
mapper.py
View file

@ -2,16 +2,20 @@
# -*- coding: utf-8 -*- from __future__ import unicode_literals # -*- coding: utf-8 -*- from __future__ import unicode_literals
""" """
Simple tool for drawing OSM data. Simple tool for working with OpenStreetMap data.
Author: Sergey Vartnov Author: Sergey Vartanov (me@enzet.ru).
""" """
import datetime
import os import os
import re import re
import sys import sys
import xml.dom.minidom import xml.dom.minidom
import extract_icon
import osm_reader
from flinger import GeoFlinger, Geo from flinger import GeoFlinger, Geo
sys.path.append('lib') sys.path.append('lib')
@ -19,24 +23,19 @@ sys.path.append('lib')
import svg import svg
from vector import Vector from vector import Vector
# class OSMGetter:
# def get(x1, x2, y1, y2):
# input_file = open(cache_folder + '/osm-' + `x1` + '-' + `y1` + '-' + \
# `x2` + '-' + `y2`
# if not os.path.isfile(input_file):
input_file_name = sys.argv[1] input_file_name = sys.argv[1]
if not os.path.isfile(input_file_name): if not os.path.isfile(input_file_name):
print 'Fatal: no such file: ' + input_file_name + '.'
sys.exit(1) sys.exit(1)
print 'Reading input OSM file...' #start_time = datetime.datetime.now()
#input_file = open(input_file_name)
#content = xml.dom.minidom.parse(input_file)
#input_file.close()
#print 'File readed in ' + str(datetime.datetime.now() - start_time) + '.'
input_file = open(input_file_name) node_map, way_map, relation_map = osm_reader.parse_osm_file(input_file_name)
content = xml.dom.minidom.parse(input_file)
input_file.close()
print 'Done.'
output_file = svg.SVG(open(sys.argv[2], 'w+')) output_file = svg.SVG(open(sys.argv[2], 'w+'))
@ -53,6 +52,11 @@ water_color = 'AACCFF'
water_border_color = '6688BB' water_border_color = '6688BB'
wood_color = 'B8CC84' wood_color = 'B8CC84'
undraw = ['operator', 'contact:facebook', 'contact:phone', 'opening_hours',
'cuisine', 'network', 'website', 'contact:website', 'phone',
'branch', 'route_ref', 'addr:flats', 'brand', 'ref', 'addr:street',
'wikipedia', 'description', 'layer', 'level']
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)
@ -66,13 +70,13 @@ if len(sys.argv) > 3:
authors = {} authors = {}
missed_tags = {} missed_tags = {}
d_street_lamp = 'm 7,1 -3.5,3 1.59375,0 1,5 1.40625,0 0,6 1,0 0,-6 1.40625,0 1,-5 L 12.5,4 9,1 z M 6.125,4 9.875,4 9.09375,8 6.90625,8 z'
d_clinic = 'M 7,5 7,7 5,7 5,9 7,9 7,11 9,11 9,9 11,9 11,7 9,7 9,5 7,5'
d_crossing = 'm 3,5 0,6 1,0 0,-6 z m 4,0 0,6 1,0 0,-6 z m 4,0 0,6 1,0 0,-6 z'
d_traffic_signal = 'M 7,1 C 6.446,1 6,1.446 6,2 L 6,4 C 6,4.1879013 6.0668244,4.3501348 6.15625,4.5 6.0668244,4.6498652 6,4.8120987 6,5 L 6,7 C 6,7.1879013 6.0668244,7.3501348 6.15625,7.5 6.0668244,7.6498652 6,7.8120987 6,8 l 0,2 c 0,0.554 0.446,1 1,1 l 0.5,0 0,3 -1.5,0 0,1 4,0 0,-1 -1.5,0 0,-3 0.5,0 c 0.554,0 1,-0.446 1,-1 L 10,8 C 10,7.8120987 9.9331756,7.6498652 9.84375,7.5 9.9331756,7.3501348 10,7.1879013 10,7 L 10,5 C 10,4.8120987 9.9331756,4.6498652 9.84375,4.5 9.9331756,4.3501348 10,4.1879013 10,4 L 10,2 C 10,1.446 9.554,1 9,1 z M 7,2 9,2 9,4 7,4 z M 7,5 9,5 9,7 7,7 z m 0,3 2,0 0,2 -2,0 z'
d_tree = 'M 7 2 C 6.446 2 6 2.446 6 3 C 5.446 3 5 3.4460001 5 4 L 5 7 C 5 7.5539999 5.446 8 6 8 C 6 8.554 6.446 9 7 9 L 7.5625 9 L 7.5625 12 L 8.4375 12 L 8.4375 9 L 9 9 C 9.554 9 10 8.554 10 8 C 10.554 8 11 7.5539999 11 7 L 11 4 C 11 3.4460001 10.554 3 10 3 C 10 2.446 9.554 2 9 2 L 7 2 z'
def get_d_from_file(file_name): def get_d_from_file(file_name):
path, x, y = icons.get_path(file_name)
if path:
return path, x, y
else:
print 'No such icon: ' + file_name
return 'M 4,4 L 4,10 10,10 10,4 4,4', 0, 0
if os.path.isfile('icons/' + file_name + '.svg'): if os.path.isfile('icons/' + file_name + '.svg'):
file_name = 'icons/' + file_name + '.svg' file_name = 'icons/' + file_name + '.svg'
size = 16 size = 16
@ -97,39 +101,21 @@ def get_d_from_file(file_name):
if m: if m:
return m.group('path'), size return m.group('path'), size
# Construct node map
def construct_node_map(): def get_min_max(node_map):
""" key = node_map.keys()[0]
Construct map of nodes. maximum = Geo(node_map[key]['lon'], node_map[key]['lat'])
""" minimum = Geo(node_map[key]['lon'], node_map[key]['lat'])
print 'Construct node map...' for node_id in node_map:
node_map = {} node = node_map[node_id]
for element in content.childNodes[0].childNodes: if node['lat'] > maximum.lat: maximum.lat = node['lat']
if element.nodeType != element.TEXT_NODE: if node['lat'] < minimum.lat: minimum.lat = node['lat']
if 'user' in element.attributes.keys(): if node['lon'] > maximum.lon: maximum.lon = node['lon']
author = element.attributes['user'].value if node['lon'] < minimum.lon: minimum.lon = node['lon']
if author in authors: return minimum, maximum
authors[author] += 1
else:
authors[author] = 1
if not ('lat' in element.attributes.keys()):
continue
node_map[element.attributes['id'].value] = \
Geo(float(element.attributes['lat'].value),
float(element.attributes['lon'].value))
if float(element.attributes['lat'].value) > maximum.lat:
maximum.lat = float(element.attributes['lat'].value)
if float(element.attributes['lat'].value) < minimum.lat:
minimum.lat = float(element.attributes['lat'].value)
if float(element.attributes['lon'].value) > maximum.lon:
maximum.lon = float(element.attributes['lon'].value)
if float(element.attributes['lon'].value) < minimum.lon:
minimum.lon = float(element.attributes['lon'].value)
print 'Done.'
return node_map
node_map = construct_node_map()
minimum, maximum = get_min_max(node_map)
if len(sys.argv) > 3: if len(sys.argv) > 3:
flinger = GeoFlinger(min1, max1, Vector(0, 0), Vector(w, h)) flinger = GeoFlinger(min1, max1, Vector(0, 0), Vector(w, h))
@ -140,9 +126,10 @@ else:
def draw_path(nodes, style, shift=Vector()): def draw_path(nodes, style, shift=Vector()):
prev_node = None prev_node = None
for node_id in nodes: for node_id in nodes:
flinged1 = flinger.fling(node_map[node_id]) + shift node = node_map[node_id]
flinged1 = flinger.fling(Geo(node['lat'], node['lon'])) + shift
if prev_node: if prev_node:
flinged2 = flinger.fling(prev_node) + shift flinged2 = flinger.fling(Geo(prev_node['lat'], prev_node['lon'])) + shift
output_file.write('L ' + `flinged1.x` + ',' + `flinged1.y` + ' ') output_file.write('L ' + `flinged1.x` + ',' + `flinged1.y` + ' ')
else: else:
output_file.write('<path d="M ' + `flinged1.x` + \ output_file.write('<path d="M ' + `flinged1.x` + \
@ -151,18 +138,18 @@ def draw_path(nodes, style, shift=Vector()):
output_file.write('" style="' + style + '" />\n') output_file.write('" style="' + style + '" />\n')
def draw_point_shape(name, x, y, fill): def draw_point_shape(name, x, y, fill):
shape, size = get_d_from_file(name) shape, xx, yy = get_d_from_file(name)
draw_point(shape, x, y, fill, size=size) draw_point(shape, x, y, fill, size=16, xx=xx, yy=yy)
def draw_point(shape, x, y, fill, size=16): def draw_point(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))
output_file.write('<path d="' + shape + \ output_file.write('<path d="' + shape + \
'" style="fill:#FFFFFF;opacity:0.5;stroke:#FFFFFF;stroke-width:3;stroke-linejoin:round;" transform="translate(' + \ '" style="fill:#FFFFFF;opacity:0.5;stroke:#FFFFFF;stroke-width:3;stroke-linejoin:round;" transform="translate(' + \
str(x - size / 2.0) + ',' + str(y - size / 2.0) + ')" />\n') str(x - size / 2.0 - xx * 16) + ',' + str(y - size / 2.0 - yy * 16) + ')" />\n')
output_file.write('<path d="' + shape + \ output_file.write('<path d="' + shape + \
'" style="fill:#' + fill + ';fill-opacity:1" transform="translate(' + \ '" style="fill:#' + fill + ';fill-opacity:1" transform="translate(' + \
str(x - size / 2.0) + ',' + str(y - size / 2.0) + ')" />\n') str(x - size / 2.0 - xx * 16) + ',' + str(y - size / 2.0 - yy * 16) + ')" />\n')
def draw_text(text, x, y, fill): def draw_text(text, x, y, fill):
if type(text) == unicode: if type(text) == unicode:
@ -177,64 +164,28 @@ def draw_text(text, x, y, fill):
output_file.write('<text x="' + x + '" y="' + y + \ output_file.write('<text x="' + x + '" y="' + y + \
'" style="font-size:10;text-anchor:middle;font-family:Myriad Pro;fill:#' + fill + ';">' + text + '</text>') '" style="font-size:10;text-anchor:middle;font-family:Myriad Pro;fill:#' + fill + ';">' + text + '</text>')
def point(k, v, x, y, fill): def point(k, v, x, y, fill, text_y):
if ('node ' + k + ': ' + v) in missed_tags: if ('node ' + k + ': ' + v) in missed_tags:
missed_tags['node ' + k + ': ' + v] += 1 missed_tags['node ' + k + ': ' + v] += 1
else: else:
missed_tags['node ' + k + ': ' + v] = 1 missed_tags['node ' + k + ': ' + v] = 1
output_file.circle(x, y, 2, fill=fill, color=fill) #output_file.circle(float(x), float(y), 2, fill=fill, color=fill)
text = k + ': ' + v text = k + ': ' + v
if type(text) == unicode: if type(text) == unicode:
text = text.encode('utf-8') text = text.encode('utf-8')
output_file.write('<text x="' + str(x) + '" y="' + str(int(y) + 10) + \ output_file.write('<text x="' + str(x) + '" y="' + str(int(float(y)) + text_y + 10) + \
'" style="font-size:10;text-anchor:middle;font-family:Myriad Pro;fill:#FF0000;">' + text + '</text>') '" style="font-size:10;text-anchor:middle;font-family:Myriad Pro;fill:#FF0000;">' + text + '</text>')
# Ways drawing # Ways drawing
def construct_way_map(): def construct_layers():
""" """
Construct map of ways and distribute them by layers. One layer may contain Construct layers. One layer may contain elements of different types.
elements of different types.
""" """
print 'Construct way map...'
layers = {} layers = {}
way_map = {}
for element in content.childNodes[0].childNodes: for way_id in way_map:
if element.nodeName == 'way': way = way_map[way_id]
way = {'nodes': [], 'tags': {}}
way_map[element.attributes['id'].value] = way
for element in content.childNodes[0].childNodes:
if element.nodeName == 'relation':
relation = {'members': [], 'tags': {}}
for child_node in element.childNodes:
if isinstance(child_node, xml.dom.minidom.Element):
if child_node.tagName == 'tag':
k = child_node.attributes['k'].value
v = child_node.attributes['v'].value
relation['tags'][k] = v
for child_node in element.childNodes:
if isinstance(child_node, xml.dom.minidom.Element):
if child_node.tagName == 'member':
index = child_node.attributes['ref'].value
if index in way_map:
way = way_map[index]
for tag in relation['tags']:
way['tags'][tag] = relation['tags'][tag]
for element in content.childNodes[0].childNodes:
if element.nodeName == 'way':
way = way_map[element.attributes['id'].value]
for child_node in element.childNodes:
if isinstance(child_node, xml.dom.minidom.Element):
if child_node.tagName == 'tag':
k = child_node.attributes['k'].value
v = child_node.attributes['v'].value
way['tags'][k] = v
if child_node.tagName == 'nd':
way['nodes'].append(child_node.attributes['ref'].value)
if not ('layer' in way['tags']): if not ('layer' in way['tags']):
way['tags']['layer'] = 0 way['tags']['layer'] = 0
if not (int(way['tags']['layer']) in layers): if not (int(way['tags']['layer']) in layers):
@ -268,37 +219,48 @@ def construct_way_map():
# empty = False # empty = False
# if not empty: # if not empty:
# print 'Unknown kind of way:', way['tags'] # print 'Unknown kind of way:', way['tags']
return layers, way_map return layers
layers, way_map = construct_way_map() layers = construct_layers()
def draw_raw_ways(): def draw_raw_ways():
for way_id in way_map: for way_id in way_map:
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):
ma = Vector()
mi = Vector(10000, 10000)
for node_id in node_ids:
node = node_map[node_id]
flinged = flinger.fling(Geo(node['lat'], node['lon']))
if flinged.x > ma.x: ma.x = flinged.x
if flinged.y > ma.y: ma.y = flinged.y
if flinged.x < mi.x: mi.x = flinged.x
if flinged.y < mi.y: mi.y = flinged.y
return Vector((ma.x + mi.x) / 2.0, (ma.y + mi.y) / 2.0)
def draw_ways(): def draw_ways():
for level in sorted(layers.keys()): for level in sorted(layers.keys()):
layer = layers[level] layer = layers[level]
#for entity in ['b', 'h1', 'h2', 'r', 'n', 'l', 'a', 'le', 'ba']: #for entity in ['b', 'h1', 'h2', 'r', 'n', 'l', 'a', 'le', 'ba']:
# Pre part.
for way in layer['le']: for way in layer['le']:
if way['tags']['leisure'] == 'park': if way['tags']['leisure'] == 'park':
style = 'fill:#' + grass_color + ';' style = 'fill:#' + grass_color + ';'
else: else:
continue continue
draw_path(way['nodes'], style) draw_path(way['nodes'], style)
# Post part.
for way in layer['l']: for way in layer['l']:
ma = Vector() text_y = 0
mi = Vector(10000, 10000) c = line_center(way['nodes'])
for node_id in way['nodes']:
node = node_map[node_id]
flinged = flinger.fling(node)
if flinged.x > ma.x: ma.x = flinged.x
if flinged.y > ma.y: ma.y = flinged.y
if flinged.x < mi.x: mi.x = flinged.x
if flinged.y < mi.y: mi.y = flinged.y
c = Vector((ma.x + mi.x) / 2.0, (ma.y + mi.y) / 2.0)
if way['tags']['landuse'] == 'grass': if way['tags']['landuse'] == 'grass':
style = 'fill:#' + grass_color + ';stroke:none;' style = 'fill:#' + grass_color + ';stroke:none;'
draw_path(way['nodes'], style) draw_path(way['nodes'], style)
@ -317,17 +279,12 @@ def draw_ways():
else: else:
style = 'fill:#0000FF;stroke:none;' style = 'fill:#0000FF;stroke:none;'
draw_path(way['nodes'], style) draw_path(way['nodes'], style)
for tag in way['tags']:
if not (tag in ['landuse', 'layer']):
point(tag, str(way['tags'][tag]), c.x, c.y, '000000', text_y)
text_y += 10
for way in layer['a']: for way in layer['a']:
ma = Vector() c = line_center(way['nodes'])
mi = Vector(10000, 10000)
for node_id in way['nodes']:
node = node_map[node_id]
flinged = flinger.fling(node)
if flinged.x > ma.x: ma.x = flinged.x
if flinged.y > ma.y: ma.y = flinged.y
if flinged.x < mi.x: mi.x = flinged.x
if flinged.y < mi.y: mi.y = flinged.y
c = Vector((ma.x + mi.x) / 2.0, (ma.y + mi.y) / 2.0)
if way['tags']['amenity'] == 'parking': if way['tags']['amenity'] == 'parking':
style = 'fill:#' + parking_color + ';stroke:none;' style = 'fill:#' + parking_color + ';stroke:none;'
draw_path(way['nodes'], style) draw_path(way['nodes'], style)
@ -357,7 +314,7 @@ def draw_ways():
draw_path(way['nodes'], style) draw_path(way['nodes'], style)
for way in layer['r']: for way in layer['r']:
v = way['tags']['railway'] v = way['tags']['railway']
style = 'fill:none;stroke-dasharray:none;stroke-linejoin:round;stroke-linecap:butt;stroke-width:' style = 'fill:none;stroke-dasharray:none;stroke-linejoin:round;stroke-linecap:round;stroke-width:'
if v == 'subway': style += '10;stroke:#DDDDDD;' if v == 'subway': style += '10;stroke:#DDDDDD;'
if v in ['narrow_gauge', 'tram']: if v in ['narrow_gauge', 'tram']:
style += '2;stroke:#000000;' style += '2;stroke:#000000;'
@ -366,11 +323,11 @@ def draw_ways():
draw_path(way['nodes'], style) draw_path(way['nodes'], style)
for way in layer['h1']: for way in layer['h1']:
if 'tunnel' in way['tags'] and way['tags']['tunnel'] == 'yes': if 'tunnel' in way['tags'] and way['tags']['tunnel'] == 'yes':
style = 'fill:none;stroke:#FFFFFF;stroke-dasharray:none;stroke-linejoin:round;stroke-linecap:butt;stroke-width:10;' style = 'fill:none;stroke:#FFFFFF;stroke-dasharray:none;stroke-linejoin:round;stroke-linecap:round;stroke-width:10;'
draw_path(way['nodes'], style) draw_path(way['nodes'], style)
for way in layer['h1']: for way in layer['h1']:
v = way['tags']['highway'] v = way['tags']['highway']
style = 'fill:none;stroke:#AAAAAA;stroke-dasharray:none;stroke-linejoin:round;stroke-linecap:butt;stroke-width:' style = 'fill:none;stroke:#AAAAAA;stroke-dasharray:none;stroke-linejoin:round;stroke-linecap:round;stroke-width:'
if v == 'motorway': style += '30' if v == 'motorway': style += '30'
elif v == 'trunk': style += '25' elif v == 'trunk': style += '25'
elif v == 'primary': style += '20;stroke:#AA8800' elif v == 'primary': style += '20;stroke:#AA8800'
@ -381,15 +338,15 @@ def draw_ways():
elif v == 'service': style += '7' elif v == 'service': style += '7'
elif v == 'track': style += '3' elif v == 'track': style += '3'
elif v in ['footway', 'pedestrian']: style += '2' elif v in ['footway', 'pedestrian']: style += '2'
elif v == 'steps': style += '5;stroke-dasharray:1,2;stroke-linecap:butt' elif v == 'steps': style += '5;stroke-dasharray:1,2;stroke-linecap:round'
elif v == 'path': style += '1;stroke-dasharray:5,5;stroke-linecap:butt' elif v == 'path': style += '1;stroke-dasharray:5,5;stroke-linecap:round'
else: else:
continue continue
style += ';' style += ';'
draw_path(way['nodes'], style) draw_path(way['nodes'], style)
for way in layer['h2']: for way in layer['h2']:
v = way['tags']['highway'] v = way['tags']['highway']
style = 'fill:none;stroke:#FFFFFF;stroke-linecap:butt;stroke-linejoin:round;stroke-width:' style = 'fill:none;stroke:#FFFFFF;stroke-linecap:round;stroke-linejoin:round;stroke-width:'
if v == 'motorway': style += '28' if v == 'motorway': style += '28'
elif v == 'trunk': style += '23' elif v == 'trunk': style += '23'
elif v == 'primary': style += '19;stroke:#FFDD66' elif v == 'primary': style += '19;stroke:#FFDD66'
@ -408,16 +365,7 @@ def draw_ways():
#if 'building:levels' in way['tags']: #if 'building:levels' in way['tags']:
#floors = float(way['tags']['building:levels']) #floors = float(way['tags']['building:levels'])
draw_path(way['nodes'], 'fill:#D0D0C0;stroke:#AAAAAA;opacity:1.0;') draw_path(way['nodes'], 'fill:#D0D0C0;stroke:#AAAAAA;opacity:1.0;')
ma = Vector() c = line_center(way['nodes'])
mi = Vector(10000, 10000)
for node_id in way['nodes']:
node = node_map[node_id]
flinged = flinger.fling(node)
if flinged.x > ma.x: ma.x = flinged.x
if flinged.y > ma.y: ma.y = flinged.y
if flinged.x < mi.x: mi.x = flinged.x
if flinged.y < mi.y: mi.y = flinged.y
c = Vector((ma.x + mi.x) / 2.0, (ma.y + mi.y) / 2.0)
for tag in way['tags']: for tag in way['tags']:
v = way['tags'][tag] v = way['tags'][tag]
if tag == 'building': if tag == 'building':
@ -461,22 +409,13 @@ def draw_ways():
pass pass
else: else:
kk = tag kk = tag
vv = unicode(v) vv = v
if ('way ' + kk + ': ' + vv) in missed_tags: if ('way ' + kk + ': ' + vv) in missed_tags:
missed_tags['way ' + kk + ': ' + vv] += 1 missed_tags['way ' + kk + ': ' + vv] += 1
else: else:
missed_tags['way ' + kk + ': ' + vv] = 1 missed_tags['way ' + kk + ': ' + vv] = 1
for way in layer['le']: for way in layer['le']:
ma = Vector() c = line_center(way['nodes'])
mi = Vector(10000, 10000)
for node_id in way['nodes']:
node = node_map[node_id]
flinged = flinger.fling(node)
if flinged.x > ma.x: ma.x = flinged.x
if flinged.y > ma.y: ma.y = flinged.y
if flinged.x < mi.x: mi.x = flinged.x
if flinged.y < mi.y: mi.y = flinged.y
c = Vector((ma.x + mi.x) / 2.0, (ma.y + mi.y) / 2.0)
if way['tags']['leisure'] == 'playground': if way['tags']['leisure'] == 'playground':
style = 'fill:#' + playground_color + ';opacity:0.2;' style = 'fill:#' + playground_color + ';opacity:0.2;'
draw_point_shape('playground', c.x, c.y, '444444') draw_point_shape('playground', c.x, c.y, '444444')
@ -509,89 +448,157 @@ def draw_raw_nodes():
flinged = flinger.fling(node) flinged = flinger.fling(node)
output_file.circle(flinged.x, flinged.y, 0.2, color='FFFFFF') output_file.circle(flinged.x, flinged.y, 0.2, color='FFFFFF')
def no_draw(key):
return key in undraw or 'name' in key or 'addr' in key
def draw_nodes(): def draw_nodes():
print 'Draw nodes...' print 'Draw nodes...'
for element in content.childNodes[0].childNodes: for node_id in node_map:
if element.nodeName != 'node': node = node_map[node_id]
continue flinged = flinger.fling(Geo(node['lat'], node['lon']))
flinged = flinger.fling(Geo(float(element.attributes['lat'].value), x = `flinged.x`
float(element.attributes['lon'].value))) y = `flinged.y`
text_y = 0 text_y = 0
if 'tags' in node:
pairs = node['tags']
else:
pairs = {} pairs = {}
for child_node in element.childNodes:
if isinstance(child_node, xml.dom.minidom.Element):
if child_node.tagName == 'tag':
pairs[child_node.attributes['k'].value] = child_node.attributes['v'].value
fill = '444444' fill = '444444'
if 'colour' in pairs: if 'colour' in pairs:
if pairs['colour'] == 'blue': if pairs['colour'] == 'blue':
fill='2233AA' fill='2233AA'
radius=3 radius=3
for k in pairs:
v = pairs[k] if pairs == {}:
x = `flinged.x` pass
y = `flinged.y` elif 'amenity' in pairs:
if k == 'amenity': k = 'amenity'
if v in ['bench', 'bicycle_parking', 'waste_basket', v = pairs['amenity']
if v in ['bench', 'bicycle_parking', 'cafe', 'waste_basket', 'clinic',
'restaurant', 'pharmacy', 'drinking_water', 'toilets', 'restaurant', 'pharmacy', 'drinking_water', 'toilets',
'fast_food', 'theatre']: 'theatre', 'bar', 'bank', 'pub', 'post_office']:
draw_point_shape(v, x, y, fill) draw_point_shape(v, x, y, fill)
elif v == 'clinic': elif v == 'fast_food':
draw_point(d_clinic, x, y, fill) main = 'fast_food'
if 'operator' in pairs:
if pairs['operator'] == "McDonald's":
main = 'mcdonalds'
if 'operator:en' in pairs:
if pairs['operator:en'] == "McDonald's":
main = 'mcdonalds'
draw_point_shape(main, x, y, fill)
elif v == 'shop':
if 'shop' in pairs:
if pairs['shop'] in ['fishing']:
draw_point_shape('shop_' + pairs['shop'], x, y, fill)
elif v == 'fountain': elif v == 'fountain':
draw_point_shape('fountain', x, y, water_border_color) draw_point_shape('fountain', x, y, water_border_color)
elif v == 'recycling': elif v == 'recycling':
if not 'recycling_type' in pairs: if not 'recycling_type' in pairs:
draw_point_shape('recycling', x, y, fill) draw_point_shape('recycling', x, y, fill)
else: else:
point(k, v, flinged.x, flinged.y, fill) point(k, v, flinged.x, flinged.y, fill, text_y)
text_y += 10
for k in pairs:
if 'karaoke' in pairs:
if pairs['karaoke'] == 'yes':
draw_point_shape('microphone', flinged.x + 16, y, fill)
else:
point(k, pairs[k], x, y, fill, text_y)
elif not no_draw(k) and k != 'amenity':
point(k, pairs[k], x, y, fill, text_y)
text_y += 10
elif 'natural' in pairs:
k = 'natural'
v = pairs['natural']
if v == 'tree':
main = 'tree'
if 'leaf_type' in pairs and pairs['leaf_type'] in ['broadleaved', 'needleleaved']:
main = pairs['leaf_type']
if 'denotation' in pairs and pairs['denotation'] == 'urban':
draw_point_shape([main, 'urban_tree_pot'], x, y, wood_color)
else:
draw_point_shape(main, x, y, wood_color)
elif v == 'cave_entrance':
draw_point_shape('cave', x, y, fill)
elif v == 'bush':
draw_point_shape('bush', x, y, wood_color)
else:
point(k, v, flinged.x, flinged.y, fill, text_y)
text_y += 10
elif 'entrance' in pairs:
k = 'entrance'
v = pairs['entrance']
if v == 'yes':
draw_point_shape('entrance', x, y, fill)
elif v == 'staircase':
draw_point_shape('staircase', x, y, fill)
elif 'highway' in pairs:
k = 'highway'
v = pairs['highway']
if v == 'crossing':
shape = 'crossing'
if 'crossing' in pairs:
if pairs['crossing'] == 'zebra':
shape = 'zebra'
elif 'crossing_ref' in pairs:
if pairs['crossing_ref'] == 'zebra':
shape = 'zebra'
draw_point_shape(shape, x, y, fill)
elif v == 'street_lamp':
draw_point_shape('street_lamp', x, y, fill)
else:
for k in pairs:
if not no_draw(k):
point(k, pairs[k], x, y, fill, text_y)
text_y += 10
for k in []:
v = pairs[k]
if k == 'amenity':
if v in ['bench', 'bicycle_parking', 'cafe', 'waste_basket',
'restaurant', 'pharmacy', 'drinking_water', 'toilets',
'fast_food', 'theatre']:
draw_point_shape(v, x, y, fill)
elif k == 'artwork_type': elif k == 'artwork_type':
if v == 'statue': if v == 'statue':
draw_point_shape('monument', x, y, fill) draw_point_shape('monument', x, y, fill)
if v == 'sculpture': if v == 'sculpture':
draw_point_shape('monument', x, y, fill) draw_point_shape('monument', x, y, fill)
else: else:
point(k, v, flinged.x, flinged.y, fill) point(k, v, flinged.x, flinged.y, fill, text_y)
text_y += 10
elif k == 'barrier': elif k == 'barrier':
if v == 'lift_gate': if v == 'lift_gate':
draw_point_shape('liftgate', x, y, fill) draw_point_shape('liftgate', x, y, fill)
elif k in ['crossing', 'crossing_ref']: elif k in ['crossing', 'crossing_ref']:
if v == 'zebra': if v == 'zebra':
draw_point(d_crossing, x, y, fill) draw_point_shape('crossing', x, y, fill)
elif k == 'entrance': elif k == 'entrance':
draw_point_shape('entrance', x, y, fill) draw_point_shape('entrance', x, y, fill)
elif k == 'highway': elif k == 'highway':
if v == 'street_lamp': if v == 'street_lamp':
draw_point(d_street_lamp, x, y, fill) draw_point_shape('street_lamp', x, y, fill)
elif v == 'bus_stop': elif v == 'bus_stop':
draw_point_shape('bus_stop', x, y, fill) draw_point_shape('bus_stop', x, y, fill)
elif v == 'traffic_signals': elif v == 'traffic_signals':
draw_point(d_traffic_signal, x, y, fill) draw_point_shape('traffic_signal', x, y, fill)
elif v == 'crossing': elif v == 'crossing':
if not ('crossing' in pairs): if not ('crossing' in pairs):
draw_point(d_crossing, x, y, fill) draw_point_shape('crossing', x, y, fill)
else: else:
point(k, v, flinged.x, flinged.y, fill) point(k, v, flinged.x, flinged.y, fill, text_y)
text_y += 10
elif k == 'man_made': elif k == 'man_made':
if v == 'pole': if v == 'pole':
draw_point_shape('pole', x, y, fill) draw_point_shape('pole', x, y, fill)
elif v == 'flagpole': elif v == 'flagpole':
draw_point_shape('flagpole', x, y, fill) draw_point_shape('flagpole', x, y, fill)
else: else:
point(k, v, flinged.x, flinged.y, fill) point(k, v, flinged.x, flinged.y, fill, text_y)
elif k == 'natural': text_y += 10
if v == 'tree':
if 'denotation' in pairs and pairs['denotation'] == 'urban':
draw_point_shape('urban_tree', x, y, wood_color)
else:
draw_point(d_tree, x, y, wood_color)
elif v == 'cave_entrance':
draw_point_shape('cave', x, y, fill)
elif v == 'bush':
draw_point_shape('bush', x, y, wood_color)
else:
point(k, v, flinged.x, flinged.y, fill)
elif k == 'recycling_type': elif k == 'recycling_type':
if v == 'centre': if v == 'centre':
draw_point_shape('recycling', x, y, fill) draw_point_shape('recycling', x, y, fill)
@ -603,12 +610,14 @@ def draw_nodes():
elif v in ['clothes', 'shoes', 'gift']: elif v in ['clothes', 'shoes', 'gift']:
draw_point_shape('shop_' + v, x, y, fill) draw_point_shape('shop_' + v, x, y, fill)
else: else:
point(k, v, flinged.x, flinged.y, fill) point(k, v, flinged.x, flinged.y, fill, text_y)
text_y += 10
elif k == 'traffic_calming': elif k == 'traffic_calming':
if v == 'bump': if v == 'bump':
draw_point_shape('bump', x, y, fill) draw_point_shape('bump', x, y, fill)
else: else:
point(k, v, flinged.x, flinged.y, fill) point(k, v, flinged.x, flinged.y, fill, text_y)
text_y += 10
elif k == 'emergency': elif k == 'emergency':
if v == 'fire_hydrant': if v == 'fire_hydrant':
draw_point_shape(v, x, y, fill) draw_point_shape(v, x, y, fill)
@ -621,12 +630,7 @@ def draw_nodes():
draw_point_shape('monument', x, y, fill) draw_point_shape('monument', x, y, fill)
if v == 'attraction': if v == 'attraction':
draw_point_shape('monument', x, y, fill) draw_point_shape('monument', x, y, fill)
elif k in [ elif k in undraw or ('name' in k):
'operator', 'contact:facebook', 'contact:phone',
'opening_hours', 'cuisine', 'network', 'website',
'contact:website', 'phone', 'branch', 'route_ref',
'addr:flats', 'brand', 'ref', 'addr:street', 'wikipedia',
] or ('name' in k):
if k == 'route_ref': if k == 'route_ref':
v = v.replace(';', ' ') v = v.replace(';', ' ')
draw_text(v, x, str(flinged.y + 18 + text_y), fill) draw_text(v, x, str(flinged.y + 18 + text_y), fill)
@ -634,13 +638,20 @@ def draw_nodes():
elif k in ['layer', 'level', 'source', 'note', 'description']: elif k in ['layer', 'level', 'source', 'note', 'description']:
pass # NOTHING TO DRAW pass # NOTHING TO DRAW
else: else:
point(k, v, flinged.x, flinged.y, fill) point(k, v, flinged.x, flinged.y, fill, text_y)
text_y += 10
print 'Done.' print 'Done.'
#draw_raw_nodes() #draw_raw_nodes()
#draw_raw_ways() #draw_raw_ways()
text_y = 0
icons = extract_icon.IconExtractor('icons.svg')
#sys.exit(0)
draw_ways() draw_ways()
draw_nodes() draw_nodes()
@ -655,7 +666,7 @@ top_missed_tags = reversed(sorted(missed_tags.keys(), key=lambda x: -missed_tags
for tag in top_missed_tags: for tag in top_missed_tags:
print tag + ' (' + str(missed_tags[tag]) + ')' print tag + ' (' + str(missed_tags[tag]) + ')'
sys.exit(1) sys.exit(0)
top_authors = sorted(authors.keys(), key=lambda x: -authors[x]) top_authors = sorted(authors.keys(), key=lambda x: -authors[x])
for author in top_authors: for author in top_authors:

View file

@ -4,39 +4,81 @@ Reading OpenStreetMap data from XML file.
Author: Sergey Vartanov Author: Sergey Vartanov
""" """
import datetime
def parse_node_full(text):
def parse_node_full(node_data, silent=False):
""" """
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().
""" """
m = re.match('id="(.*)" visible="(.*)" version="(.*)" changeset="(.*)" timestamp="(.*)" user="(.*)" uid="(.*)" lat="(.*)" lon="(.*)"', text) m = re.match('id="(.*)" visible="(.*)" version="(.*)" changeset="(.*)" ' + \
'timestamp="(.*)" user="(.*)" uid="(.*)" ' + \
'lat="(.*)" lon="(.*)"', node_data)
if m: 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), 'lat': m.group(7), 'lon': m.group(8)} 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))}
else: else:
print 'Error node' if not silent:
print 'Error: cannot parse node data: ' + node_data + '.'
return None
def parse_node(text): def parse_node(text):
""" """
Parse just identifier, latitude, and longitude from node parameters. Just parse node identifier, latitude, and longitude.
""" """
id = text[4:text.find('"', 6)] id = text[4:text.find('"', 6)]
lat_index = text.find('lat') lat_index = text.find('lat')
lon_index = text.find('lon') lon_index = text.find('lon')
lat = text[lat_index + 5:text.find('"', lat_index + 7)] lat = text[lat_index + 5:text.find('"', lat_index + 7)]
lon = text[lon_index + 5:text.find('"', lon_index + 7)] lon = text[lon_index + 5:text.find('"', lon_index + 7)]
return {'id': id, 'lat': lat, 'lon': lon} return {'id': int(id), 'lat': float(lat), 'lon': float(lon)}
def parse_way_full(text): def parse_way_full(way_data, silent=False):
m = re.match('id="(.*)" visible="(.*)" version="(.*)" changeset="(.*)" timestamp="(.*)" user="(.*)" uid="(.*)"', text) """
Parse full way parameters using regular expressions: id, visible, version,
etc. For faster parsing use parse_way().
"""
m = re.match('id="(.*)" visible="(.*)" version="(.*)" changeset="(.*)" ' + \
'timestamp="(.*)" user="(.*)" uid="(.*)"', way_data)
if m: 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)} 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)}
else: else:
print 'Error way' if not silent:
print 'Error: cannot parse way data: ' + way_data + '.'
return None
def parse_way(text): def parse_way(text):
"""
Just parse way identifier.
"""
id = text[4:text.find('"', 6)] id = text[4:text.find('"', 6)]
return {'id': id} return {'id': int(id)}
def parse_relation(text):
"""
Just parse relation identifier.
"""
id = text[4:text.find('"', 6)]
return {'id': int(id)}
def parse_member(text):
"""
Parse member type, reference, and role.
"""
if text[6] == 'w':
type = 'way'
else:
type = 'node'
ref_index = text.find('ref')
role_index = text.find('role')
ref = text[ref_index + 5:text.find('"', ref_index + 7)]
role = text[role_index + 6:text.find('"', role_index + 8)]
return {'type': type, 'ref': int(ref), 'role': role}
def parse_tag(text): def parse_tag(text):
v_index = text.find('v="') v_index = text.find('v="')
@ -44,25 +86,19 @@ def parse_tag(text):
v = text[v_index + 3:text.find('"', v_index + 4)] v = text[v_index + 3:text.find('"', v_index + 4)]
return k, v return k, v
def get_max_min(nodes):
maximum = Geo(nodes[0]['lon'], nodes[0]['lat'])
minimum = Geo(nodes[0]['lon'], nodes[0]['lat'])
for node in nodes:
if node['lat'] > maximum.lat: maximum.lat = node['lat']
if node['lat'] < minimum.lat: minimum.lat = node['lat']
if node['lon'] > maximum.lon: maximum.lon = node['lon']
if node['lon'] < minimum.lon: minimum.lon = node['lon']
return minimum, maximum
def parse_osm_file(file_name, silent=False): def parse_osm_file(file_name, silent=False):
if not silent: if not silent:
print 'Reading OSM file ' + file_name print 'Reading OSM file ' + file_name
start_time = datetime.datetime.now() start_time = datetime.datetime.now()
node_map = {} node_map = {}
way_map = {} way_map = {}
relation_map = {}
input_file = open(file_name) input_file = open(file_name)
line = input_file.readline() line = input_file.readline()
while line != '': while line != '':
# Node parsing.
if line[:6] == ' <node': if line[:6] == ' <node':
if line[-3] == '/': if line[-3] == '/':
node = parse_node(line[7:-3]) node = parse_node(line[7:-3])
@ -70,26 +106,50 @@ def parse_osm_file(file_name, silent=False):
else: else:
element = parse_node(line[7:-2]) element = parse_node(line[7:-2])
element['tags'] = {} element['tags'] = {}
elif line == ' </node>': elif line == ' </node>\n':
node_map[node['id']] = element node_map[element['id']] = element
# Way parsing.
elif line[:5] == ' <way': elif line[:5] == ' <way':
if line[-3] == '/': if line[-3] == '/':
way = parse_node(line[7:-3]) way = parse_way(line[6:-3])
node_map[node['id']] = node node_map[node['id']] = node
else: else:
element = parse_way(line[6:-2]) element = parse_way(line[6:-2])
element['tags'] = {} element['tags'] = {}
element['nodes'] = [] element['nodes'] = []
elif line == ' </way>\n':
way_map[element['id']] = element
# Relation parsing.
elif line[:10] == ' <relation':
if line[-3] == '/':
relation = parse_relation(line[11:-3])
relation_map[relation['id']] = relation
else:
element = parse_relation(line[11:-2])
element['tags'] = {}
element['members'] = []
elif line == ' </relation>\n':
relation_map[element['id']] = element
# Elements parsing.
elif line[:6] == ' <tag': elif line[:6] == ' <tag':
k, v = parse_tag(line[7:-3]) k, v = parse_tag(line[7:-3])
element['tags'][k] = v element['tags'][k] = v
elif line[:5] == ' <nd': elif line[:5] == ' <nd':
element['nodes'].append(line[11:-3]) element['nodes'].append(int(line[11:-4]))
elif line[:5] == ' <member':
member = parse_member(line[10:-3])
element['members'].append(member)
line = input_file.readline() line = input_file.readline()
input_file.close() input_file.close()
if not silent: if not silent:
print 'File readed in ' + \ print 'File readed in ' + \
str(datetime.datetime.now() - start_time) + '.' str(datetime.datetime.now() - start_time) + '.'
return node_map, way_map return node_map, way_map, relation_map