source: josm/trunk/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java@ 7293

Last change on this file since 7293 was 7194, checked in by akks, 10 years ago

Allow setting shortcut for Move Node on Way
renamed images/movewayontonode.png

  • Property svn:eol-style set to native
File size: 5.5 KB
Line 
1//License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import org.openstreetmap.josm.Main;
5import org.openstreetmap.josm.command.ChangeCommand;
6import org.openstreetmap.josm.command.Command;
7import org.openstreetmap.josm.command.MoveCommand;
8import org.openstreetmap.josm.command.SequenceCommand;
9import org.openstreetmap.josm.data.coor.EastNorth;
10import org.openstreetmap.josm.data.osm.Node;
11import org.openstreetmap.josm.data.osm.OsmPrimitive;
12import org.openstreetmap.josm.data.osm.Way;
13import org.openstreetmap.josm.data.osm.WaySegment;
14import org.openstreetmap.josm.data.projection.Projections;
15import org.openstreetmap.josm.tools.Geometry;
16import org.openstreetmap.josm.tools.MultiMap;
17import org.openstreetmap.josm.tools.Shortcut;
18
19import java.awt.event.ActionEvent;
20import java.awt.event.KeyEvent;
21import java.util.Collection;
22import java.util.Collections;
23import java.util.LinkedList;
24import java.util.List;
25import java.util.Map;
26import java.util.Set;
27import java.util.SortedSet;
28import java.util.TreeSet;
29
30import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
31import static org.openstreetmap.josm.tools.I18n.tr;
32
33public class JoinNodeWayAction extends JosmAction {
34
35 protected final boolean joinWayToNode;
36
37 protected JoinNodeWayAction(boolean joinWayToNode, String name, String iconName, String tooltip, Shortcut shortcut, boolean registerInToolbar) {
38 super(name, iconName, tooltip, shortcut, registerInToolbar);
39 this.joinWayToNode = joinWayToNode;
40 }
41
42 /**
43 * Constructs a Join Node to Way action.
44 */
45 public static JoinNodeWayAction createJoinNodeToWayAction() {
46 JoinNodeWayAction action = new JoinNodeWayAction(false,
47 tr("Join Node to Way"), "joinnodeway", tr("Include a node into the nearest way segments"),
48 Shortcut.registerShortcut("tools:joinnodeway", tr("Tool: {0}", tr("Join Node to Way")), KeyEvent.VK_J, Shortcut.DIRECT), true);
49 action.putValue("help", ht("/Action/JoinNodeWay"));
50 return action;
51 }
52
53 /**
54 * Constructs a Move Node onto Way action.
55 */
56 public static JoinNodeWayAction createMoveNodeOntoWayAction() {
57 JoinNodeWayAction action = new JoinNodeWayAction(true,
58 tr("Move Node onto Way"), "movenodeontoway", tr("Move the node onto the nearest way segments and include it"),
59 Shortcut.registerShortcut("tools:movenodeontoway", tr("Tool: {0}", tr("Move Node onto Way")), KeyEvent.VK_J, Shortcut.NONE), true);
60 return action;
61 }
62
63 @Override
64 public void actionPerformed(ActionEvent e) {
65 if (!isEnabled())
66 return;
67 Collection<Node> selectedNodes = getCurrentDataSet().getSelectedNodes();
68 // Allow multiple selected nodes too?
69 if (selectedNodes.size() != 1) return;
70
71 final Node node = selectedNodes.iterator().next();
72
73 Collection<Command> cmds = new LinkedList<>();
74
75 // If the user has selected some ways, only join the node to these.
76 boolean restrictToSelectedWays =
77 !getCurrentDataSet().getSelectedWays().isEmpty();
78
79 List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(
80 Main.map.mapView.getPoint(node), OsmPrimitive.isSelectablePredicate);
81 MultiMap<Way, Integer> insertPoints = new MultiMap<>();
82 for (WaySegment ws : wss) {
83 // Maybe cleaner to pass a "isSelected" predicate to getNearestWaySegments, but this is less invasive.
84 if (restrictToSelectedWays && !ws.way.isSelected()) {
85 continue;
86 }
87
88 if (ws.getFirstNode() != node && ws.getSecondNode() != node) {
89 insertPoints.put(ws.way, ws.lowerIndex);
90 }
91 }
92
93 for (Map.Entry<Way, Set<Integer>> entry : insertPoints.entrySet()) {
94 final Way w = entry.getKey();
95 final Set<Integer> insertPointsForWay = entry.getValue();
96 if (insertPointsForWay.isEmpty()) {
97 continue;
98 }
99
100 List<Node> nodesToAdd = w.getNodes();
101 for (int i : pruneSuccsAndReverse(insertPointsForWay)) {
102 if (joinWayToNode) {
103 EastNorth newPosition = Geometry.closestPointToSegment(
104 w.getNode(i).getEastNorth(), w.getNode(i + 1).getEastNorth(), node.getEastNorth());
105 cmds.add(new MoveCommand(node, Projections.inverseProject(newPosition)));
106 }
107 nodesToAdd.add(i + 1, node);
108 }
109 Way wnew = new Way(w);
110 wnew.setNodes(nodesToAdd);
111 cmds.add(new ChangeCommand(w, wnew));
112 }
113 if (cmds.isEmpty()) return;
114 Main.main.undoRedo.add(new SequenceCommand(getValue(NAME).toString(), cmds));
115 Main.map.repaint();
116 }
117
118 private static SortedSet<Integer> pruneSuccsAndReverse(Collection<Integer> is) {
119 SortedSet<Integer> is2 = new TreeSet<>(Collections.reverseOrder());
120 for (int i : is) {
121 if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
122 is2.add(i);
123 }
124 }
125 return is2;
126 }
127
128 @Override
129 protected void updateEnabledState() {
130 if (getCurrentDataSet() == null) {
131 setEnabled(false);
132 } else {
133 updateEnabledState(getCurrentDataSet().getSelected());
134 }
135 }
136
137 @Override
138 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
139 setEnabled(selection != null && !selection.isEmpty());
140 }
141}
Note: See TracBrowser for help on using the repository browser.