Ticket #2145: distributeaction.patch

File distributeaction.patch, 6.4 KB (added by Teemu Koskinen <teemu.koskinen@…>, 17 years ago)
  • src/org/openstreetmap/josm/actions/DistributeAction.java

     
     1// License: GPL. Copyright 2009 by Immanuel Scholz and others
     2package org.openstreetmap.josm.actions;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.awt.event.ActionEvent;
     7import java.awt.event.KeyEvent;
     8import java.util.Collection;
     9import java.util.LinkedList;
     10
     11import javax.swing.JOptionPane;
     12
     13import org.openstreetmap.josm.Main;
     14import org.openstreetmap.josm.command.Command;
     15import org.openstreetmap.josm.command.MoveCommand;
     16import org.openstreetmap.josm.command.SequenceCommand;
     17import org.openstreetmap.josm.data.osm.Node;
     18import org.openstreetmap.josm.data.osm.OsmPrimitive;
     19import org.openstreetmap.josm.data.osm.Way;
     20import org.openstreetmap.josm.tools.Shortcut;
     21
     22/**
     23 * Distributes the selected nodes to equal distances along a line.
     24 *
     25 * @author Teemu Koskinen
     26 */
     27public final class DistributeAction extends JosmAction {
     28
     29    public DistributeAction() {
     30        super(tr("Distribute Nodes"), "distribute", tr("Distribute the selected nodes to equal distances along a line."),
     31        Shortcut.registerShortcut("tools:distribute", tr("Tool: {0}", tr("Distribute Nodes")), KeyEvent.VK_B, Shortcut.GROUP_EDIT), true);
     32    }
     33
     34    /**
     35     * The general algorithm here is to find the two selected nodes
     36     * that are furthest apart, and then to distribute all other selected
     37     * nodes along the straight line between these nodes.
     38     */
     39    public void actionPerformed(ActionEvent e) {
     40        Collection<OsmPrimitive> sel = Main.ds.getSelected();
     41        Collection<Node> nodes = new LinkedList<Node>();
     42        Collection<Node> itnodes = new LinkedList<Node>();
     43        for (OsmPrimitive osm : sel)
     44            if (osm instanceof Node) {
     45                nodes.add((Node)osm);
     46                itnodes.add((Node)osm);
     47            }
     48        // special case if no single nodes are selected and exactly one way is:
     49        // then use the way's nodes
     50        if ((nodes.size() == 0) && (sel.size() == 1))
     51            for (OsmPrimitive osm : sel)
     52                if (osm instanceof Way) {
     53                    nodes.addAll(((Way)osm).nodes);
     54                    itnodes.addAll(((Way)osm).nodes);
     55                }
     56
     57        if (nodes.size() < 3) {
     58            JOptionPane.showMessageDialog(Main.parent, tr("Please select at least three nodes."));
     59            return;
     60        }
     61
     62        // Find from the selected nodes two that are the furthest apart.
     63        // Let's call them A and B.
     64        double distance = 0;
     65
     66        Node nodea = null;
     67        Node nodeb = null;
     68
     69        for (Node n : nodes) {
     70            itnodes.remove(n);
     71            for (Node m : itnodes) {
     72                double dist = Math.sqrt(n.eastNorth.distance(m.eastNorth));
     73                if (dist > distance) {
     74                    nodea = n;
     75                    nodeb = m;
     76                    distance = dist;
     77                }
     78            }
     79        }
     80
     81        // Remove the nodes A and B from the list of nodes to move
     82        nodes.remove(nodea);
     83        nodes.remove(nodeb);
     84
     85        // Find out co-ords of A and B
     86        double ax = nodea.eastNorth.east();
     87        double ay = nodea.eastNorth.north();
     88        double bx = nodeb.eastNorth.east();
     89        double by = nodeb.eastNorth.north();
     90
     91        // A list of commands to do
     92        Collection<Command> cmds = new LinkedList<Command>();
     93
     94        // Amount of nodes between A and B plus 1
     95        int num = nodes.size()+1;
     96
     97        // Current number of node
     98        int pos = 0;
     99        while (nodes.size() > 0) {
     100            pos++;
     101            Node s = null;
     102
     103            // Find the node that is furthest from B (i.e. closest to A)
     104            distance = 0.0;
     105            for (Node n : nodes) {
     106                double dist = Math.sqrt(nodeb.eastNorth.distance(n.eastNorth));
     107                if (dist > distance) {
     108                    s = n;
     109                    distance = dist;
     110                }
     111            }
     112
     113            // First move the node to A's position, then move it towards B
     114            double dx = ax - s.eastNorth.east() + (bx-ax)*pos/num;
     115            double dy = ay - s.eastNorth.north() + (by-ay)*pos/num;
     116
     117            cmds.add(new MoveCommand(s, dx, dy));
     118
     119            //remove moved node from the list
     120            nodes.remove(s);
     121        }
     122
     123        // Do it!
     124        Main.main.undoRedo.add(new SequenceCommand(tr("Distribute Nodes"), cmds));
     125        Main.map.repaint();
     126    }
     127}
  • src/org/openstreetmap/josm/gui/MainMenu.java

     
    2626import org.openstreetmap.josm.actions.CopyAction;
    2727import org.openstreetmap.josm.actions.CreateCircleAction;
    2828import org.openstreetmap.josm.actions.DeleteAction;
     29import org.openstreetmap.josm.actions.DistributeAction;
    2930import org.openstreetmap.josm.actions.DownloadAction;
    3031import org.openstreetmap.josm.actions.DuplicateAction;
    3132import org.openstreetmap.josm.actions.ExitAction;
     
    108109    public final JosmAction reverseWay = new ReverseWayAction();
    109110    public final JosmAction alignInCircle = new AlignInCircleAction();
    110111    public final JosmAction alignInLine = new AlignInLineAction();
     112    public final JosmAction distribute = new DistributeAction();
    111113    public final JosmAction ortho = new OrthogonalizeAction();
    112114    public final AddNodeAction addnode = new AddNodeAction();
    113115    public final JosmAction createCircle = new CreateCircleAction();
     
    231233        toolsMenu.addSeparator();
    232234        add(toolsMenu, alignInCircle);
    233235        add(toolsMenu, alignInLine);
     236        add(toolsMenu, distribute);
    234237        add(toolsMenu, ortho);
    235238        toolsMenu.addSeparator();
    236239        add(toolsMenu, addnode);