Version 1 (modified by 14 years ago) ( diff ) | ,
---|
#!/bin/jython ''' CheckRouteOrNetworkOrCollectionOfRoutes.jy - Validation of a rcn route, network or collection of networks relation - Depending on what is selected in JOSM when invoked This code is released under the GNU General Public License v2 or later. The GPL v3 is accessible here: http://www.gnu.org/licenses/gpl.html The GPL v2 is accessible here: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html It comes with no warranty whatsoever. This code illustrates how to use Jython (Python in the scripting plugin of JOSM) to: * loop over all members of a route relation * find out whether the member is a node, a way or a relation * add/change properties of a relation * remove properties of a relation * add members to a relation * remove members from a relation * sort all members backwards * How to set an element selected ''' from javax.swing import JOptionPane from org.openstreetmap.josm import Main import org.openstreetmap.josm.command as Command import org.openstreetmap.josm.data.osm.Node as Node import org.openstreetmap.josm.data.osm.Way as Way import org.openstreetmap.josm.data.osm.Relation as Relation import org.openstreetmap.josm.data.osm.TagCollection as TagCollection import org.openstreetmap.josm.data.osm.DataSet as DataSet import org.openstreetmap.josm.data.osm.RelationMember as RelationMember import org.openstreetmap.josm.gui.dialogs.relation.DownloadRelationMemberTask as DownloadRelationMemberTask import org.openstreetmap.josm.actions.DownloadReferrersAction as DownloadReferrersAction import org.openstreetmap.josm.actions.AutoScaleAction as AutoScaleAction import re, time # comment to disable side effect sideEffects = { 'addRouteToNetwork': None, 'removeNameRefKey_xx-yyAndcreated_by': None, 'modifyNoteTo_xx-yy': None, 'flipOrderOfMembers': None, # such that ways go from lower rcn_ref to higher rcn_ref 'sortRouteRelations': None, 'selectObjects': None, 'zoomToSelection': None, #'downloadReferrersForNodes': None, # This will download all ways and relations for nodes with an rcn_ref #'downloadReferrersForWays': None, # This will download all relations for ways that have an endnode with an rcn_ref 'downloadIncompleteMembers': None, 'createWikiReport': None, 'createGarminGPX': None, #'checkOneWays = False, # not implemented yet } logVerbosity = 10 ''' 10: only report problems that need fixing 20: report on collection 30: report on network nodes 40: report on which routes are being checked 50: report everything ''' def getMapView(): if Main.main and Main.main.map: return Main.main.map.mapView else: return None def sortRouteRelation(route, nodesDict, beginAndEndnodes): # TODO This can still be improved a lot. Now it aborts at the first sign of probable failure. # TODO It sorts the simple cases though (i.e. the ones with no forward/backward roles which actually are continuous) nextNode = None routeToReturn = Relation(route) ##print dir (routeToReturn) #routeToReturn.clearOsmId() lowestNodeInt = 10000; lowPos = 0 for nodeTuple in beginAndEndnodes: if nodeTuple[0] < lowestNodeInt: lowestNodeInt, nextNode = nodeTuple if not(nextNode): return route members=nodesDict[nextNode] processedMembers = {} #print len(nodesDict) #print dir(route) while lowPos<route.getMembersCount(): #print 'in loop', routeToReturn if len(members) == 1: member = members[0] else: member = members[1] if member in processedMembers: member = members[0] processedMembers[member] = True way = member.getWay() routeToReturn.removeMembersFor(way) routeToReturn.addMember(lowPos,member) #routeToReturn.setModified(True) currentNode = nextNode nextNode = way.getNode(way.nodesCount-1).getUniqueId() if currentNode == nextNode: nextNode = way.getNode(0).getUniqueId() if nextNode in nodesDict: members=nodesDict[nextNode] else: break del nodesDict[nextNode] #print len(nodesDict) if len(nodesDict)<3: break lowPos += 1 #print 'before return', routeToReturn return routeToReturn def checkForContinuity(membersList): listIsContinuous = True; prev_endnodes = [] for member in membersList: if member.isWay(): way = member.getWay() if logVerbosity > 50: print dir(way) if logVerbosity > 49: print way.getKeys() print way.get('name') print way.nodesCount-1, way if way.get('junction') == 'roundabout': endnodes = way.getNodes() else: if way.nodesCount: endnodes = [way.getNode(0), way.getNode(way.nodesCount-1)] else: endnodes = [] foundTheNode = False for endnode in endnodes: if logVerbosity > 49: print endnode, prev_endnodes if endnode in prev_endnodes: foundTheNode = True if prev_endnodes and not(foundTheNode): listIsContinuous = False if logVerbosity > 49: print way print endnodes print prev_endnodes break prev_endnodes = endnodes return listIsContinuous def checkRCNroute(route): if 'removeNameRefKey_xx-yyAndcreated_by' in sideEffects: commandsList = [] reNumberDashNumber = re.compile(r'\d+-\d+') newRelation = Relation(route) relationChanged = False created_by = route.get('created_by') if created_by: print 'removing created_by' newRelation.remove('created_by') relationChanged = True name = route.get('name') if name: if reNumberDashNumber.match(name): print 'removing name when it is of the form ##-##' newRelation.remove('name') relationChanged = True else: name = '' ref = route.get('ref') if ref: if reNumberDashNumber.match(ref): print 'removing ref when it is of the form ##-##' newRelation.remove('ref') relationChanged = True else: ref = '' if relationChanged: commandsList.append(Command.ChangeCommand(route, newRelation)) Main.main.undoRedo.add(Command.SequenceCommand("Removing name and/or ref and/or created_by" + name + '/' + ref, commandsList)) commandsList = [] fixme = route.get('fixme') == 'incomplete' rcn_refs = []; route_relation_names = []; memberslist = []; roleInNetwork = '' sameNodeNumberRepeated = False allWaysgoingFromLowerToHigher = []; allWaysgoingFromHigherToLower = []; branch = None newRelation = Relation(route); commandslist = []; i=0; roundabout = [] if 'sortRouteRelations' in sideEffects: nodesForSorting = {}; beginAndEndNodes = [] routeMembers = route.getMembers() for member in routeMembers: if member.isWay(): role = member.getRole() memberslist.append(member) way = member.getWay() # print way.get('name') wayNodes = way.getNodes() notfoundyet = True for endnode in wayNodes: if 'sortRouteRelations' in sideEffects: endnodeId = endnode.getUniqueId() if not(endnodeId in nodesForSorting): nodesForSorting[endnodeId] = [] nodesForSorting[endnodeId].append(member) rcn_ref = endnode.get('rcn_ref') if rcn_ref: rcn_refAsInt = int(rcn_ref) if 'sortRouteRelations' in sideEffects: beginAndEndNodes.append([rcn_refAsInt, endnodeId]) if not(rcn_refAsInt in rcn_refs): rcn_refs.append(rcn_refAsInt) else: sameNodeNumberRepeated = True referrersForNode = endnode.getReferrers(); networkNotFoundForNode = True for referrer in referrersForNode: if referrer.getType() is dummy_relation.getType(): if referrer.get('type') in ['network'] and referrer.get('network') in ['rcn']: networkNotFoundForNode = False break if networkNotFoundForNode: # node is not assigned to a network yet Main.main.getCurrentDataSet().setSelected(endnode) AutoScaleAction.zoomToSelection() selectedNode = mv.editLayer.data.getSelected() if 'downloadReferrersForNodes' in sideEffects: print "Downloading referrers for ", endnode.get('rcn_ref'), ' ', wayNodes DownloadReferrersAction.downloadReferrers(mv.editLayer, wayNodes) else: print "Would download referrers for ", endnode.get('rcn_ref'), ' ', wayNodes referrersForNode = endnode.getReferrers() for referrer in referrersForNode: if referrer.getType() is dummy_relation.getType(): networkOrRouteType = referrer.get('type') in ['network'] #, 'route'] if referrer.get('network')=='rcn' and networkOrRouteType: relname=referrer.get('name') if relname: route_relation_names.append(relname) elif not(referrer.get('type') in ['route']): route_relation_names.append('Node not assigned to network yet') # FIXME This is still buggy # build 2 structures to help check for continuity on ways if i==0: lastNodesBeforeSplit = [wayNodes] if role and role in ['forward', 'backward']: if not(branch): print 'wayNodes', wayNodes if wayNodes: if role in ['forward']: lastNodesBeforeSplit = [wayNodes[0]] else: lastNodesBeforeSplit = [wayNodes[-1]] else: return '', True, '|align="right" | way has no nodes||align="right" | {{BrowseRoute|' + str(route.getId()) + '}}||align="right" needs to be downloaded first\n' if logVerbosity > 29: print 'lastNodesBeforeSplit', lastNodesBeforeSplit print way.getNodesCount(), 'startnode', wayNodes[0], 'endnode', wayNodes[-1] print 'roundabout', roundabout print wayNodes[-1].get('rcn_ref'),not(member.getUniqueId() == routeMembers[-1].getUniqueId()) if role in ['forward'] and (wayNodes[-1] in lastNodesBeforeSplit or wayNodes[-1] in roundabout): branch = 'HigherToLower' elif role in ['backward'] and wayNodes[0] in lastNodesBeforeSplit: branch = 'HigherToLower' elif not(allWaysgoingFromHigherToLower) and wayNodes[-1].get('rcn_ref') and not(member.getUniqueId() == routeMembers[-1].getUniqueId()): # This is for when the route starts forked from a different rcn node (split node situation), we don't want it to kick in for the last member of the route branch = 'HigherToLower' elif not(branch == 'HigherToLower'): branch = 'LowerToHigher' print branch if branch == 'LowerToHigher': allWaysgoingFromLowerToHigher.append(member) elif branch == 'HigherToLower': allWaysgoingFromHigherToLower.append(member) else: branch = None; roundabout = [] allWaysgoingFromLowerToHigher.append(member) allWaysgoingFromHigherToLower.append(member) if way.get('junction') == 'roundabout': roundabout = way.getNodes() i+=1 #if modified: #commandsList.append(Command.ChangeCommand(route, newRelation)) #Main.main.undoRedo.add(Command.SequenceCommand("Removing way which has no nodes", commandsList)) #commandsList = [] continuous_forward = True; continuous_backward = True if len(allWaysgoingFromLowerToHigher) > 1: continuous_forward = checkForContinuity(allWaysgoingFromLowerToHigher) if not(continuous_forward) and not(fixme) and 'sortRouteRelations' in sideEffects: sortedRelation = sortRouteRelation(route, nodesForSorting, beginAndEndNodes) if logVerbosity>49: print route print sortedRelation commandsList.append(Command.ChangeCommand(route, sortedRelation)) Main.main.undoRedo.add(Command.SequenceCommand("Sorted route relation", commandsList)) allWaysgoingFromLowerToHigher = []; allWaysgoingFromHigherToLower = [] routeMembers = route.getMembers(); i=0 for member in routeMembers: if member.isWay(): role = member.getRole() if i==0: lastNodesBeforeSplit = [wayNodes] if role and role in ['forward', 'backward']: if not(branch): if role in ['forward']: lastNodesBeforeSplit = [wayNodes[0]] else: lastNodesBeforeSplit = [wayNodes[-1]] if logVerbosity > 29: print 'wayNodes', wayNodes print 'lastNodesBeforeSplit', lastNodesBeforeSplit print way.getNodesCount(), 'startnode', wayNodes[0], 'endnode', wayNodes[-1] print 'roundabout', roundabout if role in ['forward'] and (wayNodes[-1] in lastNodesBeforeSplit or wayNodes[-1] in roundabout): branch = 'HigherToLower' elif role in ['backward'] and wayNodes[0] in lastNodesBeforeSplit: branch = 'HigherToLower' elif wayNodes[-1].get('rcn_ref') and not(member.getUniqueId() == routeMembers[-1].getUniqueId()): # not(allWaysgoingFromHigherToLower) and ## this last part is probably not necessary anymore # This is for when the route starts forked from a different rcn node (split node situation), we don't want it to kick in for the last member of the route branch = 'HigherToLower' elif not(branch == 'HigherToLower'): branch = 'LowerToHigher' print branch if branch == 'LowerToHigher': allWaysgoingFromLowerToHigher.append(member) elif branch == 'HigherToLower': allWaysgoingFromHigherToLower.append(member) else: branch = None; roundabout = [] allWaysgoingFromLowerToHigher.append(member) allWaysgoingFromHigherToLower.append(member) if way.get('junction') == 'roundabout': roundabout = way.getNodes() i+=1 continuous_forward = checkForContinuity(allWaysgoingFromLowerToHigher) #else: else: # a route relation with only one way member continuous_forward = True if len(allWaysgoingFromHigherToLower) > 1: continuous_backward = checkForContinuity(reversed(allWaysgoingFromHigherToLower)) else: # a route relation with only one way member continuous_backward = True # Drawing conclusions about rcn_refs if logVerbosity > 39: print rcn_refs if sameNodeNumberRepeated: rcn_refs.append(rcn_refs[0]) newNote = note = repr(rcn_refs) sortedRelation = route if len(rcn_refs) > 1: #newRelation = Relation(route) relationChanged = False if rcn_refs[0] > rcn_refs[1]: rcn_refs.sort() if len(memberslist)>1 and 'flipOrderOfMembers' in sideEffects: for member in reversed(memberslist): sortedRelation.addMember( sortedRelation.getMembersCount(), member) sortedRelation.removeMember (0) commandsList.append(Command.ChangeCommand(route, sortedRelation)) Main.main.undoRedo.add(Command.SequenceCommand("Flipping order of members", commandsList)) commandsList = [] note = route.get('note') newNote = str(rcn_refs[0]).zfill(2) + '-' + str(rcn_refs[1]).zfill(2) #print note, newNote if 'modifyNoteTo_xx-yy' in sideEffects: if not(note) or note != newNote: if not(note): note = 'nothing' newRelation.put('note', newNote) relationChanged = True commandsList.append(Command.ChangeCommand(route, newRelation)) Main.main.undoRedo.add(Command.SequenceCommand("Changing note from " + note + ' to ' + newNote, commandsList)) if logVerbosity > 9: print 'Flipping members order for ', note commandsList = [] if len(route_relation_names) > 1 and route_relation_names[0] != route_relation_names[1]: # print 'This is probably a CONNECTION to another network' if logVerbosity > 9: print route_relation_names roleInNetwork = 'connection' else: print 'less than 2 end nodes with rcn_ref found' if fixme and not(continuous_forward or continuous_backward): if logVerbosity > 1: print 'FIXME flag is INCOMPLETE' if continuous_forward: wikiCF = 'align="right" | continuous' if logVerbosity > 29: print 'route is continous in the forward direction' else: wikiCF = 'align="right" style="color:red" | NOT continuous' if logVerbosity > 9: print 'route ',newNote,' is NOT CONTINUOUS in the forward direction' if logVerbosity > 49: print allWaysgoingFromLowerToHigher if continuous_backward: wikiCB = 'align="right" | continuous' if logVerbosity > 29: print 'route is continous in the backward direction' else: wikiCB = 'align="right" style="color:red" | NOT continuous' if logVerbosity > 9: print 'route ',newNote,' is NOT CONTINUOUS in the backward direction' if logVerbosity > 49: print allWaysgoingFromHigherToLower print if fixme: wikiFM = 'style="color:red" | fixme' else: wikiFM = ' | ' if fixme or not(continuous_forward) or not(continuous_backward): problem = True else: problem = False return roleInNetwork, problem, '|align="right" | ' + note + '||align="right" | {{BrowseRoute|' + str(route.getId()) + '}}||align="right" ' + wikiFM + ' ||' + wikiCF + ' ||' + wikiCB + '\n' def checkNetwork(network): name = network.get('name') if logVerbosity>19: print '********************************************' print name print '********************************************' if 'createWikiReport' in sideEffects: wikiReportOnNodes = ('{| class="wikitable" align="left" style="margin:0 0 2em 2em;"\n|-\n|+' + name + '\n|-\n!style="width:2.5em" | Node\n!Link\n! # Roads\n! # Relations\n|-\n') wikiReportOnRelations = ('{| class="wikitable" align="left" style="margin:0 0 2em 2em;"\n|-\n|+' + name + '\n|-\n!style="width:2.5em" | note\n!link\n!fixme\n! forward\n! backward\n|-\n') i=1 for networkMember in network.getMembers(): if networkMember.isRelation(): routeRelation = networkMember.getRelation() if routeRelation.hasIncompleteMembers(): if 'downloadIncompleteMembers' in sideEffects: print 'Downloading incomplete members for', routeRelation.get('note') DownloadRelationMemberTask.run(DownloadRelationMemberTask(routeRelation, routeRelation.getIncompleteMembers(), mv.editLayer )) continue else: JOptionPane.showMessageDialog(Main.parent, 'Please download all incomplete member of the route relations first') break roleFromRouteCheck, problemReported, wikiReport = checkRCNroute(routeRelation) if problemReported and 'createWikiReport' in sideEffects: wikiReportOnRelations += wikiReport + '\n|-\n' role = networkMember.getRole() if logVerbosity > 29 and role != roleFromRouteCheck: print print 'Role in network is ', role print 'Maybe this should be: ', roleFromRouteCheck if networkMember.isNode(): node = networkMember.getNode() rcn_ref = node.get('rcn_ref') expected_rcn_route_relations = node.get('expected_rcn_route_relations') if expected_rcn_route_relations: expected_rcn_route_relations = int(expected_rcn_route_relations) else: expected_rcn_route_relations = 3 if rcn_ref: if logVerbosity > 39: print rcn_ref referrersForNode = node.getReferrers() networkNotFoundForNode = True for referrer in referrersForNode: if referrer.getType() is dummy_relation.getType(): if referrer.get('type') in ['network'] and referrer.get('network') in ['rcn']: networkNotFoundForNode = False break if networkNotFoundForNode and 'downloadReferrersNodes' in sideEffects: Main.main.getCurrentDataSet().setSelected(node) AutoScaleAction.zoomToSelection() selectedNode = mv.editLayer.data.getSelected() print 'Downloading referrers for ', selectedNode.get('rcn_ref') DownloadReferrersAction.downloadReferrers(mv.editLayer, selectedNode) referrersForNode = node.getReferrers() rcnNetworkCountForNode = roads = 0 for referrer in referrersForNode: if referrer.getType() is dummy_way.getType(): if referrer.get('highway'): roads += 1 referrersForWay = referrer.getReferrers() if len(referrersForWay) < 1 and 'downloadReferrersForWays' in sideEffects: Main.main.getCurrentDataSet().setSelected(referrer) AutoScaleAction.zoomToSelection() selectedWay = mv.editLayer.data.getSelected() print 'Downloading referrers for ', referrer.get('name') , ' ', rcn_ref DownloadReferrersAction.downloadReferrers(mv.editLayer, selectedWay) referrersForWay = referrer.getReferrers() for wayReferrer in referrersForWay: if wayReferrer.getType() is dummy_relation.getType(): aRelation = wayReferrer if aRelation.get('type') == 'route' and aRelation.get('network') == 'rcn': rcnNetworkCountForNode+=1 networkMembersList = [] for subMember in network.getMembers(): if subMember.isRelation(): routeRelation = subMember.getRelation() networkMembersList.append(routeRelation.getUniqueId()) routeId = aRelation.getUniqueId() if not(routeId in networkMembersList): if aRelation.get('network') == 'rcn': roleFromRouteCheck, problemReported, wikiReport = checkRCNroute(aRelation) if problemReported and 'createWikiReport' in sideEffects: wikiReportOnRelations += wikiReport + '\n|-\n' if 'addRouteToNetwork' in sideEffects: newRelation = Relation(network) newmember = RelationMember(roleFromRouteCheck, aRelation) if logVerbosity > 9: print newRelation.getMembersCount(), ' ',i, ' ', newmember newRelation.addMember( i, newmember) commandsList = [] commandsList.append(Command.ChangeCommand(network, newRelation)) note = aRelation.get('note') if not(note): note = '' Main.main.undoRedo.add(Command.SequenceCommand("Adding " + note + " to network", commandsList)) commandsList = [] if logVerbosity > 9: print 'Added newly found RCN route relation to network: ', note i+=1 if rcnNetworkCountForNode < expected_rcn_route_relations: if logVerbosity > 9: print 'Node ', rcn_ref, ' only has ', rcnNetworkCountForNode, ' rcn routes connected to it' if 'createWikiReport' in sideEffects: wikiReportOnNodes += '|align="right" | ' + rcn_ref + '||align="right" | {{Node|' + str(node.getId()) + '}}||align="right" |' + str(roads) + ' ||align="right" style="color:red" | ' + str(rcnNetworkCountForNode) + '\n|-\n' i+=1 if logVerbosity > 19: print if 'createWikiReport' in sideEffects: wikiReportOnNodes += ('|-\n|}\n') wikiReportOnRelations += ('|-\n|}\n<br style="clear:left;" />\n') fh = open('C:/wikiReport.txt', 'a') fh.write(wikiReportOnNodes) fh.write(wikiReportOnRelations) fh.close() dummy_way = Way() dummy_relation = Relation() mv = getMapView() if mv and mv.editLayer and mv.editLayer.data: if 'createWikiReport' in sideEffects: fh = open('C:/wikiReport.txt', 'w') fh.close() selectedRelations = mv.editLayer.data.getSelectedRelations() if not(selectedRelations): JOptionPane.showMessageDialog(Main.parent, "Please select a route, network or collection relation") else: for relation in selectedRelations: if logVerbosity> 49: print relation if relation.hasIncompleteMembers(): if 'downloadIncompleteMembers' in sideEffects: print 'Downloading referrers for ', str(relation.get('name')), ' ', str(relation.get('note')) DownloadRelationMemberTask.run(DownloadRelationMemberTask(relation, relation.getIncompleteMembers(), mv.editLayer )) continue else: JOptionPane.showMessageDialog(Main.parent, 'Please download all incomplete member of the relations first') break if relation.get('network') == 'rcn': relationType = relation.get('type') if relationType == 'route': checkRCNroute(relation) elif relationType == 'network': checkNetwork(relation) elif relationType == 'collection': for collectionMember in relation.getMembers(): if collectionMember.isRelation(): networkRelation = collectionMember.getRelation() if networkRelation.hasIncompleteMembers(): if 'downloadIncompleteMembers' in sideEffects: print 'Downloading referrers for ', relation.get('name') DownloadRelationMemberTask.run(DownloadRelationMemberTask(networkRelation, networkRelation.getIncompleteMembers(), mv.editLayer )) continue else: JOptionPane.showMessageDialog(Main.parent, 'Please download all incomplete member of the network relations first') break checkNetwork(networkRelation)
Note:
See TracWiki
for help on using the wiki.