Index: /trunk/nodist/data/relation_sort.osm
===================================================================
--- /trunk/nodist/data/relation_sort.osm	(revision 16885)
+++ /trunk/nodist/data/relation_sort.osm	(revision 16886)
@@ -63,4 +63,33 @@
   <node id='-102490' action='modify' lat='0.01036552913' lon='-0.02307676889' />
   <node id='-102492' action='modify' lat='0.01029760301' lon='-0.02173183188' />
+  <node id='-103305' action='modify' lat='0.00917928039' lon='-0.02535833538' />
+  <node id='-103306' action='modify' lat='0.00919265151' lon='-0.02491040287' />
+  <node id='-103307' action='modify' lat='0.00941996054' lon='-0.02466303715' />
+  <node id='-103308' action='modify' lat='0.00943333166' lon='-0.0242886458' />
+  <node id='-103309' action='modify' lat='0.00918596595' lon='-0.02404796564' />
+  <node id='-103310' action='modify' lat='0.00920602263' lon='-0.02374042989' />
+  <node id='-103311' action='modify' lat='0.0094266461' lon='-0.02356660533' />
+  <node id='-103312' action='modify' lat='0.00944001722' lon='-0.02323232734' />
+  <node id='-103313' action='modify' lat='0.00923945043' lon='-0.02305181722' />
+  <node id='-103314' action='modify' lat='0.00943333166' lon='-0.02283119374' />
+  <node id='-103315' action='modify' lat='0.0094266461' lon='-0.02251697243' />
+  <node id='-103316' action='modify' lat='0.00924613599' lon='-0.02232309119' />
+  <node id='-103317' action='modify' lat='0.00925950711' lon='-0.02201555543' />
+  <node id='-103318' action='modify' lat='0.00909236811' lon='-0.02257045691' />
+  <node id='-103319' action='modify' lat='0.00911242479' lon='-0.02281782262' />
+  <node id='-103320' action='modify' lat='0.00903219807' lon='-0.0232724407' />
+  <node id='-103321' action='modify' lat='0.00903888363' lon='-0.02356660533' />
+  <node id='-103322' action='modify' lat='0.00898539915' lon='-0.02424853244' />
+  <node id='-103323' action='modify' lat='0.00899877027' lon='-0.02461623823' />
+  <node id='-103324' action='modify' lat='0.00851740997' lon='-0.02201555543' />
+  <node id='-103325' action='modify' lat='0.00847729661' lon='-0.0254051343' />
+  <node id='-103326' action='modify' lat='0.00796919406' lon='-0.02515776859' />
+  <node id='-103327' action='modify' lat='0.0079959363' lon='-0.02430870248' />
+  <node id='-103328' action='modify' lat='0.00801599298' lon='-0.02347300749' />
+  <node id='-103329' action='modify' lat='0.0080293641' lon='-0.02221612223' />
+  <node id='-103330' action='modify' lat='0.00765497275' lon='-0.02223617891' />
+  <node id='-103331' action='modify' lat='0.00766165831' lon='-0.02343289413' />
+  <node id='-103332' action='modify' lat='0.00765497275' lon='-0.02426190356' />
+  <node id='-103333' action='modify' lat='0.00766165831' lon='-0.02509091299' />
   <way id='-102455' action='modify'>
     <nd ref='-102406' />
@@ -188,4 +217,146 @@
     <tag k='name' v='t4w7' />
     <tag k='oneway' v='yes' />
