Ticket #40: josm166_align_in_line.patch

File josm166_align_in_line.patch, 5.2 KB (added by mcn, 20 years ago)

Patch to add Align in Line functionality - applies to SVN r166

  • src/org/openstreetmap/josm/actions/AlignInLineAction.java

     
     1package org.openstreetmap.josm.actions;
     2
     3import static org.openstreetmap.josm.tools.I18n.tr;
     4
     5import java.awt.event.ActionEvent;
     6import java.awt.event.KeyEvent;
     7import java.util.Collection;
     8import java.util.LinkedList;
     9
     10import javax.swing.JOptionPane;
     11
     12import org.openstreetmap.josm.Main;
     13import org.openstreetmap.josm.command.Command;
     14import org.openstreetmap.josm.command.MoveCommand;
     15import org.openstreetmap.josm.command.SequenceCommand;
     16import org.openstreetmap.josm.data.coor.EastNorth;
     17import org.openstreetmap.josm.data.coor.LatLon;
     18import org.openstreetmap.josm.data.osm.Node;
     19import org.openstreetmap.josm.data.osm.OsmPrimitive;
     20
     21/**
     22 * Aligns all selected nodes into a straight line (useful for
     23 * roads that should be straight, but have side roads and
     24 * therefore need multiple nodes)
     25 *
     26 * @author Matthew Newton
     27 */
     28public final class AlignInLineAction extends JosmAction {
     29
     30        public AlignInLineAction() {
     31                super(tr("Align Nodes in Line"), "clock", tr("Move the selected nodes onto a line."), KeyEvent.VK_L, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK);
     32        }
     33
     34        public void actionPerformed(ActionEvent e) {
     35/**
     36 * The general algorithm here is to find the two selected nodes
     37 * that are furthest apart, and then to align all other selected
     38 * nodes onto the straight line between these nodes.
     39 */
     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                if (nodes.size() < 3) {
     49                        JOptionPane.showMessageDialog(Main.parent, tr("Please select at least three nodes."));
     50                        return;
     51                }
     52
     53                // Find from the selected nodes two that are the furthest apart.
     54    // Let's call them A and B.
     55    double distance = 0;
     56
     57    Node nodea = null;
     58    Node nodeb = null;
     59
     60    for (Node n : nodes) {
     61      itnodes.remove(n);
     62      for (Node m : itnodes) {
     63          double dist = Math.sqrt(n.eastNorth.distance(m.eastNorth));
     64          if (dist > distance) {
     65            nodea = n;
     66            nodeb = m;
     67            distance = dist;
     68          }
     69      }
     70    }
     71
     72    // Remove the nodes A and B from the list of nodes to move
     73    nodes.remove(nodea);
     74    nodes.remove(nodeb);
     75
     76    // Find out co-ords of A and B
     77    double ax = nodea.eastNorth.east();
     78    double ay = nodea.eastNorth.north();
     79    double bx = nodeb.eastNorth.east();
     80    double by = nodeb.eastNorth.north();
     81
     82    // A list of commands to do
     83                Collection<Command> cmds = new LinkedList<Command>();
     84
     85    // OK, for each node to move, work out where to move it!
     86    for (Node n : nodes) {
     87      // Get existing co-ords of node to move
     88      double nx = n.eastNorth.east();
     89      double ny = n.eastNorth.north();
     90
     91      if (ax == bx) {
     92        // Special case if AB is vertical...
     93        nx = ax;
     94      } else if (ay == by) {
     95        // ...or horizontal
     96        ny = ay;
     97      } else {
     98        // Otherwise calculate position by solving y=mx+c
     99        double m1 = (by - ay) / (bx - ax);
     100        double c1 = ay - (ax * m1);
     101        double m2 = (-1) / m1;
     102        double c2 = n.eastNorth.north() - (n.eastNorth.east() * m2);
     103
     104        nx = (c2 - c1) / (m1 - m2);
     105        ny = (m1 * nx) + c1;
     106      }
     107
     108      // Add the command to move the node to its new position.
     109      cmds.add(new MoveCommand(n, nx - n.eastNorth.east(), ny - n.eastNorth.north() ));
     110    }
     111
     112    // Do it!
     113                Main.main.editLayer().add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
     114
     115                Main.map.repaint();
     116        }
     117}
  • src/org/openstreetmap/josm/gui/MainMenu.java

     
    99
    1010import org.openstreetmap.josm.actions.AboutAction;
    1111import org.openstreetmap.josm.actions.AlignInCircleAction;
     12import org.openstreetmap.josm.actions.AlignInLineAction;
    1213import org.openstreetmap.josm.actions.DownloadAction;
    1314import org.openstreetmap.josm.actions.DownloadIncompleteAction;
    1415import org.openstreetmap.josm.actions.ExitAction;
     
    4041        public final DownloadAction download = new DownloadAction();
    4142        public final Action reverseSegment = new ReverseSegmentAction();
    4243        public final Action alignInCircle = new AlignInCircleAction();
     44        public final Action alignInLine = new AlignInLineAction();
    4345        public final Action upload = new UploadAction();
    4446        public final Action save = new SaveAction();
    4547        public final Action saveAs = new SaveAsAction();
     
    7577                editMenu.addSeparator();
    7678                editMenu.add(reverseSegment);
    7779                editMenu.add(alignInCircle);
     80                editMenu.add(alignInLine);
    7881                editMenu.addSeparator();
    7982                editMenu.add(preferences);
    8083                add(editMenu);