Last active
December 16, 2015 13:48
-
-
Save balrog-kun/5444208 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/python2 | |
# vim: fileencoding=utf-8 encoding=utf-8 et sw=4 | |
import sys | |
import os | |
import xml.etree.cElementTree as ElementTree | |
import string | |
import math | |
def contains(poly, pos): | |
cont = 0 | |
prev = poly[0] | |
for node in poly[1:]: | |
if (node[1] > pos[1]) != (prev[1] > pos[1]) and pos[0] < node[0] + \ | |
(prev[0] - node[0]) * (pos[1] - node[1]) / (prev[1] - node[1]): | |
cont = not cont | |
prev = node | |
return cont | |
def expand(poly, dist): | |
ratio = math.cos(math.radians(poly[0][0])) | |
p = [] | |
x = poly[-2] | |
y = poly[0] | |
for z in poly[1:]: | |
v0 = ( y[0] - x[0], (y[1] - x[1]) * ratio ) | |
v1 = ( z[0] - y[0], (z[1] - y[1]) * ratio ) | |
l0 = math.hypot(v0[0], v0[1]) | |
l1 = math.hypot(v1[0], v1[1]) | |
o = ( -v0[1] / l0 - v1[1] / l1, v0[0] / l0 + v1[0] / l1 ) | |
d = abs(o[0] * v1[1] - o[1] * v1[0]) / l1; | |
l = math.hypot(o[0], o[1]) | |
# Drop it or leave it? Drop the point | |
if l > 0.2: | |
p.append(( y[0] + o[0] * dist / d, y[1] + o[1] * dist / d / ratio)) | |
x, y = ( y, z ) | |
p.append(p[0]) | |
return p | |
outroot = ElementTree.Element("osm", { "version": "0.6" }) | |
bldgroot = ElementTree.parse(sys.argv[1]).getroot() | |
addrroot = ElementTree.parse(sys.argv[2]).getroot() | |
waynodes = {} | |
bldgs = [] | |
addrs = [] | |
import rhr | |
# Read the building outlines | |
for elem in bldgroot: | |
if 'id' not in elem.attrib: | |
outroot.append(elem) | |
continue | |
id = int(elem.attrib['id']) | |
if elem.tag == 'node': | |
lat = float(elem.attrib['lat']) | |
lon = float(elem.attrib['lon']) | |
waynodes[id] = ( lat, lon ) | |
if elem.tag != 'way' or ('action' in elem.attrib and | |
elem.attrib['action'] == 'delete'): | |
outroot.append(elem) | |
continue | |
tags = {} | |
for sub in elem: | |
if sub.tag != 'tag': | |
continue | |
v = sub.attrib['v'].strip() | |
if v: | |
tags[sub.attrib['k']] = v | |
if 'building' not in tags or tags['building'] == 'no': | |
outroot.append(elem) | |
continue | |
# Tag transformations can happen here | |
# Parse the geometry, store in a convenient format, | |
# also find some point in the middle of the outline to be used to | |
# speed up distance calculation | |
way = [] | |
refs = [] | |
j = 0 | |
lat = 0.0 | |
lon = 0.0 | |
for sub in elem: | |
if sub.tag != 'nd': | |
continue | |
ref = int(sub.attrib['ref']) | |
if ref not in waynodes: | |
continue | |
way.append(waynodes[ref]) | |
refs.append(ref) | |
j += 1 | |
lat += waynodes[ref][0] | |
lon += waynodes[ref][1] | |
lat /= j | |
lon /= j | |
if refs[0] != refs[-1]: | |
outroot.append(elem) | |
continue | |
try: | |
if rhr.is_rhr(way[1:]): | |
nway = way | |
else: | |
nway = [] + way | |
nway.reverse() | |
except: | |
outroot.append(elem) | |
print('geometry error at obj ' + str(id)) | |
continue | |
eway = expand(nway, 1.5 * 360 / 40000000) | |
eeway = expand(nway, 4.0 * 360 / 40000000) | |
bldgs.append(( lat, lon, way, eway, eeway, refs, tags, elem.attrib, [] )) | |
bldgroot = None # Make python release the XML structure | |
# Read the address nodes data | |
for elem in addrroot: | |
if 'id' not in elem.attrib: | |
continue | |
tags = {} | |
for sub in elem: | |
if sub.tag != 'tag': | |
continue | |
v = sub.attrib['v'].strip() | |
if v: | |
tags[sub.attrib['k']] = v | |
if elem.tag != 'node' or ('action' in elem.attrib and | |
elem.attrib['action'] == 'delete'): | |
continue | |
lat = float(elem.attrib['lat']) | |
lon = float(elem.attrib['lon']) | |
id = int(elem.attrib['id']) | |
if 'version' in elem.attrib: | |
v = int(elem.attrib['version']) | |
else: | |
v = 1 | |
addr = ( lat, lon, tags, id, v, [] ) | |
addrs.append(addr) | |
addrroot = None | |
sys.stdout.write("Matching nodes to buildings\n") | |
for addr in addrs: | |
lat, lon = addr[:2] | |
# Find what if any building shapes contain this lat/lon | |
for elat, elon, way, eway, eeway, refs, btags, attrs, newaddrs in bldgs: | |
if 'addr:housenumber' in btags: | |
continue | |
if abs(elat - lat) + abs(elon - lon) > 0.005: | |
continue | |
if not contains(way, ( lat, lon )): | |
continue | |
newaddrs.append(addr) | |
addr[5].append(0) | |
break | |
sys.stdout.write("Matching nodes to buffered buildings\n") | |
for addr in addrs: | |
if addr[5]: | |
continue | |
lat, lon = addr[:2] | |
# Find what if any building shapes contain this lat/lon | |
for elat, elon, way, eway, eeway, refs, btags, attrs, newaddrs in bldgs: | |
if 'addr:housenumber' in btags: | |
continue | |
if abs(elat - lat) + abs(elon - lon) > 0.005: | |
continue | |
if not contains(eway, ( lat, lon )): | |
continue | |
newaddrs.append(addr) | |
addr[5].append(0) | |
break | |
sys.stdout.write("Matching nodes to double-buffered buildings\n") | |
for addr in addrs: | |
if addr[5]: | |
continue | |
lat, lon = addr[:2] | |
# Find what if any building shapes contain this lat/lon | |
for elat, elon, way, eway, eeway, refs, btags, attrs, newaddrs in bldgs: | |
if 'addr:housenumber' in btags or newaddrs: | |
continue | |
if abs(elat - lat) + abs(elon - lon) > 0.005: | |
continue | |
if not contains(eeway, ( lat, lon )): | |
continue | |
newaddrs.append(addr) | |
addr[5].append(0) | |
break | |
sys.stdout.write("Bulding new xml\n") | |
for lat, lon, way, eway, eeway, refs, tags, attrs, newaddrs in bldgs: | |
# If this building contains only a single address node, copy its tags | |
# to the building way and mark the node as no longer needed. | |
if len(newaddrs) == 1: | |
newaddrs[0][5].append(1) | |
if 'source' in newaddrs[0][2]: | |
newaddrs[0][2]['source:addr'] = newaddrs[0][2]['source'] | |
del newaddrs[0][2]['source'] | |
tags.update(newaddrs[0][2]) | |
attrs['action'] = 'modify' | |
if not rhr.is_rhr(way[1:]): | |
refs.reverse() | |
elem = ElementTree.SubElement(outroot, "way", attrs) | |
for k in tags: | |
ElementTree.SubElement(elem, 'tag', { 'k': k, 'v': tags[k] }) | |
for ref in refs: | |
ElementTree.SubElement(elem, 'nd', { 'ref': str(ref) }) | |
# Add remaining addresses as nodes | |
for lat, lon, tags, id, v, bbs in addrs: | |
if 1 in bbs: | |
continue | |
i = id | |
if i < 0: | |
i -= 2000000 | |
elem = ElementTree.SubElement(outroot, "node", { | |
'lat': str(lat), | |
'lon': str(lon), | |
"version": str(v), | |
"id": str(i) }) | |
for k in tags: | |
ElementTree.SubElement(elem, 'tag', { 'k': k, 'v': tags[k] }) | |
sys.stdout.write("Writing .osm's\n") | |
ElementTree.ElementTree(outroot).write("output.osm", "utf-8") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment