source: subversion/applications/editors/josm/plugins/utilsplugin2/src/org/openstreetmap/josm/plugins/utilsplugin2/selection/SelectHighwayAction.java

Last change on this file was 34932, checked in by gerdp, 4 weeks ago

fix #17483: respect active filters in select actions provided by utilsplugin2

File size: 7.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.plugins.utilsplugin2.selection;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.ActionEvent;
7import java.awt.event.KeyEvent;
8import java.util.ArrayList;
9import java.util.Collection;
10import java.util.Collections;
11import java.util.HashSet;
12import java.util.LinkedList;
13import java.util.List;
14import java.util.Queue;
15import java.util.Set;
16
17import javax.swing.JOptionPane;
18
19import org.openstreetmap.josm.actions.JosmAction;
20import org.openstreetmap.josm.data.osm.DataSet;
21import org.openstreetmap.josm.data.osm.Node;
22import org.openstreetmap.josm.data.osm.OsmPrimitive;
23import org.openstreetmap.josm.data.osm.Way;
24import org.openstreetmap.josm.gui.Notification;
25import org.openstreetmap.josm.tools.Shortcut;
26
27/**
28 * Select all connected ways for a street if one way is selected (determine by name/ref),
29 * select highway ways between two selected ways.
30 *
31 * @author zverik
32 */
33public class SelectHighwayAction extends JosmAction {
34
35    public SelectHighwayAction() {
36        super(tr("Select Highway"), "selecthighway", tr("Select highway for the name/ref given"),
37                Shortcut.registerShortcut("tools:selecthighway", tr("Tool: {0}", "Select Highway"),
38                        KeyEvent.VK_W, Shortcut.ALT_CTRL), true);
39    }
40
41    @Override
42    public void actionPerformed(ActionEvent e) {
43        DataSet ds = getLayerManager().getEditDataSet();
44        List<Way> selectedWays = new ArrayList<>(ds.getSelectedWays());
45
46        if (selectedWays.size() == 1) {
47            ds.setSelected(selectNamedRoad(selectedWays.get(0)));
48        } else if (selectedWays.size() == 2) {
49            ds.setSelected(selectHighwayBetween(selectedWays.get(0), selectedWays.get(1)));
50        } else {
51            new Notification(
52                    tr("Please select one or two ways for this action")
53                    ).setIcon(JOptionPane.WARNING_MESSAGE).show();
54        }
55    }
56
57    private Set<Way> selectNamedRoad(Way firstWay) {
58        Set<Way> newWays = new HashSet<>();
59        String key = firstWay.hasKey("name") ? "name" : "ref";
60        if (firstWay.hasKey(key)) {
61            String value = firstWay.get(key);
62            Queue<Node> nodeQueue = new LinkedList<>();
63            nodeQueue.add(firstWay.firstNode());
64            while (!nodeQueue.isEmpty()) {
65                Node node = nodeQueue.remove();
66                for (Way p : node.getParentWays()) {
67                    if (!p.isDisabled() && !newWays.contains(p) && p.hasKey(key) && p.get(key).equals(value)) {
68                        newWays.add(p);
69                        nodeQueue.add(p.firstNode().equals(node) ? p.lastNode() : p.firstNode());
70                    }
71                }
72            }
73        }
74        return newWays;
75    }
76
77    private Set<Way> selectHighwayBetween(Way firstWay, Way lastWay) {
78        int minRank = Math.min(getHighwayRank(firstWay), getHighwayRank(lastWay));
79        HighwayTree firstTree = new HighwayTree(firstWay, minRank);
80        HighwayTree secondTree = new HighwayTree(lastWay, minRank);
81        Way intersection = firstTree.getIntersection(secondTree);
82        while (intersection == null && (firstTree.canMoveOn() || secondTree.canMoveOn())) {
83            firstTree.processNextLevel();
84            secondTree.processNextLevel();
85            intersection = firstTree.getIntersection(secondTree);
86        }
87        Set<Way> newWays = new HashSet<>();
88        newWays.addAll(firstTree.getPath(intersection));
89        newWays.addAll(secondTree.getPath(intersection));
90        return newWays;
91    }
92
93    private static int getHighwayRank(OsmPrimitive way) {
94        if (!way.hasKey("highway"))
95            return 0;
96        String highway = way.get("highway");
97        if (highway.equals("path") || highway.equals("footway") || highway.equals("cycleway"))
98            return 1;
99        else if (highway.equals("track") || highway.equals("service"))
100            return 2;
101        else if (highway.equals("unclassified") || highway.equals("residential"))
102            return 3;
103        else if (highway.equals("tertiary") || highway.equals("tertiary_link"))
104            return 4;
105        else if (highway.equals("secondary") || highway.equals("secondary_link"))
106            return 5;
107        else if (highway.equals("primary") || highway.equals("primary_link"))
108            return 6;
109        else if (highway.equals("trunk") || highway.equals("trunk_link") || highway.equals("motorway") || highway.equals("motorway_link"))
110            return 7;
111        return 0;
112    }
113
114    @Override
115    protected void updateEnabledState() {
116        updateEnabledStateOnCurrentSelection();
117    }
118
119    @Override
120    protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
121        if (selection == null) {
122            setEnabled(false);
123            return;
124        }
125        int count = 0, rank = 100;
126        for (OsmPrimitive p : selection) {
127            if (p instanceof Way) {
128                count++;
129                rank = Math.min(rank, getHighwayRank(p));
130            }
131        }
132        setEnabled(count == 1 || (count == 2 && rank > 0));
133    }
134
135    private static class HighwayTree {
136        private List<Way> tree;
137        private List<Integer> refs;
138        private List<Node> nodesToCheck;
139        private List<Integer> nodeRefs;
140        private int minHighwayRank;
141
142        HighwayTree(Way from, int minHighwayRank) {
143            tree = new ArrayList<>(1);
144            refs = new ArrayList<>(1);
145            tree.add(from);
146            refs.add(Integer.valueOf(-1));
147            this.minHighwayRank = minHighwayRank;
148            nodesToCheck = new ArrayList<>(2);
149            nodeRefs = new ArrayList<>(2);
150            nodesToCheck.add(from.firstNode());
151            nodesToCheck.add(from.lastNode());
152            nodeRefs.add(Integer.valueOf(0));
153            nodeRefs.add(Integer.valueOf(0));
154        }
155
156        public void processNextLevel() {
157            List<Node> newNodes = new ArrayList<>();
158            List<Integer> newIdx = new ArrayList<>();
159            for (int i = 0; i < nodesToCheck.size(); i++) {
160                Node node = nodesToCheck.get(i);
161                Integer nodeRef = nodeRefs.get(i);
162                for (Way way : node.getParentWays()) {
163                    if ((way.firstNode().equals(node) || way.lastNode().equals(node)) &&
164                            !tree.contains(way) && suits(way)) {
165                        tree.add(way);
166                        refs.add(nodeRef);
167                        Node newNode = way.firstNode().equals(node) ? way.lastNode() : way.firstNode();
168                        newNodes.add(newNode);
169                        newIdx.add(Integer.valueOf(tree.size() - 1));
170                    }
171                }
172            }
173            nodesToCheck = newNodes;
174            nodeRefs = newIdx;
175        }
176
177        private boolean suits(Way w) {
178            return getHighwayRank(w) >= minHighwayRank;
179        }
180
181        public boolean canMoveOn() {
182            return !nodesToCheck.isEmpty() && tree.size() < 10000;
183        }
184
185        public Way getIntersection(HighwayTree other) {
186            for (Way w : other.tree) {
187                if (tree.contains(w))
188                    return w;
189            }
190            return null;
191        }
192
193        public List<Way> getPath(Way to) {
194            if (to == null)
195                return Collections.singletonList(tree.get(0));
196            int pos = tree.indexOf(to);
197            if (pos < 0)
198                throw new ArrayIndexOutOfBoundsException("Way " + to + " is not in the tree.");
199            List<Way> result = new ArrayList<>(1);
200            while (pos >= 0) {
201                result.add(tree.get(pos));
202                pos = refs.get(pos);
203            }
204            return result;
205        }
206    }
207}
Note: See TracBrowser for help on using the repository browser.