wiki:Nl:Help/Plugin/Scripting/Python

Andere talen:

Plug-in -> Scripting -> Python

Doel

Nog enkele voorbeelden in Python:

Een weg converteren die verbindt met een niet gesplitste rotonde met een vork

Converteren van een weg die een rotonde verbindt met een vork die bestaat uit twee wegen met éénrichtingverkeer. Splitst de weg op zijn laatste knoop en verbindt die met de 2 naastgelegen knopen van de algemene knoop van de weg van de rotonde. Deze versie werkt alleen met niet gesplitste rotondes. Bekijk het volgende voorbeeld voor een bijgewerkte versie.

from javax.swing import JOptionPane
from org.openstreetmap.josm.gui import MainApplication

import org.openstreetmap.josm.command as Command
import org.openstreetmap.josm.data.osm.Way as Way

editLayer = MainApplication.getLayerManager().getEditLayer()
if editLayer and editLayer.data:
    selected_ways = editLayer.data.getSelectedWays()
    print selected_ways

    if not(selected_ways) or len(selected_ways)>1:
        JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
                                         "Please select a single way that connects to a roundabout")
    else:
        for way in selected_ways:
            if way.get('oneway') in ['yes', '-1']:
                JOptionPane.showMessageDialog(MainApplication.getMainFrame(), "This way has oneway tag set")
            else:
                node_before = None
                node_after = None
                common_node = None
                common_node_becomes_node_before=None
                #print dir(way)
                for fln in [way.firstNode(),  way.lastNode()]:
                    print 'fln',  fln
                    for parentway in fln.getParentWays():
                        if parentway.get("junction")=='roundabout':
                            for n in parentway.getNodes():
                                if common_node:
                                    # found common node between selected way and
                                    # roundabout way in previous iteration
                                    node_after = n
                                    # we are done here
                                    break
                                if n.getId() == fln.getId():
                                    # this is the node the roundabout has in common with selected way
                                    common_node = n
                                    if not(node_before):
                                        # normally we encountered a node on the roundabout way
                                        # before this one, but if the common node is the first node
                                        # of an unsplit roundabout, we will need to take the last
                                        # node of the roundabout instead
                                        node_before = parentway.getNodes()[-2]
                                        node_after = parentway.getNodes()[1]
                                        break
                                    # if not we go through the loop one more time to put the next
                                    # node in node_after
                                    continue
                                node_before = n
                        if common_node:
                            # if common_node is already defined at this point, it means it was
                            # the first node of the selected way,
                            # so it will have to be replaced with node_before in the selected way
                            common_node_becomes_node_before = True
                            adjacent_node_to_split_on = way.getNodes()[1]
                            break
                        else:
                            common_node_becomes_node_before = False
                            adjacent_node_to_split_on = way.getNodes()[-1]
                if not(common_node) or common_node_becomes_node_before==None:
                    JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
                                               "Please select a way that connects to a roundabout")
                else:
                    print common_node.get('name')
                    print node_before.get('name')
                    print node_after.get('name')

                    commandsList = []
                    if len(way.getNodes())>2:
                        # split off last segment before roundabout if needed
                        commandsList.append(Command.SplitWayCommand.split(
                                    way, [adjacent_node_to_split_on], []))
                        MainApplication.undoRedo.add(Command.SequenceCommand(
                                    "Split selected way", commandsList))
                        commandsList = []
                    # After splitting find the segment that connects to the roundabout again
                    for waypartconnectedtoroundabout in adjacent_node_to_split_on.getParentWays():
                        if common_node in waypartconnectedtoroundabout.getNodes():
                            break
                    if len(way.getNodes())==2:
                        if common_node == waypartconnectedtoroundabout.firstNode():
                            adjacent_node_to_split_on = waypartconnectedtoroundabout.lastNode()
                        else:
                            adjacent_node_to_split_on = waypartconnectedtoroundabout.firstNode()
                    # time to actually do something
                    # make a copy of the way
                    modified_way = Way(waypartconnectedtoroundabout)
                    # replace its nodes, so it becomes a fork
                    modified_way.setNodes([node_before, adjacent_node_to_split_on, node_after])
                    # add oneway tag
                    modified_way.put('oneway', 'yes')
                    # apply the changes
                    commandsList.append(Command.ChangeCommand(
                                    waypartconnectedtoroundabout, modified_way))
                    MainApplication.undoRedo.add(Command.SequenceCommand(
                                    "Add oneway tag and create forked way", commandsList))
                    commandsList = []
                    # split this way where it forks
                    commandsList.append(Command.SplitWayCommand.split(
                                    waypartconnectedtoroundabout, [adjacent_node_to_split_on], []))
                    MainApplication.undoRedo.add(Command.SequenceCommand(
                                    "Split fork into 2 ways", commandsList))
                    commandsList = []

