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
"""
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 re
import sys
import xml.dom.minidom
import extract_icon
import osm_reader
from flinger import GeoFlinger, Geo
sys.path.append('lib')
@ -19,24 +23,19 @@ sys.path.append('lib')
import svg
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]
if not os.path.isfile(input_file_name):
print 'Fatal: no such file: ' + input_file_name + '.'
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)
content = xml.dom.minidom.parse(input_file)
input_file.close()
print 'Done.'
node_map, way_map, relation_map = osm_reader.parse_osm_file(input_file_name)
output_file = svg.SVG(open(sys.argv[2], 'w+'))
@ -53,6 +52,11 @@ water_color = 'AACCFF'
water_border_color = '6688BB'
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.rect(0, 0, w, h, color=background_color)
@ -66,13 +70,13 @@ if len(sys.argv) > 3:
authors = {}
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):
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'):
file_name = 'icons/' + file_name + '.svg'
size = 16
@ -97,39 +101,21 @@ def get_d_from_file(file_name):
if m:
return m.group('path'), size
# Construct node map
def construct_node_map():
"""
Construct map of nodes.
"""
print 'Construct node map...'
node_map = {}
for element in content.childNodes[0].childNodes:
if element.nodeType != element.TEXT_NODE:
if 'user' in element.attributes.keys():
author = element.attributes['user'].value
if author in authors:
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
def get_min_max(node_map):
key = node_map.keys()[0]
maximum = Geo(node_map[key]['lon'], node_map[key]['lat'])
minimum = Geo(node_map[key]['lon'], node_map[key]['lat'])
for node_id in node_map:
node = node_map[node_id]
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
node_map = construct_node_map()
minimum, maximum = get_min_max(node_map)
if len(sys.argv) > 3:
flinger = GeoFlinger(min1, max1, Vector(0, 0), Vector(w, h))
@ -140,9 +126,10 @@ else:
def draw_path(nodes, style, shift=Vector()):
prev_node = None
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:
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` + ' ')
else:
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')
def draw_point_shape(name, x, y, fill):
shape, size = get_d_from_file(name)
draw_point(shape, x, y, fill, size=size)
shape, xx, yy = get_d_from_file(name)
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))
y = int(float(y))
output_file.write('<path d="' + shape + \
'" 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 + \
'" 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):
if type(text) == unicode:
@ -177,64 +164,28 @@ def draw_text(text, x, y, fill):
output_file.write('<text x="' + x + '" y="' + y + \
'" 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:
missed_tags['node ' + k + ': ' + v] += 1
else:
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
if type(text) == unicode:
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>')
# Ways drawing
def construct_way_map():
def construct_layers():
"""
Construct map of ways and distribute them by layers. One layer may contain
elements of different types.
Construct layers. One layer may contain elements of different types.
"""
print 'Construct way map...'
layers = {}
way_map = {}
for element in content.childNodes[0].childNodes:
if element.nodeName == 'way':
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)
for way_id in way_map:
way = way_map[way_id]
if not ('layer' in way['tags']):
way['tags']['layer'] = 0
if not (int(way['tags']['layer']) in layers):
@ -268,37 +219,48 @@ def construct_way_map():
# empty = False
# if not empty:
# 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():
for way_id in way_map:
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)
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():
for level in sorted(layers.keys()):
layer = layers[level]
#for entity in ['b', 'h1', 'h2', 'r', 'n', 'l', 'a', 'le', 'ba']:
# Pre part.
for way in layer['le']:
if way['tags']['leisure'] == 'park':
style = 'fill:#' + grass_color + ';'
else:
continue
draw_path(way['nodes'], style)
# Post part.
for way in layer['l']:
ma = Vector()
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)
text_y = 0
c = line_center(way['nodes'])
if way['tags']['landuse'] == 'grass':
style = 'fill:#' + grass_color + ';stroke:none;'
draw_path(way['nodes'], style)
@ -317,17 +279,12 @@ def draw_ways():
else:
style = 'fill:#0000FF;stroke:none;'
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']:
ma = Vector()
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)
c = line_center(way['nodes'])
if way['tags']['amenity'] == 'parking':
style = 'fill:#' + parking_color + ';stroke:none;'
draw_path(way['nodes'], style)
@ -357,7 +314,7 @@ def draw_ways():
draw_path(way['nodes'], style)
for way in layer['r']:
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 in ['narrow_gauge', 'tram']:
style += '2;stroke:#000000;'
@ -366,11 +323,11 @@ def draw_ways():
draw_path(way['nodes'], style)
for way in layer['h1']:
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)
for way in layer['h1']:
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'
elif v == 'trunk': style += '25'
elif v == 'primary': style += '20;stroke:#AA8800'
@ -381,15 +338,15 @@ def draw_ways():
elif v == 'service': style += '7'
elif v == 'track': style += '3'
elif v in ['footway', 'pedestrian']: style += '2'
elif v == 'steps': style += '5;stroke-dasharray:1,2;stroke-linecap:butt'
elif v == 'path': style += '1;stroke-dasharray:5,5;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:round'
else:
continue
style += ';'
draw_path(way['nodes'], style)
for way in layer['h2']:
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'
elif v == 'trunk': style += '23'
elif v == 'primary': style += '19;stroke:#FFDD66'
@ -408,16 +365,7 @@ def draw_ways():
#if 'building:levels' in way['tags']:
#floors = float(way['tags']['building:levels'])
draw_path(way['nodes'], 'fill:#D0D0C0;stroke:#AAAAAA;opacity:1.0;')
ma = Vector()
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)
c = line_center(way['nodes'])
for tag in way['tags']:
v = way['tags'][tag]
if tag == 'building':
@ -461,22 +409,13 @@ def draw_ways():
pass
else:
kk = tag
vv = unicode(v)
vv = v
if ('way ' + kk + ': ' + vv) in missed_tags:
missed_tags['way ' + kk + ': ' + vv] += 1
else:
missed_tags['way ' + kk + ': ' + vv] = 1
for way in layer['le']:
ma = Vector()
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)
c = line_center(way['nodes'])
if way['tags']['leisure'] == 'playground':
style = 'fill:#' + playground_color + ';opacity:0.2;'
draw_point_shape('playground', c.x, c.y, '444444')
@ -509,89 +448,157 @@ def draw_raw_nodes():
flinged = flinger.fling(node)
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():
print 'Draw nodes...'
for element in content.childNodes[0].childNodes:
if element.nodeName != 'node':
continue
flinged = flinger.fling(Geo(float(element.attributes['lat'].value),
float(element.attributes['lon'].value)))
for node_id in node_map:
node = node_map[node_id]
flinged = flinger.fling(Geo(node['lat'], node['lon']))
x = `flinged.x`
y = `flinged.y`
text_y = 0
if 'tags' in node:
pairs = node['tags']
else:
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'
if 'colour' in pairs:
if pairs['colour'] == 'blue':
fill='2233AA'
radius=3
for k in pairs:
v = pairs[k]
x = `flinged.x`
y = `flinged.y`
if k == 'amenity':
if v in ['bench', 'bicycle_parking', 'waste_basket',
if pairs == {}:
pass
elif 'amenity' in pairs:
k = 'amenity'
v = pairs['amenity']
if v in ['bench', 'bicycle_parking', 'cafe', 'waste_basket', 'clinic',
'restaurant', 'pharmacy', 'drinking_water', 'toilets',
'fast_food', 'theatre']:
'theatre', 'bar', 'bank', 'pub', 'post_office']:
draw_point_shape(v, x, y, fill)
elif v == 'clinic':
draw_point(d_clinic, x, y, fill)
elif v == 'fast_food':
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':
draw_point_shape('fountain', x, y, water_border_color)
elif v == 'recycling':
if not 'recycling_type' in pairs:
draw_point_shape('recycling', x, y, fill)
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':
if v == 'statue':
draw_point_shape('monument', x, y, fill)
if v == 'sculpture':
draw_point_shape('monument', x, y, fill)
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':
if v == 'lift_gate':
draw_point_shape('liftgate', x, y, fill)
elif k in ['crossing', 'crossing_ref']:
if v == 'zebra':
draw_point(d_crossing, x, y, fill)
draw_point_shape('crossing', x, y, fill)
elif k == 'entrance':
draw_point_shape('entrance', x, y, fill)
elif k == 'highway':
if v == 'street_lamp':
draw_point(d_street_lamp, x, y, fill)
draw_point_shape('street_lamp', x, y, fill)
elif v == 'bus_stop':
draw_point_shape('bus_stop', x, y, fill)
elif v == 'traffic_signals':
draw_point(d_traffic_signal, x, y, fill)
draw_point_shape('traffic_signal', x, y, fill)
elif v == 'crossing':
if not ('crossing' in pairs):
draw_point(d_crossing, x, y, fill)
draw_point_shape('crossing', x, y, fill)
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':
if v == 'pole':
draw_point_shape('pole', x, y, fill)
elif v == 'flagpole':
draw_point_shape('flagpole', x, y, fill)
else:
point(k, v, flinged.x, flinged.y, fill)
elif k == 'natural':
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)
point(k, v, flinged.x, flinged.y, fill, text_y)
text_y += 10
elif k == 'recycling_type':
if v == 'centre':
draw_point_shape('recycling', x, y, fill)
@ -603,12 +610,14 @@ def draw_nodes():
elif v in ['clothes', 'shoes', 'gift']:
draw_point_shape('shop_' + v, x, y, fill)
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':
if v == 'bump':
draw_point_shape('bump', x, y, fill)
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':
if v == 'fire_hydrant':
draw_point_shape(v, x, y, fill)
@ -621,12 +630,7 @@ def draw_nodes():
draw_point_shape('monument', x, y, fill)
if v == 'attraction':
draw_point_shape('monument', x, y, fill)
elif k in [
'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):
elif k in undraw or ('name' in k):
if k == 'route_ref':
v = v.replace(';', ' ')
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']:
pass # NOTHING TO DRAW
else:
point(k, v, flinged.x, flinged.y, fill)
point(k, v, flinged.x, flinged.y, fill, text_y)
text_y += 10
print 'Done.'
#draw_raw_nodes()
#draw_raw_ways()
text_y = 0
icons = extract_icon.IconExtractor('icons.svg')
#sys.exit(0)
draw_ways()
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:
print tag + ' (' + str(missed_tags[tag]) + ')'
sys.exit(1)
sys.exit(0)
top_authors = sorted(authors.keys(), key=lambda x: -authors[x])
for author in top_authors:

View file

@ -4,39 +4,81 @@ Reading OpenStreetMap data from XML file.
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,
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:
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:
print 'Error node'
if not silent:
print 'Error: cannot parse node data: ' + node_data + '.'
return None
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)]
lat_index = text.find('lat')
lon_index = text.find('lon')
lat = text[lat_index + 5:text.find('"', lat_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):
m = re.match('id="(.*)" visible="(.*)" version="(.*)" changeset="(.*)" timestamp="(.*)" user="(.*)" uid="(.*)"', text)
def parse_way_full(way_data, silent=False):
"""
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:
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:
print 'Error way'
if not silent:
print 'Error: cannot parse way data: ' + way_data + '.'
return None
def parse_way(text):
"""
Just parse way identifier.
"""
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):
v_index = text.find('v="')
@ -44,25 +86,19 @@ def parse_tag(text):
v = text[v_index + 3:text.find('"', v_index + 4)]
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):
if not silent:
print 'Reading OSM file ' + file_name
start_time = datetime.datetime.now()
node_map = {}
way_map = {}
relation_map = {}
input_file = open(file_name)
line = input_file.readline()
while line != '':
# Node parsing.
if line[:6] == ' <node':
if line[-3] == '/':
node = parse_node(line[7:-3])
@ -70,26 +106,50 @@ def parse_osm_file(file_name, silent=False):
else:
element = parse_node(line[7:-2])
element['tags'] = {}
elif line == ' </node>':
node_map[node['id']] = element
elif line == ' </node>\n':
node_map[element['id']] = element
# Way parsing.
elif line[:5] == ' <way':
if line[-3] == '/':
way = parse_node(line[7:-3])
way = parse_way(line[6:-3])
node_map[node['id']] = node
else:
element = parse_way(line[6:-2])
element['tags'] = {}
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':
k, v = parse_tag(line[7:-3])
element['tags'][k] = v
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()
input_file.close()
if not silent:
print 'File readed in ' + \
str(datetime.datetime.now() - start_time) + '.'
return node_map, way_map
return node_map, way_map, relation_map