Ticket #6966: ticket-6966-improve-align-nodes-in-line-v1.patch
File ticket-6966-improve-align-nodes-in-line-v1.patch, 11.2 KB (added by , 13 years ago) |
---|
-
src/org/openstreetmap/josm/actions/AlignInLineAction.java
diff --git a/src/org/openstreetmap/josm/actions/AlignInLineAction.java b/src/org/openstreetmap/josm/actions/AlignInLineAction.java index a8ff579..448c467 100644
a b 1 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others 2 2 package org.openstreetmap.josm.actions; 3 3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 4 import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 6 7 7 import java.awt.event.ActionEvent; 8 8 import java.awt.event.KeyEvent; 9 import java.util.ArrayList; 9 10 import java.util.Collection; 10 import java.util.Li nkedList;11 import java.util.List; 11 12 12 13 import javax.swing.JOptionPane; 13 14 … … public final class AlignInLineAction extends JosmAction { 35 36 putValue("help", ht("/Action/AlignInLine")); 36 37 } 37 38 38 /** 39 * The general algorithm here is to find the two selected nodes 40 * that are furthest apart, and then to align all other selected 41 * nodes onto the straight line between these nodes. 42 */ 43 public void actionPerformed(ActionEvent e) { 44 if (!isEnabled()) 45 return; 46 Collection<OsmPrimitive> sel = getCurrentDataSet().getSelected(); 47 Collection<Node> nodes = new LinkedList<Node>(); 48 Collection<Node> itnodes = new LinkedList<Node>(); 49 for (OsmPrimitive osm : sel) 50 if (osm instanceof Node) { 51 nodes.add((Node)osm); 52 itnodes.add((Node)osm); 53 } 54 // special case if no single nodes are selected and exactly one way is: 55 // then use the way's nodes 56 if ((nodes.size() == 0) && (sel.size() == 1)) { 57 for (OsmPrimitive osm : sel) 58 if (osm instanceof Way) { 59 nodes.addAll(((Way)osm).getNodes()); 60 itnodes.addAll(((Way)osm).getNodes()); 61 } 62 } 63 if (nodes.size() < 3) { 64 JOptionPane.showMessageDialog( 65 Main.parent, 66 tr("Please select at least three nodes."), 67 tr("Information"), 68 JOptionPane.INFORMATION_MESSAGE 69 ); 70 return; 71 } 72 39 // the joy of single return values only... 40 private void nodePairFurthestApart(ArrayList<Node> nodes, Node[] resultOut) { 41 if(resultOut.length < 2) 42 throw new IllegalArgumentException(); 73 43 // Find from the selected nodes two that are the furthest apart. 74 44 // Let's call them A and B. 75 45 double distance = 0; … … public final class AlignInLineAction extends JosmAction { 77 47 Node nodea = null; 78 48 Node nodeb = null; 79 49 80 for (Node n : nodes) { 81 itnodes.remove(n); 82 for (Node m : itnodes) { 50 for (int i = 0; i < nodes.size()-1; i++) { 51 Node n = nodes.get(i); 52 for (int j = i+1; j < nodes.size(); j++) { 53 Node m = nodes.get(j); 83 54 double dist = Math.sqrt(n.getEastNorth().distance(m.getEastNorth())); 84 55 if (dist > distance) { 85 56 nodea = n; … … public final class AlignInLineAction extends JosmAction { 88 59 } 89 60 } 90 61 } 62 resultOut[0] = nodea; 63 resultOut[1] = nodeb; 64 } 65 66 private void showWarning() { 67 JOptionPane.showMessageDialog( 68 Main.parent, 69 tr("Please select at least three nodes."), 70 tr("Information"), 71 JOptionPane.INFORMATION_MESSAGE 72 ); 73 return; 74 } 91 75 92 // Remove the nodes A and B from the list of nodes to move 76 private static int indexWrap(int size, int i) { 77 i = i % size; // -2 % 5 = -2, -7 % 5 = -2, -5 % 5 = 0 78 if (i < 0) { 79 i = size + i; 80 } 81 return i; 82 } 83 // get the node in w at index i relative to refI 84 private static Node getNodeRelative(Way w, int refI, int i) { 85 int absI = indexWrap(w.getNodesCount(), refI + i); 86 if(w.isClosed() && refI + i < 0) { 87 absI--; // node duplicated in closed ways 88 } 89 return w.getNode(absI); 90 } 91 92 /** 93 * The general algorithm here is to find the two selected nodes 94 * that are furthest apart, and then to align all other selected 95 * nodes onto the straight line between these nodes. 96 */ 97 98 99 /** 100 * Operation depends on the selected objects: 101 */ 102 public void actionPerformed(ActionEvent e) { 103 if (!isEnabled()) 104 return; 105 106 Node[] anchors = new Node[2]; // oh, java I love you so much.. 107 108 List<Node> selectedNodes = new ArrayList<Node>(getCurrentDataSet().getSelectedNodes()); 109 Collection<Way> selectedWays = getCurrentDataSet().getSelectedWays(); 110 ArrayList<Node> nodes = new ArrayList<Node>(); 111 112 //// Decide what to align based on selection: 113 114 /// Only ways selected -> Align their nodes. 115 if ((selectedNodes.size() == 0) && (selectedWays.size() == 1)) { // TODO: handle multiple ways 116 for (Way way : selectedWays) { 117 nodes.addAll(way.getNodes()); 118 } 119 // use the nodes furthest apart as anchors 120 nodePairFurthestApart(nodes, anchors); 121 } 122 /// More than 3 nodes selected -> align those nodes 123 else if(selectedNodes.size() >= 3) { 124 nodes.addAll(selectedNodes); 125 // use the nodes furthest apart as anchors 126 nodePairFurthestApart(nodes, anchors); 127 } 128 /// One node selected -> align that node to the relevant neighbors 129 else if (selectedNodes.size() == 1) { 130 Node n = selectedNodes.iterator().next(); 131 132 Way w = null; 133 if(selectedWays.size() == 1) { 134 w = selectedWays.iterator().next(); 135 if(w.containsNode(n) == false) 136 // warning 137 return; 138 } else if(n.isReferredByWays(2) == false) { // node used in only one way 139 w = OsmPrimitive.getFilteredList(n.getReferrers(), Way.class).iterator().next(); 140 } 141 if (w == null || w.getNodesCount() < 3) 142 // warning, need at least 3 nodes 143 return; 144 145 // Find anchors 146 int nodeI = w.getNodes().indexOf(n); 147 // End-node in non-circular way selected: align this node with the two neighbors. 148 if ((nodeI == 0 || nodeI == w.getNodesCount()-1) && !w.isClosed()) { 149 int direction = nodeI == 0 ? 1 : -1; 150 anchors[0] = w.getNode(nodeI + direction); 151 anchors[1] = w.getNode(nodeI + direction*2); 152 } else { 153 // o---O---o 154 anchors[0] = getNodeRelative(w, nodeI, 1); 155 anchors[1] = getNodeRelative(w, nodeI, -1); 156 } 157 nodes.add(n); 158 } 159 160 if (anchors[0] == null || anchors[1] == null) { 161 showWarning(); 162 return; 163 } 164 165 166 Collection<Command> cmds = new ArrayList<Command>(nodes.size()); 167 168 createAlignNodesCommands(anchors, nodes, cmds); 169 170 // Do it! 171 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds)); 172 Main.map.repaint(); 173 } 174 175 private void createAlignNodesCommands(Node[] anchors, Collection<Node> nodes, Collection<Command> cmds) { 176 Node nodea = anchors[0]; 177 Node nodeb = anchors[1]; 178 179 // The anchors are aligned per definition 93 180 nodes.remove(nodea); 94 181 nodes.remove(nodeb); 95 182 … … public final class AlignInLineAction extends JosmAction { 99 186 double bx = nodeb.getEastNorth().east(); 100 187 double by = nodeb.getEastNorth().north(); 101 188 102 // A list of commands to do103 Collection<Command> cmds = new LinkedList<Command>();104 105 189 // OK, for each node to move, work out where to move it! 106 190 for (Node n : nodes) { 107 191 // Get existing co-ords of node to move … … public final class AlignInLineAction extends JosmAction { 124 208 nx = (c2 - c1) / (m1 - m2); 125 209 ny = (m1 * nx) + c1; 126 210 } 127 211 double newX = nx - n.getEastNorth().east(); 212 double newY = ny - n.getEastNorth().north(); 128 213 // Add the command to move the node to its new position. 129 cmds.add(new MoveCommand(n, n x - n.getEastNorth().east(), ny - n.getEastNorth().north()));214 cmds.add(new MoveCommand(n, newX, newY)); 130 215 } 131 132 // Do it!133 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds));134 Main.map.repaint();135 216 } 136 217 137 218 @Override -
src/org/openstreetmap/josm/actions/JoinNodeWayAction.java
diff --git a/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java b/src/org/openstreetmap/josm/actions/JoinNodeWayAction.java index afa7c9f..468c33f 100644
a b public class JoinNodeWayAction extends JosmAction { 35 35 public void actionPerformed(ActionEvent e) { 36 36 if (!isEnabled()) 37 37 return; 38 Collection<OsmPrimitive> sel = getCurrentDataSet().getSelected(); 39 if (sel.size() < 1) return; 38 Collection<Node> selectedNodes = getCurrentDataSet().getSelectedNodes(); 39 // Allow multiple selected nodes too? 40 if (selectedNodes.size() != 1) return; 41 42 Node node = selectedNodes.iterator().next(); 40 43 41 44 Collection<Command> cmds = new LinkedList<Command>(); 42 45 43 for (OsmPrimitive osm : sel) { 44 if (!(osm instanceof Node)) { 45 continue; 46 } 47 Node node = (Node) osm; 46 // If the user has selected some ways, only join the node to these. 47 boolean restrictToSelectedWays = 48 getCurrentDataSet().getSelectedWays().size() > 0; 48 49 49 50 List<WaySegment> wss = Main.map.mapView.getNearestWaySegments( 50 51 Main.map.mapView.getPoint(node), OsmPrimitive.isSelectablePredicate); 51 52 HashMap<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>(); 52 53 for (WaySegment ws : wss) { 54 // Maybe cleaner to pass a "isSelected" predicate to getNearestWaySegements, but this is atm. less invasive. 55 if(restrictToSelectedWays && !ws.way.isSelected()) { 56 continue; 57 } 58 53 59 List<Integer> is; 54 60 if (insertPoints.containsKey(ws.way)) { 55 61 is = insertPoints.get(ws.way); … … public class JoinNodeWayAction extends JosmAction { 80 86 wnew.setNodes(nodesToAdd); 81 87 cmds.add(new ChangeCommand(w, wnew)); 82 88 } 83 } 84 if (cmds.size() == 0) return; 85 Main.main.undoRedo.add(new SequenceCommand(tr("Join Node and Line"), cmds)); 86 Main.map.repaint(); 89 if (cmds.size() == 0) return; 90 Main.main.undoRedo.add(new SequenceCommand(tr("Join Node and Line"), cmds)); 91 Main.map.repaint(); 87 92 } 88 93 89 94 private static void pruneSuccsAndReverse(List<Integer> is) {