Index: src/org/openstreetmap/josm/actions/AlignInLineAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AlignInLineAction.java	(révision 6950)
+++ src/org/openstreetmap/josm/actions/AlignInLineAction.java	(copie de travail)
@@ -28,6 +28,11 @@
  * Aligns all selected nodes into a straight line (useful for
  * roads that should be straight, but have side roads and
  * therefore need multiple nodes)
+ * 
+ * Case 1: Only ways selected, align each ways taking care of intersection.
+ * Case 2: Single node selected, align this node relative to the surrounding nodes.
+ * Case 3: Single node and ways selected, align this node relative to the surrounding nodes only parts of selected ways.
+ * Case 4: Only nodes selected, align these nodes respect to the line passing through the most distant nodes.
  *
  * @author Matthew Newton
  */
@@ -109,22 +114,6 @@
             .show();
     }
 
-    private static int indexWrap(int size, int i) {
-        i = i % size; // -2 % 5 = -2, -7 % 5 = -2, -5 % 5 = 0
-        if (i < 0) {
-            i = size + i;
-        }
-        return i;
-    }
-    // get the node in w at index i relative to refI
-    private static Node getNodeRelative(Way w, int refI, int i) {
-        int absI = indexWrap(w.getNodesCount(), refI + i);
-        if(w.isClosed() && refI + i < 0) {
-            absI--;  // node duplicated in closed ways
-        }
-        return w.getNode(absI);
-    }
-
     /**
      * The general algorithm here is to find the two selected nodes
      * that are furthest apart, and then to align all other selected
@@ -140,130 +129,77 @@
         if (!isEnabled())
             return;
 
-        Node[] anchors = new Node[2]; // oh, java I love you so much..
-
         List<Node> selectedNodes = new ArrayList<Node>(getCurrentDataSet().getSelectedNodes());
         Collection<Way> selectedWays = getCurrentDataSet().getSelectedWays();
-        List<Node> nodes = new ArrayList<Node>();
+        Command cmd = null;
 
         //// Decide what to align based on selection:
 
         /// Only ways selected -> For each way align their nodes taking care of intersection
         if(selectedNodes.isEmpty() && !selectedWays.isEmpty()) {
-            alignMultiWay(selectedWays);
-            return;
+            cmd = alignMultiWay(selectedWays);
         }
-        /// More than 3 nodes selected -> align those nodes
-        else if(selectedNodes.size() >= 3) {
-            nodes.addAll(selectedNodes);
-            // use the nodes furthest apart as anchors
-            nodePairFurthestApart(nodes, anchors);
-        }
-        /// One node selected -> align that node to the relevant neighbors
-        else if (selectedNodes.size() == 1) {
-            Node n = selectedNodes.iterator().next();
-
-            Way w = null;
-            if(selectedWays.size() == 1) {
-                w = selectedWays.iterator().next();
-                if (!w.containsNode(n))
-                    // warning
-                    return;
-            } else {
-                List<Way> refWays = OsmPrimitive.getFilteredList(n.getReferrers(), Way.class);
-                if (refWays.size() == 1) { // node used in only one way
-                    w = refWays.iterator().next();
-                }
-            }
-            if (w == null || w.getNodesCount() < 3)
-                // warning, need at least 3 nodes
+        /// Only 1 node selected -> align this node relative to referers way
+        else if(selectedNodes.size() == 1) {
+            Node selectedNode = selectedNodes.get(0);
+            List<Way> involvedWays = null;
+            if(selectedWays.isEmpty())
+                /// No selected way, all way containing this node are used
+                involvedWays = OsmPrimitive.getFilteredList(selectedNode.getReferrers(), Way.class);
+            else
+                /// Selected way, use only these ways
+                involvedWays = new ArrayList<Way>(selectedWays);
+            List<Line> lines = getInvolvedLines(selectedNode, involvedWays);
+            if(lines.size() > 2 || lines.isEmpty()) {
+                showWarning();
                 return;
-
-            // Find anchors
-            int nodeI = w.getNodes().indexOf(n);
-            // End-node in non-circular way selected: align this node with the two neighbors.
-            if ((nodeI == 0 || nodeI == w.getNodesCount()-1) && !w.isClosed()) {
-                int direction = nodeI == 0 ? 1 : -1;
-                anchors[0] = w.getNode(nodeI + direction);
-                anchors[1] = w.getNode(nodeI + direction*2);
-            } else {
-                // o---O---o
-                anchors[0] = getNodeRelative(w, nodeI, 1);
-                anchors[1] = getNodeRelative(w, nodeI, -1);
             }
-            nodes.add(n);
+            cmd = alignSingleNode(selectedNodes.get(0), lines);
         }
-
-        if (anchors[0] == null || anchors[1] == null) {
-            showWarning();
-            return;
+        /// More than 3 nodes selected -> align those nodes
+        else if(selectedNodes.size() >= 3) {
+            cmd = alignOnlyNodes(selectedNodes);
         }
 
-
-        Collection<Command> cmds = new ArrayList<Command>(nodes.size());
-
-        createAlignNodesCommands(anchors, nodes, cmds);
-
         // Do it!
-        Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
-        Main.map.repaint();
-    }
-
-    private void createAlignNodesCommands(Node[] anchors, Collection<Node> nodes, Collection<Command> cmds) {
-        Node nodea = anchors[0];
-        Node nodeb = anchors[1];
-
-        // The anchors are aligned per definition
-        nodes.remove(nodea);
-        nodes.remove(nodeb);
-
-        // Find out co-ords of A and B
-        double ax = nodea.getEastNorth().east();
-        double ay = nodea.getEastNorth().north();
-        double bx = nodeb.getEastNorth().east();
-        double by = nodeb.getEastNorth().north();
-
-        // OK, for each node to move, work out where to move it!
-        for (Node n : nodes) {
-            // Get existing co-ords of node to move
-            double nx = n.getEastNorth().east();
-            double ny = n.getEastNorth().north();
-
-            if (ax == bx) {
-                // Special case if AB is vertical...
-                nx = ax;
-            } else if (ay == by) {
-                // ...or horizontal
-                ny = ay;
-            } else {
-                // Otherwise calculate position by solving y=mx+c
-                double m1 = (by - ay) / (bx - ax);
-                double c1 = ay - (ax * m1);
-                double m2 = (-1) / m1;
-                double c2 = n.getEastNorth().north() - (n.getEastNorth().east() * m2);
-
-                nx = (c2 - c1) / (m1 - m2);
-                ny = (m1 * nx) + c1;
-            }
-            double newX = nx - n.getEastNorth().east();
-            double newY = ny - n.getEastNorth().north();
-            // Add the command to move the node to its new position.
-            cmds.add(new MoveCommand(n, newX, newY));
+        if(cmd != null) {
+            Main.main.undoRedo.add(cmd);
+            Main.map.repaint();
+        } else {
+            showWarning();
         }
     }
 
     /**
+     * Align nodes in case that only nodes are selected
+     * @param nodes Nodes to be aligned
+     * @return Command that perform action
+     */
+    private Command alignOnlyNodes(List<Node> nodes) {
+        Node[] anchors = new Node[2]; // oh, java I love you so much..
+        // use the nodes furthest apart as anchors
+        nodePairFurthestApart(nodes, anchors);
+        Collection<Command> cmds = new ArrayList<Command>(nodes.size());
+        Line line = new Line(anchors[0], anchors[1]);
+        for(Node node: nodes)
+            if(node != anchors[0] && node != anchors[1])
+                cmds.add(line.projectionCommand(node));
+        return new SequenceCommand(tr("Align Nodes in Line"), cmds);
+    }
+    
+    /**
      * Align way in case of multiple way #6819
      * @param ways Collection of way to align
+     * @return Command that perform action
      */