Een weg converteren die verbindt met een gesplitste rotonde met een vork

Dit script doet hetzelfde als dat hiervoor, maar werkt ook voor rotondes waarvan de wegen zijn gesplitst. Het bemoeit zich niet met de relaties.

from javax.swing import JOptionPane
from org.openstreetmap.josm.gui import MainApplication

import org.openstreetmap.josm.command as Command
import org.openstreetmap.josm.data.osm.Way as Way

editLayer = MainApplication.getLayerManager().getEditLayer()
print '==== Fresh run ===='
if editLayer and editLayer.data:
    selected_ways = editLayer.data.getSelectedWays()
    print selected_ways

    if not(selected_ways) or len(selected_ways)>1:
        JOptionPane.showMessageDialog(MainApplication.parent, "Please select a single way that connects to a roundabout")
    else:
        for way in selected_ways:
            if way.get('oneway') in ['yes', '-1']:
                JOptionPane.showMessageDialog(MainApplication.parent, "This way has oneway tag set")
            elif way.get('junction') in ['roundabout']:
                JOptionPane.showMessageDialog(MainApplication.parent, "This way is part of a roundabout")
            else:
                node_before = None
                node_after = None
                common_node = None
                common_node_becomes_node_before=None
                roundabout_way_before = None
                roundabout_way_after = None
                for fln in [way.firstNode(),  way.lastNode()]:
                    print 'fln',  fln
                    for parentway in fln.getParentWays():
                        if parentway.get("junction")=='roundabout':
                            print parentway.get('name')
                            if parentway.isClosed():
                                # unsplit roundabout
                                for n in parentway.getNodes():
                                    if common_node:
                                        # found common node between selected way
                                        # and roundabout way in previous iteration
                                        node_after = n
                                        print node_before.get('name')
                                        print node_after.get('name')
                                        # we are done here
                                        break
                                    if n.getId() == fln.getId():
                                        # this is the node the roundabout has in common with selected way
                                        common_node = n
                                        print common_node.get('name')
                                        if not(node_before):
                                            # normally we encountered a node on the roundabout way
                                            # before this one, but if the common node is the first node
                                            # of an unsplit roundabout, we will need to take the last
                                            # node of the roundabout instead
                                            node_before = parentway.getNodes()[-2]
                                            node_after = parentway.getNodes()[1]
                                            print node_before.get('name')
                                            print node_after.get('name')
                                            break
                                        # if not we go through the loop one more time to put the next
                                        # node in node_after
                                        continue
                                    node_before = n
                            else:
                                # this is a split roundabout
                                if parentway.firstNode().getId() == fln.getId():
                                    node_after = parentway.getNodes()[1]
                                    roundabout_way_after = parentway
                                    print 'node after', node_after.get('name')
                                else:
                                    node_before = parentway.getNodes()[-2]
                                    roundabout_way_before = parentway
                                if node_before and node_after:
                                    common_node = fln
                                    break

                            if common_node:
                                # if common_node is already defined at this point, it means it was
                                # the first node of the selected way,
                                # so it will have to be replaced with node_before in the selected way
                                common_node_becomes_node_before = True
                                break
                            else:
                                common_node_becomes_node_before = False
                       
                if common_node.getId() == way.firstNode().getId():
                    adjacent_node_to_split_on = way.getNodes()[1]
                else:
                    adjacent_node_to_split_on = way.getNodes()[-1]

                if not(common_node) or ((parentway.isClosed() and common_node_becomes_node_before==None)):
                    JOptionPane.showMessageDialog(MainApplication.parent, "Please select a way that connects to a roundabout")
                else:
                    commandsList = []
                    if len(way.getNodes())>2:
                        # split off last segment before roundabout if needed
                        commandsList.append(Command.SplitWayCommand.split(
                                    way, [adjacent_node_to_split_on], []))
                        MainApplication.undoRedo.add(Command.SequenceCommand(
                                    "Split selected way", commandsList))
                        commandsList = []
                    # After splitting find the segment that connects to the roundabout again
                    for waypartconnectedtoroundabout in adjacent_node_to_split_on.getParentWays():
                        if waypartconnectedtoroundabout.get('junction') == 'roundabout':
                            continue
                        if common_node in waypartconnectedtoroundabout.getNodes():
                            break
                    if len(way.getNodes())==2:
                        if common_node == waypartconnectedtoroundabout.firstNode():
                            adjacent_node_to_split_on = waypartconnectedtoroundabout.lastNode()
                        else:
                            adjacent_node_to_split_on = waypartconnectedtoroundabout.firstNode()
                    # time to actually do something
                    # make a copy of the way
                    modified_way = Way(waypartconnectedtoroundabout)
                    # replace its nodes, so it becomes a fork
                    modified_way.setNodes([node_before, adjacent_node_to_split_on, node_after])
                    # add oneway tag
                    modified_way.put('oneway', 'yes')
                    # apply the changes
                    commandsList.append(Command.ChangeCommand(
                                    waypartconnectedtoroundabout, modified_way))
                    MainApplication.undoRedo.add(Command.SequenceCommand(
                                    "Add oneway tag and create forked way", commandsList))
                    commandsList = []
                    # split this way where it forks
                    commandsList.append(Command.SplitWayCommand.split(
                                    waypartconnectedtoroundabout, [adjacent_node_to_split_on], []))
                    MainApplication.undoRedo.add(Command.SequenceCommand(
                                    "Split fork into 2 ways", commandsList))
                    commandsList = []
                   
                    if roundabout_way_before and roundabout_way_after:
                        origway = roundabout_way_before
                        roundabout_way_before.addNode(node_after)
                        commandsList.append(Command.ChangeCommand(
                                        origway,  roundabout_way_before))
                        origway = roundabout_way_after
                        roundabout_way_after.removeNode(common_node)
                        commandsList.append(Command.ChangeCommand(
                                        origway,roundabout_way_after))
