Changeset 329 in josm for branch/0.5/src/org/openstreetmap/josm/actions
- Timestamp:
- 2007-09-24T01:36:24+02:00 (18 years ago)
- Location:
- branch/0.5/src/org/openstreetmap/josm/actions
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
branch/0.5/src/org/openstreetmap/josm/actions/CombineWayAction.java
r301 r329 10 10 import java.util.HashMap; 11 11 import java.util.LinkedList; 12 import java.util.List; 13 import java.util.ListIterator; 14 import java.util.ArrayList; 12 15 import java.util.Map; 13 16 import java.util.Set; … … 15 18 import java.util.TreeSet; 16 19 import java.util.Map.Entry; 20 import java.util.HashSet; 17 21 18 22 import javax.swing.Box; … … 31 35 import org.openstreetmap.josm.data.osm.OsmPrimitive; 32 36 import org.openstreetmap.josm.data.osm.Way; 37 import org.openstreetmap.josm.data.osm.Node; 38 import org.openstreetmap.josm.data.osm.NodePair; 33 39 import org.openstreetmap.josm.tools.GBC; 34 40 … … 42 48 public CombineWayAction() { 43 49 super(tr("Combine Way"), "combineway", tr("Combine several ways into one."), KeyEvent.VK_C, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true); 44 DataSet. listeners.add(this);50 DataSet.selListeners.add(this); 45 51 } 46 52 … … 68 74 } 69 75 70 Way oldWay = selectedWays.poll(); 71 Way newWay = new Way(oldWay); 72 LinkedList<Command> cmds = new LinkedList<Command>(); 76 // Battle plan: 77 // 1. Split the ways into small chunks of 2 nodes and weed out 78 // duplicates. 79 // 2. Take a chunk and see if others could be appended or prepended, 80 // if so, do it and remove it from the list of remaining chunks. 81 // Rather, rinse, repeat. 82 // 3. If this algorithm does not produce a single way, 83 // complain to the user. 84 // 4. Profit! 73 85 74 for (Way w : selectedWays) 75 newWay.segments.addAll(w.segments); 86 HashSet<NodePair> chunkSet = new HashSet<NodePair>(); 87 for (Way w : selectedWays) { 88 if (w.nodes.size() == 0) continue; 89 Node lastN = null; 90 for (Node n : w.nodes) { 91 if (lastN == null) { 92 lastN = n; 93 continue; 94 } 95 chunkSet.add(new NodePair(lastN, n)); 96 lastN = n; 97 } 98 } 99 LinkedList<NodePair> chunks = new LinkedList<NodePair>(chunkSet); 100 101 if (chunks.isEmpty()) { 102 JOptionPane.showMessageDialog(Main.parent, tr("All the ways were empty")); 103 return; 104 } 105 106 List<Node> nodeList = chunks.poll().toArrayList(); 107 while (!chunks.isEmpty()) { 108 ListIterator<NodePair> it = chunks.listIterator(); 109 boolean foundChunk = false; 110 while (it.hasNext()) { 111 NodePair curChunk = it.next(); 112 if (curChunk.a == nodeList.get(nodeList.size() - 1)) { // append 113 nodeList.add(curChunk.b); 114 foundChunk = true; 115 } else if (curChunk.b == nodeList.get(0)) { // prepend 116 nodeList.add(0, curChunk.a); 117 foundChunk = true; 118 } 119 if (foundChunk) { 120 it.remove(); 121 break; 122 } 123 } 124 if (!foundChunk) break; 125 } 126 127 if (!chunks.isEmpty()) { 128 JOptionPane.showMessageDialog(Main.parent, 129 tr("Could not combine ways (Hint: ways have to point into the same direction)")); 130 return; 131 } 132 133 Way newWay = new Way(selectedWays.get(0)); 134 newWay.nodes.clear(); 135 newWay.nodes.addAll(nodeList); 76 136 77 137 // display conflict dialog … … 97 157 } 98 158 99 cmds.add(new DeleteCommand(selectedWays)); 100 cmds.add(new ChangeCommand(oldWay, newWay)); 159 LinkedList<Command> cmds = new LinkedList<Command>(); 160 cmds.add(new DeleteCommand(selectedWays.subList(1, selectedWays.size()))); 161 cmds.add(new ChangeCommand(selectedWays.peek(), newWay)); 101 162 Main.main.undoRedo.add(new SequenceCommand(tr("Combine {0} ways", selectedWays.size()), cmds)); 102 Main.ds.setSelected( oldWay);163 Main.ds.setSelected(selectedWays.peek()); 103 164 } 104 165 -
branch/0.5/src/org/openstreetmap/josm/actions/DownloadIncompleteAction.java
r298 r329 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others2 package org.openstreetmap.josm.actions;3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 import static org.openstreetmap.josm.tools.I18n.trn;6 7 import java.awt.event.ActionEvent;8 import java.awt.event.InputEvent;9 import java.awt.event.KeyEvent;10 import java.io.IOException;11 import java.util.Collection;12 import java.util.HashSet;13 14 import javax.swing.JOptionPane;15 16 import org.openstreetmap.josm.Main;17 import org.openstreetmap.josm.data.osm.OsmPrimitive;18 import org.openstreetmap.josm.data.osm.Way;19 import org.openstreetmap.josm.data.osm.visitor.MergeVisitor;20 import org.openstreetmap.josm.gui.PleaseWaitRunnable;21 import org.openstreetmap.josm.io.IncompleteDownloader;22 import org.xml.sax.SAXException;23 24 /**25 * Action that opens a connection to the osm server and download map data.26 *27 * An dialog is displayed asking the user to specify a rectangle to grab.28 * The url and account settings from the preferences are used.29 *30 * @author imi31 */32 public class DownloadIncompleteAction extends JosmAction {33 34 /**35 * Open the download dialog and download the data.36 * Run in the worker thread.37 */38 private final class DownloadTask extends PleaseWaitRunnable {39 private IncompleteDownloader reader;40 41 private DownloadTask(Collection<Way> toDownload) {42 super(trn("Downloading {0} way", "Downloading {0} ways", toDownload.size(), toDownload.size()));43 reader = new IncompleteDownloader(toDownload);44 }45 46 @Override public void realRun() throws IOException, SAXException {47 reader.parse();48 }49 50 @Override protected void finish() {51 MergeVisitor merger = new MergeVisitor(Main.ds, reader.data);52 for (OsmPrimitive osm : reader.data.allPrimitives())53 osm.visit(merger);54 Main.parent.repaint();55 }56 57 @Override protected void cancel() {58 reader.cancel();59 }60 }61 62 public DownloadIncompleteAction() {63 super(tr("Download incomplete objects"), "downloadincomplete", tr("Download all (selected) incomplete ways from the OSM server."), KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK | InputEvent.ALT_DOWN_MASK, true);64 }65 66 public void actionPerformed(ActionEvent e) {67 Collection<Way> ways = new HashSet<Way>();68 for (Way w : Main.ds.ways)69 if (w.isIncomplete() && w.selected)70 ways.add(w);71 if (ways.isEmpty()) {72 JOptionPane.showMessageDialog(Main.parent, tr("Please select an incomplete way."));73 return;74 }75 if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog(Main.parent, tr("Download {0} incomplete ways?", ways.size()), tr("Download?"), JOptionPane.YES_NO_OPTION))76 return;77 PleaseWaitRunnable task = new DownloadTask(ways);78 Main.worker.execute(task);79 }80 } -
branch/0.5/src/org/openstreetmap/josm/actions/ReverseSegmentAction.java
r301 r329 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others2 /**3 *4 */5 package org.openstreetmap.josm.actions;6 7 import static org.openstreetmap.josm.tools.I18n.tr;8 9 import java.awt.event.ActionEvent;10 import java.awt.event.KeyEvent;11 import java.util.Collection;12 import java.util.LinkedList;13 14 import javax.swing.JOptionPane;15 16 import org.openstreetmap.josm.Main;17 import org.openstreetmap.josm.command.ChangeCommand;18 import org.openstreetmap.josm.command.Command;19 import org.openstreetmap.josm.command.SequenceCommand;20 import org.openstreetmap.josm.data.osm.Node;21 import org.openstreetmap.josm.data.osm.OsmPrimitive;22 import org.openstreetmap.josm.data.osm.Segment;23 import org.openstreetmap.josm.data.osm.Way;24 import org.openstreetmap.josm.data.osm.visitor.Visitor;25 26 public final class ReverseSegmentAction extends JosmAction {27 28 public ReverseSegmentAction() {29 super(tr("Reverse segments"), "segmentflip", tr("Reverse the direction of all selected Segments."), KeyEvent.VK_R, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true);30 }31 32 public void actionPerformed(ActionEvent e) {33 final Collection<Segment> sel = new LinkedList<Segment>();34 new Visitor(){35 public void visit(Node n) {}36 public void visit(Segment s) {sel.add(s);}37 public void visit(Way w) {sel.addAll(w.segments);}38 public void visitAll() {39 for (OsmPrimitive osm : Main.ds.getSelected())40 osm.visit(this);41 }42 }.visitAll();43 44 if (sel.isEmpty()) {45 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least one segment."));46 return;47 }48 Collection<Command> c = new LinkedList<Command>();49 for (Segment s : sel) {50 Segment snew = new Segment(s);51 Node n = snew.from;52 snew.from = snew.to;53 snew.to = n;54 c.add(new ChangeCommand(s, snew));55 }56 Main.main.undoRedo.add(new SequenceCommand(tr("Reverse Segments"), c));57 Main.map.repaint();58 }59 } -
branch/0.5/src/org/openstreetmap/josm/actions/SplitWayAction.java
r301 r329 16 16 import java.util.LinkedList; 17 17 import java.util.List; 18 import java.util.Set; 18 19 import java.util.Map.Entry; 19 20 … … 27 28 import org.openstreetmap.josm.data.SelectionChangedListener; 28 29 import org.openstreetmap.josm.data.osm.DataSet; 30 import org.openstreetmap.josm.data.osm.Relation; 29 31 import org.openstreetmap.josm.data.osm.Node; 30 32 import org.openstreetmap.josm.data.osm.OsmPrimitive; 31 import org.openstreetmap.josm.data.osm.Segment;32 33 import org.openstreetmap.josm.data.osm.Way; 33 34 import org.openstreetmap.josm.data.osm.visitor.NameVisitor; … … 35 36 36 37 /** 37 * Splits a way into multiple ways (all identical except the segments 38 * belonging to the way). 38 * Splits a way into multiple ways (all identical except for their node list). 39 39 * 40 * Various split modes are used depending on what is selected. 41 * 42 * 1. One or more NODES (and, optionally, also one way) selected: 43 * 44 * (All nodes must be part of the same way. If a way is also selected, that way 45 * must contain all selected nodes.) 46 * 47 * Way is split AT the node(s) into contiguous ways. If the original contained 48 * one or more parts that were not reachable from any of the nodes, they form an 49 * extra new way. Examples (numbers are unselected nodes, letters are selected 50 * nodes) 51 * 52 * 1---A---2 becomes 1---A and A---2 53 * 54 * 1---A---2---B---3 becomes 1---A and A---2---B and B---3 55 * 56 * 2 57 * | 58 * 1---A---3 becomes 1---A and 2---A and A---3 59 * 60 * 1---A---2 3---4 becomes 1---A and A---2 and 3---4 61 * 62 * If the selected node(s) do not clearly define the way that is to be split, 63 * then the way must be selected for disambiguation (e.g. you have two ways, 64 * 1---2---3 and 4---2---5, and select node 2, then you must also select the 65 * way you want to split). 66 * 67 * This function will result in at least two ways, unless the selected node is 68 * at the end of the way AND the way is contiguous, which will lead to an error 69 * message. 70 * 71 * After executing the operation, the selection will be cleared. 72 * 73 * 2. One or more SEGMENTS (and, optionally, also one way) selected: 74 * 75 * (All segments must be part of the same way) 76 * 77 * The way is split in a fashion that makes a new way from the selected segments, 78 * i.e. the selected segments are removed from the way to form a new one. 79 * 80 * This function will result in exactly two ways. 81 * 82 * If splitting the segments out of the way makes a non-contiguous part from 83 * something that was contiguous before, the action is aborted and an error 84 * message is shown. 85 * 86 * 3. Exactly one WAY selected 87 * 88 * If the way is contiguous, you will get an error message. If the way is not 89 * contiguous it is split it into 2...n contiguous ways. 40 * Ways are just split at the selected nodes. The nodes remain in their 41 * original order. Selected nodes at the end of a way are ignored. 90 42 */ 91 43 … … 94 46 private Way selectedWay; 95 47 private List<Node> selectedNodes; 96 private List<Segment> selectedSegments;97 48 98 49 /** … … 101 52 public SplitWayAction() { 102 53 super(tr("Split Way"), "splitway", tr("Split a way at the selected node."), KeyEvent.VK_P, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true); 103 DataSet. listeners.add(this);54 DataSet.selListeners.add(this); 104 55 } 105 56 … … 121 72 selectedWay = null; 122 73 selectedNodes = null; 123 selectedSegments = null;124 74 125 75 Visitor splitVisitor = new Visitor(){ … … 129 79 selectedNodes.add(n); 130 80 } 131 public void visit(Segment s) {132 if (selectedSegments == null)133 selectedSegments = new LinkedList<Segment>();134 selectedSegments.add(s);135 }136 81 public void visit(Way w) { 137 82 selectedWay = w; 138 83 } 84 public void visit(Relation e) { 85 // enties are not considered 86 } 139 87 }; 140 88 … … 148 96 for (Node n : selectedNodes) { 149 97 for (Way w : Main.ds.ways) { 150 for ( Segment s : w.segments) {151 if (n.equals( s.from) || n.equals(s.to)) {98 for (Node wn : w.nodes) { 99 if (n.equals(wn)) { 152 100 Integer old = wayOccurenceCounter.get(w); 153 101 wayOccurenceCounter.put(w, (old == null) ? 1 : old+1); … … 183 131 184 132 HashSet<Node> nds = new HashSet<Node>(selectedNodes); 185 for (Segment s : selectedWay.segments) { 186 nds.remove(s.from); 187 nds.remove(s.to); 133 for (Node n : selectedWay.nodes) { 134 nds.remove(n); 188 135 } 189 136 if (!nds.isEmpty()) { … … 193 140 return; 194 141 } 195 196 // If only segments are selected, guess which way to use.197 } else if (selectedWay == null && selectedSegments != null) {198 199 HashMap<Way, Integer> wayOccurenceCounter = new HashMap<Way, Integer>();200 for (Segment s : selectedSegments) {201 for (Way w : Main.ds.ways) {202 if (w.segments.contains(s)) {203 Integer old = wayOccurenceCounter.get(w);204 wayOccurenceCounter.put(w, (old == null) ? 1 : old+1);205 break;206 }207 }208 }209 if (wayOccurenceCounter.isEmpty()) {210 JOptionPane.showMessageDialog(Main.parent,211 trn("The selected segment is not part of any way.",212 "The selected segments are not part of any way.", selectedSegments.size()));213 return;214 }215 216 for (Entry<Way, Integer> entry : wayOccurenceCounter.entrySet()) {217 if (entry.getValue().equals(selectedSegments.size())) {218 if (selectedWay != null) {219 JOptionPane.showMessageDialog(Main.parent,220 trn("There is more than one way using the segment you selected. Please select the way also.",221 "There is more than one way using the segments you selected. Please select the way also.", selectedSegments.size()));222 return;223 }224 selectedWay = entry.getKey();225 }226 }227 228 if (selectedWay == null) {229 JOptionPane.showMessageDialog(Main.parent, tr("The selected segments do not share the same way."));230 return;231 }232 233 // If a way and segments are selected, verify that the segments are part of the way.234 } else if (selectedWay != null && selectedSegments != null) {235 236 if (!selectedWay.segments.containsAll(selectedSegments)) {237 JOptionPane.showMessageDialog(Main.parent,238 trn("The selected way does not contain the selected segment.",239 "The selected way does not contain all the selected segments.", selectedSegments.size()));240 return;241 }242 }243 244 // finally check if the selected way is complete.245 if (selectedWay.isIncomplete()) {246 JOptionPane.showMessageDialog(Main.parent, tr("Warning: This way is incomplete. Try to download it before splitting."));247 return;248 142 } 249 143 … … 261 155 private boolean checkSelection(Collection<? extends OsmPrimitive> selection) { 262 156 boolean way = false; 263 boolean segment = false;264 157 boolean node = false; 265 158 for (OsmPrimitive p : selection) { 266 if (p instanceof Way && !way) 159 if (p instanceof Way && !way) { 267 160 way = true; 268 else if (p instanceof Node && !segment)161 } else if (p instanceof Node) { 269 162 node = true; 270 else if (p instanceof Segment && !node) 271 segment = true; 272 else 163 } else { 273 164 return false; 274 165 } 275 return way || segment || node; 166 } 167 return node; 276 168 } 277 169 … … 279 171 * Split a way into two or more parts, starting at a selected node. 280 172 * 173 * FIXME: what do the following "arguments" refer to? 281 174 * @param way the way to split 282 175 * @param nodes the node(s) to split the way at; must be part of the way. 283 176 */ 284 177 private void splitWay() { 285 286 // The basic idea is to first divide all segments forming this way into 287 // groups, and later form new ways according to the groups. Initally, 288 // all segments are copied into allSegments, and then gradually removed 289 // from there as new groups are built. 290 291 LinkedList<Segment> allSegments = new LinkedList<Segment>(); 292 allSegments.addAll(selectedWay.segments); 293 List<List<Segment>> segmentSets = new ArrayList<List<Segment>>(); 294 295 if (selectedNodes != null) { 296 297 // This is the "split at node" mode. 298 299 boolean split = true; 300 Segment splitSeg = null; 301 while (split) { 302 split = false; 303 304 // Look for a "split segment". A split segment is any segment 305 // that touches one of the split nodes and has not yet been 306 // assigned to one of the segment groups. 307 for (Segment s : allSegments) { 308 for (Node node : selectedNodes) { 309 if (s.from.equals(node) || s.to.equals(node)) { 310 split = true; 311 splitSeg = s; 312 break; 313 } 314 } 315 if (split) 316 break; 178 // We take our way's list of nodes and copy them to a way chunk (a 179 // list of nodes). Whenever we stumble upon a selected node, we start 180 // a new way chunk. 181 182 Set<Node> nodeSet = new HashSet<Node>(selectedNodes); 183 List<List<Node>> wayChunks = new LinkedList<List<Node>>(); 184 List<Node> currentWayChunk = new ArrayList<Node>(); 185 wayChunks.add(currentWayChunk); 186 187 Iterator<Node> it = selectedWay.nodes.iterator(); 188 while (it.hasNext()) { 189 Node currentNode = it.next(); 190 boolean atEndOfWay = currentWayChunk.isEmpty() || !it.hasNext(); 191 currentWayChunk.add(currentNode); 192 if (nodeSet.contains(currentNode) && !atEndOfWay) { 193 currentWayChunk = new ArrayList<Node>(); 194 currentWayChunk.add(currentNode); 195 wayChunks.add(currentWayChunk); 317 196 } 318 319 // If a split segment was found, move this segment and all segments 320 // connected to it into a new segment group, stopping only if we 321 // reach another split node. Segment moving is done recursively by 322 // the moveSegments method. 323 if (split) { 324 LinkedList<Segment> subSegments = new LinkedList<Segment>(); 325 moveSegments(allSegments, subSegments, splitSeg, selectedNodes); 326 segmentSets.add(subSegments); 327 } 328 329 // The loop continues until no more split segments were found. 330 // Nb. not all segments touching a split node are split segments; 331 // e.g. 332 // 333 // 2 4 334 // | | 335 // 1---A---3---C---5 336 // 337 // This way will be split into 5 ways (1---A,2---A,A---3---C,4---C, 338 // C---5). Depending on which is processed first, either A---3 becomes 339 // a split segment and 3---C is moved as a connecting segment, or vice 340 // versa. The result is, of course, the same but this explains why we 341 // cannot simply start a new way for each segment connecting to a split 342 // node. 343 } 344 345 } else if (selectedSegments != null) { 346 347 // This is the "split segments" mode. It is quite easy as the segments to 348 // remove are already explicitly selected, but some restrictions have to 349 // be observed to make sure that no non-contiguous parts are created. 350 351 // first create a "scratch" copy of the full segment list and move all 352 // segments connected to the first selected segment into a temporary list. 353 LinkedList<Segment> copyOfAllSegments = new LinkedList<Segment>(allSegments); 354 LinkedList<Segment> partThatContainsSegments = new LinkedList<Segment>(); 355 moveSegments(copyOfAllSegments, partThatContainsSegments, selectedSegments.get(0), null); 356 357 // this list must now contain ALL selected segments; otherwise, segments 358 // from unconnected parts of the way have been selected and this is not allowed 359 // as it would create a new non-contiguous way. 360 if (!partThatContainsSegments.containsAll(selectedSegments)) { 361 JOptionPane.showMessageDialog(Main.parent, tr("The selected segments are not in the same contiguous part of the way.")); 362 return; 363 } 364 365 // if the contiguous part that contains the segments becomes non-contiguous 366 // after the removal of the segments, that is also an error. 367 partThatContainsSegments.removeAll(selectedSegments); 368 if (!partThatContainsSegments.isEmpty()) { 369 LinkedList<Segment> contiguousSubpart = new LinkedList<Segment>(); 370 moveSegments(partThatContainsSegments, contiguousSubpart, partThatContainsSegments.get(0), null); 371 // if partThatContainsSegments was contiguous before, it will now be empty as all segments 372 // connected to the first segment therein have been moved 373 if (!partThatContainsSegments.isEmpty()) { 374 JOptionPane.showMessageDialog(Main.parent, tr("Removing the selected segments would make a part of the way non-contiguous.")); 375 return; 376 } 377 } 378 379 ArrayList<Segment> subSegments = new ArrayList<Segment>(); 380 subSegments.addAll(selectedSegments); 381 allSegments.removeAll(selectedSegments); 382 segmentSets.add(subSegments); 383 384 } else { 385 386 // This is the "split way into contiguous parts" mode. 387 // We use a similar mechanism to splitting at nodes, but we do not 388 // select split segments. Instead, we randomly grab a segment out 389 // of the way and move all connecting segments to a new group. If 390 // segments remain in the original way, we repeat the procedure. 391 392 while (!allSegments.isEmpty()) { 393 LinkedList<Segment> subSegments = new LinkedList<Segment>(); 394 moveSegments(allSegments, subSegments, allSegments.get(0), null); 395 segmentSets.add(subSegments); 396 } 397 } 398 399 // We now have a number of segment groups. 400 401 // If segments remain in allSegments, this means that they were not reachable 402 // from any of the split nodes, and they will be made into an extra way. 403 if (!allSegments.isEmpty()) { 404 segmentSets.add(allSegments); 405 } 406 407 // If we do not have at least two parts, then the way was circular or the node(s) 408 // were at one end of the way. User error ;-) 409 if (segmentSets.size() < 2) { 410 if (selectedNodes != null) { 411 JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected node. (Hint: To split circular ways, select two nodes.)")); 412 } else { 413 JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split because it is contiguous. (Hint: To split at a node, select that node.)")); 414 } 197 } 198 199 if (wayChunks.size() < 2) { 200 JOptionPane.showMessageDialog(Main.parent, tr("The way cannot be split at the selected nodes. (Hint: Select nodes in the middle of the way.)")); 415 201 return; 416 202 } 417 203 418 // sort the list of segment lists according to their number of elements, so that 419 // the biggest part of the way comes first. That way, we will "change" the largest 420 // part of the way by removing a few segments, and "add" new, smaller ways; looks 421 // nicer. 422 Collections.sort(segmentSets, new Comparator<Collection<Segment>>() { 423 public int compare(Collection<Segment> a, Collection<Segment> b) { 424 if (a.size() < b.size()) 425 return 1; 426 if (b.size() < a.size()) 427 return -1; 428 return 0; 429 } 430 }); 431 432 // build a list of commands, and also a list of ways 433 Collection<Command> commandList = new ArrayList<Command>(segmentSets.size()); 434 Collection<Way> newSelection = new ArrayList<Way>(segmentSets.size()); 435 Iterator<List<Segment>> segsIt = segmentSets.iterator(); 204 // build a list of commands, and also a new selection list 205 Collection<Command> commandList = new ArrayList<Command>(wayChunks.size()); 206 Collection<Way> newSelection = new ArrayList<Way>(wayChunks.size()); 436 207 437 // the first is always a change to the existing way; 208 Iterator<List<Node>> chunkIt = wayChunks.iterator(); 209 210 // First, change the original way 438 211 Way changedWay = new Way(selectedWay); 439 changedWay. segments.clear();440 changedWay. segments.addAll(segsIt.next());212 changedWay.nodes.clear(); 213 changedWay.nodes.addAll(chunkIt.next()); 441 214 commandList.add(new ChangeCommand(selectedWay, changedWay)); 442 215 newSelection.add(selectedWay); 443 216 444 // and commands 1...n are additions ofnew ways.445 while ( segsIt.hasNext()) {217 // Second, create new ways 218 while (chunkIt.hasNext()) { 446 219 Way wayToAdd = new Way(); 447 220 if (selectedWay.keys != null) 448 221 wayToAdd.keys = new HashMap<String, String>(selectedWay.keys); 449 wayToAdd.segments.clear(); 450 wayToAdd.segments.addAll(segsIt.next()); 222 wayToAdd.nodes.addAll(chunkIt.next()); 451 223 commandList.add(new AddCommand(wayToAdd)); 452 224 newSelection.add(wayToAdd); … … 455 227 NameVisitor v = new NameVisitor(); 456 228 v.visit(selectedWay); 457 Main.main.undoRedo.add(new SequenceCommand(tr("Split way {0} into {1} parts",v.name, segmentSets.size()), commandList)); 229 Main.main.undoRedo.add( 230 new SequenceCommand(tr("Split way {0} into {1} parts", 231 v.name, wayChunks.size()), 232 commandList)); 458 233 Main.ds.setSelected(newSelection); 459 234 } … … 465 240 setEnabled(checkSelection(newSelection)); 466 241 } 467 468 /**469 * Move contiguous segments from one collection to another. The given segment is moved first, and470 * then the procedure is recursively called for all segments that connect to the first segment at471 * either end.472 *473 * @param source the source collection474 * @param destination the destination collection475 * @param start the first segment to be moved476 * @param stopNodes collection of nodes which should be considered end points for moving (may be null).477 */478 private void moveSegments(Collection<Segment> source, LinkedList<Segment> destination, Segment start, Collection<Node> stopNodes) {479 source.remove(start);480 if (destination.isEmpty() || destination.iterator().next().from.equals(start.to))481 destination.addFirst(start);482 else483 destination.addLast(start);484 Segment moveSeg = start;485 while(moveSeg != null) {486 moveSeg = null;487 488 for (Node node : new Node[] { start.from, start.to }) {489 if (stopNodes != null && stopNodes.contains(node))490 continue;491 for (Segment sourceSeg : source) {492 if (sourceSeg.from.equals(node) || sourceSeg.to.equals(node)) {493 moveSeg = sourceSeg;494 break;495 }496 }497 if (moveSeg != null)498 break;499 }500 if (moveSeg != null) {501 moveSegments(source, destination, moveSeg, stopNodes);502 }503 }504 }505 242 } -
branch/0.5/src/org/openstreetmap/josm/actions/mapmode/AddNodeAction.java
r314 r329 24 24 import org.openstreetmap.josm.data.osm.Node; 25 25 import org.openstreetmap.josm.data.osm.OsmPrimitive; 26 import org.openstreetmap.josm.data.osm.Segment;27 26 import org.openstreetmap.josm.data.osm.Way; 27 import org.openstreetmap.josm.data.osm.WaySegment; 28 28 import org.openstreetmap.josm.gui.MapFrame; 29 29 import org.openstreetmap.josm.tools.ImageProvider; … … 33 33 * and there is it. Nothing more, nothing less. 34 34 * 35 * FIXME: "nothing more, nothing less" is a bit out-of-date 36 * 35 37 * Newly created nodes are selected. Shift modifier does not cancel the old 36 38 * selection as usual. … … 41 43 public class AddNodeAction extends MapMode { 42 44 43 enum Mode {node, node segment, autonode}45 enum Mode {node, nodeway, autonode} 44 46 private final Mode mode; 45 47 … … 49 51 putValue("help", "Action/AddNode"); 50 52 actions.add(new AddNodeAction(mf,tr("Add node"), Mode.node, tr("Add a new node to the map"))); 51 actions.add(new AddNodeAction(mf, tr("Add node into segment"), Mode.nodesegment,tr( "Add a node into an existingsegment")));52 actions.add(new AddNodeAction(mf, tr("Add node and connect"), Mode.autonode,tr( "Add a node and connect it to the selected node (with CTRL: add node into segment; with SHIFT: re-use existing node)")));53 actions.add(new AddNodeAction(mf, tr("Add node into way"), Mode.nodeway,tr( "Add a node into an existing way"))); 54 actions.add(new AddNodeAction(mf, tr("Add node and connect"), Mode.autonode,tr( "Add a node and connect it to the selected node (with CTRL: add node into way; with SHIFT: re-use existing node)"))); 53 55 setCurrent(0); 54 56 } … … 83 85 * position. 84 86 * 85 * If in nodesegment mode, add the node to the line segment by splitting the 86 * segment. The new created segment will be inserted in every way the segment 87 * was part of. 87 * If in nodeway mode, insert the node into the way. 88 88 */ 89 89 @Override public void mouseClicked(MouseEvent e) { … … 98 98 99 99 Command c = new AddCommand(n); 100 if (mode == Mode.node segment) {101 Segments = Main.map.mapView.getNearestSegment(e.getPoint());102 if (s == null) 100 if (mode == Mode.nodeway) { 101 WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint()); 102 if (ws == null) 103 103 return; 104 104 105 105 // see if another segment is also near 106 Segment other = Main.map.mapView.getNearestSegment(e.getPoint(), Collections.singleton(s)); 106 WaySegment other = Main.map.mapView.getNearestWaySegment(e.getPoint(), 107 Collections.singleton(ws)); 108 109 Node n1 = ws.way.nodes.get(ws.lowerIndex), 110 n2 = ws.way.nodes.get(ws.lowerIndex + 1); 107 111 108 112 if (other == null && (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) == 0) { 109 113 // moving the new point to the perpendicular point 110 // FIXME: when two segments are split, should move the new point to the 114 // FIXME: when two way segments are split, should move the new point to the 111 115 // intersection point! 112 EastNorth A = s.from.eastNorth;113 EastNorth B = s.to.eastNorth;116 EastNorth A = n1.eastNorth; 117 EastNorth B = n2.eastNorth; 114 118 double ab = A.distance(B); 115 119 double nb = n.eastNorth.distance(B); … … 124 128 125 129 // split the first segment 126 splitSegmentAtNode(s, n, cmds); 130 splitWaySegmentAtNode(ws, n, cmds); 127 131 128 132 // if a second segment was found, split that as well 129 if (other != null) splitSegmentAtNode(other, n, cmds); 133 if (other != null) splitWaySegmentAtNode(other, n, cmds); 130 134 131 135 c = new SequenceCommand(tr((other == null) ? 132 "Add node into segment" : "Add common node into twosegments"), cmds);136 "Add node into way" : "Add common node into two ways"), cmds); 133 137 } 134 138 … … 136 140 if (mode == Mode.autonode) { 137 141 138 Segment insertInto = null; 142 WaySegment insertInto = null; 139 143 Node reuseNode = null; 140 144 141 // If CTRL is held, insert the node into a potentially existing segment 145 // If CTRL is held, insert the node into a potentially existing way segment 142 146 if ((e.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0) { 143 insertInto = Main.map.mapView.getNearestSegment(e.getPoint()); 147 insertInto = Main.map.mapView.getNearestWaySegment(e.getPoint()); 148 if (insertInto == null) System.err.println("Couldn't find nearby way segment"); 144 149 if (insertInto == null) 145 150 return; … … 150 155 // continuation of the "add node and connect" stuff) 151 156 else if ((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0) { 152 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint() , false);157 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint()); 153 158 if (clicked == null || !(clicked instanceof Node)) 154 159 return; … … 159 164 if (selection.size() == 1 && selection.iterator().next() instanceof Node) { 160 165 Node n1 = (Node)selection.iterator().next(); 166 161 167 Collection<Command> cmds = new LinkedList<Command>(); 162 168 163 169 if (reuseNode != null) { 164 170 // in re-use node mode, n1 must not be identical to clicked node 171 if (n1 == reuseNode) System.err.println("n1 == reuseNode"); 165 172 if (n1 == reuseNode) return; 166 173 // replace newly created node with existing node … … 171 178 } 172 179 173 Segment s = new Segment(n1, n); 174 180 /* Keep track of the way we change, it might be the same into 181 * which we insert the node. 182 */ 183 Way newInsertInto = null; 175 184 if (insertInto != null) 176 splitSegmentAtNode(insertInto, n, cmds); 177 178 cmds.add(new AddCommand(s)); 185 newInsertInto = splitWaySegmentAtNode(insertInto, n, cmds); 179 186 180 187 Way way = getWayForNode(n1); 181 if (way != null) { 182 Way newWay = new Way(way); 183 if (way.segments.get(0).from == n1) { 184 Node tmp = s.from; 185 s.from = s.to; 186 s.to = tmp; 187 newWay.segments.add(0, s); 188 } else 189 newWay.segments.add(s); 190 cmds.add(new ChangeCommand(way, newWay)); 191 } 192 193 c = new SequenceCommand(tr((insertInto == null) ? "Add node and connect" : "Add node into segment and connect"), cmds); 188 if (way == null) { 189 way = new Way(); 190 way.nodes.add(n1); 191 cmds.add(new AddCommand(way)); 192 } else { 193 if (insertInto != null && way == insertInto.way) { 194 way = newInsertInto; 195 } else { 196 Way wnew = new Way(way); 197 cmds.add(new ChangeCommand(way, wnew)); 198 way = wnew; 199 } 200 } 201 202 if (way.nodes.get(way.nodes.size() - 1) == n1) { 203 way.nodes.add(n); 204 } else { 205 way.nodes.add(0, n); 206 } 207 208 c = new SequenceCommand(tr((insertInto == null) ? "Add node and connect" : "Add node into way and connect"), cmds); 194 209 } 195 210 } … … 201 216 202 217 /** 203 * @return If the node is partof exactly one way, return this.218 * @return If the node is the end of exactly one way, return this. 204 219 * <code>null</code> otherwise. 205 220 */ … … 207 222 Way way = null; 208 223 for (Way w : Main.ds.ways) { 209 for (Segment s : w.segments) { 210 if (s.from == n || s.to == n) { 224 int i = w.nodes.indexOf(n); 225 if (i == -1) continue; 226 if (i == 0 || i == w.nodes.size() - 1) { 211 227 if (way != null) 212 228 return null; 213 if (s.from == s.to)214 return null;215 229 way = w; 216 230 } 217 231 } 218 }219 232 return way; 220 233 } 221 234 222 private void splitSegmentAtNode(Segment s, Node n, Collection<Command> cmds) { 223 Segment s1 = new Segment(s); 224 s1.to = n; 225 Segment s2 = new Segment(s.from, s.to); 226 s2.from = n; 227 if (s.keys != null) 228 s2.keys = new HashMap<String, String>(s.keys); 229 230 cmds.add(new ChangeCommand(s, s1)); 231 cmds.add(new AddCommand(s2)); 232 233 // Add the segment to every way 234 for (Way wold : Main.ds.ways) { 235 if (wold.segments.contains(s)) { 236 Way wnew = new Way(wold); 237 Collection<Segment> segs = new ArrayList<Segment>(wnew.segments); 238 wnew.segments.clear(); 239 for (Segment waySeg : segs) { 240 wnew.segments.add(waySeg); 241 if (waySeg == s) 242 wnew.segments.add(s2); 243 } 244 cmds.add(new ChangeCommand(wold, wnew)); 245 } 246 } 235 private Way splitWaySegmentAtNode(WaySegment ws, Node n, Collection<Command> cmds) { 236 Way wnew = new Way(ws.way); 237 wnew.nodes.add(ws.lowerIndex + 1, n); 238 cmds.add(new ChangeCommand(ws.way, wnew)); 239 return wnew; 247 240 } 248 241 } -
branch/0.5/src/org/openstreetmap/josm/actions/mapmode/AddSegmentAction.java
r301 r329 15 15 import org.openstreetmap.josm.Main; 16 16 import org.openstreetmap.josm.command.AddCommand; 17 import org.openstreetmap.josm.command.ChangeCommand; 17 18 import org.openstreetmap.josm.data.osm.Node; 18 19 import org.openstreetmap.josm.data.osm.OsmPrimitive; 19 import org.openstreetmap.josm.data.osm. Segment;20 import org.openstreetmap.josm.data.osm.Way; 20 21 import org.openstreetmap.josm.gui.MapFrame; 21 22 import org.openstreetmap.josm.tools.ImageProvider; … … 51 52 */ 52 53 public AddSegmentAction(MapFrame mapFrame) { 53 super(tr(" Add segment"),54 super(tr("Connect two nodes"), 54 55 "addsegment", 55 tr(" Add a segment betweentwo nodes."),56 tr("Connect two nodes using ways."), 56 57 KeyEvent.VK_G, 57 58 mapFrame, … … 72 73 } 73 74 74 75 /** 76 * Called when user hits space bar while dragging. 77 */ 75 78 @Override public void actionPerformed(ActionEvent e) { 76 79 super.actionPerformed(e); … … 85 88 return; 86 89 87 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint(), true); 88 if (clicked == null || !(clicked instanceof Node)) 89 return; 90 Node clicked = Main.map.mapView.getNearestNode(e.getPoint()); 91 if (clicked == null) return; 90 92 91 93 drawHint(false); 92 first = second = (Node)clicked;94 first = second = clicked; 93 95 } 94 96 … … 101 103 return; 102 104 103 OsmPrimitive clicked = Main.map.mapView.getNearest(e.getPoint(), (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0); 104 if (clicked == null || clicked == second || !(clicked instanceof Node)) 105 return; 105 Node hovered = Main.map.mapView.getNearestNode(e.getPoint()); 106 if (hovered == second) return; 106 107 107 108 drawHint(false); 108 109 second = (Node)clicked; 109 second = hovered; 110 110 drawHint(true); 111 111 } … … 116 116 @Override public void mouseReleased(MouseEvent e) { 117 117 if (e.getButton() == MouseEvent.BUTTON1) { 118 drawHint(false); 118 119 makeSegment(); 119 first = null; // release segment drawing120 first = null; 120 121 } 122 } 123 124 /** 125 * @return If the node is the end of exactly one way, return this. 126 * <code>null</code> otherwise. 127 */ 128 private Way getWayForNode(Node n) { 129 Way way = null; 130 for (Way w : Main.ds.ways) { 131 int i = w.nodes.indexOf(n); 132 if (i == -1) continue; 133 if (i == 0 || i == w.nodes.size() - 1) { 134 if (way != null) 135 return null; 136 way = w; 137 } 138 } 139 return way; 121 140 } 122 141 … … 126 145 */ 127 146 private void makeSegment() { 128 if (first == null || second == null) { 129 first = null; 130 second = null; 131 return; 132 } 133 134 drawHint(false); 147 Node n1 = first; 148 Node n2 = second; 135 149 136 Node start = first;137 Node end = second;150 // this is to allow continued segment drawing by hitting the space bar 151 // at every intermediate node 138 152 first = second; 139 153 second = null; 154 155 if (n1 == null || n2 == null || n1 == n2) return; 156 157 Way w = getWayForNode(n1); 158 Way wnew; 159 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 140 160 141 if (start != end) { 142 // try to find a segment 143 for (Segment ls : Main.ds.segments) 144 if (!ls.deleted && ((start == ls.from && end == ls.to) || (end == ls.from && start == ls.to))) 145 return; // already a segment here - be happy, do nothing. 146 147 Segment ls = new Segment(start, end); 148 Main.main.undoRedo.add(new AddCommand(ls)); 149 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 150 sel.add(ls); 161 if (w == null) { 162 // create a new way and add it to the current selection. 163 wnew = new Way(); 164 wnew.nodes.add(n1); 165 wnew.nodes.add(n2); 166 Main.main.undoRedo.add(new AddCommand(wnew)); 167 sel.add(wnew); 168 Main.ds.setSelected(sel); 169 } else { 170 // extend an existing way; only add to current selection if 171 // it is not already in there. 172 wnew = new Way(w); 173 if (wnew.nodes.get(wnew.nodes.size() - 1) == n1) { 174 wnew.nodes.add(n2); 175 } else { 176 wnew.nodes.add(0, n2); 177 } 178 Main.main.undoRedo.add(new ChangeCommand(w, wnew)); 179 // do not use wnew below; ChangeCommand only uses wnew as a 180 // message about changes to be done to w but will not replace w! 181 if (!sel.contains(w)) { 182 sel.add(w); 183 } 184 // do not move this into the if block above since it also 185 // fires the selection change event which is desired. 151 186 Main.ds.setSelected(sel); 152 187 } -
branch/0.5/src/org/openstreetmap/josm/actions/mapmode/AddWayAction.java
r301 r329 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others2 package org.openstreetmap.josm.actions.mapmode;3 4 import static org.openstreetmap.josm.tools.I18n.tr;5 import static org.openstreetmap.josm.tools.I18n.trn;6 7 import java.awt.event.KeyEvent;8 import java.awt.event.MouseEvent;9 import java.util.Arrays;10 import java.util.Collection;11 import java.util.HashSet;12 import java.util.LinkedList;13 14 import javax.swing.JOptionPane;15 16 import org.openstreetmap.josm.Main;17 import org.openstreetmap.josm.actions.ReorderAction;18 import org.openstreetmap.josm.command.AddCommand;19 import org.openstreetmap.josm.command.ChangeCommand;20 import org.openstreetmap.josm.command.DeleteCommand;21 import org.openstreetmap.josm.data.SelectionChangedListener;22 import org.openstreetmap.josm.data.osm.DataSet;23 import org.openstreetmap.josm.data.osm.OsmPrimitive;24 import org.openstreetmap.josm.data.osm.Segment;25 import org.openstreetmap.josm.data.osm.Way;26 import org.openstreetmap.josm.gui.MapFrame;27 import org.openstreetmap.josm.tools.ImageProvider;28 29 /**30 * Add a new way. The action is split into the first phase, where a new way get31 * created or selected and the second, where this way is modified.32 *33 * Way creation mode:34 * If there is a selection when the mode is entered, all segments in this35 * selection form a new way. All non-segment objects are deselected. If there36 * were ways selected, the user is asked whether to select all segments of these37 * ways or not, except there is exactly one way selected, which enter the38 * edit ways mode for this way immediatly.39 *40 * If there is no selection on entering, and the user clicks on an segment,41 * the way editing starts the with a new way and this segment. If the user click42 * on a way (not holding Alt down), then this way is edited in the way edit mode.43 *44 * Way editing mode:45 * The user can click on subsequent segments. If the segment belonged to the way46 * it get removed from the way. Elsewhere it get added to the way. JOSM try to add47 * the segment in the correct position. This is done by searching for connections48 * to the segment at its 'to' node which are also in the way. The segemnt is49 * inserted in the way as predecessor of the found segment (or at last segment, if50 * nothing found).51 *52 * @author imi53 */54 public class AddWayAction extends MapMode implements SelectionChangedListener {55 private Way way;56 57 /**58 * Create a new AddWayAction.59 * @param mapFrame The MapFrame this action belongs to.60 * @param followMode The mode to go into when finished creating a way.61 */62 public AddWayAction(MapFrame mapFrame) {63 super(tr("Add Way"), "addway", tr("Add a new way to the data."), KeyEvent.VK_W, mapFrame, ImageProvider.getCursor("normal", "way"));64 DataSet.listeners.add(this);65 }66 67 @Override public void enterMode() {68 super.enterMode();69 way = makeWay();70 Main.ds.setSelected(way);71 Main.map.mapView.addMouseListener(this);72 }73 74 @Override public void exitMode() {75 super.exitMode();76 way = null;77 Main.map.mapView.removeMouseListener(this);78 }79 80 @Override public void mouseClicked(MouseEvent e) {81 if (e.getButton() != MouseEvent.BUTTON1)82 return;83 84 Segment s = Main.map.mapView.getNearestSegment(e.getPoint());85 if (s == null)86 return;87 88 // special case for initial selecting one way89 if (way == null && (e.getModifiers() & MouseEvent.ALT_DOWN_MASK) == 0) {90 Way w = Main.map.mapView.getNearestWay(e.getPoint());91 if (w != null) {92 way = w;93 Main.ds.setSelected(way);94 for (Segment seg : way.segments) {95 if (seg.incomplete) {96 JOptionPane.showMessageDialog(Main.parent,tr("Warning: This way is incomplete. Try to download it before adding segments."));97 return;98 }99 }100 return;101 }102 }103 104 if (way != null && way.segments.contains(s)) {105 Way copy = new Way(way);106 107 copy.segments.remove(s);108 if (copy.segments.isEmpty()) {109 Main.main.undoRedo.add(new DeleteCommand(Arrays.asList(new OsmPrimitive[]{way})));110 way = null;111 } else112 Main.main.undoRedo.add(new ChangeCommand(way, copy));113 } else {114 if (way == null) {115 way = new Way();116 way.segments.add(s);117 Main.main.undoRedo.add(new AddCommand(way));118 } else {119 Way copy = new Way(way);120 int i;121 for (i = 0; i < way.segments.size(); ++i)122 if (way.segments.get(i).from == s.to)123 break;124 copy.segments.add(i, s);125 Main.main.undoRedo.add(new ChangeCommand(way, copy));126 }127 }128 Main.ds.setSelected(way);129 }130 131 /**132 * Form a way, either out of the (one) selected way or by creating a way over the selected133 * line segments.134 */135 private Way makeWay() {136 Collection<OsmPrimitive> selection = Main.ds.getSelected();137 if (selection.isEmpty())138 return null;139 140 if (selection.size() == 1 && selection.iterator().next() instanceof Way) {141 Way way = (Way)selection.iterator().next();142 for (Segment seg : way.segments) {143 if (seg.incomplete) {144 JOptionPane.showMessageDialog(Main.parent, tr("Warning: This way is incomplete. Try to download it before adding segments."));145 break;146 }147 }148 return way;149 }150 151 HashSet<Segment> segmentSet = new HashSet<Segment>();152 int numberOfSelectedWays = 0;153 for (OsmPrimitive osm : selection) {154 if (osm instanceof Way)155 numberOfSelectedWays++;156 else if (osm instanceof Segment)157 segmentSet.add((Segment)osm);158 }159 160 Way wayToAdd = null;161 boolean reordered = false;162 if (numberOfSelectedWays > 0) {163 int answer = JOptionPane.showConfirmDialog(Main.parent,trn("{0} way has been selected.\nDo you wish to select all segments belonging to the way instead?","{0} ways have been selected.\nDo you wish to select all segments belonging to the ways instead?",numberOfSelectedWays,numberOfSelectedWays),tr("Add segments from ways"), JOptionPane.YES_NO_OPTION);164 if (answer == JOptionPane.YES_OPTION) {165 for (OsmPrimitive osm : selection)166 if (osm instanceof Way)167 segmentSet.addAll(((Way)osm).segments);168 } else if (numberOfSelectedWays == 1) {169 answer = JOptionPane.showConfirmDialog(Main.parent,tr("Do you want to add all other selected segments to the one selected way?"),tr("Add segments to way?"), JOptionPane.YES_NO_OPTION);170 if (answer == JOptionPane.YES_OPTION) {171 for (OsmPrimitive osm : selection) {172 if (osm instanceof Way) {173 wayToAdd = (Way)osm;174 answer = JOptionPane.showConfirmDialog(Main.parent,tr("Reorder all line segments?"), tr("Reorder?"), JOptionPane.YES_NO_CANCEL_OPTION);175 if (answer == JOptionPane.CANCEL_OPTION)176 return wayToAdd;177 if (answer == JOptionPane.YES_OPTION) {178 segmentSet.addAll(wayToAdd.segments);179 reordered = true;180 } else181 segmentSet.removeAll(wayToAdd.segments);182 break;183 }184 }185 }186 }187 }188 189 if (segmentSet.isEmpty())190 return null;191 192 LinkedList<Segment> rawSegments = new LinkedList<Segment>(segmentSet);193 LinkedList<Segment> sortedSegments = ReorderAction.sortSegments(rawSegments, true);194 195 if (wayToAdd != null) {196 Way w = new Way(wayToAdd);197 if (reordered)198 w.segments.clear();199 w.segments.addAll(sortedSegments);200 Main.main.undoRedo.add(new ChangeCommand(wayToAdd, w));201 return wayToAdd;202 }203 204 if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog(Main.parent,trn("Create a new way out of {0} segment?","Create a new way out of {0} segments?",sortedSegments.size(),sortedSegments.size()), tr("Create new way"), JOptionPane.YES_NO_OPTION))205 return null;206 207 Way w = new Way();208 w.segments.addAll(sortedSegments);209 Main.main.undoRedo.add(new AddCommand(w));210 return w;211 }212 213 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {214 if (newSelection.size() == 1) {215 OsmPrimitive osm = newSelection.iterator().next();216 way = osm instanceof Way ? (Way)osm : null;217 } else218 way = null;219 }220 } -
branch/0.5/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
r301 r329 24 24 import org.openstreetmap.josm.data.osm.Node; 25 25 import org.openstreetmap.josm.data.osm.OsmPrimitive; 26 import org.openstreetmap.josm.data.osm.Segment;27 26 import org.openstreetmap.josm.data.osm.Way; 28 27 import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor; … … 38 37 * @see #deleteWithReferences(OsmPrimitive) 39 38 * 40 * Pressing Alt will select the way instead of a segment, as usual.41 *42 39 * If the user did not press Ctrl and the object has any references, the user 43 40 * is informed and nothing is deleted. … … 57 54 super(tr("Delete"), 58 55 "delete", 59 tr("Delete nodes , streets or segments."),56 tr("Delete nodes or ways."), 60 57 KeyEvent.VK_D, 61 58 mapFrame, … … 92 89 return; 93 90 94 OsmPrimitive sel = Main.map.mapView.getNearest(e.getPoint() , (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);91 OsmPrimitive sel = Main.map.mapView.getNearest(e.getPoint()); 95 92 if (sel == null) 96 93 return; … … 105 102 106 103 /** 107 * Delete the primitives and everything they reference s.104 * Delete the primitives and everything they reference. 108 105 * 109 * If a node is deleted, the node and all segments,ways andareas106 * If a node is deleted, the node and all ways and relations 110 107 * the node is part of are deleted as well. 111 108 * 112 * If a segment is deleted, all ways the segment is part of 113 * are deleted as well. No nodes are deleted. 109 * If a way is deleted, all relations the way is member of are also deleted. 114 110 * 115 * If a way is deleted, only the way and no segments or nodes are 116 * deleted. 117 * 118 * If an area is deleted, only the area gets deleted. 111 * If a way is deleted, only the way and no nodes are deleted. 119 112 * 120 113 * @param selection The list of all object to be deleted. … … 134 127 * inform the user and do not delete. 135 128 * 136 * If deleting a node which is part of exactly two segments, and both segments 137 * have no conflicting keys, join them and remove the node. 138 * If the two segments are part of the same way, remove the deleted segment 139 * from the way. 129 * If a node is to be deleted which is in the middle of exactly one way, 130 * the node is removed from the way's node list and after that removed 131 * itself. 140 132 * 141 133 * @param selection The objects to delete. … … 149 141 if (!selection.containsAll(v.data)) { 150 142 if (osm instanceof Node && joinIfPossible) { 151 String reason = deleteNodeAndJoin Segment((Node)osm);143 String reason = deleteNodeAndJoinWay((Node)osm); 152 144 if (reason != null && msgBox) { 153 145 JOptionPane.showMessageDialog(Main.parent,tr("Cannot delete node.")+" "+reason); … … 167 159 } 168 160 169 private String deleteNodeAndJoinSegment(Node n) { 170 ArrayList<Segment> segs = new ArrayList<Segment>(2); 171 for (Segment s : Main.ds.segments) { 172 if (!s.deleted && (s.from == n || s.to == n)) { 173 if (segs.size() > 1) 174 return tr("Used by more than two segments."); 175 segs.add(s); 176 } 177 } 178 if (segs.size() != 2) 179 return tr("Used by only one segment."); 180 Segment seg1 = segs.get(0); 181 Segment seg2 = segs.get(1); 182 if (seg1.from == seg2.to) { 183 Segment s = seg1; 184 seg1 = seg2; 185 seg2 = s; 186 } 187 if (seg1.from == seg2.from || seg1.to == seg2.to) 188 return tr("Wrong direction of segments."); 189 for (Entry<String, String> e : seg1.entrySet()) 190 if (seg2.keySet().contains(e.getKey()) && !seg2.get(e.getKey()).equals(e.getValue())) 191 return tr("Conflicting keys"); 192 ArrayList<Way> ways = new ArrayList<Way>(2); 161 private String deleteNodeAndJoinWay(Node n) { 162 ArrayList<Way> ways = new ArrayList<Way>(1); 193 163 for (Way w : Main.ds.ways) { 194 if (w.deleted) 195 continue; 196 if ((w.segments.contains(seg1) && !w.segments.contains(seg2)) || (w.segments.contains(seg2) && !w.segments.contains(seg1))) 197 return tr("Segments are part of different ways."); 198 if (w.segments.contains(seg1) && w.segments.contains(seg2)) 164 if (!w.deleted && w.nodes.contains(n)) { 199 165 ways.add(w); 200 166 } 201 Segment s = new Segment(seg1);202 s.to = seg2.to;203 if (s.keys == null)204 s.keys = seg2.keys;205 else if (seg2.keys != null)206 s.keys.putAll(seg2.keys);207 Collection<Command> cmds = new LinkedList<Command>();208 for (Way w : ways) {209 Way copy = new Way(w);210 copy.segments.remove(seg2);211 cmds.add(new ChangeCommand(w, copy));212 167 } 213 cmds.add(new ChangeCommand(seg1, s)); 214 cmds.add(new DeleteCommand(Arrays.asList(new OsmPrimitive[]{n, seg2}))); 215 Main.main.undoRedo.add(new SequenceCommand(tr("Delete Node"), cmds)); 168 169 if (ways.size() > 1) 170 return tr("Used by more than one way."); 171 172 if (ways.size() == 1) { 173 // node in way 174 Way w = ways.get(0); 175 176 int i = w.nodes.indexOf(n); 177 if (w.nodes.lastIndexOf(n) != i) 178 return tr("Occurs more than once in the same way."); 179 if (i == 0 || i == w.nodes.size() - 1) 180 return tr("Is at the end of a way"); 181 182 Way wnew = new Way(w); 183 wnew.nodes.remove(i); 184 185 Collection<Command> cmds = new LinkedList<Command>(); 186 cmds.add(new ChangeCommand(w, wnew)); 187 cmds.add(new DeleteCommand(Collections.singleton(n))); 188 Main.main.undoRedo.add(new SequenceCommand(tr("Delete Node"), cmds)); 189 } else { 190 // unwayed node 191 Main.main.undoRedo.add(new DeleteCommand(Collections.singleton(n))); 192 } 216 193 return null; 217 194 } -
branch/0.5/src/org/openstreetmap/josm/actions/mapmode/MapMode.java
r298 r329 15 15 /** 16 16 * A class implementing MapMode is able to be selected as an mode for map editing. 17 * As example scrolling the map is a MapMode, connecting Nodes to new Segments17 * As example scrolling the map is a MapMode, connecting Nodes to new Ways 18 18 * is another. 19 19 * -
branch/0.5/src/org/openstreetmap/josm/actions/mapmode/MoveAction.java
r312 r329 162 162 163 163 Collection<OsmPrimitive> sel = Main.ds.getSelected(); 164 OsmPrimitive osm = Main.map.mapView.getNearest(e.getPoint() , (e.getModifiersEx() & MouseEvent.ALT_DOWN_MASK) != 0);164 OsmPrimitive osm = Main.map.mapView.getNearest(e.getPoint()); 165 165 if (osm != null) { 166 166 if (!sel.contains(osm)) -
branch/0.5/src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java
r298 r329 17 17 import org.openstreetmap.josm.data.osm.Node; 18 18 import org.openstreetmap.josm.data.osm.OsmPrimitive; 19 import org.openstreetmap.josm.data.osm.Segment;20 19 import org.openstreetmap.josm.gui.MapFrame; 21 20 import org.openstreetmap.josm.gui.SelectionManager; … … 55 54 * pixel are considered "only click". If that happens, the nearest Node will 56 55 * be selected if there is any within 10 pixel range. If there is no Node within 57 * 10 pixel, the nearest Segment (or Street, if user hold down the Alt-Key)58 * within 10 pixel range is selected. If there is no Segment within10 pixel59 * and the user clicked in or 10 pixel away from an area,this area is selected.60 * If there is even no area, nothing is selected.Shift and Ctrl key applies to61 * this as usual. For more,@see MapView#getNearest(Point, boolean)56 * 10 pixel, the nearest Way within 10 pixel range is selected. If there is no 57 * Way within 10 pixel and the user clicked in or 10 pixel away from an area, 58 * this area is selected. If there is even no area, nothing is selected. 59 * Shift and Ctrl key applies to this as usual. For more, 60 * @see MapView#getNearest(Point) 62 61 * 63 62 * @author imi … … 65 64 public class SelectionAction extends MapMode implements SelectionEnded { 66 65 67 enum Mode {select, straight}68 private final Mode mode;69 70 66 public static class Group extends GroupAction { 71 67 public Group(MapFrame mf) { 72 68 super(KeyEvent.VK_S,0); 73 69 putValue("help", "Action/Selection"); 74 actions.add(new SelectionAction(mf, tr("Selection"), Mode.select, tr("Select objects by dragging or clicking."))); 75 actions.add(new SelectionAction(mf, tr("Straight line"), Mode.straight, tr("Select objects in a straight line."))); 70 actions.add(new SelectionAction(mf, tr("Selection"), tr("Select objects by dragging or clicking."))); 76 71 setCurrent(0); 77 72 } … … 84 79 private SelectionManager selectionManager; 85 80 86 private Node straightStart = null;87 private Node lastEnd = null;88 private Collection<OsmPrimitive> oldSelection = null;89 90 //TODO: Implement reverse references into data objects and remove this91 private final Map<Node, Collection<Segment>> reverseSegmentMap = new HashMap<Node, Collection<Segment>>();92 93 81 /** 94 82 * Create a new SelectionAction in the given frame. 95 83 * @param mapFrame The frame this action belongs to 96 84 */ 97 public SelectionAction(MapFrame mapFrame, String name, Mode mode, String desc) { 98 super(name, "selection/"+mode, desc, mapFrame, ImageProvider.getCursor("normal", "selection")); 99 this.mode = mode; 100 putValue("help", "Action/Selection/"+Character.toUpperCase(mode.toString().charAt(0))+mode.toString().substring(1)); 85 public SelectionAction(MapFrame mapFrame, String name, String desc) { 86 super(name, "selection/select", desc, mapFrame, ImageProvider.getCursor("normal", "selection")); 87 putValue("help", "Action/Selection"); 101 88 this.selectionManager = new SelectionManager(this, false, mapFrame.mapView); 102 89 } … … 104 91 @Override public void enterMode() { 105 92 super.enterMode(); 106 if (mode == Mode.select)107 93 selectionManager.register(Main.map.mapView); 108 else {109 Main.map.mapView.addMouseMotionListener(this);110 Main.map.mapView.addMouseListener(this);111 for (Segment s : Main.ds.segments) {112 addBackReference(s.from, s);113 addBackReference(s.to, s);114 }115 }116 }117 118 private void addBackReference(Node n, Segment s) {119 Collection<Segment> c = reverseSegmentMap.get(n);120 if (c == null) {121 c = new HashSet<Segment>();122 reverseSegmentMap.put(n, c);123 }124 c.add(s);125 94 } 126 95 127 96 @Override public void exitMode() { 128 97 super.exitMode(); 129 if (mode == Mode.select)130 98 selectionManager.unregister(Main.map.mapView); 131 else {132 Main.map.mapView.removeMouseMotionListener(this);133 Main.map.mapView.removeMouseListener(this);134 reverseSegmentMap.clear();135 }136 99 } 137 100 … … 163 126 Main.map.mapView.repaint(); 164 127 } 165 166 @Override public void mouseDragged(MouseEvent e) {167 Node old = lastEnd;168 lastEnd = Main.map.mapView.getNearestNode(e.getPoint());169 if (straightStart == null)170 straightStart = lastEnd;171 if (straightStart != null && lastEnd != null && straightStart != lastEnd && old != lastEnd) {172 Collection<OsmPrimitive> path = new HashSet<OsmPrimitive>();173 Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>();174 path.add(straightStart);175 calculateShortestPath(path, straightStart, lastEnd);176 if ((e.getModifiers() & MouseEvent.CTRL_MASK) != 0) {177 sel.addAll(oldSelection);178 sel.removeAll(path);179 } else if ((e.getModifiers() & MouseEvent.SHIFT_MASK) != 0) {180 sel = path;181 sel.addAll(oldSelection);182 } else183 sel = path;184 Main.ds.setSelected(sel);185 }186 }187 188 @Override public void mousePressed(MouseEvent e) {189 straightStart = Main.map.mapView.getNearestNode(e.getPoint());190 lastEnd = null;191 oldSelection = Main.ds.getSelected();192 }193 194 @Override public void mouseReleased(MouseEvent e) {195 straightStart = null;196 lastEnd = null;197 oldSelection = null;198 }199 200 /**201 * Get the shortest path by stepping through the node with a common segment with start202 * and nearest to the end (greedy algorithm).203 */204 private void calculateShortestPath(Collection<OsmPrimitive> path, Node start, Node end) {205 for (Node pivot = start; pivot != null;)206 pivot = addNearest(path, pivot, end);207 }208 209 private Node addNearest(Collection<OsmPrimitive> path, Node start, Node end) {210 Collection<Segment> c = reverseSegmentMap.get(start);211 if (c == null)212 return null; // start may be a waypoint without segments213 double min = Double.MAX_VALUE;214 Node next = null;215 Segment seg = null;216 for (Segment s : c) {217 Node other = s.from == start ? s.to : s.from;218 if (other == end) {219 next = other;220 seg = s;221 min = 0;222 break;223 }224 double distance = other.eastNorth.distance(end.eastNorth);225 if (distance < min) {226 min = distance;227 next = other;228 seg = s;229 }230 }231 if (min < start.eastNorth.distance(end.eastNorth) && next != null) {232 path.add(next);233 path.add(seg);234 return next;235 }236 return null;237 }238 128 } -
branch/0.5/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
r319 r329 9 9 import org.openstreetmap.josm.data.osm.Node; 10 10 import org.openstreetmap.josm.data.osm.OsmPrimitive; 11 import org.openstreetmap.josm.data.osm.Segment;12 11 import org.openstreetmap.josm.data.osm.Way; 12 import org.openstreetmap.josm.data.osm.Relation; 13 13 14 14 /** … … 119 119 if (osm instanceof Node) 120 120 return type.equals("node"); 121 if (osm instanceof Segment)122 return type.equals("segment");123 121 if (osm instanceof Way) 124 122 return type.equals("way"); 123 if (osm instanceof Relation) 124 return type.equals("relation"); 125 125 throw new IllegalStateException("unknown class "+osm.getClass()); 126 126 } … … 144 144 private static class Incomplete extends Match { 145 145 @Override public boolean match(OsmPrimitive osm) { 146 return osm instanceof Way && ((Way)osm).isIncomplete(); 146 // return osm instanceof Way && ((Way)osm).isIncomplete(); 147 return false; 147 148 } 148 149 @Override public String toString() {return "incomplete";}
Note:
See TracChangeset
for help on using the changeset viewer.