Index: uk/me/parabola/imgfmt/app/net/RoadDef.java
===================================================================
--- uk/me/parabola/imgfmt/app/net/RoadDef.java	(revision 3064)
+++ uk/me/parabola/imgfmt/app/net/RoadDef.java	(working copy)
@@ -481,6 +481,10 @@
 		this.node = node;
 	}
 
+	public RouteNode getNode(){
+		return node;
+	}
+	
 	private boolean hasNodInfo() {
 		return (netFlags & NET_FLAG_NODINFO) != 0;
 	}
Index: uk/me/parabola/imgfmt/app/net/RouteArc.java
===================================================================
--- uk/me/parabola/imgfmt/app/net/RouteArc.java	(revision 3064)
+++ uk/me/parabola/imgfmt/app/net/RouteArc.java	(working copy)
@@ -65,7 +65,10 @@
 	private final byte lengthRatio;
 	private final int pointsHash;
 	private boolean isForward;
+	private final float lengthInMeter;
 
+	private boolean isDirect;
+
 	/**
 	 * Create a new arc. An arc can contain multiple points (eg. A->B->C->D->E)
 	 * @param roadDef The road that this arc segment is part of.
@@ -76,7 +79,6 @@
 	 * @param directBearing The direct heading (signed degrees) (A->E)
 	 * @param arcLength the length of the arc in meter (A->B->C->D->E)
 	 * @param directLength the length of the arc in meter (A-E) 
-	 * @param curveEnabled false means don't write curve bytes 
 	 * @param pointsHash
 	 */
 	public RouteArc(RoadDef roadDef,
@@ -84,8 +86,8 @@
 					double initialBearing, double finalBearing, double directBearing,
 					double arcLength,
 					double directLength,
-					boolean curveEnabled,
 					int pointsHash) {
+		this.isDirect = true; // unless changed
 		this.roadDef = roadDef;
 		this.source = source;
 		this.dest = dest;
@@ -98,6 +100,7 @@
 			len = (1 << 22) - 1;
 		}
 		this.length = len;
+		this.lengthInMeter = (float) arcLength;
 		this.pointsHash = pointsHash;
 		int ratio = 0;
 		if (arcLength > directLength){
@@ -108,7 +111,7 @@
 		if (ratio == 0 && length >= (1 << 14))
 			ratio = 0x1f;
 		lengthRatio = (byte)ratio;
-		haveCurve = curveEnabled && lengthRatio > 0;
+		haveCurve = lengthRatio > 0;
 	}
 
 	public float getInitialHeading() {
@@ -208,9 +211,11 @@
 	//old 3.2808 / 16;
 	private static int convertMeters(double l) {
 		return (int) (l * LENGTH_FACTOR + 0.5);
+	}
 
+	public float getLengthInMeter(){
+		return lengthInMeter;
 	}
-
 	public void write(ImgFileWriter writer, RouteArc lastArc, boolean useCompactDirs, Byte compactedDir) {
 		boolean first = lastArc == null;
 		if (first){
@@ -259,13 +264,16 @@
 		for (int aLendat : lendat)
 			writer.put((byte) aLendat);
 
-		if (useCompactDirs){
-			// determine if we have to write direction info
-			if (compactedDir != null)
-				writer.put(compactedDir);
-		} else 
-			writer.put((byte)(initialHeading * 256 / 360));
-		
+		if (first || lastArc.indexA != this.indexA || lastArc.isForward != isForward){
+			if (useCompactDirs){
+				// determine if we have to write direction info
+				if (compactedDir != null)
+					writer.put(compactedDir);
+			} else 
+				writer.put((byte)(initialHeading * 256 / 360));
+		} else {
+//			System.out.println("skipped writing of initial dir");
+		}
 		if (haveCurve) {
 			int[] curvedat = encodeCurve();
 			for (int aCurvedat : curvedat)
@@ -400,4 +408,13 @@
 			log.debug("setting destination class", destinationClass);
 		flagA |= (destinationClass & MASK_DESTCLASS);
 	}
+
+	public void setIndirect() {
+		this.isDirect = false;
+		
+	}
+
+	public boolean isDirect() {
+		return isDirect;
+	}
 }
Index: uk/me/parabola/imgfmt/app/net/RouteNode.java
===================================================================
--- uk/me/parabola/imgfmt/app/net/RouteNode.java	(revision 3064)
+++ uk/me/parabola/imgfmt/app/net/RouteNode.java	(working copy)
@@ -20,6 +20,7 @@
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
+
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.imgfmt.app.CoordNode;
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
@@ -72,11 +73,17 @@
 	private char lonOff;
 	private List<RouteArc[]> throughRoutes;
 
+	// this is the max. road class that can be reached from any
+	// of the arcs of this node
 	// this is for setting destination class on arcs
-	// we're taking the maximum of roads this node is
-	// on for now -- unsure of precise mechanic
 	private int nodeClass;
 
+	// bit mask co
+	private byte forwardDestClassMask;
+	private byte reverseDestClassMask;
+	
+	private byte sourceClassMask;
+	
 	public RouteNode(Coord coord) {
 		this.coord = (CoordNode) coord;
 		setBoundary(this.coord.getOnBoundary());
@@ -104,6 +111,10 @@
 			log.debug("adding arc", arc.getRoadDef(), cl);
 		if (cl > nodeClass)
 			nodeClass = cl;
+		if (arc.isForward())
+			forwardDestClassMask |= 1 << cl;
+		else
+			reverseDestClassMask |= 1 << cl;
 		flags |= F_ARCS;
 	}
 
@@ -464,6 +475,8 @@
 					// 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
@@ -480,7 +493,10 @@
 					// 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()) &&
@@ -553,6 +569,8 @@
 				}
 
 				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
@@ -885,4 +903,118 @@
 		else
 			log.warn("Failed to add through route between ways " + roadIdA + " and " + roadIdB + " at " + coord.toOSMURL() + " - perhaps they don't meet here?");
 	}
