Index: src/uk/me/parabola/imgfmt/app/net/AngleChecker.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/AngleChecker.java	(revision 4921)
+++ src/uk/me/parabola/imgfmt/app/net/AngleChecker.java	(working copy)
@@ -68,8 +68,9 @@
 	// If this is >= above, then compactDirs will be used unless other, non-vehicle access angles are sharp
 	private static final float SHARP_DEGREES = COMPACT_DIR_DEGREES;
 	// Experimentation found no benefit in increasing angle beyond 2 "sectors"
-	private static final float MIN_ANGLE = 11.25f; // don't reduce angles to less than this (arbitrary)
-	
+	private static final float MIN_ANGLE = 23f; // don't reduce angles to less than this (1 sector + bit)
+	private static final float STRAIGHT_EPSILON = 3f; // for angle.straightAnough()
+
 	// helper class to collect multiple arcs with (nearly) the same initial headings
 	private class ArcGroup {
 		float initialHeading;
@@ -106,7 +107,27 @@
 		public boolean isForward() {
 			return isForwardTrueCount == arcs.size();
 		}
-		
+
+		public boolean sameWay(ArcGroup other) {
+			for (RoadDef thisRoad : roadDefs)
+				for (RoadDef otherRoad : other.roadDefs) {
+					if (thisRoad.getId() == otherRoad.getId())
+						return true;
+				}
+			return false;
+		}
+
+		public boolean sameName(ArcGroup other) {
+			for (RoadDef thisRoad : roadDefs)
+				for (RoadDef otherRoad : other.roadDefs) {
+					String thisName = thisRoad.getName();
+					if (thisName != null)
+						if (thisName.equals(otherRoad.getName()))
+							return true;
+				}
+			return false;
+		}
+
 		public void modInitialHeading(float modIH) {
 			initialHeading += modIH;
 			if (initialHeading >= 180)
@@ -116,6 +137,7 @@
 
 			for (RouteArc arc : arcs) {
 				arc.modInitialHeading(modIH);
+				log.info("modInitHead", arc, modIH, initialHeading);
 			}
 		}
 
@@ -152,12 +174,20 @@
 
 		// Combine arcs with nearly the same initial heading.
 
+		if (log.isInfoEnabled())
+			log.info("fixSharpAngles", node, sharpAnglesCheckMask, arcs.size());
+
 		// first get direct arcs leaving the node
 		List<RouteArc> directArcs = new ArrayList<>();
 		for (RouteArc arc : arcs) {
-			if (arc.isDirect())
+			if (arc.isDirect()) {
+				if (log.isInfoEnabled()) {
+					RoadDef rd = arc.getRoadDef();
+					log.info("directArc", /*arc,*/ arc.getInitialHeading(), rd.getId(), rd.getName(),
+							 rd.getRoadSpeed(), rd.getRoadClass(), rd.paved());
+				}
 				directArcs.add(arc);
-			else
+			} else
 				// AngleChecker runs before addArcsToMajorRoads so there shouldn't be any indirect arcs yet.
 				// If this changes, extra care needs to be taken check they are positioned correctly in the list
 				// of arcs or that their heading is kept consistent with changes to their direct base arc.
@@ -237,6 +267,11 @@
 		class AngleAttr {
 			float angle;
 			float minAngle;
+
+			private boolean straightAnough() {
+				return angle > 180-STRAIGHT_EPSILON && angle < 180+STRAIGHT_EPSILON;
+			}
+
 		}
 
 		AngleAttr[] angles = new AngleAttr[n];
@@ -249,6 +284,8 @@
 			if (i+1 >= n)
 				aa.angle += 360;
 			aa.minAngle = Math.min(MIN_ANGLE, aa.angle);
+			log.info("AngleCalc", node, ag1.getInitialHeading(), aa.angle, ag2.getInitialHeading(), aa.minAngle);
+
 			float saveMinAngle = aa.minAngle;
 
 			if (ag1.isOneway() && ag2.isOneway() && (ag1.isForward() == ag2.isForward()))
@@ -317,8 +354,10 @@
 			if (wantedIncrement <= 0)
 				continue;
 			float oldAngle = aa.angle;
+			ArcGroup ag0 = null;
 			ArcGroup ag1 = arcGroups.get(i);
 			ArcGroup ag2 = arcGroups.get(i+1 < n ? i+1 : 0);
+			ArcGroup ag3 = null;
 			if (log.isInfoEnabled()){
 				log.info("sharp angle", aa.angle, "° at", node.getCoord(),
 						 "headings", getCompassBearing(ag1.getInitialHeading()), getCompassBearing(ag2.getInitialHeading()),
@@ -336,13 +375,47 @@
 			float deltaNext = nextAA.angle - nextAA.minAngle;
 
 			if (deltaNext > 0 && deltaPred > 0) { // can take from both
-				if (ag1.maxRoadClass == ag2.maxRoadClass &&
-					ag1.maxRoadSpeed == ag2.maxRoadSpeed) { // take from both in ratio to available
+				int chooseWhich = 0; // -ve to prefer to take from prev, +ve take from next
+				// order of {road_class, sameWay, straightness, roadName, road_speed} adjusted for priority
+				// Hoping sameWay before road_class fixing more problems than it might cause
+				if (chooseWhich == 0)
+					chooseWhich = ag1.maxRoadClass - ag2.maxRoadClass;
+				if (chooseWhich == 0) {
+					// if the two arcs either side of the sharp angle belong to the same
+					// way then change the arc on the other side hoping to trigger
+					// the correct turn-instruction
+					ag0 = arcGroups.get(i > 0 ? i-1 : n-1);
+					ag3 = n == 3 ? ag0 : arcGroups.get(i+2 < n ? i+2 : i+2-n);
+					if (ag2.sameWay(ag3))
+						chooseWhich = -1;
+					else if (ag1.sameWay(ag0))
+						chooseWhich = +1;
+				}
+				if (chooseWhich == 0) {
+					// where there is a straight road with a sharp turn-off then just adjust
+					// the turn-off. This is treated as a special case because the general
+					// logic below will adjust the adjust the straight road slightly more
+					// than the turn-off and, in some cases, with compactDirs, turn-instructions
+					if (nextAA.straightAnough())
+						chooseWhich = -1;
+					else if (predAA.straightAnough())
+						chooseWhich = +1;
+				}
+				if (chooseWhich == 0) {
+					// NB set ag0 & 3 if move this before sameWay()
+					// Way might have changed but could still be the same road by name or ref
+					if (ag2.sameName(ag3))
+						chooseWhich = -1;
+					else if (ag1.sameName(ag0))
+						chooseWhich = +1;
+				}
+				if (chooseWhich == 0)
+					chooseWhich = ag1.maxRoadSpeed - ag2.maxRoadSpeed;
+
+				if (chooseWhich == 0 ) { // take from both in ratio to available
 					deltaNext = Math.min(deltaNext, wantedIncrement * deltaNext / (deltaNext + deltaPred));
 					deltaPred = Math.min(deltaPred, wantedIncrement - deltaNext);
-			    } else if (ag1.maxRoadClass > ag2.maxRoadClass ||
-						   (ag1.maxRoadClass == ag2.maxRoadClass &&
-							ag1.maxRoadSpeed > ag2.maxRoadSpeed)) { // take as much as poss from next
+				} else if (chooseWhich > 0) { // take as much as poss from next
 					if (deltaNext >= wantedIncrement) {
 						deltaNext = wantedIncrement;
 						deltaPred = 0;
@@ -349,7 +422,7 @@
 					} else {
 						deltaPred = Math.min(deltaPred, wantedIncrement - deltaNext);
 					}
-				} else  { // take as much as possible from pred
+				} else { // take as much as possible from pred
 					if (deltaPred >= wantedIncrement) {
 						deltaPred = wantedIncrement;
 						deltaNext = 0;
@@ -357,6 +430,7 @@
 						deltaNext = Math.min(deltaNext, wantedIncrement - deltaPred);
 					}
 				}
+
 			} else if (deltaNext > 0) {
 				if (deltaNext > wantedIncrement)
 					deltaNext = wantedIncrement;
Index: src/uk/me/parabola/imgfmt/app/net/RouteArc.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/RouteArc.java	(revision 4921)
+++ src/uk/me/parabola/imgfmt/app/net/RouteArc.java	(working copy)
@@ -418,7 +418,9 @@
 			int compactedRatio = lengthRatio / 2 - 8;
 			assert compactedRatio > 0 && compactedRatio < 8;
 			curveData = new int[1];
-			curveData[0] = (compactedRatio << 5) | ((dh >> 3) & 0x1f);
+			//curveData[0] = (compactedRatio << 5) | ((dh >> 3) & 0x1f);
+			//try rounding this as well
+			curveData[0] = (compactedRatio << 5) | (((dh+4) >> 3) & 0x1f);
 			
 			/* check math:
 			int dhx = curveData[0] & 0x1f;