+  </way>
+  <way id='-103860' action='modify'>
+    <nd ref='-103306' />
+    <nd ref='-103307' />
+    <tag k='name' v='t5w2a' />
+  </way>
+  <way id='-103861' action='modify'>
+    <nd ref='-103316' />
+    <nd ref='-103318' />
+    <tag k='name' v='t5w11b' />
+  </way>
+  <way id='-103862' action='modify'>
+    <nd ref='-103309' />
+    <nd ref='-103322' />
+    <tag k='name' v='t5w4b' />
+  </way>
+  <way id='-103863' action='modify'>
+    <nd ref='-103313' />
+    <nd ref='-103320' />
+    <tag k='name' v='t5w8b' />
+  </way>
+  <way id='-103864' action='modify'>
+    <nd ref='-103305' />
+    <nd ref='-103306' />
+    <tag k='name' v='t5w1' />
+  </way>
+  <way id='-103865' action='modify'>
+    <nd ref='-103309' />
+    <nd ref='-103310' />
+    <tag k='name' v='t5w5' />
+  </way>
+  <way id='-103866' action='modify'>
+    <nd ref='-103311' />
+    <nd ref='-103312' />
+    <tag k='name' v='t5w7a' />
+  </way>
+  <way id='-103867' action='modify'>
+    <nd ref='-103314' />
+    <nd ref='-103315' />
+    <tag k='name' v='t5w10a' />
+  </way>
+  <way id='-103868' action='modify'>
+    <nd ref='-103317' />
+    <nd ref='-103324' />
+    <nd ref='-103325' />
+    <nd ref='-103305' />
+    <tag k='name' v='t5w13' />
+  </way>
+  <way id='-103869' action='modify'>
+    <nd ref='-103308' />
+    <nd ref='-103309' />
+    <tag k='name' v='t5w4a' />
+  </way>
+  <way id='-103870' action='modify'>
+    <nd ref='-103307' />
+    <nd ref='-103308' />
+    <tag k='name' v='t5w3a' />
+  </way>
+  <way id='-103871' action='modify'>
+    <nd ref='-103323' />
+    <nd ref='-103306' />
+    <tag k='name' v='t5w2b' />
+  </way>
+  <way id='-103872' action='modify'>
+    <nd ref='-103322' />
+    <nd ref='-103323' />
+    <tag k='name' v='t5w3b' />
+  </way>
+  <way id='-103873' action='modify'>
+    <nd ref='-103321' />
+    <nd ref='-103310' />
+    <tag k='name' v='t5w6b' />
+  </way>
+  <way id='-103874' action='modify'>
+    <nd ref='-103310' />
+    <nd ref='-103311' />
+    <tag k='name' v='t5w6a' />
+  </way>
+  <way id='-103875' action='modify'>
+    <nd ref='-103312' />
+    <nd ref='-103313' />
+    <tag k='name' v='t5w8a' />
+  </way>
+  <way id='-103876' action='modify'>
+    <nd ref='-103320' />
+    <nd ref='-103321' />
+    <tag k='name' v='t5w7b' />
+  </way>
+  <way id='-103877' action='modify'>
+    <nd ref='-103319' />
+    <nd ref='-103313' />
+    <tag k='name' v='t5w9b' />
+  </way>
+  <way id='-103878' action='modify'>
+    <nd ref='-103313' />
+    <nd ref='-103314' />
+    <tag k='name' v='t5w9a' />
+  </way>
+  <way id='-103879' action='modify'>
+    <nd ref='-103315' />
+    <nd ref='-103316' />
+    <tag k='name' v='t5w11a' />
+  </way>
+  <way id='-103880' action='modify'>
+    <nd ref='-103318' />
+    <nd ref='-103319' />
+    <tag k='name' v='t5w10b' />
+  </way>
+  <way id='-103881' action='modify'>
+    <nd ref='-103316' />
+    <nd ref='-103317' />
+    <tag k='name' v='t5w12' />
+  </way>
+  <way id='-103882' action='modify'>
+    <nd ref='-103326' />
+    <nd ref='-103327' />
+    <tag k='name' v='t6w1a' />
+  </way>
+  <way id='-103883' action='modify'>
+    <nd ref='-103330' />
+    <nd ref='-103331' />
+    <tag k='name' v='t6w3b' />
+  </way>
+  <way id='-103884' action='modify'>
+    <nd ref='-103327' />
+    <nd ref='-103328' />
+    <tag k='name' v='t6w2a' />
+  </way>
+  <way id='-103885' action='modify'>
+    <nd ref='-103328' />
+    <nd ref='-103329' />
+    <tag k='name' v='t6w3a' />
+  </way>
+  <way id='-103886' action='modify'>
+    <nd ref='-103331' />
+    <nd ref='-103332' />
+    <tag k='name' v='t6w2b' />
+  </way>
+  <way id='-103887' action='modify'>
+    <nd ref='-103332' />
+    <nd ref='-103333' />
+    <tag k='name' v='t6w1b' />
   </way>
   <relation id='-102471' action='modify'>
@@ -198,4 +369,5 @@
     <member type='node' ref='-102394' role='tree' />
     <member type='node' ref='-102454' role='house' />
+    <tag k='name' v='street' />
     <tag k='test' v='street' />
     <tag k='type' v='street' />