#                        middleway = Way(roundabout_way_after).setNodes(
#                                        [node_before, common_node, node_after])
#                        commandsList.append(Command.AddCommand(editLayer.data, middleway))
#                        MainApplication.undoRedo.add(Command.SequenceCommand(
#                                        "Add way on roundabout where fork attaches", commandsList))
                        commandsList.append(Command.SplitWayCommand.split(
                                        roundabout_way_before, [node_before], []))
                        MainApplication.undoRedo.add(Command.SequenceCommand(
                                        "Split roundabout way", commandsList))
                        commandsList = []

Een verzameling routes naar een Garmin GPX-bestand exporteren

Exporteer een verzameling routes naar een Garmin GPX-bestand (geen bijzonder goed voorbeeld, omdat er geen relaties voor colllections meer bestaan):

#!/bin/jython
'''
RWN2Garmin.py  - Numbered networks to Garmin GPX file converter
This code is released under the GNU General Public License v2 or later.

The GPL v3 is accessible here:
https://www.gnu.org/licenses/gpl.html

It comes with no warranty whatsoever.

'''
from javax.swing import JOptionPane, JDialog
from java.awt.event import ActionListener, ActionEvent
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.TagCollection as TagCollection
import org.openstreetmap.josm.data.osm.DataSet as DataSet
import time

f = open('C:/export.gpx', 'w')
f.write('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n')
f.write('<gpx xmlns="https://www.topografix.com/GPX/1/1" creator="OSM Route Manager" version="1.1" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.topografix.com/GPX/1/1 https://www.topografix.com/GPX/1/1/gpx.xsd">\n')
f.write('<!-- All data by OpenStreetMap, licensed under cc-by-sa-2.0 (https://creativecommons.org/licenses/by-sa/2.0/). -->\n')