-    private void alignMultiWay(Collection<Way> ways) {
+    private Command alignMultiWay(Collection<Way> ways) {
         // Collect all nodes and compute line equation
         HashSet<Node> nodes = new HashSet<Node>();
         HashMap<Way, Line> lines = new HashMap<Way, Line>();
         for(Way w: ways) {
             if(w.firstNode() == w.lastNode()) {
                 showWarning(tr("Can not align a polygon. Abort."));
-                return;
+                return null;
             }
             nodes.addAll(w.getNodes());
             lines.put(w, new Line(w));
@@ -284,20 +220,50 @@
                 Command cmd = lines.get(referers.get(0)).intersectionCommand(n, lines.get(referers.get(1)));
                 if(cmd == null) {
                     showWarning(tr("Two parallels ways found. Abort."));
-                    return;
+                    return null;
                 }
                 cmds.add(cmd);
             }
             else {
                 showWarning(tr("Intersection of three or more ways can not be solved. Abort."));
-                return;
+                return null;
             }
         }
-        Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
-        Main.map.repaint();
+        return new SequenceCommand(tr("Align Nodes in Line"), cmds);
     }
 
     /**
+     * Get lines useful to do alignment of a single node
+     * @param node Node to be aligned
+     * @param refWays Ways where useful lines will be searched
+     * @return List of useful lines
+     */
+    private List<Line> getInvolvedLines(Node node, List<Way> refWays) {
+        ArrayList<Line> lines = new ArrayList<Line>();
+        for(Way way: refWays) {
+            List<Node> nodes = way.getNodes();
+            for(int i = 1; i < nodes.size()-1; i++)
+                if(nodes.get(i) == node)
+                    lines.add(new Line(nodes.get(i-1), nodes.get(i+1)));
+        }
+        return lines;
+    }
+
+    /**
+     * Align a single node relative to a set of lines #9081
+     * @param node Node to be aligned
+     * @param lines Lines to align node on
+     * @return Command that perform action
+     */
+    private Command alignSingleNode(Node node, List<Line> lines) {
+        if(lines.size() == 1)
+            return lines.get(0).projectionCommand(node);
+        else if(lines.size() == 2)
+            return lines.get(0).intersectionCommand(node,  lines.get(1));
+        return null;
+    }
+
+    /**
      * Class that describe a line
      */
     private class Line {
@@ -312,15 +278,11 @@
          */
         private double xM, yM; // Coordinate of a point of the line 
 
-        /**
-         * Init a line equation from a way.
-         * @param way
-         */
-        public Line(Way way) {
-            xM = way.firstNode().getEastNorth().getX();
-            yM = way.firstNode().getEastNorth().getY();
-            double xB = way.lastNode().getEastNorth().getX();
-            double yB = way.lastNode().getEastNorth().getY();
+        public Line(Node first, Node last) {
+            xM = first.getEastNorth().getX();
+            yM = first.getEastNorth().getY();
+            double xB = last.getEastNorth().getX();
+            double yB = last.getEastNorth().getY();
             a = yB - yM;
             b = xM - xB;
             double norm = Math.sqrt(a*a + b*b);
@@ -331,6 +293,14 @@
             b /= norm;
             c = -(a*xM + b*yM);
         }
+        
+        /**
+         * Init a line equation from a way using its extremities.
+         * @param way
+         */
+        public Line(Way way) {
+            this(way.firstNode(), way.lastNode());
+        }
 
         /**
          * Orthogonal projection of a node N along this line.
