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

Last change on this file since 6083 was 6069, checked in by stoecker, 11 years ago

see #8853 remove tabs, trailing spaces, windows line ends, strange characters

  • Property svn:eol-style set to native
File size: 5.9 KB
Line 
1// License: GPL. Copyright 2009 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.event.ActionEvent;
8import java.awt.event.KeyEvent;
9import java.util.Collection;
10import java.util.HashSet;
11import java.util.Iterator;
12import java.util.LinkedList;
13import java.util.Set;
14
15import javax.swing.JOptionPane;
16
17import org.openstreetmap.josm.Main;
18import org.openstreetmap.josm.command.Command;
19import org.openstreetmap.josm.command.MoveCommand;
20import org.openstreetmap.josm.command.SequenceCommand;
21import org.openstreetmap.josm.data.osm.Node;
22import org.openstreetmap.josm.data.osm.OsmPrimitive;
23import org.openstreetmap.josm.data.osm.Way;
24import org.openstreetmap.josm.tools.Shortcut;
25
26/**
27 * Distributes the selected nodes to equal distances along a line.
28 *
29 * @author Teemu Koskinen
30 */
31public final class DistributeAction extends JosmAction {
32
33 /**
34 * Constructs a new {@code DistributeAction}.
35 */
36 public DistributeAction() {
37 super(tr("Distribute Nodes"), "distribute", tr("Distribute the selected nodes to equal distances along a line."),
38 Shortcut.registerShortcut("tools:distribute", tr("Tool: {0}", tr("Distribute Nodes")), KeyEvent.VK_B,
39 Shortcut.SHIFT), true);
40 putValue("help", ht("/Action/DistributeNodes"));
41 }
42
43 /**
44 * The general algorithm here is to find the two selected nodes
45 * that are furthest apart, and then to distribute all other selected
46 * nodes along the straight line between these nodes.
47 */
48 public void actionPerformed(ActionEvent e) {
49 if (!isEnabled())
50 return;
51 Collection<OsmPrimitive> sel = getCurrentDataSet().getSelected();
52 Collection<Node> nodes = new LinkedList<Node>();
53 Collection<Node> itnodes = new LinkedList<Node>();
54 for (OsmPrimitive osm : sel)
55 if (osm instanceof Node) {
56 nodes.add((Node)osm);
57 itnodes.add((Node)osm);
58 }
59 // special case if no single nodes are selected and exactly one way is:
60 // then use the way's nodes
61 if ((nodes.size() == 0) && (sel.size() == 1)) {
62 for (OsmPrimitive osm : sel)
63 if (osm instanceof Way) {
64 nodes.addAll(((Way)osm).getNodes());
65 itnodes.addAll(((Way)osm).getNodes());
66 }
67 }
68
69 Set<Node> ignoredNodes = removeNodesWithoutCoordinates(nodes);
70 ignoredNodes.addAll(removeNodesWithoutCoordinates(itnodes));
71 if (!ignoredNodes.isEmpty()) {
72 Main.warn(tr("Ignoring {0} nodes with null coordinates", ignoredNodes.size()));
73 ignoredNodes.clear();
74 }
75
76 if (nodes.size() < 3) {
77 JOptionPane.showMessageDialog(
78 Main.parent,
79 tr("Please select at least three nodes."),
80 tr("Information"),
81 JOptionPane.INFORMATION_MESSAGE
82 );
83 return;
84 }
85
86 // Find from the selected nodes two that are the furthest apart.
87 // Let's call them A and B.
88 double distance = 0;
89
90 Node nodea = null;
91 Node nodeb = null;
92
93 for (Node n : nodes) {
94 itnodes.remove(n);
95 for (Node m : itnodes) {
96 double dist = Math.sqrt(n.getEastNorth().distance(m.getEastNorth()));
97 if (dist > distance) {
98 nodea = n;
99 nodeb = m;
100 distance = dist;
101 }
102 }
103 }
104
105 // Remove the nodes A and B from the list of nodes to move
106 nodes.remove(nodea);
107 nodes.remove(nodeb);
108
109 // Find out co-ords of A and B
110 double ax = nodea.getEastNorth().east();
111 double ay = nodea.getEastNorth().north();
112 double bx = nodeb.getEastNorth().east();
113 double by = nodeb.getEastNorth().north();
114
115 // A list of commands to do
116 Collection<Command> cmds = new LinkedList<Command>();
117
118 // Amount of nodes between A and B plus 1
119 int num = nodes.size()+1;
120
121 // Current number of node
122 int pos = 0;
123 while (nodes.size() > 0) {
124 pos++;
125 Node s = null;
126
127 // Find the node that is furthest from B (i.e. closest to A)
128 distance = 0.0;
129 for (Node n : nodes) {
130 double dist = Math.sqrt(nodeb.getEastNorth().distance(n.getEastNorth()));
131 if (dist > distance) {
132 s = n;
133 distance = dist;
134 }
135 }
136
137 // First move the node to A's position, then move it towards B
138 double dx = ax - s.getEastNorth().east() + (bx-ax)*pos/num;
139 double dy = ay - s.getEastNorth().north() + (by-ay)*pos/num;
140
141 cmds.add(new MoveCommand(s, dx, dy));
142
143 //remove moved node from the list
144 nodes.remove(s);
145 }
146
147 // Do it!
148 Main.main.undoRedo.add(new SequenceCommand(tr("Distribute Nodes"), cmds));
149 Main.map.repaint();
150 }
151
152 private Set<Node> removeNodesWithoutCoordinates(Collection<Node> col) {
153 Set<Node> result = new HashSet<Node>();
154 for (Iterator<Node> it = col.iterator(); it.hasNext();) {
155 Node n = it.next();
156 if (n.getCoor() == null) {
157 it.remove();
158 result.add(n);
159 }
160 }
161 return result;
162 }
163
164 @Override
165 protected void updateEnabledState() {
166 if (getCurrentDataSet() == null) {
167 setEnabled(false);
168 } else {
169 updateEnabledState(getCurrentDataSet().getSelected());
170 }
171 }
172
173 @Override
174 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
175 setEnabled(selection != null && !selection.isEmpty());
176 }
177}
Note: See TracBrowser for help on using the repository browser.