+
+	
+	/**
+	 * Travel recursively through all nodes of a road, and from each node to all roads with
+	 * lower road class. 
+	 * @param majorRoad
+	 */
+	public void addIndirectArcs(RoadDef majorRoad) {
+		if (Integer.highestOneBit(sourceClassMask) >= (1 << majorRoad.getRoadClass()))
+			return;
+		// mark the node: we visited it with the road class of the major road  
+		sourceClassMask |= (1 << majorRoad.getRoadClass());
+		RouteNode next = null;
+		for (int i = 0; i < arcs.size(); i++){
+			RouteArc arc = arcs.get(i);
+			if (arc.isForward() && arc.getRoadDef() == majorRoad && arc.isDirect()){
+				next = arc.getDest();
+			} else if (arc.getRoadDef().getRoadClass() < majorRoad.getRoadClass() ){
+				// arc on different different road with smaller road class
+				// tell the nodes on this road that they can reach this better road
+				// arc starts at current node, continue at destination with the same 
+				// direction 
+				//System.out.println(rd.getId() + " -> " + arc.getRoadDef().getId());
+				arc.getDest().visitNodesAndAddArcs(0, arc.isForward(), arc.getLengthInMeter(), arc.getRoadDef(), majorRoad.getRoadClass(), this, 180 - arc.getInitialHeading());
+			}
+		}
+		if (next != null)
+			next.addIndirectArcs(majorRoad);
+	}
+	
+	/**
+	 * Add indirect arcs to nodes on roads with higher road classes.
+	 * @param depth recursion depth
+	 * @param forward the isForward() flag of the arc we came from 
+	 * @param arcLength the summed arc length
+	 * @param minorRoad the minor road for which we want to add arcs 
+	 * @param roadClass the road class of the major road
+	 * @param targetNode the target node for the new arc
+	 * @param finalHeading the final heading of the first arc that goes from 
+	 * the major road to the minor road
+	 * @param outputCurveData 
+	 */
+	private void visitNodesAndAddArcs(int depth, boolean forward, double arcLength, RoadDef minorRoad, int roadClass, RouteNode targetNode, float finalHeading){
+//		System.out.println(depth + " " + this.toString() + " " + arcLength + " " + roadClass);
+		for (RouteRestriction rr: restrictions){
+			boolean restricted = rr.isRestricted(minorRoad);
+			if (restricted){
+				return; // maybe too cautious, but on the safe side
+			}
+		}
+		RouteArc sameArc = null;
+		if (depth > 0){
+			for (RouteArc arc: arcs){
+				if (arc.getDest() == targetNode && arc.isForward() != forward){
+					// we already have an arc to the target node
+					if (arc.isDirect() || arc.getRoadDef().getRoadClass() > roadClass)
+						return;
+					sameArc = arc; 
+					break;
+				}
+			}
+		}
+		RouteArc newArc = null;
+		byte oldDestClassMask = forward ? forwardDestClassMask: reverseDestClassMask;
+		for (int i = 0; i < arcs.size(); i++){
+			RouteArc arc = arcs.get(i);
+			if (arc.isDirect() == false || arc.getRoadDef() != minorRoad)
+				continue; 
+			// we found a direct arc that is on the minor road 
+			if (arc.isForward() == forward){
+				// we travel on if we add an arc to the current node or if depth is zero 
+				if ((oldDestClassMask & (1 << roadClass)) == 0)
+					arc.getDest().visitNodesAndAddArcs(depth + 1, forward,
+							arcLength + arc.getLengthInMeter(), minorRoad,
+							roadClass, targetNode, finalHeading);
+				if (depth == 0)
+					break;
+			} else {
+				if (depth == 0)
+					continue; // arc exists
+				if (sameArc != null || (oldDestClassMask & (1 << roadClass)) != 0){
+					if (arc.isDirect())
+						continue;
+					// should not happen: 
+					// we already have an indirect link to the same target node via the same road
+					log.error("duplicate indirect arc on road",minorRoad,"to node",targetNode); 
+				}
+				
+				// create a new arc
+				Coord c1 = arc.getDest().getCoord();
+				Coord c2 = targetNode.getCoord();
+				newArc = new RouteArc(arc.getRoadDef(), 
+						this,
+						targetNode,
+						arc.getInitialHeading(),
+						finalHeading,
+						this.getCoord().bearingTo(c2), 
+						arcLength - arc.getLengthInMeter(), 
+						c1.distance(c2),
+						this.getCoord().hashCode() + c2.hashCode());
+				if (arc.isForward())
+					newArc.setForward();
+				newArc.setIndirect();
+				i++;
+				arcs.add(i, newArc); // add it directly after the existing direct arc
+				log.info("added indirect arc from node",this,"to node",targetNode);
+				// note for which classes we already have arcs
+				if (forward)
+					forwardDestClassMask |= 1 << roadClass;
+				else 
+					reverseDestClassMask |= 1 << roadClass;
+			}
+		}
+	}
 }