@@ -209,4 +381,5 @@
     <member type='way' ref='-102458' role='forward' />
     <member type='way' ref='-102460' role='' />
+    <tag k='name' v='loop' />
     <tag k='test' v='loop' />
   </relation>
@@ -221,4 +394,5 @@
     <member type='node' ref='-102434' role='' />
     <member type='node' ref='-102438' role='' />
+    <tag k='name' v='generic' />
     <tag k='test' v='generic' />
   </relation>
@@ -230,4 +404,5 @@
     <member type='way' ref='-102469' role='street' />
     <member type='node' ref='-102454' role='house' />
+    <tag k='name' v='associatedStreet' />
     <tag k='test' v='associatedStreet' />
     <tag k='type' v='associatedStreet' />
@@ -241,5 +416,144 @@
     <member type='way' ref='-102503' role='' />
     <member type='way' ref='-102504' role='' />
+    <tag k='name' v='direction' />
     <tag k='test' v='direction' />
   </relation>
+  <relation id='-102591' action='modify'>
+    <member type='way' ref='-103864' role='' />
+    <member type='way' ref='-103881' role='' />
+    <member type='way' ref='-103874' role='forward' />
+    <member type='way' ref='-103870' role='forward' />
+    <member type='way' ref='-103875' role='forward' />
+    <member type='way' ref='-103867' role='forward' />
+    <member type='way' ref='-103873' role='forward' />
+    <member type='way' ref='-103878' role='forward' />
+    <member type='way' ref='-103871' role='forward' />
+    <member type='way' ref='-103879' role='forward' />
+    <member type='way' ref='-103860' role='forward' />
+    <member type='way' ref='-103880' role='forward' />
+    <member type='way' ref='-103865' role='' />
+    <member type='way' ref='-103866' role='forward' />
+    <member type='way' ref='-103876' role='forward' />
+    <member type='way' ref='-103862' role='forward' />
+    <member type='way' ref='-103861' role='forward' />
+    <member type='way' ref='-103872' role='forward' />
+    <member type='way' ref='-103869' role='forward' />
+    <member type='way' ref='-103877' role='forward' />
+    <member type='way' ref='-103863' role='forward' />
+    <tag k='name' v='three-loops-ends-way' />
+    <tag k='test' v='three-loops-ends-way' />
+  </relation>
+  <relation id='-102592' action='modify'>
+    <member type='way' ref='-103874' role='forward' />
+    <member type='way' ref='-103861' role='forward' />
+    <member type='way' ref='-103866' role='forward' />
+    <member type='way' ref='-103873' role='forward' />
+    <member type='way' ref='-103880' role='forward' />
+    <member type='way' ref='-103867' role='forward' />
+    <member type='way' ref='-103872' role='forward' />
+    <member type='way' ref='-103862' role='forward' />
+    <member type='way' ref='-103865' role='' />
+    <member type='way' ref='-103870' role='forward' />
+    <member type='way' ref='-103876' role='forward' />
+    <member type='way' ref='-103875' role='forward' />
+    <member type='way' ref='-103877' role='forward' />
+    <member type='way' ref='-103869' role='forward' />
+    <member type='way' ref='-103860' role='forward' />
+    <member type='way' ref='-103871' role='forward' />
+    <member type='way' ref='-103863' role='forward' />
+    <member type='way' ref='-103879' role='forward' />
+    <member type='way' ref='-103878' role='forward' />
+    <tag k='name' v='three-loops-ends-node' />
+    <tag k='test' v='three-loops-ends-node' />
+  </relation>
+  <relation id='-102593' action='modify'>
+    <member type='way' ref='-103865' role='' />
+    <member type='way' ref='-103874' role='forward' />
+    <member type='way' ref='-103872' role='forward' />
+    <member type='way' ref='-103878' role='forward' />
+    <member type='way' ref='-103880' role='forward' />
+    <member type='way' ref='-103869' role='forward' />
+    <member type='way' ref='-103863' role='forward' />
+    <member type='way' ref='-103862' role='forward' />
+    <member type='way' ref='-103876' role='forward' />
+    <member type='way' ref='-103866' role='forward' />
+    <member type='way' ref='-103873' role='forward' />
+    <member type='way' ref='-103877' role='forward' />
+    <member type='way' ref='-103875' role='forward' />
+    <member type='way' ref='-103867' role='forward' />
+    <member type='way' ref='-103870' role='forward' />
+    <tag k='name' v='one-loop-ends-split' />
+    <tag k='test' v='one-loop-ends-split' />
+  </relation>
+  <relation id='-102594' action='modify'>
+    <member type='way' ref='-103866' role='forward' />
+    <member type='way' ref='-103875' role='forward' />
+    <member type='way' ref='-103876' role='forward' />
+    <member type='way' ref='-103863' role='forward' />
+    <member type='way' ref='-103878' role='forward' />
+    <member type='way' ref='-103867' role='forward' />
+    <member type='way' ref='-103877' role='forward' />
+    <member type='way' ref='-103880' role='forward' />
+    <tag k='name' v='no-loop-ends-split' />
+    <tag k='test' v='no-loop-ends-split' />
+  </relation>
+  <relation id='-102595' action='modify'>
+    <member type='way' ref='-103864' role='' />
+    <member type='way' ref='-103876' role='forward' />
+    <member type='way' ref='-103870' role='forward' />
+    <member type='way' ref='-103873' role='forward' />
+    <member type='way' ref='-103867' role='forward' />
+    <member type='way' ref='-103869' role='forward' />
+    <member type='way' ref='-103872' role='forward' />
+    <member type='way' ref='-103874' role='forward' />
+    <member type='way' ref='-103879' role='forward' />
+    <member type='way' ref='-103877' role='forward' />
+    <member type='way' ref='-103861' role='forward' />
+    <member type='way' ref='-103865' role='' />
+    <member type='way' ref='-103863' role='forward' />
+    <member type='way' ref='-103868' role='' />
+    <member type='way' ref='-103860' role='forward' />
+    <member type='way' ref='-103871' role='forward' />
+    <member type='way' ref='-103866' role='forward' />
+    <member type='way' ref='-103875' role='forward' />
+    <member type='way' ref='-103862' role='forward' />
+    <member type='way' ref='-103881' role='' />
+    <member type='way' ref='-103880' role='forward' />
+    <member type='way' ref='-103878' role='forward' />
+    <tag k='name' v='three-loops-ends-loop' />
+    <tag k='test' v='three-loops-ends-loop' />
+  </relation>
+  <relation id='-102596' action='modify'>
+    <member type='way' ref='-103882' role='forward' />
+    <member type='way' ref='-103887' role='forward' />
+    <member type='way' ref='-103886' role='forward' />
+    <member type='way' ref='-103883' role='forward' />
+    <member type='way' ref='-103885' role='forward' />
+    <member type='way' ref='-103884' role='forward' />
+    <tag k='name' v='parallel-oneway' />
+    <tag k='test' v='parallel-oneway' />
+  </relation>
+  <relation id='-102605' action='modify'>
+    <member type='way' ref='-103864' role='' />
+    <member type='way' ref='-103874' role='forward' />
+    <member type='way' ref='-103870' role='forward' />
+    <member type='way' ref='-103875' role='forward' />
+    <member type='way' ref='-103867' role='forward' />
+    <member type='way' ref='-103873' role='forward' />
+    <member type='way' ref='-103878' role='forward' />
+    <member type='way' ref='-103871' role='forward' />
+    <member type='way' ref='-103879' role='forward' />
+    <member type='way' ref='-103860' role='forward' />
+    <member type='way' ref='-103880' role='forward' />
+    <member type='way' ref='-103865' role='' />
+    <member type='way' ref='-103866' role='forward' />
+    <member type='way' ref='-103876' role='forward' />
+    <member type='way' ref='-103881' role='' />
+    <member type='way' ref='-103861' role='forward' />
+    <member type='way' ref='-103872' role='forward' />
+    <member type='way' ref='-103869' role='forward' />
+    <member type='way' ref='-103877' role='forward' />
+    <tag k='name' v='incomplete-loops' />
+    <tag k='test' v='incomplete-loops' />
+  </relation>
 </osm>
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationNodeMap.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationNodeMap.java	(revision 16885)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationNodeMap.java	(revision 16886)
@@ -177,17 +177,20 @@
     private Integer popForwardOnewayPart(Integer way) {
         if (onewayMap.ways.containsKey(way)) {
-            for (Node n : onewayMap.ways.get(way)) {
-                Integer i = findAdjacentWay(onewayMap, n);
-                if (i == null) {
-                    continue;
-                }
-
-                lastOnewayNode = processBackwardIfEndOfLoopReached(i);
-                if (lastOnewayNode != null)
-                    return popBackwardOnewayPart(firstOneway);
-
-                deleteWayNode(onewayMap, i, n);
-                return i;
-            }
+            Node exitNode = onewayMap.ways.get(way).iterator().next();
+
+            if (checkIfEndOfLoopReached(exitNode)) {
+                lastOnewayNode = exitNode;
+                return popBackwardOnewayPart(firstOneway);
+            }
+
+            Integer i = deleteAndGetAdjacentNode(onewayMap, exitNode);
+            if (i != null) return i;
+
+            // When our forward route ends in a dead end try to start
+            // the backward route anyway from the split point
+            // (firstOneWay), to support routes with split a split start
+            // or end.
+            lastOnewayNode = exitNode;
+            return popBackwardOnewayPart(firstOneway);
         }
 
@@ -196,15 +199,14 @@
     }
 
