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

Last change on this file was 35674, checked in by GerdP, 3 years ago
  • simplify updateEnabledState
  • minor performance improvements
  • checkstyle or sonarling issues, javadoc corrections
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("Selection: {0}", tr("Select Highway")),
38 KeyEvent.VK_W, Shortcut.ALT_CTRL), true);
39 }
40
41 @Override
42 public void actionPerformed(ActionEvent e) {
43 DataSet ds = getLayerManager().getActiveDataSet();
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 static 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 static 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 ("path".equals(highway) || "footway".equals(highway) || "cycleway".equals(highway))
98 return 1;
99 else if ("track".equals(highway) || "service".equals(highway))
100 return 2;
101 else if ("unclassified".equals(highway) || "residential".equals(highway))
102 return 3;
103 else if ("tertiary".equals(highway) || "tertiary_link".equals(highway))
104 return 4;
105 else if ("secondary".equals(highway) || "secondary_link".equals(highway))
106 return 5;
107 else if ("primary".equals(highway) || "primary_link".equals(highway))
108 return 6;
109 else if ("trunk".equals(highway) || "trunk_link".equals(highway) || "motorway".equals(highway) || "motorway_link".equals(highway))
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 int count = 0;
122 int rank = 100;
123 if (selection != null) {
124 for (OsmPrimitive p : selection) {
125 if (p instanceof Way) {
126 count++;
127 if (count > 2)
128 break;
129 rank = Math.min(rank, getHighwayRank(p));
130 }
131 }
132 }
133 setEnabled(count == 1 || (count == 2 && rank > 0));
134 }
135
136 private static class HighwayTree {
137 private List<Way> tree;
138 private List<Integer> refs;
139 private List<Node> nodesToCheck;
140 private List<Integer> nodeRefs;
141 private int minHighwayRank;
142
143 HighwayTree(Way from, int minHighwayRank) {
144 tree = new ArrayList<>(1);
145 refs = new ArrayList<>(1);
146 tree.add(from);
147 refs.add(Integer.valueOf(-1));
148 this.minHighwayRank = minHighwayRank;
149 nodesToCheck = new ArrayList<>(2);
150 nodeRefs = new ArrayList<>(2);
151 nodesToCheck.add(from.firstNode());
152 nodesToCheck.add(from.lastNode());
153 nodeRefs.add(Integer.valueOf(0));
154 nodeRefs.add(Integer.valueOf(0));
155 }
156
157 public void processNextLevel() {
158 List<Node> newNodes = new ArrayList<>();
159 List<Integer> newIdx = new ArrayList<>();
160 for (int i = 0; i < nodesToCheck.size(); i++) {
161 Node node = nodesToCheck.get(i);
162 Integer nodeRef = nodeRefs.get(i);
163 for (Way way : node.getParentWays()) {
164 if ((way.firstNode().equals(node) || way.lastNode().equals(node)) &&
165 !tree.contains(way) && suits(way)) {
166 tree.add(way);
167 refs.add(nodeRef);
168 Node newNode = way.firstNode().equals(node) ? way.lastNode() : way.firstNode();
169 newNodes.add(newNode);
170 newIdx.add(Integer.valueOf(tree.size() - 1));
171 }
172 }
173 }
174 nodesToCheck = newNodes;
175 nodeRefs = newIdx;
176 }
177
178 private boolean suits(Way w) {
179 return getHighwayRank(w) >= minHighwayRank;
180 }
181
182 public boolean canMoveOn() {
183 return !nodesToCheck.isEmpty() && tree.size() < 10000;
184 }
185
186 public Way getIntersection(HighwayTree other) {
187 for (Way w : other.tree) {
188 if (tree.contains(w))
189 return w;
190 }
191 return null;
192 }
193
194 public List<Way> getPath(Way to) {
195 if (to == null)
196 return Collections.singletonList(tree.get(0));
197 int pos = tree.indexOf(to);
198 if (pos < 0)
199 throw new ArrayIndexOutOfBoundsException("Way " + to + " is not in the tree.");
200 List<Way> result = new ArrayList<>(1);
201 while (pos >= 0) {
202 result.add(tree.get(pos));
203 pos = refs.get(pos);
204 }
205 return result;
206 }
207 }
208}
Note: See TracBrowser for help on using the repository browser.