editLayer = Main.getLayerManager().getEditLayer()
if editLayer and editLayer.data:
    selectedRelations = mv.editLayer.data.getSelectedRelations()

    if not(selectedRelations):
        JOptionPane.showMessageDialog(Main.parent, "Please select a collection relation")
    else:
        print
        for collection in selectedRelations:
            print 'COLLECTION:', collection
            for member in collection.getMembers():
                print 'MEMBER:',member
                if member.isNode():
                    node = member.getNode()
                    coords = node.getCoor()
                    lon = coords.getX()
                    lat = coords.getY()
                    rwn_ref = node.get('rwn_ref')
                    f.write('\t<wpt lat="' + str(lat) + '" lon="' + str(lon) + '">\n')
                    if rwn_ref:
                        f.write('\t\t<name>' + rwn_ref + '</name>\n')
                    f.write('\t</wpt>\n')
            for member in collection.getMembers():
                if member.isRelation():
                    routerelation = member.getRelation()
                    f.write('\t<trk>\n')
                    networkname =  routerelation.get('network:name')
                    if not(networkname):
                        networkname =  ''
                    else:
                        networkname += ' '
                    note = routerelation.get('note')
                    if not(note): note =  ''
                    f.write('\t\t<name>' + networkname + note + '</name>\n')
                    f.write('\t\t<src>OpenStreetMap.org</src>\n')
                    f.write('\t\t<type>foot</type>\n')
                    for routerelmember in routerelation.getMembers():
                        if routerelmember.isWay():
                            f.write('\t\t<trkseg>\n')
                            way=routerelmember.getWay()
                            for waynode in way.getNodes():
                                 coords = waynode.getCoor()
                                 lon = coords.getX()
                                 lat = coords.getY()
                                 f.write('\t\t\t<trkpt lat="' + str(lat) + '" lon="' + str(lon) + '"> </trkpt>\n')

                            f.write('\t\t</trkseg>\n')
                    f.write('\t</trk>\n')
f.write('</gpx>\n')
f.close()

Ontbrekende ouder-elementen voor het geselecteerde element downloaden

#!/bin/jython
'''

This code is released under the GNU General
Public License v2 or later.

The GPL v3 is accessible here:
https://www.gnu.org/licenses/gpl.html

The GPL v2 is accessible here:
https://www.gnu.org/licenses/old-licenses/gpl-2.0.html

It comes with no warranty whatsoever.

This code illustrates how to use Jython to:
* Download all referrers for an element

'''
from javax.swing import JOptionPane
from org.openstreetmap.josm import Main
import org.openstreetmap.josm.actions.DownloadReferrersAction as DownloadReferrersAction

editLayer = Main.getLayerManager().getEditLayer()
if editLayer and editLayer.data:
    selectedElements = editLayer.data.getSelected()
    
    if not(selectedElements):
        JOptionPane.showMessageDialog(Main.parent, "Selecteer een element")
    else:
        DownloadReferrersAction.downloadReferrers(editLayer, selectedElements)

Ontbrekende leden van de relatie downloaden

#!/bin/jython
'''

This code is released under the GNU General
Public License v2 or later.

The GPL v3 is accessible here:
https://www.gnu.org/licenses/gpl.html

The GPL v2 is accessible here:
https://www.gnu.org/licenses/old-licenses/gpl-2.0.html

It comes with no warranty whatsoever.

This code illustrates how to use Jython to:
* Download all missing members of a relation

'''
from javax.swing import JOptionPane
from org.openstreetmap.josm import Main
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

editLayer = Main.getLayerManager().getEditLayer()
if editLayer:
    selectedRelations = editLayer.data.getSelectedRelations())
    
    if not(selectedRelations):
        JOptionPane.showMessageDialog(Main.parent, "Selecteer een relatie")
    else:
        for relation in selectedRelations:
            if relation.hasIncompleteMembers():
                #print dir(relation)
                print dir(DownloadRelationMemberTask)
                DownloadRelationMemberTask.run(DownloadRelationMemberTask(relation, relation.getIncompleteMembers(), editLayer ))

Een RCN-routerelatie valideren

