source: josm/src/org/openstreetmap/josm/actions/AlignInLineAction.java@ 178

Last change on this file since 178 was 178, checked in by imi, 17 years ago
  • fixed display of tooltip shortcuts
  • added icon=... to annotation presets
  • added support for putting annotation presets in the toolbar
File size: 3.4 KB
Line 
1package org.openstreetmap.josm.actions;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.event.ActionEvent;
6import java.awt.event.KeyEvent;
7import java.util.Collection;
8import java.util.LinkedList;
9
10import javax.swing.JOptionPane;
11
12import org.openstreetmap.josm.Main;
13import org.openstreetmap.josm.command.Command;
14import org.openstreetmap.josm.command.MoveCommand;
15import org.openstreetmap.josm.command.SequenceCommand;
16import org.openstreetmap.josm.data.osm.Node;
17import org.openstreetmap.josm.data.osm.OsmPrimitive;
18
19/**
20 * Aligns all selected nodes into a straight line (useful for
21 * roads that should be straight, but have side roads and
22 * therefore need multiple nodes)
23 *
24 * @author Matthew Newton
25 */
26public final class AlignInLineAction extends JosmAction {
27
28 public AlignInLineAction() {
29 super(tr("Align Nodes in Line"), "alignline", tr("Move the selected nodes onto a line."), KeyEvent.VK_L, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true);
30 }
31
32 /**
33 * The general algorithm here is to find the two selected nodes
34 * that are furthest apart, and then to align all other selected
35 * nodes onto the straight line between these nodes.
36 */
37 public void actionPerformed(ActionEvent e) {
38 Collection<OsmPrimitive> sel = Main.ds.getSelected();
39 Collection<Node> nodes = new LinkedList<Node>();
40 Collection<Node> itnodes = new LinkedList<Node>();
41 for (OsmPrimitive osm : sel)
42 if (osm instanceof Node) {
43 nodes.add((Node)osm);
44 itnodes.add((Node)osm);
45 }
46 if (nodes.size() < 3) {
47 JOptionPane.showMessageDialog(Main.parent, tr("Please select at least three nodes."));
48 return;
49 }
50
51 // Find from the selected nodes two that are the furthest apart.
52 // Let's call them A and B.
53 double distance = 0;
54
55 Node nodea = null;
56 Node nodeb = null;
57
58 for (Node n : nodes) {
59 itnodes.remove(n);
60 for (Node m : itnodes) {
61 double dist = Math.sqrt(n.eastNorth.distance(m.eastNorth));
62 if (dist > distance) {
63 nodea = n;
64 nodeb = m;
65 distance = dist;
66 }
67 }
68 }
69
70 // Remove the nodes A and B from the list of nodes to move
71 nodes.remove(nodea);
72 nodes.remove(nodeb);
73
74 // Find out co-ords of A and B
75 double ax = nodea.eastNorth.east();
76 double ay = nodea.eastNorth.north();
77 double bx = nodeb.eastNorth.east();
78 double by = nodeb.eastNorth.north();
79
80 // A list of commands to do
81 Collection<Command> cmds = new LinkedList<Command>();
82
83 // OK, for each node to move, work out where to move it!
84 for (Node n : nodes) {
85 // Get existing co-ords of node to move
86 double nx = n.eastNorth.east();
87 double ny = n.eastNorth.north();
88
89 if (ax == bx) {
90 // Special case if AB is vertical...
91 nx = ax;
92 } else if (ay == by) {
93 // ...or horizontal
94 ny = ay;
95 } else {
96 // Otherwise calculate position by solving y=mx+c
97 double m1 = (by - ay) / (bx - ax);
98 double c1 = ay - (ax * m1);
99 double m2 = (-1) / m1;
100 double c2 = n.eastNorth.north() - (n.eastNorth.east() * m2);
101
102 nx = (c2 - c1) / (m1 - m2);
103 ny = (m1 * nx) + c1;
104 }
105
106 // Add the command to move the node to its new position.
107 cmds.add(new MoveCommand(n, nx - n.eastNorth.east(), ny - n.eastNorth.north() ));
108 }
109
110 // Do it!
111 Main.main.editLayer().add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
112 Main.map.repaint();
113 }
114}
Note: See TracBrowser for help on using the repository browser.