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

Last change on this file since 1924 was 1862, checked in by jttt, 15 years ago

Way refactoring - added method that will in future replace public field nodes

  • Property svn:eol-style set to native
File size: 4.9 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.ActionEvent;
7import java.awt.event.KeyEvent;
8import java.util.Collection;
9import java.util.LinkedList;
10
11import javax.swing.JOptionPane;
12
13import org.openstreetmap.josm.Main;
14import org.openstreetmap.josm.command.Command;
15import org.openstreetmap.josm.command.MoveCommand;
16import org.openstreetmap.josm.command.SequenceCommand;
17import org.openstreetmap.josm.data.osm.Node;
18import org.openstreetmap.josm.data.osm.OsmPrimitive;
19import org.openstreetmap.josm.data.osm.Way;
20import org.openstreetmap.josm.gui.OptionPaneUtil;
21import org.openstreetmap.josm.tools.Shortcut;
22
23/**
24 * Aligns all selected nodes into a straight line (useful for
25 * roads that should be straight, but have side roads and
26 * therefore need multiple nodes)
27 *
28 * @author Matthew Newton
29 */
30public final class AlignInLineAction extends JosmAction {
31
32 public AlignInLineAction() {
33 super(tr("Align Nodes in Line"), "alignline", tr("Move the selected nodes in to a line."),
34 Shortcut.registerShortcut("tools:alignline", tr("Tool: {0}", tr("Align Nodes in Line")), KeyEvent.VK_L, Shortcut.GROUP_EDIT), true);
35 }
36
37 /**
38 * The general algorithm here is to find the two selected nodes
39 * that are furthest apart, and then to align all other selected
40 * nodes onto the straight line between these nodes.
41 */
42 public void actionPerformed(ActionEvent e) {
43 if (!isEnabled())
44 return;
45 Collection<OsmPrimitive> sel = getCurrentDataSet().getSelected();
46 Collection<Node> nodes = new LinkedList<Node>();
47 Collection<Node> itnodes = new LinkedList<Node>();
48 for (OsmPrimitive osm : sel)
49 if (osm instanceof Node) {
50 nodes.add((Node)osm);
51 itnodes.add((Node)osm);
52 }
53 // special case if no single nodes are selected and exactly one way is:
54 // then use the way's nodes
55 if ((nodes.size() == 0) && (sel.size() == 1)) {
56 for (OsmPrimitive osm : sel)
57 if (osm instanceof Way) {
58 nodes.addAll(((Way)osm).getNodes());
59 itnodes.addAll(((Way)osm).getNodes());
60 }
61 }
62 if (nodes.size() < 3) {
63 OptionPaneUtil.showMessageDialog(
64 Main.parent,
65 tr("Please select at least three nodes."),
66 tr("Information"),
67 JOptionPane.INFORMATION_MESSAGE
68 );
69 return;
70 }
71
72 // Find from the selected nodes two that are the furthest apart.
73 // Let's call them A and B.
74 double distance = 0;
75
76 Node nodea = null;
77 Node nodeb = null;
78
79 for (Node n : nodes) {
80 itnodes.remove(n);
81 for (Node m : itnodes) {
82 double dist = Math.sqrt(n.getEastNorth().distance(m.getEastNorth()));
83 if (dist > distance) {
84 nodea = n;
85 nodeb = m;
86 distance = dist;
87 }
88 }
89 }
90
91 // Remove the nodes A and B from the list of nodes to move
92 nodes.remove(nodea);
93 nodes.remove(nodeb);
94
95 // Find out co-ords of A and B
96 double ax = nodea.getEastNorth().east();
97 double ay = nodea.getEastNorth().north();
98 double bx = nodeb.getEastNorth().east();
99 double by = nodeb.getEastNorth().north();
100
101 // A list of commands to do
102 Collection<Command> cmds = new LinkedList<Command>();
103
104 // OK, for each node to move, work out where to move it!
105 for (Node n : nodes) {
106 // Get existing co-ords of node to move
107 double nx = n.getEastNorth().east();
108 double ny = n.getEastNorth().north();
109
110 if (ax == bx) {
111 // Special case if AB is vertical...
112 nx = ax;
113 } else if (ay == by) {
114 // ...or horizontal
115 ny = ay;
116 } else {
117 // Otherwise calculate position by solving y=mx+c
118 double m1 = (by - ay) / (bx - ax);
119 double c1 = ay - (ax * m1);
120 double m2 = (-1) / m1;
121 double c2 = n.getEastNorth().north() - (n.getEastNorth().east() * m2);
122
123 nx = (c2 - c1) / (m1 - m2);
124 ny = (m1 * nx) + c1;
125 }
126
127 // Add the command to move the node to its new position.
128 cmds.add(new MoveCommand(n, nx - n.getEastNorth().east(), ny - n.getEastNorth().north() ));
129 }
130
131 // Do it!
132 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
133 Main.map.repaint();
134 }
135
136 @Override
137 protected void updateEnabledState() {
138 setEnabled(getCurrentDataSet() != null && !getCurrentDataSet().getSelected().isEmpty());
139 }
140}
Note: See TracBrowser for help on using the repository browser.