#!/bin/jython
'''
- Validation of a rcn route relation

This code is released under the GNU General
Public License v2 or later.

The GPL v3 is accessible here:
https://www.gnu.org/licenses/gpl.html

The GPL v2 is accessible here:
https://www.gnu.org/licenses/old-licenses/gpl-2.0.html

It comes with no warranty whatsoever.

This code illustrates how to use Jython 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 re

commandsList = []
reNumberDashNumber = re.compile(r'\d+-\d+')
def getMapView():
    if Main.main and Main.main.map:
        return Main.main.map.mapView
    else:
        return None

mv = getMapView()
if mv and mv.editLayer and mv.editLayer.data:
    dummy_relation = Relation()
    selectedRelations = mv.editLayer.data.getSelectedRelations()

    if not(selectedRelations):
        JOptionPane.showMessageDialog(Main.parent, "Please select a route relation")
    else:
        print
        for route in selectedRelations:
            newRelation = Relation(route)
            relationChanged = False
            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 " + name + '/' + ref, commandsList))
                commandsList = []

            rcn_refs = []; route_relation_names = []; memberslist = []
            endnodes = []; prev_endnodes = []
            continuous_forward = True; continuous_backward = True
            prev_role = None; prev_endnodes_before_forward = None; last_endnodes_before_backward = None
            for member in route.getMembers():
                if member.isWay():
                    role = member.getRole()
                    memberslist.append(member)
                    way = member.getWay()
                    #JOptionPane.showMessageDialog(Main.parent, 'way is selected')
                    endnodes = [way.getNode(0), way.getNode(way.nodesCount-1)]
                    notfoundyet = True
                    for endnode in endnodes:
                        # inventorizing of rcn_ref on end nodes
                        rcn_ref = endnode.get('rcn_ref')
                        if rcn_ref:
                            rcn_refs.append(int(rcn_ref))
                            for referrer in endnode.getReferrers():
                                if referrer.getType() is dummy_relation.getType():
                                    if referrer.get('type')=='network' and referrer.get('network')=='rcn':
                                        relname=referrer.get('name')
                                        if relname:
                                            route_relation_names.append(relname)
                                        
                                    elif referrer.get('type')=='collection':
                                        route_relation_names.append('Node not assigned to network yet')
                        # checking for continuity on ways
                        if notfoundyet:
                            if role:
                                if prev_role:
                                    if role=='forward' and prev_role=='forward' and endnode in prev_endnodes:
                                        notfoundyet = False
                                    elif role=='forward' and prev_role=='backward' and endnode in last_endnodes_before_backward:
                                        notfoundyet = False
                                    elif role=='backward' and prev_role=='forward' and endnode in prev_endnodes:
                                        notfoundyet = False
                                    elif role=='backward' and prev_role=='backward' and endnode in prev_endnodes:
                                        notfoundyet = False
                                else:
                                    if role=='forward' and endnode in prev_endnodes:
                                        notfoundyet = False
                                    elif role=='backward' and endnode in prev_endnodes:
                                        notfoundyet = False
                            else:
                                if prev_role:
                                    if prev_role=='forward' and endnode in prev_endnodes:
                                        notfoundyet = False
                                    elif prev_role=='backward' and endnode in last_endnodes_before_backward:
                                        notfoundyet = False
                                else:
                                    if endnode in prev_endnodes:
                                        notfoundyet = False
                    # Analysis of continuity of ways
                    if prev_endnodes and notfoundyet:
                        if role:
                            if role == 'forward':
                                continuous_forward = False
                            elif role == 'backward':
                                continuous_backward = False
                        else:
                            continuous_forward = False
                            continuous_backward = False
                    if role=='forward':
                        if not(prev_endnodes_before_forward):
                            prev_endnodes_before_forward  = prev_endnodes
                    elif prev_role=='forward' and role=='backward':
                        if not(last_endnodes_before_backward):
                            last_endnodes_before_backward = prev_endnodes
                    elif not(role) and prev_role=='backward':
                        prev_endnodes_before_forward = None
                    prev_role = role
                    prev_endnodes = endnodes
            # Drawing conclusions about continuity of ways
            if continuous_forward:
                print 'route is continous in the forward direction'
            else:
                print 'route is NOT CONTINUOUS in the forward direction'
            if continuous_backward:
                print 'route is continous in the backward direction'
            else:
                print 'route is NOT CONTINUOUS in the backward direction'

            # Drawing conclusions about rcn_refs
            print rcn_refs
            if len(rcn_refs) > 1:
                newRelation = Relation(route)
                relationChanged = False

                if rcn_refs[0] > rcn_refs[1]:
                    rcn_refs.sort()
                    print 'Flipping members order'
                    for member in reversed(memberslist):
                        newRelation.addMember( newRelation.getMembersCount(), member)
                        newRelation.removeMember (0)
                    commandsList.append(Command.ChangeCommand(route, newRelation))
                    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)
                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))
                    commandsList = []

                if len(route_relation_names) > 1 and route_relation_names[0] != route_relation_names[1]:
                    print
                    print 'This is probably a CONNECTION to another network'
                    print route_relation_names
            else:
                print 'less than 2 end nodes with rcn_ref found'

Help/Plugin/Scripting/Python/RCN_Route_Validator (en)

Extra wegen die resultaat zijn van de bewerkingen van Potlatch verwijderen

Extra wegen die resultaat zijn van de bewerkingen Weg splitsen van Potlatch onder relaties van Beperkingen Afslaan verwijderen

#!/bin/jython

'''
RepairTurns.py  - Remove extra ways resulting from Potlatch way split operations under turn restriction relations

