Index: src/uk/me/parabola/imgfmt/app/Coord.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/Coord.java	(revision 3631)
+++ src/uk/me/parabola/imgfmt/app/Coord.java	(working copy)
@@ -49,6 +49,7 @@
 	private final static short PART_OF_SHAPE2 = 0x0100; // use only in ShapeMerger
 	private final static short END_OF_WAY = 0x0200; // use only in WrongAngleFixer
 	private final static short HOUSENUMBER_NODE = 0x0400; // start/end of house number interval
+	private final static short ADDED_HOUSENUMBER_NODE = 0x0800; // node was added for house numbers
 	
 	public final static int HIGH_PREC_BITS = 30;
 	public final static int DELTA_SHIFT = 6;
@@ -88,7 +89,7 @@
 		int lon30 = toBit30(longitude);
 		this.latDelta = (byte) ((this.latitude << 6) - lat30); 
 		this.lonDelta = (byte) ((this.longitude << 6) - lon30);
-		
+
 		// verify math
 		assert (this.latitude << 6) - latDelta == lat30;
 		assert (this.longitude << 6) - lonDelta == lon30;
@@ -340,7 +341,6 @@
 	}
 	
 	/**
-	 * Set or unset flag for {@link WrongAngleFixer} 
 	 * @param b true or false
 	 */
 	public void setNumberNode(boolean b) {
@@ -350,6 +350,23 @@
 			this.flags &= ~HOUSENUMBER_NODE; 
 	}
 	
