Changes between Version 9 and Version 10 of Help/Plugin/Scripting/Python


Ignore:
Timestamp:
2012-06-20T18:01:33+02:00 (14 years ago)
Author:
hlaw
Comment:

New script

Legend:

Unmodified
Added
Removed
Modified
  • Help/Plugin/Scripting/Python

    v9 v10  
    404404
    405405[wiki:Python/RCN_Route_Validator]
     406
     407Remove extra ways resulting from Potlatch way split operations under turn restriction relations
     408
     409{{{#!python
     410
     411#!/bin/jython
     412
     413'''
     414RepairTurns.py  - Remove extra ways resulting from Potlatch way split operations under turn restriction relations
     415
     416This code is released under the GNU General
     417Public License v2 or later.
     418
     419The GPL v3 is accessible here:
     420http://www.gnu.org/licenses/gpl.html
     421
     422The GPL v2 is accessible here:
     423http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
     424
     425It comes with no warranty whatsoever.
     426
     427This code Loops through selected turn restriction relations, trying to remove ways split from originally the same way (with to / from roles) under turn restriction relations which should no longer remain as members of these relations, as a result of a Potlatch issue: https://trac.openstreetmap.org/ticket/3254
     428
     429Only work for turn restrictions with one via node
     430
     431e.g. Original      : from: Way1, via: Node, to:Way2
     432     Split         : from: Way1a, from: Way1b, via: Node, to: Way2
     433     After running : from: Way1b, via: Node, to: Way2
     434
     435This code illustrates how to use Jython to:
     436* process selected items
     437* download missing primitives in the same thread (blocking)
     438* process, validate and remove members from relations
     439
     440'''
     441from javax.swing import JOptionPane
     442from org.openstreetmap.josm import Main
     443import org.openstreetmap.josm.data.osm.Node as Node
     444import org.openstreetmap.josm.data.osm.Way as Way
     445import org.openstreetmap.josm.data.osm.Relation as Relation
     446import org.openstreetmap.josm.data.osm.TagCollection as TagCollection
     447import org.openstreetmap.josm.data.osm.DataSet as DataSet
     448import org.openstreetmap.josm.data.osm.RelationMember as RelationMember
     449import org.openstreetmap.josm.gui.dialogs.relation.DownloadRelationMemberTask as DownloadRelationMemberTask
     450import org.openstreetmap.josm.io.MultiFetchServerObjectReader as MultiFetchServerObjectReader
     451import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor as PleaseWaitProgressMonitor
     452import org.openstreetmap.josm.command as Command
     453
     454class RestrictionError(Exception):
     455    pass
     456
     457def getMapView():
     458    if Main.main and Main.main.map:
     459        return Main.main.map.mapView
     460    else:
     461        return None
     462
     463def getMembers (restriction):
     464    memberlist = dict()
     465    for member in restriction.getMembers():
     466        memberRole = member.getRole()
     467        if memberRole == "via":
     468            if member.isNode() and not "via" in memberlist:
     469                memberlist[memberRole] = [member]
     470            else:
     471                raise RestrictionError, "More than one via role or via not a node"
     472        elif memberRole in ("from", "to"):
     473            if member.isWay():
     474                try:
     475                    memberlist[memberRole].append (member)
     476                except KeyError:
     477                    memberlist[memberRole] = [member]
     478            else:
     479                raise RestrictionError, "From or to role not a way"
     480        else:
     481            raise RestrictionError, "Unknown role " + memberRole
     482
     483    if len(memberlist.keys())<3:
     484        raise RestrictionError, "Some roles missing: Only " + ",".join (memberlist.keys()) + " found"
     485    return memberlist
     486
     487def downloadPrimitives (primitives, editlayer):
     488    """
     489        Download a list of primitives from server, and merge into editlayer. Blocking.
     490    """
     491    monitor = PleaseWaitProgressMonitor()
     492    monitor.showForegroundDialog()   
     493
     494    print "Downloading"
     495    try:
     496        objectReader = MultiFetchServerObjectReader().append (primitives)
     497        dataSet = objectReader.parseOsm (monitor)
     498        editlayer.mergeFrom (dataSet)
     499        editlayer.onPostDownloadFromServer()
     500        if (not objectReader.getMissingPrimitives().isEmpty()) :
     501            raise RestrictionError, "Unable to download missing primitives"
     502        print "Download completed"   
     503    finally:
     504        monitor.close()
     505
     506def checkIfConnected (node, way, reverse):
     507    """
     508        Return (connected, next node to compare (i.e. other end of the node) if true)
     509    """
     510    if (way.isOneway() != 0 and reverse):
     511        return node == way.lastNode(True), way.firstNode(True) # True: auto process case whan isOneway == -1
     512    if (way.isOneway() != 0):     # not reverse
     513        return node == way.firstNode(True), way.lastNode(True)
     514    if node == way.firstNode():
     515        return True, way.lastNode()
     516    if node == way.lastNode():
     517        return True, way.firstNode()
     518    return False, node   
     519
     520
     521def repairrestriction (relation, memberlist, editLayer):
     522    """
     523        Download missing members if needed, get list of members to remove, and remove them if no error raised during checking
     524    """
     525    incompleteMembers = relation.getIncompleteMembers()
     526    if incompleteMembers:
     527          downloadPrimitives (incompleteMembers, editLayer);       
     528
     529    fromRemovalList = []; toRemovalList = []
     530   
     531    if len (memberlist["from"]) >= 1:
     532        currnode = memberlist["via"][0].getNode()
     533        firstMember = True
     534        failed = False;
     535        # trace "from" members to confirm if split from one way
     536        for member in reversed(memberlist['from']):
     537            connected, currnode = checkIfConnected (currnode, member.getWay(), True)
     538            if not connected:
     539                if not firstMember:
     540                    raise RestrictionError, "from ways not continuous from via node"
     541                failed = True
     542                break
     543            if not firstMember:
     544                fromRemovalList.append (member)
     545            else:
     546                firstMember = False
     547
     548        if failed: # Second attempt in case sequence reversed when split
     549            currnode = memberlist["via"][0].getNode()
     550            for member in memberlist['from']:
     551                connected, currnode = checkIfConnected (currnode, member.getWay(), True)
     552                if not connected:
     553                    raise RestrictionError, "from ways not continuous from via node"
     554                if not firstMember:
     555                    fromRemovalList.append (member)
     556                else:
     557                    firstMember = False
     558                                                                       
     559    if len (memberlist["to"]) >= 1:
     560        currnode = memberlist["via"][0].getNode()
     561        firstMember = True
     562        failed = False
     563        # trace "to" members to confirm if split from one way
     564        for member in memberlist['to']:
     565            connected, currnode = checkIfConnected (currnode, member.getWay(), False)
     566            if not connected:
     567                if not firstMember:
     568                    raise RestrictionError, "to ways not continuous from via node"
     569                failed = True
     570                break
     571            if not firstMember:
     572                toRemovalList.append (member)
     573            else:
     574                firstMember = False
     575
     576        if failed: # Second attempt in case sequence reversed when split
     577            currnode = memberlist["via"][0].getNode()
     578            for member in reversed(memberlist['to']):
     579                connected, currnode = checkIfConnected (currnode, member.getWay(), False)
     580                if not connected:
     581                    raise RestrictionError, "to ways not continuous from via node"
     582                if not firstMember:
     583                    toRemovalList.append (member)
     584                else:
     585                    firstMember = False         
     586                         
     587    # to remove ways in fromRemovalList, toRemovalList         
     588    newRelation = Relation(relation)
     589    waysToRemove = set()
     590    for removalList in [fromRemovalList, toRemovalList]:
     591        waysToRemove |= set ([m.getWay() for m in removalList])
     592    newRelation.removeMembersFor (waysToRemove)
     593    print "Remove way(s) id:" + ",".join ([str(w.getId()) for w in waysToRemove])
     594    return Command.ChangeCommand (relation, newRelation)   
     595   
     596   
     597validrestrictiontypes = ('only_straight_on', 'only_right_turn', 'only_left_turn', 'no_right_turn', 'no_left_turn', 'no_straight_on', 'no_u_turn')
     598mv = getMapView()
     599if mv and mv.editLayer and mv.editLayer.data:
     600    selectedRelations = mv.editLayer.data.getSelectedRelations()
     601   
     602    if not(selectedRelations):
     603        JOptionPane.showMessageDialog(Main.parent, "Please select one or more relations")
     604    else:
     605        commandsList = []
     606        for relation in selectedRelations:
     607            if relation.get('type') == "restriction" and relation.get('restriction') in validrestrictiontypes:
     608                try:
     609                    memberlist = getMembers (relation)     
     610                    #print "".join(v * len(memberlist[v]) for v in memberlist.keys())           
     611                    if (len (memberlist["from"])) > 1 or (len (memberlist["to"])) > 1 :
     612                        # Repair attempt
     613                        print "Attempt repair",
     614                        print "relation id: " + str(relation.getId())
     615                        command = repairrestriction (relation, memberlist, mv.editLayer)
     616                        print "Success"                         
     617                        commandsList.append (command)
     618                except RestrictionError, e:
     619                    print str(e), "; relation id: "+ str(relation.getId())
     620               
     621       
     622        Main.main.undoRedo.add(Command.SequenceCommand("Repair turn restrictions", commandsList))
     623        commandsList=[]
     624}}}