Deze week ga ik het wat uittesten in de praktijk.
#!/usr/bin/python # -*- coding: utf-8 -*- import xml.sax import sys import getopt import io import re import time; nodeId = -1 ''' This Python 2.7 compliant script will turn WayPoints coming from a Garmin device into an OSM-compliant file that can be imported with JOSM. It relies on the syntax used in the name of the waypoints The following stuff is recognized: - VB for amenity: waste_basket (Vuilbak) - BK for amenity: bench (Bank or Zitbank) - FIREH for emergency: fire_hydrant - M50/M70/Z70/Z30/Z50 for maxspeeds (Z for zones) - PIKNIK for tourism: picnic_site - WSS [name] for historic: wayside_shrine - CDC for power: cable_distribution_cabinet - ESS for power: sub_station - STOP/GW for highway: stop / give_way - LLI/RLI for highway: street_lamp - PAAL, KGATE, SWINGGATE, SWGATE, GATE, FBAR for barrier: bollard / kissing_gate, swing_gate, swing_gate, gate, cycle_barrier - house number notations, e.g. R10, L10-12, L10+-+20, L10+12---13+15 Execution: parseWayPoints.py -fwaypoint file has to end on '.gpx' The output is a file name the same as the waypoint file, but ending on '.osm' ''' class Node(): def __init__(self, lon, lat): global nodeId self.lon = lon self.lat = lat self.id = nodeId nodeId = nodeId - 1 def moveABit(self): return Node(self.lon + 0.00001, self.lat + 0.00001) def moveABitMore(self, move): return Node(self.lon + move, self.lat + move) class NodePlacer(): def __init__(self, file): self.file = file self.updatedText = '' self.nodeCount = 0 self.node = None def placeNode(self, node, tags): self.file.write(' ') for kv in tags: self.file.write(' \n') self.node = node def placeMovedNode(self, node, tags): node = node.moveABit() self.placeNode(node, tags) class AmenityNode(NodePlacer): def __init__(self, file): NodePlacer.__init__(self, file) def match(self, node, text): if text.find("BK VB") > -1 or text.find("VB BK") > -1 : self.placeNode(node, [('amenity', 'waste_basket')] ) self.placeMovedNode(node, [('amenity', 'bench')] ) self.updatedText = text.replace("BK VB", "").replace('VB BK', '') self.nodeCount = 2 return True if text.find("VB") > -1: self.placeNode(node, [('amenity', 'waste_basket')] ) self.updatedText = text.replace('VB', '') self.nodeCount = 1 return True if text.find("BK") > -1: self.placeNode(node, [('amenity', 'bench')] ) self.updatedText = text.replace('BK', '') self.nodeCount = 1 return True if text.find("FIREH") > -1: self.placeNode(node, [('emergency', 'fire_hydrant')] ) self.updatedText = text.replace('FIREH', '') self.nodeCount = 1 return True return False class PicnicNode(NodePlacer): def __init__(self, file): NodePlacer.__init__(self, file) def match(self, node, text): if text.find("PIKNIK") > -1: self.placeNode(node, [('tourism', 'picnic_site')] ) self.updatedText.replace('PIKNIK', '') self.nodeCount = 1 return True class MaxSpeedNode(NodePlacer): def __init__(self, file): NodePlacer.__init__(self, file) def match(self, node, text): if text.find("M50") > -1: self.placeNode(node, [('maxspeed', '50'), ('zone:traffic', 'BE:rural')]) self.nodeCount = 1 self.updatedText = text.replace('M50', '') if text.find('M70') > -1: self.placeNode(node, [('maxspeed', '70'), ('zone:traffic', 'BE:rural')]) self.nodeCount = 1 self.updatedText = text.replace('M70', '') if text.find('Z70') > -1: self.placeNode(node, [('maxspeed', '70'), ('zone:traffic', 'BE:rural'), ('source:maxspeed', 'zone70')]) self.nodeCount = 1 self.updatedText = text.replace('Z70', '') if text.find('Z50') > -1: self.placeNode(node, [('maxspeed', '50'), ('zone:traffic', 'BE:rural'), ("source:maxspeed", "zone50")]) self.nodeCount = 1 self.updatedText = text.replace('Z50', '') if text.find('Z30') > -1: self.placeNode(node, [('maxspeed', '30'), ('zone:traffic', 'BE:urban'), ("source:maxspeed", "zone30")]) self.nodeCount = 1 self.updatedText = text.replace('Z30', '') class WaySideShrineNode(NodePlacer): def __init__(self, file): NodePlacer.__init__(self, file) self.wssPattern = re.compile(r'\A[LR]+[ ]WSS([ A-Za-z0-9]*)') def match(self, node, text): wssMatch = self.wssPattern.match(text) if wssMatch: if (wssMatch.group(1) == ""): self.placeNode(node, [('historic', 'wayside_shrine'), ('religion', 'christian'), ('denomination', 'roman_catholic')]) else: self.placeNode(node, [('historic', 'wayside_shrine'), ('religion', 'christian'), ('denomination', 'roman_catholic'), ('name', wssMatch.group(1).strip())]) self.updatedText = '' self.nodeCount = 1 return True return False class BarrierNode(NodePlacer): def __init__(self, file): NodePlacer.__init__(self, file) def match(self, node, text): if text.find("PAAL") > -1: self.placeNode(node, [('barrier', 'bollard'), ('foot','yes'), ('bicycle', 'yes')] ) self.updatedText = text.replace('PAAL', '') self.nodeCount = 1 return True if text.find("SWINGGATE") > -1 or text.find("SWGATE") > -1: self.placeNode(node, [('barrier', 'swing_gate'), ('foot','yes'), ('bicycle', 'yes')] ) self.updatedText = text.replace('SWINGGATE', '').replace('SWGATE', '') self.nodeCount = 1 return True if text.find("KGATE") > -1 or text.find("KISSGATE") > -1: self.placeNode(node, [('barrier', 'kiss_gate'), ('foot','yes'), ('bicycle', 'no')] ) self.updatedText = '' self.nodeCount = 1 return True if text.find("GATE") > -1: self.placeNode(node, [('barrier', 'gate'), ('foot','yes'), ('bicycle', 'yes')] ) self.updatedText = text.replace('GATE', '') self.nodeCount = 1 return True if text.find("FBAR") > -1 : self.placeNode(node, [('barrier', 'cycle_barrier'), ('foot','yes'), ('bicycle', 'yes')] ) self.updatedText = text.replace('FBAR', '') self.nodeCount = 1 return True class PowerNode(NodePlacer): def __init__(self, file): NodePlacer.__init__(self, file) def match(self, node, text): if text == "L ESS" or text == "R ESS" or text == "ESS": self.placeNode(node, [('power', 'sub_station')] ) self.updatedText = '' self.nodeCount = 1 return True if text == "L CDC" or text == "R CDC" or text == "CDC": self.placeNode(node, [('power', 'cable_distribution_cabinet')] ) self.updatedText = '' self.nodeCount = 1 return True class HighwayNode(NodePlacer): def __init__(self, file): NodePlacer.__init__(self, file) def match(self, node, text): if text == "RLI" or text == "LLI" : self.placeNode(node, [('highway', 'street_lamp')] ) self.updatedText = '' self.nodeCount = 1 return True if text == "STOP" : self.placeNode(node, [('highway', 'stop')] ) self.updatedText = '' self.nodeCount = 1 return True if text.find("GW") == 0: self.placeNode(node, [('highway', 'give_way')] ) self.updatedText = '' self.nodeCount = 1 return True class HouseNumberNode(NodePlacer): def __init__(self, file): NodePlacer.__init__(self, file) self.numberPattern = re.compile('[0-9]') self.houseNumberPattern = re.compile(r'\A[+-]*([0-9]+[a-zA-Z]*)') self.terracePattern = re.compile(r'[+-]*([0-9]+[a-zA-Z]*)\+\-\+([0-9]+[a-zA-Z]*)') def match(self, node, text): if not ( text.startswith("L") or text.startswith("R")): return False numberpart = text.strip('LR ') terraceMatch = self.terracePattern.match(numberpart) if terraceMatch: group1 = int(terraceMatch.group(1)) group2 = int(terraceMatch.group(2)) startNr = min(group1, group2) endNr = max(group1, group2) terraceNrs = range(startNr, endNr + 1, 2) self.nodeCount = 0 for nr in terraceNrs: self.placeNode(node, [('building', 'house'), ('addr:housenumber', str(nr))]) node = node.moveABitMore(0.00005) self.nodeCount = self.nodeCount + 1 self.updatedText = 'L' + self.terracePattern.sub('', numberpart, 1) return True houseNumberMatch = self.houseNumberPattern.match(numberpart) if houseNumberMatch: self.placeNode(node, [('building', 'house'), ('addr:housenumber', houseNumberMatch.group(1).strip())]) self.updatedText = 'L' + self.houseNumberPattern.sub('', numberpart, 1) self.nodeCount = 1 return True class WaypointContentHandler(xml.sax.ContentHandler): def __init__(self, filename): xml.sax.ContentHandler.__init__(self) self.nodeCount = 0 self.text = "" self.f = open(filename, 'w') self.f.write('\n') self.f.write('') self.file.write(' \n') self.f.write('\n') self._matchers = [ AmenityNode(self.f), PicnicNode(self.f), HighwayNode(self.f), BarrierNode(self.f), PowerNode(self.f), HouseNumberNode(self.f), WaySideShrineNode(self.f), MaxSpeedNode(self.f) ] def startElement(self, tagname, attrs): if tagname == "wpt": self.node = Node(float(attrs.getValue("lon")), float(attrs.getValue("lat"))) if tagname == "name": self.text = '' def endElement(self, tagname): if tagname == "name": self.tagNode(self.node, self.text.strip()) def endDocument(self): self.f.write(' \n') self.f.close() def characters(self, content): self.text = self.text + content def tagNode(self, node, text): for matcher in self._matchers: theText = text matcher.node = None while matcher.match(node, theText): theText = matcher.updatedText.strip() self.nodeCount = self.nodeCount + matcher.nodeCount if matcher.node is None: node = node.moveABitMore(0.00005) else: node = matcher.node.moveABitMore(0.00005) class FileNameGenerator(): def generateFileName(self, waypointFile): outputfile = waypointFile.replace('gpx', 'osm') return outputfile def main(argv): file = '' try: opts, args = getopt.getopt(argv,"hf:",["file="]) except getopt.GetoptError: print 'parseWayPoints.py -f' sys.exit(2) for opt, arg in opts: if opt == '-h': print 'Usage: parseWayPoints.py -f ' sys.exit(0) elif opt in ("-f", "--file"): file = arg if file == '': print 'No file specified' sys.exit(2) print 'Parsing WayPoint file: ', file outputfile = FileNameGenerator().generateFileName(file) print outputfile waypointHandler = WaypointContentHandler(outputfile) fileHandle = io.open(file, "r") xml.sax.parse(fileHandle, waypointHandler) print 'Wrote ' + outputfile + ' containing ' + str(waypointHandler.nodeCount) + ' nodes.' if __name__ == "__main__": main(sys.argv[1:])
Nice script - thanks for pointing me to it.
ReplyDeleteIt would be IMHO more handy when you would set the shortcuts and the values to replace them with at the beginning of the file so other users can find change them more easily.
Though I am not much of a coder I'd even think a coding like
if
there is set a variable of "VB" set to be replaced with "amenity;waste_basked"; do so, else
fi
so you wouldn't have that much redundant lines for hardcoded values in that script.
But who am I proposing such things and myself not being able to code it. :)
Yes, you are correct about that. It would make the script more customizable.
DeleteMaybe, one day, when time permits ....