+	/**
+	 * @return if this is the beginning/end of a house number interval 
+	 */
+	public boolean isAddedNumberNode(){
+		return (flags & ADDED_HOUSENUMBER_NODE) != 0;
+	}
+	
+	/**
+	 * @param b true or false
+	 */
+	public void setAddedNumberNode(boolean b) {
+		if (b) 
+			this.flags |= ADDED_HOUSENUMBER_NODE;
+		else 
+			this.flags &= ~ADDED_HOUSENUMBER_NODE; 
+	}
+	
 	public int hashCode() {
 		// Use a factor for latitude to span over the whole integer range:
 		// max lat: 4194304
Index: src/uk/me/parabola/imgfmt/app/net/AngleChecker.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/AngleChecker.java	(nonexistent)
+++ src/uk/me/parabola/imgfmt/app/net/AngleChecker.java	(working copy)
@@ -0,0 +1,274 @@
+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;
+import java.util.Map;
+
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.util.EnhancedProperties;
+
+public class AngleChecker {
+	private static final Logger log = Logger.getLogger(AngleChecker.class);
+
+	private boolean fixSharpAngles;
+	private boolean cycleMap;
+
+
+	// helper class to collect multiple arcs with the same points
+	private class ArcGroup {
+		float initialHeading;
+		int isOneWayTrueCount;
+		int isForwardTrueCount;
+		int maxRoadSpeed;
+		byte orAccessMask;
+		
+		List<RouteArc> arcs = new ArrayList<>();  
+		public void addArc(RouteArc arc) {
+			arcs.add(arc);
+			if (arc.getRoadDef().isOneway())
+				isOneWayTrueCount++;
+			if (arc.isForward())
+				isForwardTrueCount++;
+			if (arc.getRoadDef().getRoadSpeed() > maxRoadSpeed)
+				maxRoadSpeed = arc.getRoadDef().getRoadSpeed();
+			orAccessMask |= arc.getRoadDef().getAccess();
+		}
+		public float getInitialHeading() {
+			return initialHeading;
+		}
+		public boolean isOneway() {
+			return isOneWayTrueCount == arcs.size();
+		}
+		public boolean isForward() {
+			return isForwardTrueCount == arcs.size();
+		}
+		public RouteNode getDest() {
+			return arcs.get(0).getDest();
+		}
+		public void setInitialHeading(float modIH) {
+			initialHeading = modIH;
+			for (RouteArc arc : arcs){
+				arc.setInitialHeading(modIH);
+			}
+		}
+		public String toString(){
+			return arcs.get(0).toString();
+		}
+	}
+	
+	public void config(EnhancedProperties props) {
+		fixSharpAngles = props.getProperty("fix-sharp-angles", false);
+		cycleMap = props.getProperty("cycle-map", false);
+	}
+
+	public void check(Map<Integer, RouteNode> nodes) {
+		if (fixSharpAngles){
+			byte sharpAnglesCheckMask = cycleMap ? (byte) (0xff & ~AccessTagsAndBits.FOOT) : AccessTagsAndBits.BIKE;
+
+			for (RouteNode node : nodes.values()){
+				fixSharpAngles(node, sharpAnglesCheckMask);				
+			}
+		}
+	}
+
+	public void fixSharpAngles(RouteNode node, byte sharpAnglesCheckMask) {
+		// get direct arcs leaving the node
+		
+		List<ArcGroup> arcs = buildArcGroups(node);
+		
+		int n = arcs.size();
+		// sort the arcs by initial heading 
+		Collections.sort(arcs, new Comparator<ArcGroup>() {
+				public int compare(ArcGroup ag1, ArcGroup ag2) {
+					if (ag1.initialHeading < ag2.initialHeading)
+						return -1;
+					if (ag1.initialHeading > ag2.initialHeading)
+						return 1;
+					return 0;
+				}
+			});
+		
+		for (int i = 1; i < n; i++){
+			ArcGroup arc1 = arcs.get(i-1);
+			ArcGroup arc2 = arcs.get(i < n ? i : 0);
+			int angle = Math.round(arc2.getInitialHeading() - arc1.getInitialHeading());
+			int minNeededAngle = 45; // maybe depends on speed or class
+			if (angle >= minNeededAngle) 
+				continue;
+			byte pathAccessMask = (byte) (arc1.orAccessMask & arc2.orAccessMask);
+			if (pathAccessMask == 0){
+				// no common vehicle allowed on both arcs
+				continue;
+			}
+			if (arc1.maxRoadSpeed == 0 && arc2.maxRoadSpeed == 0)
+				continue;
+			if (arc1.isOneway() && arc1.isForward())
+				continue; // the "incoming" arc is a wrong direction oneway 
+			if (arc2.isOneway() && arc2.isForward() == false)
+				continue;// the "outgoing" arc is a wrong direction oneway
+			String sharpAngle = "";
+			if (log.isInfoEnabled()){
+				sharpAngle = "sharp angle "  + angle + "° at " + node.getCoord().toDegreeString();
+				log.info(sharpAngle, "headings",getCompassBearing(arc1.getInitialHeading()) , getCompassBearing(arc2.getInitialHeading()),"speeds",arc1.maxRoadSpeed, arc2.maxRoadSpeed);
+			}
+			
+			// check which vehicles are allowed to use both arcs
+			if (pathAccessMask == AccessTagsAndBits.FOOT){
+				log.info("ignoring", sharpAngle, "because it can only be used by pedestrians");
+				continue;
+			}
+			if ((pathAccessMask & sharpAnglesCheckMask) == 0){
+				log.info("ignoring", sharpAngle, "because it can not be used by bike");
+				continue;
+				
+			}
+			if (arc1.isOneway() && arc2.isOneway()){
+				// both arcs are one-ways, probably the road splits here 
+				// to avoid the sharp angles we are looking for
+				log.info("ignoring", sharpAngle, "because it seems to be a flare road");
+				continue;   
+			}
+
+//			for (RouteRestriction rr : node.getRestrictions()){
+//				if (rr.getArcs().size() > 2) 
+//					continue;
+//				boolean foundRest = false;
+//				if (rr.getArcs().get(0) == arc1 && rr.getArcs().get(1) == arc2){
+//					if ((rr.getMkgmapExeptMask() & pathAccessMask) != 0){
+//						log.info("ignoring", sharpAngle, "because of existing route restriction");
+//						foundRest = true;
+//						break;
+//					}
+//				}
+//				if (foundRest)
+//					continue;
+//			}
+			List<RouteArc> alternativeArcs = arc1.getDest().getDirectArcsBetween(arc2.getDest());
+			if (alternativeArcs.isEmpty() == false){
+				log.info("ignoring", sharpAngle, "because of existing arc between dest nodes",String.format("%.2fm", arc1.getDest().getCoord().distance(arc2.getDest().getCoord())),arc1,arc2, alternativeArcs.get(0));
+				continue;
+			}
+			boolean fixed = false;
+			int wantedIncrement = minNeededAngle - angle;
+			
+			ArcGroup next = arcs.get((i + 1 >= n ? 0 : i+1));
+			int nextAngle = Math.round(next.getInitialHeading() - arc2.getInitialHeading());
+			if (i + 1 >= n)
+				nextAngle += 360;
+			ArcGroup pred = arcs.get((i - 2 < 0 ? n - 1 : i - 2));
+			int predAngle = Math.round(arc1.getInitialHeading() - pred.getInitialHeading());
+			if (i -2 < 0)
+				predAngle += 360;
+			// we can increase the angle by changing the heading values of one or both arcs
+			// XXX: an alternative may be to always change both headings when angles allow it
+			// for now, start decreasing the larger angle 
+			if (nextAngle > minNeededAngle && (nextAngle > predAngle || predAngle - minNeededAngle < wantedIncrement)){
+				int deltaNext = nextAngle - minNeededAngle;
+				int usedIncrement = Math.min(wantedIncrement, deltaNext - 1);
+				float actIH = arc2.getInitialHeading();
+				float modIH = actIH + usedIncrement;
+				if (modIH > 180)
+					modIH -= 360;
+				arc2.setInitialHeading(modIH);
+				int modAngle = Math.round(arc2.getInitialHeading() - arc1.getInitialHeading());
+				if (modAngle < 0)
+					modAngle += 360;
+				if (modAngle >= minNeededAngle)
+					fixed = true;
+				log.info("sharp angle", angle+"°", "at",node.getCoord().toDegreeString(), "changing arc with heading", getCompassBearing(actIH), "->",getCompassBearing(arc2.getInitialHeading()), "angle is now",modAngle+"°");
+				angle = modAngle;
+			} 
+			if (!fixed && predAngle > minNeededAngle){
+				int deltapred = predAngle - minNeededAngle;
+				int usedIncrement = Math.min(wantedIncrement, deltapred - 1);
+				float actIH = arc1.getInitialHeading();
+				float modIH = actIH - usedIncrement;
+				if (modIH < -180)
+					modIH += 360;
+				arc1.setInitialHeading(modIH);
+				int modAngle = Math.round(arc2.getInitialHeading() - arc1.getInitialHeading());
+				if (modAngle < 0)
+					modAngle += 360;
+				if (modAngle >= minNeededAngle)
+					fixed = true;
+				log.info("sharp angle", angle+"°", "at",node.getCoord().toDegreeString(), "changing arc with heading", getCompassBearing(actIH), "->",getCompassBearing(arc1.getInitialHeading()), "angle is now",modAngle+"°");
+				angle = modAngle;
+			}
+			if (!fixed){
+				// XXX maybe add code to create a new MapRoad connecting the destination nodes? 
+				log.info("sharp angle", angle+"°", "at",node.getCoord().toDegreeString(), "don't know how to fix it");
+			}
+			
+		}
+		return;
+	}
+
+	private List<ArcGroup> buildArcGroups(RouteNode node) {
+		List<ArcGroup> arcGroups = new ArrayList<>();
+		List<RouteArc> directArcs = new ArrayList<>();
+		for (RouteArc arc : node.getArcs()){
+			if (arc.isDirect()){
+				directArcs.add(arc);
+			}
+		}
+		if (directArcs.size() < 2)
+			return arcGroups; // should not happen
+		
+		// sort the arcs by initial heading 
+		Collections.sort(directArcs, new Comparator<RouteArc>() {
+				public int compare(RouteArc ra1, RouteArc ra2) {
+					if (ra1.getInitialHeading() < ra2.getInitialHeading())
+						return -1;
+					if (ra1.getInitialHeading() > ra2.getInitialHeading())
+						return 1;
+					int d = Integer.compare(ra1.getPointsHash(), ra2.getPointsHash());
+					if (d != 0)
+						return d;
+					d = Long.compare(ra1.getRoadDef().getId() , ra2.getRoadDef().getId());
+					if (d != 0)
+						return d;
+					return d;
+				}
+			});
+		Iterator<RouteArc> iter = directArcs.listIterator();
+		RouteArc arc1 = iter.next();
+		boolean addArc1 = false;
+		while (iter.hasNext() || addArc1){
+			ArcGroup ag = new ArcGroup();
+			ag.initialHeading = arc1.getInitialHeading();
+			ag.addArc(arc1);
+			arcGroups.add(ag);
+			addArc1 = false;
+			while (iter.hasNext()){
+				RouteArc arc2 = iter.next();
+//				if (arc1.getInitialHeading() == arc2.getInitialHeading()){
+//					if (arc1.getRoadDef().getId() != arc2.getRoadDef().getId()){
+//						log.error(node.getCoord().toDegreeString(), arc1.getPointsHash() == arc2.getPointsHash());
+//					}
+//				}
+				
+				if (Math.abs(arc1.getInitialHeading()- arc2.getInitialHeading()) < 1){
+					if (arc1.getDest() != arc2.getDest())
+						log.warn("sharp angle < 1° at",node.getCoord().toDegreeString(),",maybe duplicated OSM way with bearing",getCompassBearing(arc1.getInitialHeading()));
+					ag.addArc(arc2);
+				} else{
+					arc1 = arc2;
+					if (iter.hasNext() == false)
+						addArc1 = true;
+					break;
+				}
+			}
+		}
+		return arcGroups;
+	}
+
+	private String getCompassBearing (float bearing){
+		float cb = (bearing + 360) % 360;
+		return Math.round(cb) + "°";
+	}
+
+	
+}
Index: src/uk/me/parabola/imgfmt/app/net/RoadNetwork.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/RoadNetwork.java	(revision 3631)
+++ src/uk/me/parabola/imgfmt/app/net/RoadNetwork.java	(working copy)
@@ -29,6 +29,7 @@
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.imgfmt.app.CoordNode;
 import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapDetails;
 import uk.me.parabola.util.EnhancedProperties;
 
 /**
@@ -49,25 +50,22 @@
 	private final List<RouteNode> boundary = new ArrayList<>();
 	private final List<RoadDef> roadDefs = new ArrayList<>();
 	private List<RouteCenter> centers = new ArrayList<>();
-	private int adjustTurnHeadings ;
+	private AngleChecker angleChecker = new AngleChecker();
+
 	private boolean checkRoundabouts;
 	private boolean checkRoundaboutFlares;
 	private int maxFlareLengthRatio ;
 	private boolean reportSimilarArcs;
 
+	public RoadNetwork() {
+	}
+
 	public void config(EnhancedProperties props) {
-		String ath = props.getProperty("adjust-turn-headings");
-		if(ath != null) {
-			if(ath.length() > 0)
-				adjustTurnHeadings = Integer.decode(ath);
-			else
-				adjustTurnHeadings = RouteNode.ATH_DEFAULT_MASK;
-		}
 		checkRoundabouts = props.getProperty("check-roundabouts", false);
 		checkRoundaboutFlares = props.getProperty("check-roundabout-flares", false);
 		maxFlareLengthRatio = props.getProperty("max-flare-length-ratio", 0);
-
 		reportSimilarArcs = props.getProperty("report-similar-arcs", false);
+		angleChecker.config(props);
 	}
 
 	public void addRoad(RoadDef roadDef, List<Coord> coordList) {
@@ -128,7 +126,6 @@
 
 				RouteNode node1 = getOrAddNode(lastId, lastCoord);
 				RouteNode node2 = getOrAddNode(id, co);
-
 				if(node1 == node2)
 					log.error("Road " + roadDef + " contains consecutive identical nodes at " + co.toOSMURL() + " - routing will be broken");
 				else if(arcLength == 0)
@@ -135,25 +132,27 @@
 					log.warn("Road " + roadDef + " contains zero length arc at " + co.toOSMURL());
 
 				Coord forwardBearingPoint = coordList.get(lastIndex + 1);
-				if(lastCoord.equals(forwardBearingPoint)) {
+				if(lastCoord.equals(forwardBearingPoint) || forwardBearingPoint.isAddedNumberNode()) {
 					// bearing point is too close to last node to be
 					// useful - try some more points
 					for(int bi = lastIndex + 2; bi <= index; ++bi) {
-						if(!lastCoord.equals(coordList.get(bi))) {
-							forwardBearingPoint = coordList.get(bi);
-							break;
-						}
+						Coord coTest = coordList.get(bi);
+						if (coTest.isAddedNumberNode() || lastCoord.equals(coTest))
+							continue;
+						forwardBearingPoint = coTest;
+						break;
 					}
 				}
 				Coord reverseBearingPoint = coordList.get(index - 1);
-				if(co.equals(reverseBearingPoint)) {
+				if(co.equals(reverseBearingPoint) || reverseBearingPoint.isAddedNumberNode()) {
 					// bearing point is too close to this node to be
 					// useful - try some more points
 					for(int bi = index - 2; bi >= lastIndex; --bi) {
-						if(!co.equals(coordList.get(bi))) {
-							reverseBearingPoint = coordList.get(bi);
-							break;
-						}
+						Coord coTest = coordList.get(bi);
+						if (coTest.isAddedNumberNode() || co.equals(coTest))
+							continue;
+						reverseBearingPoint = coTest;
+						break;
 					}
 				}
 				
@@ -162,24 +161,16 @@
 
 				double reverseInitialBearing = co.bearingTo(reverseBearingPoint);
 				double directLength = (lastIndex + 1 == index) ? arcLength : lastCoord.distance(co);
-				double reverseFinalBearing, forwardFinalBearing, reverseDirectBearing;
+				double reverseDirectBearing = 0;
 				if (directLength > 0){
 					// bearing on rhumb line is a constant, so we can simply revert
 					reverseDirectBearing = (forwardDirectBearing <= 0) ? 180 + forwardDirectBearing: -(180 - forwardDirectBearing) % 180.0;
-					forwardFinalBearing = (reverseInitialBearing <= 0) ? 180 + reverseInitialBearing : -(180 - reverseInitialBearing) % 180.0;
-					reverseFinalBearing = (forwardInitialBearing <= 0) ? 180 + forwardInitialBearing : -(180 - forwardInitialBearing) % 180.0;
 				}
-				else {
-					reverseDirectBearing = 0;
-					forwardFinalBearing = 0;
-					reverseFinalBearing = 0;
-				}
 				// Create forward arc from node1 to node2
 				RouteArc arc = new RouteArc(roadDef,
 											node1,
 											node2,
 											forwardInitialBearing,
-											forwardFinalBearing,
 											forwardDirectBearing,
 											arcLength,
 											arcLength,
@@ -192,7 +183,6 @@
 				RouteArc reverseArc = new RouteArc(roadDef,
 								   node2, node1,
 								   reverseInitialBearing,
-								   reverseFinalBearing,
 								   reverseDirectBearing,
 								   arcLength,
 								   arcLength,
@@ -269,8 +259,7 @@
 					if(reportSimilarArcs)
 						node.reportSimilarArcs();
 				}
-				if(adjustTurnHeadings != 0)
-					node.tweezeArcs(adjustTurnHeadings);
+				
 				nod1.addNode(node);
 				n++;
 			}
@@ -281,6 +270,7 @@
 
 	public List<RouteCenter> getCenters() {
 		if (centers.isEmpty()){
+			angleChecker.check(nodes);
 			addArcsToMajorRoads();
 			splitCenters();
 		}
Index: src/uk/me/parabola/imgfmt/app/net/RouteArc.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/RouteArc.java	(revision 3631)
+++ src/uk/me/parabola/imgfmt/app/net/RouteArc.java	(working copy)
@@ -43,7 +43,6 @@
 
 	// heading / bearing: 
 	private float initialHeading; // degrees (A-> B in an arc ABCD) 
-	private final float finalHeading; // degrees (C-> D in an arc ABCD)
 	private final float directHeading; // degrees (A-> D in an arc ABCD)
 
 	private final RoadDef roadDef;
@@ -81,7 +80,6 @@
 	 * @param source The source node. (A)
 	 * @param dest The destination node (E).
 	 * @param initialBearing The initial heading (signed degrees) (A->B)
-	 * @param finalBearing The final heading (signed degrees) (D->E)
 	 * @param directBearing The direct heading (signed degrees) (A->E)
 	 * @param arcLength the length of the arc in meter (A->B->C->D->E)
 	 * @param pathLength the length of the arc in meter (summed length for additional arcs)
@@ -90,7 +88,7 @@
 	 */
 	public RouteArc(RoadDef roadDef,
 					RouteNode source, RouteNode dest,
-					double initialBearing, double finalBearing, double directBearing,
+					double initialBearing, double directBearing,
 					double arcLength,
 					double pathLength,
 					double directLength,
@@ -100,7 +98,6 @@
 		this.source = source;
 		this.dest = dest;
 		this.initialHeading = (float) initialBearing;
-		this.finalHeading = (float) finalBearing;
 		this.directHeading = (directBearing < 180) ? (float) directBearing : -180.0f;
 		int len = NODHeader.metersToRaw(arcLength);
 		if (len >= (1 << 22)) {
@@ -129,12 +126,21 @@
 		return initialHeading;
 	}
 
+	public float getDirectHeading() {
+		return directHeading;
+	}
+
 	public void setInitialHeading(float ih) {
 		initialHeading = ih;
 	}
 
 	public float getFinalHeading() {
-		return finalHeading;
+		float fh = 0;
+		if (lengthInMeter != 0){
+			fh = getReverseArc().getInitialHeading();
+			fh = (fh <= 0) ? 180.0f + fh : -(180.0f - fh) % 180.0f;
+		}
+		return fh;
 	}
 
 	public RouteNode getSource() {
Index: src/uk/me/parabola/imgfmt/app/net/RouteNode.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/RouteNode.java	(revision 3631)
+++ src/uk/me/parabola/imgfmt/app/net/RouteNode.java	(working copy)
@@ -17,7 +17,6 @@
 import it.unimi.dsi.fastutil.ints.IntArrayList;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -24,7 +23,6 @@
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.imgfmt.app.CoordNode;
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
-import uk.me.parabola.imgfmt.app.Label;
 import uk.me.parabola.log.Logger;
 
 /**
@@ -53,10 +51,6 @@
 	// only used internally in mkgmap
 	private static final int F_DISCARDED = 0x100; // node has been discarded
 
-	private static final int MAX_MAIN_ROAD_HEADING_CHANGE = 120;
-	private static final int MIN_DIFF_BETWEEN_OUTGOING_AND_OTHER_ARCS = 45;
-	private static final int MIN_DIFF_BETWEEN_INCOMING_AND_OTHER_ARCS = 50;
-
 	private int offsetNod1 = -1;
 
 	// arcs from this node
@@ -352,310 +346,6 @@
 		return coord.compareTo(otherNode.getCoord());
 	}
 
-	private static boolean possiblySameRoad(RouteArc raa, RouteArc rab) {
-
-		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) {
-				for(Label labb : rdb.getLabels()) {
-					if(labb != null && labb.getOffset() != 0) {
-						bothArcsNamed = true;
-						if(laba.equals(labb)) {
-							// the roads have the same label
-							if(rda.isLinkRoad() == rdb.isLinkRoad()) {
-								// if both are a link road or both are
-								// not a link road, consider them the
-								// same road
-								return true;
-							}
-							// One is a link road and the other isn't
-							// so consider them different roads - this
-							// is because people often give a link
-							// road that's leaving some road the same
-							// ref as that road but it suits us better
-							// to consider them as different roads
-							return false;
-						}
-					}
-				}
-			}
-		}
-
-		if(bothArcsNamed) {
-			// both roads have names and they don't match
-			return false;
-		}
-
-		// at least one road is unnamed
-		if(rda.isRoundabout() && rdb.isRoundabout()) {
-			// hopefully, segments of the same (unnamed) roundabout
-			return true;
-		}
-
-		return false;
-	}
-
-	private static boolean rightTurnRequired(float inHeading, float outHeading, float otherHeading) {
-		// 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;
-
-		otherHeading -= inHeading;
-		while(otherHeading < -180)
-			otherHeading += 360;
-		while(otherHeading > 180)
-			otherHeading -= 360;
-
-		return otherHeading > outHeading;
-	}
-
-	private static final int ATH_OUTGOING = 1;
-	private static final int ATH_INCOMING = 2;
-
-	public static final int ATH_DEFAULT_MASK = ATH_OUTGOING | ATH_INCOMING;
-
-	public void tweezeArcs(int mask) {
-		if(arcs.size() >= 3) {
-
-			// detect the "shallow turn" scenario where at a junction
-			// on some "main" road, the side road leaves the main
-			// road at a very shallow angle and the GPS says "keep
-			// right/left" when it would be better if it said "turn
-			// right/left"
-
-			// also helps to produce a turn instruction when the main
-			// road bends sharply but the side road keeps close to the
-			// original heading
-
-			// the code tries to detect a pair of arcs (the "incoming"
-			// arc and the "outgoing" arc) that are the "main road"
-			// and the remaining arc (called the "other" arc) which is
-			// the "side road"
-
-			// having worked out the roles for the arcs, the heuristic
-			// applied is that if the main road doesn't change its
-			// heading by more than maxMainRoadHeadingChange, ensure
-			// that the side road heading differs from the outgoing
-			// heading by at least
-			// minDiffBetweenOutgoingAndOtherArcs and the side road
-			// heading differs from the incoming heading by at least
-			// minDiffBetweenIncomingAndOtherArcs
-
-			// 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>();
-			for (RouteArc arc : arcs){
-				if (arc.isDirect())
-					inArcs.add(arc.getReverseArc());
-			}
-
-			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() && inRoadDef.isOneway()) {
-					// ignore reverse arc if road is oneway
-					continue;
-				}
-
-				float inHeading = inArc.getFinalHeading();
-				// determine the outgoing arc that is likely to be the
-				// same road as the incoming arc
-				RouteArc outArc = null;
-
-				if(throughRoutes != null) {
-					// through_route relations have the highest precedence
-					for(RouteArc[] pair : throughRoutes) {
-						if(pair[0] == inArc) {
-							outArc = pair[1];
-							log.info("Found through route from " + inRoadDef + " to " + outArc.getRoadDef());
-							break;
-						}
-					}
-				}
-
-				if(outArc == null) {
-					// next, if oa has the same RoadDef as inArc, it's
-					// definitely the same road
-					for(RouteArc oa : arcs) {
-						if (oa.isDirect() == false)
-							continue;
-						if(oa.getDest() != inArc.getSource()) {
-							// this arc is not going to the same node as
-							// inArc came from
-							if(oa.getRoadDef() == inRoadDef) {
-								outArc = oa;
-								break;
-							}
-						}
-					}
-				}
-
-				if(outArc == null) {
-					// next, although the RoadDefs don't match, use
-					// possiblySameRoad() to see if the roads' id or
-					// labels (names/refs) match
-					for(RouteArc oa : arcs) {
-						if (oa.isDirect() == false)
-							continue;
-						if(oa.getDest() != inArc.getSource()) {
-							// this arc is not going to the same node as
-							// inArc came from
-							if((oa.isForward() || !oa.getRoadDef().isOneway()) &&
-							   possiblySameRoad(inArc, oa)) {
-								outArc = oa;
-								break;
-							}
-						}
-					}
-				}
-
-				// if we did not find the outgoing arc, give up with
-				// this incoming arc
-				if(outArc == null) {
-					//log.info("Can't continue road " + inRoadDef + " at " + coord.toOSMURL());
-					continue;
-				}
-
-				// remember that this arc is an outgoing arc
-				outgoingArcs.add(outArc);
-
-				float outHeading = outArc.getInitialHeading();
-				float mainHeadingDelta = outHeading - inHeading;
-				while(mainHeadingDelta > 180)
-					mainHeadingDelta -= 360;
-				while(mainHeadingDelta < -180)
-					mainHeadingDelta += 360;
-				//log.info(inRoadDef + " continues to " + outArc.getRoadDef() + " with a heading change of " + mainHeadingDelta + " at " + coord.toOSMURL());
-
-				if(Math.abs(mainHeadingDelta) > MAX_MAIN_ROAD_HEADING_CHANGE) {
-					// if the continuation road heading change is
-					// greater than maxMainRoadHeadingChange don't
-					// adjust anything
-					continue;
-				}
-
-				for(RouteArc otherArc : arcs) {
-					if (otherArc.isDirect() == false)
-						continue;
-
-					// for each other arc leaving this node, tweeze
-					// its heading if its heading change from the
-					// outgoing heading is less than
-					// minDiffBetweenOutgoingAndOtherArcs or its
-					// heading change from the incoming heading is
-					// less than minDiffBetweenIncomingAndOtherArcs
-
-					if(otherArc.getDest() == inArc.getSource() ||
-					   otherArc == outArc) {
-						// we're looking at the incoming or outgoing
-						// arc, ignore it
-						continue;
-					}
-
-					if(!otherArc.isForward() &&
-					   otherArc.getRoadDef().isOneway()) {
-						// ignore reverse arc if road is oneway
-						continue;
-					}
-
-					if(inRoadDef.isLinkRoad() &&
-					   otherArc.getRoadDef().isLinkRoad()) {
-						// it's a link road leaving a link road so
-						// leave the angle unchanged to avoid
-						// introducing a time penalty by increasing
-						// the angle (this stops the router using link
-						// roads that "cut the corner" at roundabouts)
-						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;
-					}
-
-					float otherHeading = otherArc.getInitialHeading();
-					float outToOtherDelta = otherHeading - outHeading;
-					while(outToOtherDelta > 180)
-						outToOtherDelta -= 360;
-					while(outToOtherDelta < -180)
-						outToOtherDelta += 360;
-					float inToOtherDelta = otherHeading - inHeading;
-					while(inToOtherDelta > 180)
-						inToOtherDelta -= 360;
-					while(inToOtherDelta < -180)
-						inToOtherDelta += 360;
-
-					float newHeading = otherHeading;
-					if(rightTurnRequired(inHeading, outHeading, otherHeading)) {
-						// side road to the right
-						if((mask & ATH_OUTGOING) != 0 &&
-						   Math.abs(outToOtherDelta) < MIN_DIFF_BETWEEN_OUTGOING_AND_OTHER_ARCS)
-							newHeading = outHeading + MIN_DIFF_BETWEEN_OUTGOING_AND_OTHER_ARCS;
-						if((mask & ATH_INCOMING) != 0 &&
-						   Math.abs(inToOtherDelta) < MIN_DIFF_BETWEEN_INCOMING_AND_OTHER_ARCS) {
-							float nh = inHeading + MIN_DIFF_BETWEEN_INCOMING_AND_OTHER_ARCS;
-							if(nh > newHeading)
-								newHeading = nh;
-						}
-
-						if(newHeading > 180)
-							newHeading -= 360;
-					}
-					else {
-						// side road to the left
-						if((mask & ATH_OUTGOING) != 0 &&
-						   Math.abs(outToOtherDelta) < MIN_DIFF_BETWEEN_OUTGOING_AND_OTHER_ARCS)
-							newHeading = outHeading - MIN_DIFF_BETWEEN_OUTGOING_AND_OTHER_ARCS;
-						if((mask & ATH_INCOMING) != 0 &&
-						   Math.abs(inToOtherDelta) < MIN_DIFF_BETWEEN_INCOMING_AND_OTHER_ARCS) {
-							float nh = inHeading - MIN_DIFF_BETWEEN_INCOMING_AND_OTHER_ARCS;
-							if(nh < newHeading)
-								newHeading = nh;
-						}
-
-						if(newHeading < -180)
-							newHeading += 360;
-					}
-					if(Math.abs(newHeading - otherHeading) > 0.0000001) {
-						otherArc.setInitialHeading(newHeading);
-						log.info("Adjusting turn heading from " + otherHeading + " to " + newHeading + " at junction of " + inRoadDef + " and " + otherArc.getRoadDef() + " at " + coord.toOSMURL());
-					}
-				}
-			}
-		}
-	}
-
 	public void checkRoundabouts() {
 
 		List<RouteArc> roundaboutArcs = new ArrayList<RouteArc>();
@@ -1010,7 +700,6 @@
 								sourceNode, 
 								destNode, 
 								roadArcs.get(i).getInitialHeading(), // not used
-								arcToDest.getFinalHeading(),  // not used
 								c1.bearingTo(c2),
 								partialArcLength, // from stepNode to destNode on road
 								pathLength, // from sourceNode to destNode on road
@@ -1111,4 +800,16 @@
 	public int hashCode(){
 		return getCoord().getId();
 	}
+
+	public List<RouteArc> getDirectArcsBetween(RouteNode otherNode) {
+		List<RouteArc> result = new ArrayList<>();
+		for(RouteArc a : arcs){
+			if(a.isDirect() && a.getDest() == otherNode){
+				result.add(a);
+			}
+		}
+		return result;
+	}
+
+	
 }
Index: src/uk/me/parabola/imgfmt/app/net/RouteRestriction.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/RouteRestriction.java	(revision 3631)
+++ src/uk/me/parabola/imgfmt/app/net/RouteRestriction.java	(working copy)
@@ -63,6 +63,8 @@
 	private final byte exceptMask;
 	private final byte flags; // meaning of bits 0x01 and 0x10 are not clear 
 
+	private byte mkgmapExceptMask;
+
 	private final static byte F_EXCEPT_FOOT      = 0x02;
 	private final static byte F_EXCEPT_EMERGENCY = 0x04;
 	private final static byte F_MORE_EXCEPTIONS  = 0x08;
@@ -82,6 +84,7 @@
 	 */
 	public RouteRestriction(RouteNode viaNode, List<RouteArc> traffArcs, byte mkgmapExceptMask) {
 		this.viaNode = viaNode;
+		this.mkgmapExceptMask = mkgmapExceptMask;
 		this.arcs = new ArrayList<>(traffArcs);
 		for (int i = 0; i < arcs.size(); i++){
 			RouteArc arc = arcs.get(i);
@@ -231,4 +234,8 @@
 	public void setLast() {
 		last = true;
 	}
+	
+	public byte getMkgmapExeptMask(){
+		return mkgmapExceptMask;
+	}
 }
Index: src/uk/me/parabola/mkgmap/osmstyle/housenumber/ExtNumbers.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/housenumber/ExtNumbers.java	(revision 3631)
+++ src/uk/me/parabola/mkgmap/osmstyle/housenumber/ExtNumbers.java	(working copy)
@@ -1070,6 +1070,7 @@
 	 */
 	private int addAsNumberNode(int pos, Coord toAdd){
 		toAdd.setNumberNode(true);
+		toAdd.setAddedNumberNode(true);
 		getRoad().getPoints().add(pos, toAdd);
 		
 		ExtNumbers work = next;
Index: src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGroup.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGroup.java	(revision 3631)
+++ src/uk/me/parabola/mkgmap/osmstyle/housenumber/HousenumberGroup.java	(working copy)
@@ -164,9 +164,11 @@
 		if (timesToAdd == 2){
 			// add two new points between c1 and c2
 			points.add(seg + 1, pointToUse);
+			pointToUse.setAddedNumberNode(true);
 			pointToUse = new Coord (pointToUse);
 			pointToUse.setNumberNode(true);
 			points.add(seg + 1, pointToUse);
+			pointToUse.setAddedNumberNode(true);
 			linkNode = pointToUse;
 		} else {
 		// copy it
@@ -174,6 +176,7 @@
 			pointToUse.setNumberNode(true);
 			// add copy before c2 
 			points.add(seg + 1, pointToUse);
+			pointToUse.setAddedNumberNode(true);
 			if (pointToUse.highPrecEquals(c1)){
 				linkNode = c1;
 			} else { 