This code is released under the GNU General
Public License v2 or later.

The GPL v3 is accessible here:
https://www.gnu.org/licenses/gpl.html

It comes with no warranty whatsoever.

This 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

Only works for turn restrictions with one via node

e.g. Original      : from: Way1, via: Node, to:Way2
     Split         : from: Way1a, from: Way1b, via: Node, to: Way2
     After running : from: Way1b, via: Node, to: Way2

This code illustrates how to use Jython to:
* process selected items
* download missing primitives in the same thread (blocking)
* process, validate and remove members from relations

'''
from javax.swing import JOptionPane
from org.openstreetmap.josm import Main
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.io.MultiFetchServerObjectReader as MultiFetchServerObjectReader
import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor as PleaseWaitProgressMonitor
import org.openstreetmap.josm.command as Command

class RestrictionError(Exception):
    pass

def getMembers (restriction):
    memberlist = dict()
    for member in restriction.getMembers():
        memberRole = member.getRole()
        if memberRole == "via":
            if member.isNode() and not "via" in memberlist:
                memberlist[memberRole] = [member]
            else:
                raise RestrictionError, "More than one via role or via not a node"
        elif memberRole in ("from", "to"):
            if member.isWay():
                try:
                    memberlist[memberRole].append (member)
                except KeyError:
                    memberlist[memberRole] = [member]
            else:
                raise RestrictionError, "From or to role not a way"
        else: 
            raise RestrictionError, "Unknown role " + memberRole

    if len(memberlist.keys())<3:
        raise RestrictionError, "Some roles missing: Only " + ",".join (memberlist.keys()) + " found"
    return memberlist

def downloadPrimitives (primitives, editlayer):
    """
        Download a list of primitives from server, and merge into editlayer. Blocking.
    """
    monitor = PleaseWaitProgressMonitor()
    monitor.showForegroundDialog()   

    print "Downloading"
    try:
        objectReader = MultiFetchServerObjectReader().append (primitives)
        dataSet = objectReader.parseOsm (monitor)
        editlayer.mergeFrom (dataSet)
        editlayer.onPostDownloadFromServer()
        if (not objectReader.getMissingPrimitives().isEmpty()) :
            raise RestrictionError, "Unable to download missing primitives"
        print "Download completed"    
    finally:
        monitor.close()

def checkIfConnected (node, way, reverse):
    """
        Return (connected, next node to compare (i.e. other end of the node) if true)
    """
    if (way.isOneway() != 0 and reverse):
        return node == way.lastNode(True), way.firstNode(True) # True: auto process case when isOneway == -1
    if (way.isOneway() != 0):     # not reverse
        return node == way.firstNode(True), way.lastNode(True)
    if node == way.firstNode():
        return True, way.lastNode()
    if node == way.lastNode():
        return True, way.firstNode()
    return False, node   


def repairrestriction (relation, memberlist, editLayer):
    """
        Download missing members if needed, get list of members to remove, and remove them if no error raised during checking
    """
    incompleteMembers = relation.getIncompleteMembers()
    if incompleteMembers:
          downloadPrimitives (incompleteMembers, editLayer);        

    fromRemovalList = []; toRemovalList = []
    
    if len (memberlist["from"]) >= 1:
        currnode = memberlist["via"][0].getNode()
        firstMember = True
        failed = False;
        # trace "from" members to confirm if split from one way
        for member in reversed(memberlist['from']):
            connected, currnode = checkIfConnected (currnode, member.getWay(), True)
            if not connected:
                if not firstMember:
                    raise RestrictionError, "from ways not continuous from via node" 
                failed = True
                break
            if not firstMember:
                fromRemovalList.append (member)
            else:
                firstMember = False

        if failed: # Second attempt in case sequence reversed when split
            currnode = memberlist["via"][0].getNode()
            for member in memberlist['from']:
                connected, currnode = checkIfConnected (currnode, member.getWay(), True)
                if not connected:
                    raise RestrictionError, "from ways not continuous from via node"
                if not firstMember:
                    fromRemovalList.append (member)
                else:
                    firstMember = False
                                                                        
    if len (memberlist["to"]) >= 1:
        currnode = memberlist["via"][0].getNode()
        firstMember = True
        failed = False
        # trace "to" members to confirm if split from one way
        for member in memberlist['to']:
            connected, currnode = checkIfConnected (currnode, member.getWay(), False)
            if not connected:
                if not firstMember:
                    raise RestrictionError, "to ways not continuous from via node" 
                failed = True
                break
            if not firstMember:
                toRemovalList.append (member)
            else:
                firstMember = False

        if failed: # Second attempt in case sequence reversed when split
            currnode = memberlist["via"][0].getNode()
            for member in reversed(memberlist['to']):
                connected, currnode = checkIfConnected (currnode, member.getWay(), False)
                if not connected:
                    raise RestrictionError, "to ways not continuous from via node"
                if not firstMember:
                    toRemovalList.append (member)
                else:
                    firstMember = False          
                         
    # to remove ways in fromRemovalList, toRemovalList          
    newRelation = Relation(relation)
    waysToRemove = set()
    for removalList in [fromRemovalList, toRemovalList]:
        waysToRemove |= set ([m.getWay() for m in removalList])
    newRelation.removeMembersFor (waysToRemove)
    print "Remove way(s) id:" + ",".join ([str(w.getId()) for w in waysToRemove])
    return Command.ChangeCommand (relation, newRelation)   
    
    
validrestrictiontypes = ('only_straight_on', 'only_right_turn', 'only_left_turn', 'no_right_turn', 'no_left_turn', 'no_straight_on', 'no_u_turn')
editLayer = Main.getLayerManager().getEditLayer()
if editLayer and editLayer.data:
    selectedRelations = editLayer.data.getSelectedRelations()
   
    if not(selectedRelations):
        JOptionPane.showMessageDialog(Main.parent, "Please select one or more relations")
    else:
        commandsList = []
        for relation in selectedRelations:
            if relation.get('type') == "restriction" and relation.get('restriction') in validrestrictiontypes:
                try:
                    memberlist = getMembers (relation)               
                    if (len (memberlist["from"])) > 1 or (len (memberlist["to"])) > 1 :
                        # Repair attempt
                        print "Attempt repair",
                        print "relation id: " + str(relation.getId())
                        command = repairrestriction (relation, memberlist, mv.editLayer)
                        print "Success"                         
                        commandsList.append (command)
                except RestrictionError, e:
                    print str(e), "; relation id: "+ str(relation.getId())
                
        
        Main.main.undoRedo.add(Command.SequenceCommand("Repair turn restrictions", commandsList))
        commandsList=[]

Terug naar Plugin Scripting
Terug naar Plug-in Help
Terug naar Help

Last modified 2 years ago Last modified on 2022-12-29T16:07:59+01:00
Note: See TracWiki for help on using the wiki.