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

Last change on this file since 2284 was 2256, checked in by Gubaer, 15 years ago

Removed inefficient DataSet:getSelected() when responding to fireSelectionChanged() in JOSM actions, see thread on dev
Still uses DataSet:getSelected() when responding to layer change events, this is less critical.

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