Changeset 4558 in josm


Ignore:
Timestamp:
2011-11-02T10:12:33+01:00 (9 years ago)
Author:
stoecker
Message:

fix #6966 - patch by olejorgenb - allow to align only one selected node

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/AlignInLineAction.java

    r2323 r4558  
    22package org.openstreetmap.josm.actions;
    33
     4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
    45import static org.openstreetmap.josm.tools.I18n.tr;
    5 import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
    66
    77import java.awt.event.ActionEvent;
    88import java.awt.event.KeyEvent;
     9import java.util.ArrayList;
    910import java.util.Collection;
    10 import java.util.LinkedList;
     11import java.util.List;
    1112
    1213import javax.swing.JOptionPane;
     
    3637    }
    3738
    38     /**
    39      * The general algorithm here is to find the two selected nodes
    40      * that are furthest apart, and then to align all other selected
    41      * nodes onto the straight line between these nodes.
    42      */
    43     public void actionPerformed(ActionEvent e) {
    44         if (!isEnabled())
    45             return;
    46         Collection<OsmPrimitive> sel = getCurrentDataSet().getSelected();
    47         Collection<Node> nodes = new LinkedList<Node>();
    48         Collection<Node> itnodes = new LinkedList<Node>();
    49         for (OsmPrimitive osm : sel)
    50             if (osm instanceof Node) {
    51                 nodes.add((Node)osm);
    52                 itnodes.add((Node)osm);
    53             }
    54         // special case if no single nodes are selected and exactly one way is:
    55         // then use the way's nodes
    56         if ((nodes.size() == 0) && (sel.size() == 1)) {
    57             for (OsmPrimitive osm : sel)
    58                 if (osm instanceof Way) {
    59                     nodes.addAll(((Way)osm).getNodes());
    60                     itnodes.addAll(((Way)osm).getNodes());
    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 
     39    // the joy of single return values only...
     40    private void nodePairFurthestApart(ArrayList<Node> nodes, Node[] resultOut) {
     41        if(resultOut.length < 2)
     42            throw new IllegalArgumentException();
    7343        // Find from the selected nodes two that are the furthest apart.
    7444        // Let's call them A and B.
     
    7848        Node nodeb = null;
    7949
    80         for (Node n : nodes) {
    81             itnodes.remove(n);
    82             for (Node m : itnodes) {
     50        for (int i = 0; i < nodes.size()-1; i++) {
     51            Node n = nodes.get(i);
     52            for (int j = i+1; j < nodes.size(); j++) {
     53                Node m = nodes.get(j);
    8354                double dist = Math.sqrt(n.getEastNorth().distance(m.getEastNorth()));
    8455                if (dist > distance) {
     
    8960            }
    9061        }
    91 
    92         // Remove the nodes A and B from the list of nodes to move
     62        resultOut[0] = nodea;
     63        resultOut[1] = nodeb;
     64    }
     65
     66    private void showWarning() {
     67        JOptionPane.showMessageDialog(
     68                Main.parent,
     69                tr("Please select at least three nodes."),
     70                tr("Information"),
     71                JOptionPane.INFORMATION_MESSAGE
     72        );
     73        return;
     74    }
     75
     76    private static int indexWrap(int size, int i) {
     77        i = i % size; // -2 % 5 = -2, -7 % 5 = -2, -5 % 5 = 0
     78        if (i < 0) {
     79            i = size + i;
     80        }
     81        return i;
     82    }
     83    // get the node in w at index i relative to refI
     84    private static Node getNodeRelative(Way w, int refI, int i) {
     85        int absI = indexWrap(w.getNodesCount(), refI + i);
     86        if(w.isClosed() && refI + i < 0) {
     87            absI--;  // node duplicated in closed ways
     88        }
     89        return w.getNode(absI);
     90    }
     91
     92    /**
     93     * The general algorithm here is to find the two selected nodes
     94     * that are furthest apart, and then to align all other selected
     95     * nodes onto the straight line between these nodes.
     96     */
     97
     98
     99    /**
     100     * Operation depends on the selected objects:
     101     */
     102    public void actionPerformed(ActionEvent e) {
     103        if (!isEnabled())
     104            return;
     105
     106        Node[] anchors = new Node[2]; // oh, java I love you so much..
     107
     108        List<Node> selectedNodes = new ArrayList<Node>(getCurrentDataSet().getSelectedNodes());
     109        Collection<Way> selectedWays = getCurrentDataSet().getSelectedWays();
     110        ArrayList<Node> nodes = new ArrayList<Node>();
     111
     112        //// Decide what to align based on selection:
     113
     114        /// Only ways selected -> Align their nodes.
     115        if ((selectedNodes.size() == 0) && (selectedWays.size() == 1)) { // TODO: handle multiple ways
     116            for (Way way : selectedWays) {
     117                nodes.addAll(way.getNodes());
     118            }
     119            // use the nodes furthest apart as anchors
     120            nodePairFurthestApart(nodes, anchors);
     121        }
     122        /// More than 3 nodes selected -> align those nodes
     123        else if(selectedNodes.size() >= 3) {
     124            nodes.addAll(selectedNodes);
     125            // use the nodes furthest apart as anchors
     126            nodePairFurthestApart(nodes, anchors);
     127        }
     128        /// One node selected -> align that node to the relevant neighbors
     129        else if (selectedNodes.size() == 1) {
     130            Node n = selectedNodes.iterator().next();
     131
     132            Way w = null;
     133            if(selectedWays.size() == 1) {
     134                w = selectedWays.iterator().next();
     135                if(w.containsNode(n) == false)
     136                    // warning
     137                    return;
     138            } else if(n.isReferredByWays(2) == false) { // node used in only one way
     139                w = OsmPrimitive.getFilteredList(n.getReferrers(), Way.class).iterator().next();
     140            }
     141            if (w == null || w.getNodesCount() < 3)
     142                // warning, need at least 3 nodes
     143                return;
     144
     145            // Find anchors
     146            int nodeI = w.getNodes().indexOf(n);
     147            // End-node in non-circular way selected: align this node with the two neighbors.
     148            if ((nodeI == 0 || nodeI == w.getNodesCount()-1) && !w.isClosed()) {
     149                int direction = nodeI == 0 ? 1 : -1;
     150                anchors[0] = w.getNode(nodeI + direction);
     151                anchors[1] = w.getNode(nodeI + direction*2);
     152            } else {
     153                // o---O---o
     154                anchors[0] = getNodeRelative(w, nodeI, 1);
     155                anchors[1] = getNodeRelative(w, nodeI, -1);
     156            }
     157            nodes.add(n);
     158        }
     159
     160        if (anchors[0] == null || anchors[1] == null) {
     161            showWarning();
     162            return;
     163        }
     164
     165
     166        Collection<Command> cmds = new ArrayList<Command>(nodes.size());
     167
     168        createAlignNodesCommands(anchors, nodes, cmds);
     169
     170        // Do it!
     171        Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
     172        Main.map.repaint();
     173    }
     174
     175    private void createAlignNodesCommands(Node[] anchors, Collection<Node> nodes, Collection<Command> cmds) {
     176        Node nodea = anchors[0];
     177        Node nodeb = anchors[1];
     178
     179        // The anchors are aligned per definition
    93180        nodes.remove(nodea);
    94181        nodes.remove(nodeb);
     
    99186        double bx = nodeb.getEastNorth().east();
    100187        double by = nodeb.getEastNorth().north();
    101 
    102         // A list of commands to do
    103         Collection<Command> cmds = new LinkedList<Command>();
    104188
    105189        // OK, for each node to move, work out where to move it!
     
    125209                ny = (m1 * nx) + c1;
    126210            }
    127 
     211            double newX = nx - n.getEastNorth().east();
     212            double newY = ny - n.getEastNorth().north();
    128213            // Add the command to move the node to its new position.
    129             cmds.add(new MoveCommand(n, nx - n.getEastNorth().east(), ny - n.getEastNorth().north() ));
    130         }
    131 
    132         // Do it!
    133         Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
    134         Main.map.repaint();
     214            cmds.add(new MoveCommand(n, newX, newY));
     215        }
    135216    }
    136217
Note: See TracChangeset for help on using the changeset viewer.