Changeset 4558 in josm


Ignore:
Timestamp:
02.11.2011 10:12:33 (7 months 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.