Index: uk/me/parabola/imgfmt/app/net/RouteRestriction.java
===================================================================
--- uk/me/parabola/imgfmt/app/net/RouteRestriction.java	(revision 3064)
+++ uk/me/parabola/imgfmt/app/net/RouteRestriction.java	(working copy)
@@ -181,4 +181,14 @@
 	public void setLast() {
 		last = true;
 	}
+
+	/**
+	 * Check if there is a restriction when travelling along a given road via this node.
+	 * @param rd the road
+	 * @return true if there is a restriction 
+	 */
+	public boolean isRestricted(RoadDef rd) {
+		return (from.getRoadDef() == rd && to.getRoadDef() == rd);
+			
+	}
 }
Index: uk/me/parabola/mkgmap/general/RoadNetwork.java
===================================================================
--- uk/me/parabola/mkgmap/general/RoadNetwork.java	(revision 3064)
+++ uk/me/parabola/mkgmap/general/RoadNetwork.java	(working copy)
@@ -66,7 +66,8 @@
 	private boolean checkRoundaboutFlares;
 	private int maxFlareLengthRatio ;
 	private boolean reportSimilarArcs;
-	private boolean outputCurveData;
+	// keeps track of the highest road class that is used
+	private int maxRoadClass = 0; // 
 
 	public void config(EnhancedProperties props) {
 		String ath = props.getProperty("adjust-turn-headings");
@@ -81,14 +82,13 @@
 		maxFlareLengthRatio = props.getProperty("max-flare-length-ratio", 0);
 
 		reportSimilarArcs = props.getProperty("report-similar-arcs", false);
-
-		outputCurveData = !props.getProperty("no-arc-curves", false);
 	}
 
 	public void addRoad(MapRoad road) {
 		//mapRoads.add(road);
 		roadDefs.add(road.getRoadDef()); //XXX
-
+		if (road.getRoadDef().getRoadClass() > maxRoadClass)
+			maxRoadClass = road.getRoadDef().getRoadClass();
 		CoordNode lastCoord = null;
 		int lastIndex = 0;
 		double roadLength = 0;
@@ -178,7 +178,6 @@
 											forwardDirectBearing,
 											arcLength,
 											directLength,
-											outputCurveData,
 											pointsHash);
 				arc.setForward();
 				node1.addArc(arc);
@@ -192,7 +191,6 @@
 								   reverseDirectBearing,
 								   arcLength,
 								   directLength,
-								   outputCurveData,
 								   pointsHash);
 				node2.addArc(arc);
 				node1.addIncomingArc(arc);
@@ -254,12 +252,30 @@
 	}
 
 	public List<RouteCenter> getCenters() {
-		if (centers.isEmpty())
+		if (centers.isEmpty()){
+			addArcsToMajorRoads();
 			splitCenters();
+		}
 		return centers;
 	}
 
 	/**
+	 * add indirect arcs for each road class (in decending order)
+	 */
+	private void addArcsToMajorRoads() {
+		long t1 = System.currentTimeMillis();
+		for (int cl = maxRoadClass; cl >= 1; --cl){
+			for (RoadDef rd: roadDefs){
+				if (rd.getRoadClass() == cl){
+					rd.getNode().addIndirectArcs(rd);
+				}
+			}
+			
+		}
+		log.error(" added arcs in " + (System.currentTimeMillis() - t1) + " ms");
+	}
+
+	/**
 	 * Get the list of nodes on the boundary of the network.
 	 *
 	 * Currently empty.
