Changeset 4558 in josm
- Timestamp:
- 2011-11-02T10:12:33+01:00 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/AlignInLineAction.java
r2323 r4558 2 2 package org.openstreetmap.josm.actions; 3 3 4 import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 4 5 import static org.openstreetmap.josm.tools.I18n.tr; 5 import static org.openstreetmap.josm.gui.help.HelpUtil.ht;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; … … 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. … … 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) { … … 89 60 } 90 61 } 91 92 // Remove the nodes A and B from the list of nodes to move 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 } 75 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); … … 99 186 double bx = nodeb.getEastNorth().east(); 100 187 double by = nodeb.getEastNorth().north(); 101 102 // A list of commands to do103 Collection<Command> cmds = new LinkedList<Command>();104 188 105 189 // OK, for each node to move, work out where to move it! … … 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, nx - n.getEastNorth().east(), ny - n.getEastNorth().north() )); 130 } 131 132 // Do it! 133 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds)); 134 Main.map.repaint(); 214 cmds.add(new MoveCommand(n, newX, newY)); 215 } 135 216 } 136 217
Note:
See TracChangeset
for help on using the changeset viewer.