source: josm/trunk/src/org/openstreetmap/josm/actions/DistributeAction.java@ 3718

Last change on this file since 3718 was 3083, checked in by bastiK, 14 years ago

added svn:eol-style=native to source files

  • Property svn:eol-style set to native
File size: 5.0 KB
Line 
1// License: GPL. Copyright 2009 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 * Distributes the selected nodes to equal distances along a line.
25 *
26 * @author Teemu Koskinen
27 */
28public final class DistributeAction extends JosmAction {
29
30 public DistributeAction() {
31 super(tr("Distribute Nodes"), "distribute", tr("Distribute the selected nodes to equal distances along a line."),
32 Shortcut.registerShortcut("tools:distribute", tr("Tool: {0}", tr("Distribute Nodes")), KeyEvent.VK_B, Shortcut.GROUP_EDIT), true);
33 putValue("help", ht("/Action/Distribute"));
34 }
35
36 /**
37 * The general algorithm here is to find the two selected nodes
38 * that are furthest apart, and then to distribute all other selected
39 * nodes along 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
62 if (nodes.size() < 3) {
63 JOptionPane.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 // Amount of nodes between A and B plus 1
105 int num = nodes.size()+1;
106
107 // Current number of node
108 int pos = 0;
109 while (nodes.size() > 0) {
110 pos++;
111 Node s = null;
112
113 // Find the node that is furthest from B (i.e. closest to A)
114 distance = 0.0;
115 for (Node n : nodes) {
116 double dist = Math.sqrt(nodeb.getEastNorth().distance(n.getEastNorth()));
117 if (dist > distance) {
118 s = n;
119 distance = dist;
120 }
121 }
122
123 // First move the node to A's position, then move it towards B
124 double dx = ax - s.getEastNorth().east() + (bx-ax)*pos/num;
125 double dy = ay - s.getEastNorth().north() + (by-ay)*pos/num;
126
127 cmds.add(new MoveCommand(s, dx, dy));
128
129 //remove moved node from the list
130 nodes.remove(s);
131 }
132
133 // Do it!
134 Main.main.undoRedo.add(new SequenceCommand(tr("Distribute Nodes"), cmds));
135 Main.map.repaint();
136 }
137
138 @Override
139 protected void updateEnabledState() {
140 if (getCurrentDataSet() == null) {
141 setEnabled(false);
142 } else {
143 updateEnabledState(getCurrentDataSet().getSelected());
144 }
145 }
146
147 @Override
148 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
149 setEnabled(selection != null && !selection.isEmpty());
150 }
151}
Note: See TracBrowser for help on using the repository browser.