-    private Node processBackwardIfEndOfLoopReached(Integer way) { //find if we didn't reach end of the loop (and process backward part)
-        if (onewayReverseMap.ways.containsKey(way)) {
-            for (Node n : onewayReverseMap.ways.get(way)) {
-                if (map.nodes.containsKey(n)
-                        || (onewayMap.nodes.containsKey(n) && onewayMap.nodes.get(n).size() > 1))
-                    return n;
-                if (firstCircular != null && firstCircular == n)
-                    return firstCircular;
-            }
-        }
-        return null;
+    // Check if the given node can be the end of the loop (i.e. it has
+    // an outgoing bidirectional or multiple outgoing oneways, or we
+    // looped back to our first circular node)
+    private boolean checkIfEndOfLoopReached(Node n) {
+        if (map.nodes.containsKey(n)
+                || (onewayMap.nodes.containsKey(n) && onewayMap.nodes.get(n).size() > 1))
+            return true;
+        if (firstCircular != null && firstCircular == n)
+            return true;
+        return false;
     }
 
@@ -267,6 +269,9 @@
         } else {
             done(way);
-        }
-        nw.ways.get(way).remove(n);
+            // For bidirectional ways, remove the entry node, so
+            // subsequent lookups will only return the other node(s) as
+            // valid exit nodes.
+            nw.ways.get(way).remove(n);
+        }
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculator.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculator.java	(revision 16885)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculator.java	(revision 16886)
@@ -146,5 +146,5 @@
 
         if (!wct.linkPrev) {
-            wct.direction = determineDirectionOfFirst(i, m);
+            wct.direction = determineDirectionOfFirst(i, m, false);
             if (RelationSortUtils.isOneway(m)) {
                 wct.isOnewayLoopForwardPart = true;
@@ -218,5 +218,5 @@
     }
 
-    private Direction determineDirectionOfFirst(final int i, final RelationMember m) {
+    private Direction determineDirectionOfFirst(final int i, final RelationMember m, boolean reversed) {
         Direction result = RelationSortUtils.roundaboutType(m);
         if (result != NONE)
@@ -224,5 +224,5 @@
 
         if (RelationSortUtils.isOneway(m)) {
-            if (RelationSortUtils.isBackward(m)) return BACKWARD;
+            if (RelationSortUtils.isBackward(m) != reversed) return BACKWARD;
             else return FORWARD;
         } else { /** guess the direction and see if it fits with the next member */
@@ -248,4 +248,27 @@
             }
 
+            // Support split-start routes. When the current way does
+            // not fit as forward or backward and we have no backward
+            // ways yet (onewayBeginning) and the most recent oneway
+            // head starts a new segment (!linkPrev), instead of
+            // disconnecting the current way, make it the start of the
+            // backward route. To render properly, unset isOnewayHead on
+            // the most recent head (since the current backward way does
+            // no longer start there).
+            if (dirFW == NONE && dirBW == NONE && RelationSortUtils.isOneway(m) && !wct.isOnewayHead) {
+                WayConnectionType prevHead = null;
+                for (int j = i - 1; j >= 0; --j) {
+                    if (con.get(j).isOnewayHead) {
+                        prevHead = con.get(j);
+                        break;
+                    }
+                }
+
+                if (prevHead != null && !prevHead.linkPrev) {
+                    dirBW = determineDirectionOfFirst(i, m, true);
+                    prevHead.isOnewayHead = false;
+                }
+            }
+
             if (dirBW != NONE) {
                 onewayBeginning = false;
@@ -269,12 +292,7 @@
             if (dirFW == NONE && dirBW == NONE) {
                 wct.linkPrev = false;
-                if (RelationSortUtils.isOneway(m)) {
-                    wct.isOnewayHead = true;
-                    lastForwardWay = i-1;
-                    lastBackwardWay = i-1;
-                } else {
-                    lastForwardWay = UNCONNECTED;
-                    lastBackwardWay = UNCONNECTED;
-                }
+                wct.isOnewayHead = true;
+                lastForwardWay = i-1;
+                lastBackwardWay = i-1;
                 onewayBeginning = true;
             }
Index: /trunk/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSorterTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSorterTest.java	(revision 16885)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSorterTest.java	(revision 16886)
@@ -59,4 +59,8 @@
     }
 
+    // This cluster of tests checks whether these relations are sorted
+    // as expected, so these relations are of course not sorted in the
+    // data file.
+
     @Test
     public void testGeneric() {
@@ -79,3 +83,101 @@
         Assert.assertArrayEquals(new String[]{"t2w1", "t2w2", "t2n1", "t2n2", "t2n3", "t2n4", "playground", "tree"}, actual);
     }
+
+    // The following cluster of tests does the same, but with various
+    // configurations involving split / dual carriageway routes (i.e.
+    // containing members with role=forward or role=backward). Again,
+    // these are intentionally not already sorted.
+
+    @Test
+    public void testThreeLoopsEndsLoop() {
+        Relation relation = getRelation("three-loops-ends-loop");
+        // Check the first way before sorting, otherwise the sorter
+        // might pick a different loop starting point than expected below
+        Assert.assertEquals("t5w1", relation.getMembers().get(0).getMember().get("name"));
+
+        String[] actual = getNames(sorter.sortMembers(relation.getMembers()));
+        Assert.assertArrayEquals(new String[]{
+            "t5w1", "t5w2a", "t5w3a", "t5w4a", "t5w2b", "t5w3b", "t5w4b",
+            "t5w5", "t5w6a", "t5w7a", "t5w8a", "t5w6b", "t5w7b", "t5w8b",
+            "t5w9a", "t5w10a", "t5w11a", "t5w9b", "t5w10b", "t5w11b",
+            "t5w12", "t5w13",
+        }, actual);
+    }
+
+    @Test
+    public void testThreeLoopsEndsWay() {
+        Relation relation = getRelation("three-loops-ends-way");
+        // Check the first way before sorting, otherwise the sorter
+        // might sort in reverse compared to what is expected below
+        Assert.assertEquals("t5w1", relation.getMembers().get(0).getMember().get("name"));
+
+        String[] actual = getNames(sorter.sortMembers(relation.getMembers()));
+        Assert.assertArrayEquals(new String[]{
+            "t5w1", "t5w2a", "t5w3a", "t5w4a", "t5w2b", "t5w3b", "t5w4b",
+            "t5w5", "t5w6a", "t5w7a", "t5w8a", "t5w6b", "t5w7b", "t5w8b",
+            "t5w9a", "t5w10a", "t5w11a", "t5w9b", "t5w10b", "t5w11b",
+            "t5w12",
+        }, actual);
+    }
+
+    @Test
+    public void testThreeLoopsEndsNode() {
+        Relation relation = getRelation("three-loops-ends-node");
+        String[] actual = getNames(sorter.sortMembers(relation.getMembers()));
+        Assert.assertArrayEquals(new String[]{
+            "t5w4a", "t5w3a", "t5w2a", "t5w2b", "t5w3b", "t5w4b",
+            "t5w5", "t5w6a", "t5w7a", "t5w8a", "t5w6b", "t5w7b", "t5w8b",
+            "t5w9a", "t5w10a", "t5w11a", "t5w11b", "t5w10b", "t5w9b",
+        }, actual);
+    }
+
+    @Test
+    public void testOneLoopEndsSplit() {
+        Relation relation = getRelation("one-loop-ends-split");
+        String[] actual = getNames(sorter.sortMembers(relation.getMembers()));
+        Assert.assertArrayEquals(new String[]{
+            "t5w3a", "t5w4a", "t5w3b", "t5w4b",
+            "t5w5", "t5w6a", "t5w7a", "t5w8a", "t5w6b", "t5w7b", "t5w8b",
+            "t5w9a", "t5w10a", "t5w9b", "t5w10b",
+        }, actual);
+    }
+
+    @Test
+    public void testNoLoopEndsSplit() {
+        Relation relation = getRelation("no-loop-ends-split");
+        // TODO: This is not yet sorted properly, so this route is
+        // presorted in the data file, making this a bit of a dummy test
+        // for now.
+        String[] actual = getNames(relation.getMembers());
+        Assert.assertArrayEquals(new String[]{
+            "t5w7a", "t5w8a", "t5w7b", "t5w8b",
+            "t5w9a", "t5w10a", "t5w9b", "t5w10b",
+        }, actual);
+    }
+
+    @Test
+    public void testIncompleteLoops() {
+        Relation relation = getRelation("incomplete-loops");
+        // TODO: This is not yet sorted perfectly (might not be possible)
+        String[] actual = getNames(sorter.sortMembers(relation.getMembers()));
+        Assert.assertArrayEquals(new String[]{
+            "t5w1", "t5w2a", "t5w3a", "t5w4a", "t5w2b", "t5w3b",
+            "t5w5", "t5w6a", "t5w7a", "t5w8a", "t5w9a", "t5w10a", "t5w11a", "t5w6b", "t5w7b",
+            "t5w12", "t5w11b", "t5w10b", "t5w9b",
+        }, actual);
+    }
+
+    @Test
+    public void testParallelOneWay() {
+        Relation relation = getRelation("parallel-oneway");
+        // TODO: This is not always sorted properly, only when the right
+        // way is already at the top, so check that
+        Assert.assertEquals("t6w1a", relation.getMembers().get(0).getMember().get("name"));
+
+        String[] actual = getNames(sorter.sortMembers(relation.getMembers()));
+        Assert.assertArrayEquals(new String[]{
+            "t6w1a", "t6w2a", "t6w3a",
+            "t6w1b", "t6w2b", "t6w3b",
+        }, actual);
+    }
 }
Index: /trunk/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculatorTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculatorTest.java	(revision 16885)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculatorTest.java	(revision 16886)
@@ -105,4 +105,8 @@
     }
 
+    // This cluster of tests checks the rendering before and after
+    // sorting of a few relations. Initially, these relations are
+    // intentionally not sorted to ensure the sorting has some work.
+
     @Test
     public void testGeneric() {
@@ -130,5 +134,105 @@
         //TODO Sorting doesn't work well in this case
         actual = getConnections(wayConnectionTypeCalculator.updateLinks(sorter.sortMembers(relation.getMembers())));
-        Assert.assertEquals("[BACKWARD, BACKWARD, BACKWARD, FPH FORWARD, FPH FORWARD, FPH FORWARD, FPH FORWARD]", actual);
+        Assert.assertEquals("[BACKWARD, BACKWARD, BACKWARD, FP FORWARD, BP BACKWARD, BP BACKWARD, BPT BACKWARD]", actual);
+    }
+
+    // The following cluster of tests checks various configurations
+    // involving split / dual carriageway routes (i.e. containing
+    // members with role=forward or role=backward). Again, these are
+    // intentionally not sorted.
+
+    @Test
+    public void testThreeLoopsEndsLoop() {
+        Relation relation = getRelation("three-loops-ends-loop");
+        // Check the first way before sorting, otherwise the sorter
+        // might pick a different loop starting point than expected below
+        Assert.assertEquals("t5w1", relation.getMembers().get(0).getMember().get("name"));
+        String actual = getConnections(wayConnectionTypeCalculator.updateLinks(sorter.sortMembers(relation.getMembers())));
+        String expected = "[" +
+            "L FORWARD, LFPH FORWARD, LFP FORWARD, LFP FORWARD, LBP BACKWARD, LBP BACKWARD, LBPT BACKWARD, " +
+            "L FORWARD, LFPH FORWARD, LFP FORWARD, LFP FORWARD, LBP BACKWARD, LBP BACKWARD, LBPT BACKWARD, " +
+            "LFPH FORWARD, LFP FORWARD, LFP FORWARD, LBP BACKWARD, LBP BACKWARD, LBPT BACKWARD, " +
+            "L FORWARD, L FORWARD" +
+        "]";
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testThreeLoopsEndsWay() {
+        Relation relation = getRelation("three-loops-ends-way");
+        // Check the first way before sorting, otherwise the sorter
+        // might sort in reverse compared to what is expected below
+        Assert.assertEquals("t5w1", relation.getMembers().get(0).getMember().get("name"));
+        String actual = getConnections(wayConnectionTypeCalculator.updateLinks(sorter.sortMembers(relation.getMembers())));
+        String expected = "[" +
+            "FORWARD, FPH FORWARD, FP FORWARD, FP FORWARD, BP BACKWARD, BP BACKWARD, BPT BACKWARD, " +
+            "FORWARD, FPH FORWARD, FP FORWARD, FP FORWARD, BP BACKWARD, BP BACKWARD, BPT BACKWARD, " +
+            "FPH FORWARD, FP FORWARD, FP FORWARD, BP BACKWARD, BP BACKWARD, BPT BACKWARD, " +
+            "FORWARD" +
+        "]";
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testThreeLoopsEndsNode() {
+        Relation relation = getRelation("three-loops-ends-node");
+        String actual = getConnections(wayConnectionTypeCalculator.updateLinks(sorter.sortMembers(relation.getMembers())));
+        String expected = "[" +
+            "FPH FORWARD, BP BACKWARD, BP BACKWARD, BP BACKWARD, BP BACKWARD, BPT BACKWARD, " +
+            "FORWARD, FPH FORWARD, FP FORWARD, FP FORWARD, BP BACKWARD, BP BACKWARD, BPT BACKWARD, " +
+            "FPH FORWARD, FP FORWARD, FP FORWARD, FP FORWARD, FP FORWARD, BPT BACKWARD" +
+        "]";
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testOneLoopEndsSplit() {
+        Relation relation = getRelation("one-loop-ends-split");
+        String actual = getConnections(wayConnectionTypeCalculator.updateLinks(sorter.sortMembers(relation.getMembers())));
+        String expected = "[" +
+            "FP FORWARD, FP FORWARD, BP BACKWARD, BPT BACKWARD, " +
+            "FORWARD, FPH FORWARD, FP FORWARD, FP FORWARD, BP BACKWARD, BP BACKWARD, BPT BACKWARD, " +
+            "FPH FORWARD, FP FORWARD, BP BACKWARD, BP BACKWARD" +
+        "]";
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testNoLoopEndsSplit() {
+        Relation relation = getRelation("no-loop-ends-split");
+        // TODO: This is not yet sorted properly, so this route is
+        // presorted in the data file
+        String actual = getConnections(wayConnectionTypeCalculator.updateLinks(relation.getMembers()));
+        String expected = "[" +
+            "FP FORWARD, FP FORWARD, BP BACKWARD, BPT BACKWARD, " +
+            "FPH FORWARD, FP FORWARD, BP BACKWARD, BP BACKWARD" +
+        "]";
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testIncompleteLoops() {
+        Relation relation = getRelation("incomplete-loops");
+        // TODO: This is not yet sorted perfectly (might not be possible)
+        String actual = getConnections(wayConnectionTypeCalculator.updateLinks(sorter.sortMembers(relation.getMembers())));
+        String expected = "[" +
+            "FORWARD, FPH FORWARD, FP FORWARD, FP FORWARD, BP BACKWARD, BP BACKWARD, " +
+            "FORWARD, FPH FORWARD, FP FORWARD, FP FORWARD, FP FORWARD, FP FORWARD, FP FORWARD, BP BACKWARD, BP BACKWARD, " +
+            "BACKWARD, FPH FORWARD, FP FORWARD, FP FORWARD" +
+        "]";
+        Assert.assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testParallelOneWay() {
+        Relation relation = getRelation("parallel-oneway");
+        // TODO: This is not always sorted properly, only when the right
+        // way is already at the top, so check that
+        Assert.assertEquals("t6w1a", relation.getMembers().get(0).getMember().get("name"));
+        String actual = getConnections(wayConnectionTypeCalculator.updateLinks(sorter.sortMembers(relation.getMembers())));
+        String expected = "[" +
+            "FP FORWARD, FP FORWARD, FP FORWARD, BP BACKWARD, BP BACKWARD, BP BACKWARD" +
+        "]";
+        Assert.assertEquals(expected, actual);
     }
 
