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

Revision 4855, 5.1 KB checked in by simon04, 3 weeks ago (diff)

see #7184 - remap shortcuts of ImproveWayAccuracyAction ([W]), DistributeAction ([Shift]+[B])

  • 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, Shortcut.GROUP_EDIT, Shortcut.SHIFT_DEFAULT), true);
33        putValue("help", ht("/Action/DistributeNodes"));
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.