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

Revision 4982, 5.0 KB checked in by stoecker, 3 months ago (diff)

see #7226 - patch by akks (fixed a bit) - fix shortcut deprecations

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