| 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.


