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

Last change on this file since 3965 was 2323, checked in by Gubaer, 14 years ago

Added explicit help topics
See also current list of help topics with links to source files and to help pages

  • Property svn:eol-style set to native
File size: 5.1 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;
5import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
6
7import java.awt.event.ActionEvent;
8import java.awt.event.KeyEvent;
9import java.util.Collection;
10import java.util.LinkedList;
11
12import javax.swing.JOptionPane;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.command.Command;
16import org.openstreetmap.josm.command.MoveCommand;
17import org.openstreetmap.josm.command.SequenceCommand;
18import org.openstreetmap.josm.data.osm.Node;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.Way;
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 putValue("help", ht("/Action/AlignInLine"));
36 }
37
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
73 // Find from the selected nodes two that are the furthest apart.
74 // Let's call them A and B.
75 double distance = 0;
76
77 Node nodea = null;
78 Node nodeb = null;
79
80 for (Node n : nodes) {
81 itnodes.remove(n);
82 for (Node m : itnodes) {
83 double dist = Math.sqrt(n.getEastNorth().distance(m.getEastNorth()));
84 if (dist > distance) {
85 nodea = n;
86 nodeb = m;
87 distance = dist;
88 }
89 }
90 }
91
92 // Remove the nodes A and B from the list of nodes to move
93 nodes.remove(nodea);
94 nodes.remove(nodeb);
95
96 // Find out co-ords of A and B
97 double ax = nodea.getEastNorth().east();
98 double ay = nodea.getEastNorth().north();
99 double bx = nodeb.getEastNorth().east();
100 double by = nodeb.getEastNorth().north();
101
102 // A list of commands to do
103 Collection<Command> cmds = new LinkedList<Command>();
104
105 // OK, for each node to move, work out where to move it!
106 for (Node n : nodes) {
107 // Get existing co-ords of node to move
108 double nx = n.getEastNorth().east();
109 double ny = n.getEastNorth().north();
110
111 if (ax == bx) {
112 // Special case if AB is vertical...
113 nx = ax;
114 } else if (ay == by) {
115 // ...or horizontal
116 ny = ay;
117 } else {
118 // Otherwise calculate position by solving y=mx+c
119 double m1 = (by - ay) / (bx - ax);
120 double c1 = ay - (ax * m1);
121 double m2 = (-1) / m1;
122 double c2 = n.getEastNorth().north() - (n.getEastNorth().east() * m2);
123
124 nx = (c2 - c1) / (m1 - m2);
125 ny = (m1 * nx) + c1;
126 }
127
128 // 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();
135 }
136
137 @Override
138 protected void updateEnabledState() {
139 setEnabled(getCurrentDataSet() != null && !getCurrentDataSet().getSelected().isEmpty());
140 }
141
142 @Override
143 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
144 setEnabled(selection != null && !selection.isEmpty());
145 }
146}
Note: See TracBrowser for help on using the repository browser.