Index: trunk/src/org/openstreetmap/josm/actions/mapmode/ParallelWays.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/ParallelWays.java	(revision 5980)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/ParallelWays.java	(revision 5981)
@@ -6,5 +6,7 @@
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.openstreetmap.josm.Main;
@@ -36,5 +38,5 @@
         // Possible/sensible to use PrimetiveDeepCopy here?
 
-        //// Make a deep copy of the ways, keeping the copied ways connected
+        // Make a deep copy of the ways, keeping the copied ways connected
         // TODO: This assumes the first/last nodes of the ways are the only possible shared nodes.
         HashMap<Node, Node> splitNodeMap = new HashMap<Node, Node>(sourceWays.size());
@@ -62,11 +64,29 @@
         sourceWays = null; // Ensure that we only use the copies from now
 
-        //// Find a linear ordering of the nodes. Fail if there isn't one.
+        // Find a linear ordering of the nodes. Fail if there isn't one.
         CombineWayAction.NodeGraph nodeGraph = CombineWayAction.NodeGraph.createUndirectedGraphFromNodeWays(ways);
-        sortedNodes = nodeGraph.buildSpanningPath();
-        if (sortedNodes == null)
+        List<Node> sortedNodesPath = nodeGraph.buildSpanningPath();
+        if (sortedNodesPath == null)
             throw new IllegalArgumentException("Ways must have spanning path"); // Create a dedicated exception?
+        
+        // Fix #8631 - Remove duplicated nodes from graph to be robust with self-intersecting ways
+        Set<Node> removedNodes = new HashSet<Node>();
+        sortedNodes = new ArrayList<Node>();
+        for (int i = 0; i < sortedNodesPath.size(); i++) {
+            Node n = sortedNodesPath.get(i);
+            if (i < sortedNodesPath.size()-1) {
+                if (sortedNodesPath.get(i+1).getCoor().equals(n.getCoor())) {
+                    removedNodes.add(n);
+                    for (Way w : ways)
+                        w.removeNode(n);
+                    continue;
+                }
+            }
+            if (!removedNodes.contains(n)) {
+                sortedNodes.add(n);
+            }
+        }
 
-        //// Ugly method of ensuring that the offset isn't inverted. I'm sure there is a better and more elegant way, but I'm starting to get sleepy, so I do this for now.
+        // Ugly method of ensuring that the offset isn't inverted. I'm sure there is a better and more elegant way, but I'm starting to get sleepy, so I do this for now.
         {
             Way refWay = ways.get(refWayIndex);
@@ -83,5 +103,5 @@
         }
 
-        //// Initialize the required parameters. (segment normals, etc.)
+        // Initialize the required parameters. (segment normals, etc.)
         nodeCount = sortedNodes.size();
         pts = new EastNorth[nodeCount];
@@ -110,9 +130,7 @@
      */
     public void changeOffset(double d) {
-        //// This is the core algorithm:
-        /* 1. Calculate a parallel line, offset by 'd', to each segment in
-         *    the path
-         * 2. Find the intersection of lines belonging to neighboring
-         *    segments. These become the new node positions
+        // This is the core algorithm:
+        /* 1. Calculate a parallel line, offset by 'd', to each segment in the path
+         * 2. Find the intersection of lines belonging to neighboring segments. These become the new node positions
          * 3. Do some special casing for closed paths
          *
@@ -161,9 +179,6 @@
     private List<Command> makeAddWayAndNodesCommandList() {
         ArrayList<Command> commands = new ArrayList<Command>(sortedNodes.size() + ways.size());
-        for (int i = 0; i < sortedNodes.size() - 1; i++) {
+        for (int i = 0; i < sortedNodes.size() - (isClosedPath() ? 1 : 0); i++) {
             commands.add(new AddCommand(sortedNodes.get(i)));
-        }
-        if (!isClosedPath()) {
-            commands.add(new AddCommand(sortedNodes.get(sortedNodes.size() - 1)));
         }
         for (Way w : ways) {
