diff --git a/src/uk/me/parabola/imgfmt/app/net/RouteNode.java b/src/uk/me/parabola/imgfmt/app/net/RouteNode.java
index 2b8ca79..e86f2de 100644
--- a/src/uk/me/parabola/imgfmt/app/net/RouteNode.java
+++ b/src/uk/me/parabola/imgfmt/app/net/RouteNode.java
@@ -15,6 +15,8 @@
 package uk.me.parabola.imgfmt.app.net;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 
@@ -298,6 +300,12 @@ public class RouteNode implements Comparable<RouteNode> {
 
 		RoadDef rda = raa.getRoadDef();
 		RoadDef rdb = rab.getRoadDef();
+
+		if(rda.getId() == rdb.getId()) {
+			// roads have the same (OSM) id
+			return true;
+		}
+
 		boolean bothArcsNamed = false;
 		for(Label laba : rda.getLabels()) {
 			if(laba != null && laba.getOffset() != 0) {
@@ -339,6 +347,26 @@ public class RouteNode implements Comparable<RouteNode> {
 		return false;
 	}
 
+	private static boolean rightTurnRequired(int inHeading, int outHeading, int sideHeading) {
+		// given the headings of the incoming, outgoing and side
+		// roads, decide whether a side road is to the left or the
+		// right of the main road
+
+		outHeading -= inHeading;
+		while(outHeading < -180)
+			outHeading += 360;
+		while(outHeading > 180)
+			outHeading -= 360;
+
+		sideHeading -= inHeading;
+		while(sideHeading < -180)
+			sideHeading += 360;
+		while(sideHeading > 180)
+			sideHeading -= 360;
+
+		return sideHeading > outHeading;
+	}
+
 	private static int ATH_OUTGOING = 1;
 	private static int ATH_INCOMING = 2;
 
@@ -375,9 +403,29 @@ public class RouteNode implements Comparable<RouteNode> {
 			final int minDiffBetweenOutgoingAndOtherArcs = 45;
 			final int minDiffBetweenIncomingAndOtherArcs = 50;
 
-			for(RouteArc inArc : incomingArcs) {
+			// list of outgoing arcs discovered at this node
+			List<RouteArc> outgoingArcs = new ArrayList<RouteArc>();
+
+			// sort incoming arcs by decreasing class/speed
+			List<RouteArc> inArcs = new ArrayList<RouteArc>(incomingArcs);
+
+			Collections.sort(inArcs, new Comparator<RouteArc>() {
+					public int compare(RouteArc ra1, RouteArc ra2) {
+						int c1 = ra1.getRoadDef().getRoadClass();
+						int c2 = ra2.getRoadDef().getRoadClass();
+						if(c1 == c2)
+							return (ra2.getRoadDef().getRoadSpeed() - 
+									ra1.getRoadDef().getRoadSpeed());
+						return c2 - c1;
+					}
+				});
+
+			// look at incoming arcs in order of decreasing class/speed
+			for(RouteArc inArc : inArcs) {
+
+				RoadDef inRoadDef = inArc.getRoadDef();
 
-				if(!inArc.isForward() && inArc.getRoadDef().isOneway()) {
+				if(!inArc.isForward() && inRoadDef.isOneway()) {
 					// ignore reverse arc if road is oneway
 					continue;
 				}
@@ -392,7 +440,7 @@ public class RouteNode implements Comparable<RouteNode> {
 					for(RouteArc[] pair : throughRoutes) {
 						if(pair[0] == inArc) {
 							outArc = pair[1];
-							log.info("Found through route from " + inArc.getRoadDef() + " to " + outArc.getRoadDef());
+							log.info("Found through route from " + inRoadDef + " to " + outArc.getRoadDef());
 							break;
 						}
 					}
@@ -405,7 +453,7 @@ public class RouteNode implements Comparable<RouteNode> {
 						if(oa.getDest() != inArc.getSource()) {
 							// this arc is not going to the same node as
 							// inArc came from
-							if(oa.getRoadDef() == inArc.getRoadDef()) {
+							if(oa.getRoadDef() == inRoadDef) {
 								outArc = oa;
 								break;
 							}
@@ -415,7 +463,7 @@ public class RouteNode implements Comparable<RouteNode> {
 
 				if(outArc == null) {
 					// next, although the RoadDefs don't match, use
-					// possiblySameRoad() to see if the road
+					// possiblySameRoad() to see if the roads' id or
 					// labels (names/refs) match
 					for(RouteArc oa : arcs) {
 						if(oa.getDest() != inArc.getSource()) {
@@ -430,43 +478,60 @@ public class RouteNode implements Comparable<RouteNode> {
 					}
 				}
 
-				if(outArc == null) {
+				if(outArc == null && inRoadDef.getNumLabels() == 0) {
 					// last ditch attempt to find the outgoing arc -
-					// try and find a single arc that has the same
-					// road class and speed as the incoming arc
-					int inArcClass = inArc.getRoadDef().getRoadClass();
-					int inArcSpeed = inArc.getRoadDef().getRoadSpeed();
+					// try and find a single (anonymous) arc that has
+					// the same road class and speed as the incoming
+					// arc
+					int inArcClass = inRoadDef.getRoadClass();
+					int inArcSpeed = inRoadDef.getRoadSpeed();
 					for(RouteArc oa : arcs) {
-						if(oa.getDest() != inArc.getSource() &&
+						if(oa.getRoadDef().getNumLabels() == 0 &&
+						   oa.getDest() != inArc.getSource() &&
 						   oa.getRoadDef().getRoadClass() == inArcClass &&
 						   oa.getRoadDef().getRoadSpeed() == inArcSpeed) {
 							if(outArc != null) {
 								// multiple arcs have the same road
-								// class as the incoming arc so don't
-								// use any of them as the outgoing arc
+								// class/speed as the incoming arc so
+								// don't use any of them as the
+								// outgoing arc
 								outArc = null;
 								break;
 							}
-							outArc = oa;
+							// oa has the same class/speed as inArc,
+							// now check that oa is not part of
+							// another road by matching names rather
+							// than class/speed because they could be
+							// different
+							boolean paired = false;
+							for(RouteArc z : arcs)
+								if(z != oa && possiblySameRoad(z, oa))
+									paired = true;
+							if(!paired)
+								outArc = oa;
 						}
 					}
 					if(outArc != null)
-						log.info("Matched outgoing arc " + outArc.getRoadDef() + " to " + inArc.getRoadDef() + " using road class (" + inArcClass + ") and speed (" + inArcSpeed + ")"); 
+						log.info("Matched outgoing arc " + outArc.getRoadDef() + " to " + inRoadDef + " using road class (" + inArcClass + ") and speed (" + inArcSpeed + ") at " + coord.toOSMURL()); 
 				}
 
 				// if we did not find the outgoing arc, give up with
 				// this incoming arc
 				if(outArc == null) {
-					//log.info("Can't continue road " + inArc.getRoadDef() + " at " + coord.toOSMURL());
+					//log.info("Can't continue road " + inRoadDef + " at " + coord.toOSMURL());
 					continue;
 				}
+
+				// remember that this arc is an outgoing arc
+				outgoingArcs.add(outArc);
+
 				int outHeading = outArc.getInitialHeading();
 				int mainHeadingDelta = outHeading - inHeading;
 				while(mainHeadingDelta > 180)
 					mainHeadingDelta -= 360;
 				while(mainHeadingDelta < -180)
 					mainHeadingDelta += 360;
-				//log.info(inArc.getRoadDef() + " continues to " + outArc.getRoadDef() + " with a heading change of " + mainHeadingDelta + " at " + coord.toOSMURL());
+				//log.info(inRoadDef + " continues to " + outArc.getRoadDef() + " with a heading change of " + mainHeadingDelta + " at " + coord.toOSMURL());
 
 				if(Math.abs(mainHeadingDelta) > maxMainRoadHeadingChange) {
 					// if the continuation road heading change is
@@ -497,7 +562,7 @@ public class RouteNode implements Comparable<RouteNode> {
 						continue;
 					}
 
-					if(inArc.getRoadDef().isLinkRoad() &&
+					if(inRoadDef.isLinkRoad() &&
 					   otherArc.getRoadDef().isLinkRoad()) {
 						// it's a link road leaving a link road so
 						// leave the angle unchanged to avoid
@@ -507,6 +572,13 @@ public class RouteNode implements Comparable<RouteNode> {
 						continue;
 					}
 
+					if(outgoingArcs.contains(otherArc)) {
+						// this arc was previously matched as an
+						// outgoing arc so we don't want to change its
+						// heading now
+						continue;
+					}
+
 					int otherHeading = otherArc.getInitialHeading();
 					int outToOtherDelta = otherHeading - outHeading;
 					while(outToOtherDelta > 180)
@@ -520,13 +592,13 @@ public class RouteNode implements Comparable<RouteNode> {
 						inToOtherDelta += 360;
 
 					int newHeading = otherHeading;
-					if(outToOtherDelta > 0) {
+					if(rightTurnRequired(inHeading, outHeading, otherHeading)) {
 						// side road to the right
 						if((mask & ATH_OUTGOING) != 0 &&
-						   outToOtherDelta < minDiffBetweenOutgoingAndOtherArcs)
+						   Math.abs(outToOtherDelta) < minDiffBetweenOutgoingAndOtherArcs)
 							newHeading = outHeading + minDiffBetweenOutgoingAndOtherArcs;
 						if((mask & ATH_INCOMING) != 0 &&
-						   inToOtherDelta < minDiffBetweenIncomingAndOtherArcs) {
+						   Math.abs(inToOtherDelta) < minDiffBetweenIncomingAndOtherArcs) {
 							int nh = inHeading + minDiffBetweenIncomingAndOtherArcs;
 							if(nh > newHeading)
 								newHeading = nh;
@@ -535,13 +607,13 @@ public class RouteNode implements Comparable<RouteNode> {
 						if(newHeading > 180)
 							newHeading -= 360;
 					}
-					else if(outToOtherDelta < 0) {
+					else {
 						// side road to the left
 						if((mask & ATH_OUTGOING) != 0 &&
-						   outToOtherDelta > -minDiffBetweenOutgoingAndOtherArcs)
+						   Math.abs(outToOtherDelta) < minDiffBetweenOutgoingAndOtherArcs)
 							newHeading = outHeading - minDiffBetweenOutgoingAndOtherArcs;
 						if((mask & ATH_INCOMING) != 0 &&
-						   inToOtherDelta > -minDiffBetweenIncomingAndOtherArcs) {
+						   Math.abs(inToOtherDelta) < minDiffBetweenIncomingAndOtherArcs) {
 							int nh = inHeading - minDiffBetweenIncomingAndOtherArcs;
 							if(nh < newHeading)
 								newHeading = nh;
@@ -552,7 +624,7 @@ public class RouteNode implements Comparable<RouteNode> {
 					}
 					if(newHeading != otherHeading) {
 						otherArc.setInitialHeading(newHeading);
-						log.info("Adjusting turn heading from " + otherHeading + " to " + newHeading + " at junction of " + inArc.getRoadDef() + " and " + otherArc.getRoadDef() + " at " + coord.toOSMURL());
+						log.info("Adjusting turn heading from " + otherHeading + " to " + newHeading + " at junction of " + inRoadDef + " and " + otherArc.getRoadDef() + " at " + coord.toOSMURL());
 					}
 				}
 			}
