source: subversion/applications/editors/josm/plugins/terracer/src/org/openstreetmap/josm/plugins/terracer/ReverseTerraceAction.java

Last change on this file was 34584, checked in by donvip, 8 months ago

rename package, fix warning

File size: 5.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.plugins.terracer;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.ActionEvent;
7import java.awt.event.KeyEvent;
8import java.util.Collection;
9import java.util.Collections;
10import java.util.HashSet;
11import java.util.LinkedList;
12
13import javax.swing.JOptionPane;
14
15import org.openstreetmap.josm.actions.JosmAction;
16import org.openstreetmap.josm.command.ChangePropertyCommand;
17import org.openstreetmap.josm.command.Command;
18import org.openstreetmap.josm.command.SequenceCommand;
19import org.openstreetmap.josm.data.UndoRedoHandler;
20import org.openstreetmap.josm.data.osm.Node;
21import org.openstreetmap.josm.data.osm.OsmPrimitive;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.gui.MainApplication;
24import org.openstreetmap.josm.tools.Shortcut;
25
26/**
27 * Tool to reverse the house numbers in a terrace.
28 *
29 * Useful for when you're using the Terracer tool and the house numbers come out
30 * in the wrong direction, or when someone has added house numbers in the wrong
31 * direction anyway.
32 *
33 * Finds all connected ways which have a building=* tag on them in order (breadth
34 * first search) and then changes the tags to be the reverse of the order in which
35 * they were found.
36 */
37public class ReverseTerraceAction extends JosmAction {
38
39    public ReverseTerraceAction() {
40        super(tr("Reverse a terrace"),
41            "reverse_terrace",
42            tr("Reverses house numbers on a terrace."),
43            Shortcut.registerShortcut("tools:ReverseTerrace",
44                    tr("Tool: {0}", tr("Reverse a Terrace")),
45                    KeyEvent.VK_V, Shortcut.ALT_CTRL_SHIFT),
46                        true);
47    }
48
49    /**
50     * Breadth-first searches based on the selection while the selection is a way
51     * with a building=* tag and then applies the addr:housenumber tag in reverse order.
52     */
53    @Override
54    public void actionPerformed(ActionEvent e) {
55        Collection<Way> selectedWays = MainApplication.getLayerManager().getEditDataSet().getSelectedWays();
56
57        // Set to keep track of all the nodes that have been visited - that is: if
58        // we encounter them again we will not follow onto the connected ways.
59        HashSet<Node> visitedNodes = new HashSet<>();
60
61        // Set to keep track of the ways the algorithm has seen, but not yet visited.
62        // Since when a way is visited all of its nodes are marked as visited, there
63        // is no need to keep a visitedWays set.
64        HashSet<Way> front = new HashSet<>();
65
66        // Find the first or last way from the teracced houses.
67        // It should be connected to exactly one other way.
68        for (Way w : selectedWays) {
69            int conn = 0;
70            for (Way v : selectedWays) {
71                if (w.equals(v)) continue;
72                if (!Collections.disjoint(w.getNodes(), v.getNodes())) {
73                    ++conn;
74                }
75            }
76            if (conn == 1) {
77                front.add(w);
78                break;
79            }
80        }
81
82        if (front.isEmpty()) {
83            JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
84                    tr("Cannot reverse!"));
85            return;
86        }
87
88        // This is like a visitedWays set, but in a linear order.
89        LinkedList<Way> orderedWays = new LinkedList<>();
90
91        // And the tags to reverse on the orderedWays.
92        LinkedList<String> houseNumbers = new LinkedList<>();
93
94        while (front.size() > 0) {
95            // Java apparently doesn't have useful methods to get single items from sets...
96            Way w = front.iterator().next();
97
98            // Visit all the nodes in the way, adding the building's they're members of
99            // to the front.
100            for (Node n : w.getNodes()) {
101                if (!visitedNodes.contains(n)) {
102                    for (OsmPrimitive prim : n.getReferrers()) {
103                        if (prim.keySet().contains("building") && prim instanceof Way) {
104                            front.add((Way) prim);
105                        }
106                    }
107                    visitedNodes.add(n);
108                }
109            }
110
111            // We've finished visiting this way, so record the attributes we're interested
112            // in for re-writing.
113            front.remove(w);
114            orderedWays.addLast(w);
115            houseNumbers.addFirst(w.get("addr:housenumber"));
116        }
117
118        Collection<Command> commands = new LinkedList<>();
119        for (int i = 0; i < orderedWays.size(); ++i) {
120            commands.add(new ChangePropertyCommand(
121                    orderedWays.get(i),
122                    "addr:housenumber",
123                    houseNumbers.get(i)));
124        }
125
126        UndoRedoHandler.getInstance().add(new SequenceCommand(tr("Reverse Terrace"), commands));
127        MainApplication.getLayerManager().getEditDataSet().setSelected(orderedWays);
128    }
129
130    @Override
131    protected void updateEnabledState() {
132        setEnabled(getLayerManager().getEditDataSet() != null);
133    }
134}
Note: See TracBrowser for help on using the repository browser.