Index: src/uk/me/parabola/imgfmt/app/net/GeneralRouteRestriction.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/GeneralRouteRestriction.java	(revision 3189)
+++ src/uk/me/parabola/imgfmt/app/net/GeneralRouteRestriction.java	(working copy)
@@ -38,6 +38,7 @@
 	private CoordNode fromNode, toNode;
 	private List<Long> viaWayIds = new ArrayList<>();
 	private List<CoordNode> viaNodes = new ArrayList<>();
+	private char dirIndicator; // s(traight),l(eft),r(ight),u, ? for unknown 
 
 	public GeneralRouteRestriction(String type, byte exceptionMask, String sourceDesc) {
 		if ("not".equals(type))
@@ -50,6 +51,7 @@
 			throw new IllegalArgumentException("invalid type " + type);
 		this.exceptionMask = exceptionMask;
 		this.sourceDesc = sourceDesc;
+		this.setDirIndicator('?');
 	}
 	
 	public long getFromWayId() {
@@ -99,4 +101,12 @@
 	public String getSourceDesc(){
 		return sourceDesc;
 	}
+
+	public char getDirIndicator() {
+		return dirIndicator;
+	}
+
+	public void setDirIndicator(char dirIndicator) {
+		this.dirIndicator = dirIndicator;
+	}
 }
Index: src/uk/me/parabola/imgfmt/app/net/RouteNode.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/RouteNode.java	(revision 3189)
+++ src/uk/me/parabola/imgfmt/app/net/RouteNode.java	(working copy)
@@ -137,6 +137,22 @@
 	}
 
 	/**
+	 * get all direct arcs on a given way id  
+	 * @param roadId
+	 * @return
+	 */
+	public List<RouteArc> getDirectArcsOnWay(long roadId) {
+		List<RouteArc> result = new ArrayList<>();
+		for(RouteArc a : arcs){
+			if(a.isDirect()){
+				if(a.getRoadDef().getId() == roadId)
+					result.add(a);
+			}
+		}
+		return result;
+	}
+	
+	/**
 	 * Find arc to given node on given road. 
 	 * @param otherNode
 	 * @param roadDef
@@ -668,7 +684,7 @@
 						if(newHeading < -180)
 							newHeading += 360;
 					}
-					if(newHeading != otherHeading) {
+					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());
 					}
Index: src/uk/me/parabola/imgfmt/app/net/RouteRestriction.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/RouteRestriction.java	(revision 3189)
+++ src/uk/me/parabola/imgfmt/app/net/RouteRestriction.java	(working copy)
@@ -111,11 +111,13 @@
 	public List<RouteArc> getArcs(){
 		return arcs;
 	}
+	
 	/**
-	 * Writes a Table C entry with 3 or 4 nodes.
+	 * Writes a Table C entry with 3 or more nodes.
 	 *
 	 * @param writer The writer.
 	 * @param tableOffset The offset in NOD 1 of the tables area.
+	 * 
 	 */
 	public void write(ImgFileWriter writer, int tableOffset) {
 		writer.put(RESTRICTION_TYPE); 
@@ -128,34 +130,28 @@
 
 		int numArcs = arcs.size();
 		int[] offsets = new int[numArcs+1];
-		// first arc is inverse arc
 		int pos = 0;
 		boolean viaWritten = false;
 		for (int i = 0; i < numArcs; i++){
 			RouteArc arc = arcs.get(i);
+			// the arcs must have a specific order and direction
+			// first arc: dest is from node , last arc: dest is to node
+			// if there only two arcs, both will have the via node as source node.
+			// For more n via nodes, the order is like this: 
+			// from <- via(1) <- via(2) <- ... <- this via node -> via( n-1) -> via(n) -> to
+			if (arc.isInternal())
+				offsets[pos++] = calcOffset(arc.getDest(), tableOffset);
+			else 
+				offsets[pos++] = arc.getIndexB();
 			if (arc.getSource() == viaNode){
-				if (arc.isInternal())
-					offsets[pos++] = calcOffset(arc.getDest(), tableOffset);
-				else 
-					offsets[pos++] = arc.getIndexB();
+				// there will be two nodes with source node = viaNode, but we write the source only once
 				if (!viaWritten){
 					offsets[pos++] = calcOffset(viaNode, tableOffset);
 					viaWritten = true;
 				}
-			} else {
-				if (arc.isInternal())
-					offsets[pos++] = calcOffset(arc.getDest(), tableOffset);
-				else 
-					offsets[pos++] = arc.getIndexB();
 			}
 		}
-//		for (int i = 1; i < offsets.length; i++){
-//			if (offsets[i-1] == offsets[i]){
-//				assert false : "failed to calculate offsets for restriction at via node "
-//						+ viaNode.getCoord()
-//						+ "(" + viaNode.getCoord().toDegreeString() + ")";
-//			}
-//		}
+
 		for (int offset : offsets)
 			writer.putChar((char) offset);
 
Index: src/uk/me/parabola/mkgmap/general/LineClipper.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/LineClipper.java	(revision 3189)
+++ src/uk/me/parabola/mkgmap/general/LineClipper.java	(working copy)
@@ -21,7 +21,6 @@
 
 import uk.me.parabola.imgfmt.app.Area;
 import uk.me.parabola.imgfmt.app.Coord;
-import uk.me.parabola.log.Logger;
 
 /**
  * Routine to clip a polyline to a given bounding box.
@@ -29,8 +28,6 @@
  * @see <a href="http://www.skytopia.com/project/articles/compsci/clipping.html">A very clear explaination of the Liang-Barsky algorithm</a>
  */
 public class LineClipper {
-	private static final Logger log = Logger.getLogger(LineClipper.class);
-
 	/**
 	 * Clips a polyline by the given bounding box.  This may produce several
 	 * separate lines if the line meanders in and out of the box.
Index: src/uk/me/parabola/mkgmap/general/RoadNetwork.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/RoadNetwork.java	(revision 3189)
+++ src/uk/me/parabola/mkgmap/general/RoadNetwork.java	(working copy)
@@ -18,10 +18,12 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.logging.Level;
+import java.util.Map.Entry;
+import java.util.TreeMap;
 
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.imgfmt.app.CoordNode;
@@ -55,6 +57,7 @@
 	public static final int NO_TRUCK = 7;
 	public static final int NO_MAX = 8;
 
+	private final static int MAX_RESTRICTIONS_ARCS = 7;
 	private final Map<Long, RouteNode> nodes = new LinkedHashMap<Long, RouteNode>();
 
 	// boundary nodes
@@ -132,7 +135,6 @@
 				else if(arcLength == 0)
 					log.warn("Road " + road.getRoadDef() + " contains zero length arc at " + co.toOSMURL());
 
-
 				Coord forwardBearingPoint = coordList.get(lastIndex + 1);
 				if(lastCoord.equals(forwardBearingPoint)) {
 					// bearing point is too close to last node to be
@@ -297,6 +299,10 @@
 	 * to write them (2014-04-02). 
 	 * Depending on the data in grr we create one or more such restrictions.
 	 * A restriction with 4 (or more) nodes is added to each via node.     
+	 * 
+	 * The OSM restriction gives a from way id and a to way id and one or more 
+	 * via nodes. It is possible that the to-way is a loop, so we have to identify
+	 * the correct arc. 
 	 * @param grr the object that holds the details about the route restriction
 	 */
 	public int addRestriction(GeneralRouteRestriction grr) {
@@ -304,18 +310,6 @@
 			return addNoThroughRoute(grr);
 		String sourceDesc = grr.getSourceDesc();
 		
-		long fromId = grr.getFromNode().getId();
-		long toId = grr.getToNode().getId();
-		RouteNode fn = nodes.get(fromId);
-		RouteNode tn = nodes.get(toId);
-		if (fn == null  || tn == null){
-			if (fn == null)
-				log.error(sourceDesc, "can't locate 'from' RouteNode with id", fromId);
-			if (tn == null)
-				log.error(sourceDesc, "can't locate 'to' RouteNode with id", toId);
-			return 0; 
-		}
-
 		List<RouteNode> viaNodes = new ArrayList<>();
 		for (CoordNode via : grr.getViaNodes()){
 			RouteNode vn = nodes.get(via.getId());
@@ -325,32 +319,129 @@
 			}
 			viaNodes.add(vn);
 		}
+		
 		long firstViaId = grr.getViaNodes().get(0).getId();
 		long lastViaId = grr.getViaNodes().get(grr.getViaNodes().size()-1).getId();
 		RouteNode firstViaNode = nodes.get(firstViaId);
 		RouteNode lastViaNode = nodes.get(lastViaId);
-		
-		List<RouteArc> fromArcs = firstViaNode.getDirectArcsTo(fn, grr.getFromWayId()); // inverse arcs gets used
-		List<RouteArc> toArcs = lastViaNode.getDirectArcsTo(tn, grr.getToWayId());
-		if (fromArcs.isEmpty() || toArcs.isEmpty()){
-			if (fromArcs.isEmpty())
-				log.error(sourceDesc, "can't locate arc from 'via' node ",firstViaId,"to 'from' node",fromId,"on way",grr.getFromWayId());
-			if (toArcs.isEmpty())
-				log.error(sourceDesc, "can't locate arc from 'via' node ",lastViaId,"to 'to' node",toId,"on way",grr.getToWayId());
+		List<List<RouteArc>> viaArcsList = new ArrayList<>();
+		if (grr.getViaNodes().size() != grr.getViaWayIds().size() + 1){
+			log.error(sourceDesc, "internal error: number of via nodes and via ways doesn't fit");
 			return 0;
 		}
-		
-		List<List<RouteArc>> viaArcsList = new ArrayList<>();
 		for (int i = 1; i < grr.getViaNodes().size(); i++){
 			RouteNode vn = viaNodes.get(i-1);
-			List<RouteArc> viaArcs = vn.getDirectArcsTo(viaNodes.get(i), grr.getViaWayIds().get(i-1));
+			Long viaWayId = grr.getViaWayIds().get(i-1);
+			List<RouteArc> viaArcs = vn.getDirectArcsTo(viaNodes.get(i), viaWayId);
 			if (viaArcs.isEmpty()){
-				log.error(sourceDesc, "can't locate arc from 'via' node ",vn.getCoord().getId(),"to next 'via' node on way",grr.getViaWayIds().get(i));
+				log.error(sourceDesc, "can't locate arc from 'via' node at",vn.getCoord().toOSMURL(),"to next 'via' node on way",viaWayId);
 				return 0;
 			}
 			viaArcsList.add(viaArcs);
 		}
 		
+		// determine the from node and arc(s)
+		long fromId = 0;
+		RouteNode fn = null;
+		if (grr.getFromNode() != null){
+			fromId = grr.getFromNode().getId();
+			// polish input data provides id
+			fn = nodes.get(fromId);
+			if (fn == null ){
+				log.error(sourceDesc, "can't locate 'from' RouteNode with id", fromId);
+				return 0; 
+			}
+		} else {
+			List<RouteArc> possibleFromArcs = firstViaNode.getDirectArcsOnWay(grr.getFromWayId());
+			for (RouteArc arc : possibleFromArcs){
+				if (fn == null)
+					fn = arc.getDest();
+				else if (fn != arc.getDest()){
+					log.warn(sourceDesc, "found different 'from' arcs for way",grr.getFromWayId(),"restriction is ignored");
+					return 0;
+				}
+			}
+			if (fn == null){
+				log.warn(sourceDesc, "can't locate 'from' RouteNode for 'from' way", grr.getFromWayId());
+				return 0;
+			} else 
+				fromId = fn.getCoord().getId();
+		}
+		List<RouteArc> fromArcs = fn.getDirectArcsTo(firstViaNode, grr.getFromWayId()); 
+		if (fromArcs.isEmpty()){
+			log.error(sourceDesc, "can't locate arc from 'from' node ",fromId,"to 'via' node",firstViaId,"on way",grr.getFromWayId());
+			return 0;
+		}
+		
+		// a bit more complex: determine the to-node and arc(s) 
+		RouteNode uTurnNode = (viaNodes.size() > 1) ? viaNodes.get(viaNodes.size()-2): fn;
+		long uTurnWay = (viaNodes.size() > 1) ? grr.getViaWayIds().get(grr.getViaWayIds().size()-1) : grr.getFromWayId(); 
+		
+		RouteNode tn = null;
+		long toId = 0; 
+		List<RouteArc> toArcs = new ArrayList<>();
+		if (grr.getToNode() != null){ 
+			// polish input data provides id
+			toId = grr.getToNode().getId();
+			tn = nodes.get(toId);
+			if (tn == null ){
+				log.error(sourceDesc, "can't locate 'to' RouteNode with id", toId);
+				return 0; 
+			}
+		} else {
+			// we can have multiple arcs between last via node and to node. The 
+			// arcs can be on the same OSM way or on different OSM ways.
+			// We can have multiple arcs with different RoadDef objects that refer to the same 
+			// OSM way id. The direction indicator tells us what arc is probably meant.
+			List<RouteArc> possibleToArcs = lastViaNode.getDirectArcsOnWay(grr.getToWayId());
+			RouteArc fromArc = fromArcs.get(0);
+
+			boolean ignoreAngle = false;
+			if (fromArc.getLengthInMeter() <= 0.0001)
+				ignoreAngle = true;
+			if (grr.getDirIndicator() == '?')
+				ignoreAngle = true;
+			log.info(sourceDesc, "found", possibleToArcs.size(), "candidates for to-arc");
+
+			// group the available arcs by angle 
+			Map<Integer, List<RouteArc>> angleMap = new TreeMap<>();
+			for (RouteArc arc : possibleToArcs){
+				if (arc.getLengthInMeter() <= 0.0001)
+					ignoreAngle = true;
+				Integer angle = Math.round(getAngle(fromArc, arc));
+				List<RouteArc> list = angleMap.get(angle);
+				if (list == null){
+					list = new ArrayList<>();
+					angleMap.put(angle, list);
+				}
+				list.add(arc);
+			}
+
+			// find the group that fits best 
+			Iterator<Entry<Integer, List<RouteArc>>> iter = angleMap.entrySet().iterator();
+			Integer bestAngle = null;
+			while (iter.hasNext()){
+				Entry<Integer, List<RouteArc>> entry = iter.next();
+				if (ignoreAngle || matchDirectionInfo(entry.getKey(), grr.getDirIndicator()) ){
+					if (bestAngle == null)
+						bestAngle = entry.getKey();
+					else {
+						bestAngle = getBetterAngle(bestAngle, entry.getKey(), grr.getDirIndicator());
+					}
+				}
+			}
+			
+			if (bestAngle == null){
+				log.warn(sourceDesc,"the angle of the from and to way don't match the restriction");
+				return 0;
+			} else 
+				toArcs = angleMap.get(bestAngle);
+		}
+		if (toArcs.isEmpty()){
+			log.error(sourceDesc, "can't locate arc from 'via' node ",lastViaId,"to 'to' node",toId,"on way",grr.getToWayId());
+			return 0;
+		}
+		
 		List<RouteArc> badArcs = new ArrayList<>();
 		
 		if (grr.getType() == GeneralRouteRestriction.RestrType.TYPE_NOT){
@@ -362,10 +453,8 @@
 			// this is the inverse logic, grr gives the allowed path, we have to find the others
 			int uTurns = 0;
 			
-			RouteNode uTurnNode = (viaNodes.size() > 1) ? viaNodes.get(viaNodes.size()-2): fn;
-			long uTurnWay = (viaNodes.size() > 1) ? grr.getViaWayIds().get(grr.getViaWayIds().size()-1) : grr.getFromWayId(); 
 			for (RouteArc badArc : lastViaNode.arcsIteration()){
-				if (!badArc.isDirect() || badArc.getRoadDef().getId() == grr.getToWayId()) 
+				if (!badArc.isDirect() || toArcs.contains(badArc))
 					continue;
 				if (badArc.getDest() == uTurnNode && badArc.getRoadDef().getId() == uTurnWay){
 					// ignore u-turn
@@ -382,11 +471,18 @@
 				return 0;
 			}
 		}
+		
 		// create all possible paths for which the restriction applies 
 		List<List<RouteArc>> arcLists = new ArrayList<>();
 		arcLists.add(fromArcs);
 		arcLists.addAll(viaArcsList);
 		arcLists.add(badArcs);
+		if (arcLists.size() > MAX_RESTRICTIONS_ARCS){
+			log.warn(sourceDesc, "has more than", MAX_RESTRICTIONS_ARCS, "arcs, this is not supported");
+			return 0;
+		}
+		
+		// remove arcs which cannot be travelled by the vehicles listed in the restriction
 		for (int i = 0; i < arcLists.size(); i++){
 			List<RouteArc> arcs =  arcLists.get(i);
 			int countNoEffect = 0;
@@ -398,7 +494,7 @@
 					arcs.remove(j);
 				}
 				else if (arc.getRoadDef().isOneway()){
-					if (i == 0 && arc.isForward() || i > 0 && !arc.isForward()){
+					if (!arc.isForward()){
 						countOneway++;
 						arcs.remove(j);
 					}
@@ -427,6 +523,10 @@
 				return 0;
 			}
 		}
+		
+		// determine all possible combinations of arcs. In most cases,
+		// this will be 0 or one, but if the style creates multiple roads for one
+		// OSM way, this can be a larger number
 		int numCombis = 1;
 		int [] indexes = new int[arcLists.size()];
 		for (int i = 0; i < indexes.length; i++){
@@ -438,16 +538,17 @@
 		for (int i = 0; i < numCombis; i++){
 			for (RouteNode vn : viaNodes){
 				path.clear();
+				boolean viaNodeFound = false;
 				int pathNoAccessMask = 0;
 				for (int j = 0; j < indexes.length; j++){
 					RouteArc arc = arcLists.get(j).get(indexes[j]);
+					if (arc.getDest() == vn || viaNodeFound == false){
+						arc = getReverseArc(arc);
+						if (arc.getSource() == vn)
+							viaNodeFound = true;
+					}
 					pathNoAccessMask |= arc.getRoadDef().getTabAAccess();
-					if (arc.getDest() != vn)
-						path.add(arc);
-					else {
-						RouteArc reverseArc = vn.getDirectArcTo(arc.getSource(), arc.getRoadDef());
-						path.add(reverseArc);
-					}
+					path.add(arc);
 				}
 				if (isUsable(pathNoAccessMask, grr.getExceptionMask())){
 					vn.addRestriction(new RouteRestriction(vn, path, grr.getExceptionMask()));
@@ -463,9 +564,11 @@
 				}
 			}
 		}
+
+		// double check
 		if (indexes[0] != arcLists.get(0).size())
 			log.error(sourceDesc, " failed to generate all possible paths");
-		log.info(sourceDesc, "added",added,"route restrictions to img file");
+		log.info(sourceDesc, "added",added,"route restriction(s) to img file");
 		return added;
 	}
 
@@ -523,14 +626,22 @@
 			return 0;
 		}
 		int added = 0;
+		
 		for (RouteArc out: vn.arcsIteration()){
 			if (!out.isDirect())
 				continue;
+			int pathNoAccessMask = out.getRoadDef().getTabAAccess();
 			for (RouteArc in: vn.arcsIteration()){
-				if (!in.isDirect() || in == out)
+				if (!in.isDirect() || in == out || in.getDest() == out.getDest())
 					continue;
-				vn.addRestriction(new RouteRestriction(vn, Arrays.asList(in,out), grr.getExceptionMask()));
-				added++;
+				pathNoAccessMask |= in.getRoadDef().getTabAAccess();
+				if (isUsable(pathNoAccessMask, grr.getExceptionMask())){
+					vn.addRestriction(new RouteRestriction(vn, Arrays.asList(in,out), grr.getExceptionMask()));
+					added++;
+				} else {
+					if (log.isDebugEnabled())
+						log.debug(grr.getSourceDesc(),"ignored no-through-route",in,"to",out);
+				}
 			}
 		}
 		return added;
@@ -542,5 +653,95 @@
 
 		node.addThroughRoute(roadIdA, roadIdB);
 	}
-
+	
+	/**
+	 * Calculate the "angle" between to arcs. The arcs may not be connected.
+	 * We do this by "virtually" moving the toArc so that its source 
+	 * node lies on the destination node of the from arc.
+	 * This makes only sense if move is not over a large distance, we assume that this 
+	 * is the case as via ways should be short. 
+	 * @param fromArc arc with from node as source and first via node as destination
+	 * @param toArc arc with last via node as source
+	 * @return angle at in degree [-180;180]
+	 */
+	private float getAngle(RouteArc fromArc, RouteArc toArc){
+		// note that the values do not depend on the isForward() attribute
+		float headingFrom = fromArc.getFinalHeading();
+		float headingTo = toArc.getInitialHeading();
+		float angle = headingTo - headingFrom;
+		while(angle > 180)
+			angle -= 360;
+		while(angle < -180)
+			angle += 360;
+		return angle;
+	}
+	
+	private RouteArc getReverseArc(RouteArc arc){
+		return arc.getDest().getDirectArcTo(arc.getSource(), arc.getRoadDef());
+	}
+		
+	/**
+	 * Find the angle that comes closer to the direction indicated.
+	 * 
+	 * @param angle1 1st angle -180:180 degrees
+	 * @param angle2 2nd angle -180:180 degrees
+	 * @param dirIndicator l:left, r:right, u:u_turn, s: straight_on
+	 * @return
+	 */
+	private Integer getBetterAngle (Integer angle1, Integer angle2, char dirIndicator){
+		switch (dirIndicator){
+		case 'l':
+			if (Math.abs(-90-angle2) < Math.abs(-90-angle1))
+				return angle2; // closer to -90
+			break;
+		case 'r':
+			if (Math.abs(90-angle2) < Math.abs(90-angle1))
+				return angle2; // closer to 90
+			break;
+		case 'u': 
+			double d1 = (angle1 < 0 ) ? -180-angle1 : 180-angle1; 
+			double d2 = (angle2 < 0 ) ? -180-angle2 : 180-angle2; 
+			if (Math.abs(d2) < Math.abs(d1))
+				return angle2; // closer to -180
+			break;
+		case 's': 
+			if (Math.abs(angle2) < Math.abs(angle1))
+				return angle2; // closer to 0
+			break;
+		}
+		
+		return angle1;
+	}
+	
+	/**
+	 * Check if angle is in the range indicated by the direction
+	 * @param angle the angle -180:180 degrees
+	 * @param dirIndicator l:left, r:right, u:u_turn, s: straight_on 
+	 * @return
+	 */
+	private boolean matchDirectionInfo (float angle, char dirIndicator){
+		switch (dirIndicator){
+		case 'l':
+			if (angle < -3 && angle > - 177)
+				return true;
+			break;
+		case 'r':
+			if (angle > 3 && angle < 177)
+				return true;
+			break;
+		case 'u':
+			if (angle < -87 || angle > 93)
+				return true;
+			break;
+		case 's':
+			if (angle > -87 && angle < 87)
+				return true;
+			break;
+		case '?':
+			return true;
+		}
+		return false;
+	}
+	
+	
 }
Index: src/uk/me/parabola/mkgmap/osmstyle/RoadMerger.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/RoadMerger.java	(revision 3189)
+++ src/uk/me/parabola/mkgmap/osmstyle/RoadMerger.java	(working copy)
@@ -45,7 +45,8 @@
 	private static final double MAX_MERGE_ANGLE = 130d;
 	
 	/** maps which coord of a way(id) are restricted - they should not be merged */
-	private final MultiIdentityHashMap<Coord, Long> restrictions;
+	private final MultiIdentityHashMap<Coord, Long> restrictions = new MultiIdentityHashMap<Coord, Long>();
+
 	/** Contains a list of all roads (GType + Way) */
 	private final List<Road> roads;
 
@@ -361,9 +362,7 @@
 		}
 	}
 
-	public RoadMerger(List<Way> ways, List<GType> gtypes,
-			List<RestrictionRelation> restrictions,
-			List<Relation> throughRouteRelations) {
+	public RoadMerger(List<Way> ways, List<GType> gtypes) {
 		assert ways.size() == gtypes.size();
 
 		this.roads = new ArrayList<Road>(ways.size());
@@ -373,22 +372,25 @@
 				roads.add(new Road(i, ways.get(i), gtypes.get(i)));
 		}
 
-		this.restrictions = new MultiIdentityHashMap<Coord, Long>();
-		workoutRestrictionRelations(restrictions);
-		workoutThroughRoutes(throughRouteRelations);
 	}
 
 	/**
-	 * We must not merge roads at via points of restriction relations.
+	 * We must not merge roads at via points of restriction relations
+	 * if the way is referenced in the restriction.
 	 * @param restrictionRels
 	 */
 	private void workoutRestrictionRelations(List<RestrictionRelation> restrictionRels) {
 		for (RestrictionRelation rel : restrictionRels) {
-			if (!rel.isValid()) 
-				continue;
+			Set<Long> restrictionWayIds = rel.getWayIds();
 			for (Coord via: rel.getViaCoords()){
-				for (Long wayId : rel.getConnectedWayIds(via))
-					restrictions.add(via, wayId);
+				HashSet<Road> roadAtVia = new HashSet<>();
+				roadAtVia.addAll(startPoints.get(via));
+				roadAtVia.addAll(endPoints.get(via));
+				for (Road r: roadAtVia){
+					long wayId = r.getWay().getId();
+					if (restrictionWayIds.contains(wayId))
+						restrictions.add(via, wayId);
+				}
 			}
 		}
 	}
@@ -493,7 +495,9 @@
 	 * @param resultingWays list for the merged (and not mergeable) ways
 	 * @param resultingGTypes list for the merged (and not mergeable) GTypes
 	 */
-	public void merge(List<Way> resultingWays, List<GType> resultingGTypes) {
+	public void merge(List<Way> resultingWays, List<GType> resultingGTypes,
+			List<RestrictionRelation> restrictions,
+			List<Relation> throughRouteRelations) {
 
 		int noRoadsBeforeMerge = this.roads.size();
 		int noMerges = 0;
@@ -520,6 +524,8 @@
 			startPoints.add(start, road);
 			endPoints.add(end, road);
 		}
+		workoutRestrictionRelations(restrictions);
+		workoutThroughRoutes(throughRouteRelations);
 
 		// a set of all points where no more merging is possible
 		Set<Coord> mergeCompletedPoints = Collections.newSetFromMap(new IdentityHashMap<Coord, Boolean>());
Index: src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(revision 3189)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(working copy)
@@ -254,18 +254,9 @@
 		}
 		if (roads.isEmpty() || roads.get(roads.size()-1).getId() != way.getId()){
 			removeRestrictionsWithWay(Level.WARNING, way, "is not routable");
-		} else {
-			Way road = roads.get(roads.size()-1);
-			if (road  != way){
-				List<RestrictionRelation> rrList = wayRelMap.get(way.getId());
-				for (RestrictionRelation rr : rrList){
-					rr.replaceWay(way, road);
-				}
-			}
 		}
 	}
 
-
 	private void addConvertedWay(Way way, GType foundType) {
 		if (foundType.getFeatureKind() == FeatureKind.POLYLINE) {
 			GType type = new GType(foundType);
@@ -544,7 +535,7 @@
 	}
 
 	/**
-	 * Remove all restriction relations that refer to a way if that way will not appear
+	 * Remove all restriction relations that are invalid if the way will not appear
 	 * in the NOD file.
 	 * @param logLevel 
 	 * @param way the way that was removed
@@ -553,7 +544,7 @@
 	private void removeRestrictionsWithWay(Level logLevel, Way way, String reason){
 		List<RestrictionRelation> rrList = wayRelMap.get(way.getId());
 		for (RestrictionRelation rr : rrList){
-			if (rr.isValidWithoputWay(way) == false){
+			if (rr.isValidWithoputWay(way.getId()) == false){
 				if (log.isLoggable(logLevel)){
 					log.log(logLevel, "restriction",rr.toBrowseURL()," is ignored because referenced way",way.toBrowseURL(),reason);
 				}
@@ -563,32 +554,6 @@
 	}
 
 	/**
-	 * If a way was split (e.g. at tile boundary or because it has a loop),
-	 * and that way is part of a restriction relation, we have to update the 
-	 * references in the restriction.   
-	 * @param way way that was split
-	 * @param nWay new (part of that) way
-	 * @param reason reason for splitting
-	 * @param via the via node 
-	 */
-	private void replaceWayInRestrictions(Way way, Way nWay, String reason, Coord via){
-		List<RestrictionRelation> rrList = wayRelMap.get(way.getId());
-		for (RestrictionRelation rr : rrList){
-			if (rr.getViaCoords().contains(via)){
-				if (way.getPoints().get(0) == via && nWay.getPoints().get(0) != via){
-					long dd = 4;
-				}
-				if (way.getPoints().get(way.getPoints().size()-1) == via && nWay.getPoints().get(nWay.getPoints().size()-1) != via){
-					long dd = 4;
-				}
-				boolean changed = rr.replaceWay(way, nWay);
-				if (changed)
-					log.info("way",way.getId(),"in restriction", rr.getId(),reason,via.toOSMURL());
-			}
-		}
-	}
-	
-	/**
 	 * Merges roads with identical attributes (gtype, OSM tags) to reduce the size of the 
 	 * road network.
 	 */
@@ -599,12 +564,12 @@
 		}
 		
 		// instantiate the RoadMerger - the roads and roadTypes lists are copied
-		RoadMerger merger = new RoadMerger(roads, roadTypes, restrictions, throughRouteRelations);
+		RoadMerger merger = new RoadMerger(roads, roadTypes);
 		// clear the lists
 		roads.clear();
 		roadTypes.clear();
 		// merge the roads and copy the results to the roads and roadTypes list
-		merger.merge(roads, roadTypes);
+		merger.merge(roads, roadTypes, restrictions, throughRouteRelations);
 	}
 	
 	public void end() {
@@ -634,6 +599,11 @@
 				points.addAll(modWay.getPoints());
 			}
 		}
+		for (Long wayId: deletedRoads){
+			if (wayRelMap.containsKey(wayId)){
+				log.error("internal error: was that is used in valid restriction relation was removed, id:",wayId);
+			}
+		}
 		deletedRoads = null;
 		modifiedRoads = null;
 
@@ -928,7 +898,11 @@
 			}
 			GeneralRouteRestriction rr = new GeneralRouteRestriction("no_through", exceptMask, "CoordPOI at " + p.toOSMURL());
 			rr.setViaNodes(Arrays.asList(viaNode));
-			collector.addRestriction(rr);
+			int added = collector.addRestriction(rr);
+			if (added == 0){
+				log.info("Access restriction in POI node " + node.toBrowseURL() + " was ignored, has no effect on any connected way");
+			} else 
+				log.info("Access restriction in POI node " + node.toBrowseURL() + " was translated to",added,"route restriction(s)");
 		}
 	}
 
@@ -952,7 +926,7 @@
 		// earlier by the RelationStyleHook
 		if(relation instanceof RestrictionRelation) {
 			RestrictionRelation rr = (RestrictionRelation)relation;
-			if(rr.isValid(bbox)) {
+			if(rr.isValid()) {
 				restrictions.add(rr);
 				for (long id : rr.getWayIds())
 					wayRelMap.add(id, rr);
@@ -1308,9 +1282,6 @@
 							// make sure it becomes a node
 							co.incHighwayCount();
 						}
-						if (co.isViaNodeOfRestriction()){
-							replaceWayInRestrictions(way, nWay, "was clipped at tile boundary at", co);
-						}
 					}
 					clippedWays.add(nWay);
 				}
@@ -1575,7 +1546,6 @@
 					arcLength += d;
 				}
 			}
-
 			if(p.getHighwayCount() > 1) {
 				// this point is a node connecting highways
 				CoordNode coordNode = nodeIdMap.get(p);
@@ -1627,7 +1597,6 @@
 		MapLine line = new MapLine();
 		elementSetup(line, gt, way);
 		line.setPoints(points);
-		
 		MapRoad road = new MapRoad(way.getId(), line);
 
 		boolean doFlareCheck = true;
@@ -1683,11 +1652,16 @@
 			road.ferry(true);
 
 		int numNodes = nodeIndices.size();
+		if (way.isViaWay() && numNodes > 2){
+			List<RestrictionRelation> rrList = wayRelMap.get(way.getId());
+			for (RestrictionRelation rr : rrList){
+				rr.updateViaWay(way, nodeIndices);
+			}
+		}
 		road.setNumNodes(numNodes);
 		if(numNodes > 0) {
 			// replace Coords that are nodes with CoordNodes
 			boolean hasInternalNodes = false;
-			
 			for(int i = 0; i < numNodes; ++i) {
 				int n = nodeIndices.get(i);
 				if(n > 0 && n < points.size() - 1)
@@ -1764,15 +1738,9 @@
 
 		// remove the points after the split from the original way
 		// it's probably more efficient to remove from the end first
-		for(int i = numPointsInWay - 1; i > index; --i){
-			Coord co = wayPoints.remove(i);
-			if (co.isViaNodeOfRestriction()){ 
-				// special case: way may be part of restriction
-				if(wayPoints.get(0) != co){
-					replaceWayInRestrictions(way, trailingWay, "was split at", co);
-				}
-			}
-		}
+		for(int i = numPointsInWay - 1; i > index; --i)
+			wayPoints.remove(i);
+		
 		return trailingWay;
 	}
 
Index: src/uk/me/parabola/mkgmap/osmstyle/WrongAngleFixer.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/WrongAngleFixer.java	(revision 3189)
+++ src/uk/me/parabola/mkgmap/osmstyle/WrongAngleFixer.java	(working copy)
@@ -104,6 +104,8 @@
 			replacement = new CoordPOI(replacement);
 			((CoordPOI) replacement).setNode(((CoordPOI) toRepl).getNode());
 		}
+		if (toRepl.isViaNodeOfRestriction())
+			replacement.setViaNodeOfRestriction(true);
 		replacements.put(toRepl, replacement);
 		while (toRepl.getHighwayCount() > replacement.getHighwayCount())
 			replacement.incHighwayCount();
@@ -507,13 +509,13 @@
 							+ "_mod_non_routable", points);
 				}
 			}
-		}
 		
-		for (RestrictionRelation rr: restrictions){
-			for (Coord p: rr.getViaCoords()){ 
-				Coord replacement = getReplacement(p, null, replacements);
-				if (p != replacement){
-					rr.replaceViaCoord(p, replacement);
+			for (RestrictionRelation rr: restrictions){
+				for (Coord p: rr.getViaCoords()){ 
+					Coord replacement = getReplacement(p, null, replacements);
+					if (p != replacement){
+						rr.replaceViaCoord(p, replacement);
+					}
 				}
 			}
 		}
Index: src/uk/me/parabola/mkgmap/reader/osm/LinkDestinationHook.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/LinkDestinationHook.java	(revision 3189)
+++ src/uk/me/parabola/mkgmap/reader/osm/LinkDestinationHook.java	(working copy)
@@ -146,9 +146,6 @@
 		for (Relation rel : saver.getRelations().values()) {
 			if (rel instanceof RestrictionRelation) {
 				RestrictionRelation rrel = (RestrictionRelation) rel;
-				if (rrel.isValid()==false)
-					// ignore invalid restrictions
-					continue;
 				for (Long wayId : rrel.getWayIds())
 					restrictions.add(wayId, rrel);
 			}
@@ -217,6 +214,8 @@
 		if (wayRestrictions.isEmpty()) {
 			return;
 		}
+		if (oldWay.isViaWay())
+			newWay.setViaWay(true);
 		// create a copy because original list may be modified within the loop
 		for (RestrictionRelation rr : new ArrayList<>(wayRestrictions)) {
 			Coord lastPointNewWay = newWay.getPoints().get(0);
@@ -223,14 +222,15 @@
 			List<Coord> viaCoords = rr.getViaCoords();
 			for (Coord via : viaCoords){
 				if (via == lastPointNewWay) {
-					if (rr.isToWay(oldWay)) {
+					if (rr.isToWay(oldWay.getId())) {
 						log.debug("Change to-way",oldWay.getId(),"to",newWay.getId(),"for relation",rr.getId(),"at",lastPointNewWay.toOSMURL());
-						rr.replaceWay(oldWay, newWay);
+						rr.replaceWay(oldWay.getId(), newWay.getId());
 						restrictions.remove(oldWay.getId(), rr);
 						restrictions.add(newWay.getId(), rr);
-					} else if (rr.isFromWay(oldWay)){
+						
+					} else if (rr.isFromWay(oldWay.getId())){
 						log.debug("Change from-way",oldWay.getId(),"to",newWay.getId(),"for relation",rr.getId(),"at",lastPointNewWay.toOSMURL());
-						rr.replaceWay(oldWay, newWay);
+						rr.replaceWay(oldWay.getId(), newWay.getId());
 						restrictions.remove(oldWay.getId(), rr);
 						restrictions.add(newWay.getId(), rr);
 					} 
Index: src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java	(revision 3189)
+++ src/uk/me/parabola/mkgmap/reader/osm/RelationStyleHook.java	(working copy)
@@ -53,7 +53,7 @@
 			}			
 			relationRules.resolveType(rel, TypeResult.NULL_RESULT);
 			if (rel instanceof RestrictionRelation){
-				((RestrictionRelation) rel).eval();
+				((RestrictionRelation) rel).eval(saver.getBoundingBox());
 			}
 		}
 		super.end();
Index: src/uk/me/parabola/mkgmap/reader/osm/RestrictionRelation.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/RestrictionRelation.java	(revision 3189)
+++ src/uk/me/parabola/mkgmap/reader/osm/RestrictionRelation.java	(working copy)
@@ -15,6 +15,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
@@ -34,23 +35,31 @@
 /**
  * Representation of an OSM turn restriction
  *
- * @author Mark Burton
+ * @author Mark Burton, GerdP
  */
 public class RestrictionRelation extends Relation {
     private static final Logger log = Logger.getLogger(RestrictionRelation.class);
 
-    private List<Way> fromWays = new ArrayList<>();
-    private List<Way> toWays = new ArrayList<>();
-    private List<Way> viaWays = new ArrayList<>();
-    private List<Coord> viaPoints = new ArrayList<>();
+    private List<Long> fromWayIds = new ArrayList<>(2);
+    private List<Long> toWayIds = new ArrayList<>(2);
+    private List<Long> viaWayIds = new ArrayList<>(2);
+    private List<Coord> viaPoints = new ArrayList<>(2);
     private Coord viaCoord;
     private String restriction;
 	private byte exceptMask;
-	
+	private char dirIndicator; 
     private String messagePrefix;
     private boolean valid;
     private boolean evalWasCalled;
-
+    
+	// These tags are not loaded by default but if they exist issue a warning
+	final static String[] unsupportedTags = { "day_on", "day_off", "hour_on", "hour_off" };
+	
+	final static List<String> supportedRestrictions = Arrays.asList(
+		"no_right_turn", "no_left_turn", "no_u_turn", "no_straight_on", 
+		"only_right_turn", "only_left_turn", "only_straight_on", 
+		"no_entry", "no_exit"	     
+	);
 	/**
 	 * Create an instance based on an existing relation.  We need to do
 	 * this because the type of the relation is not known until after all
@@ -63,24 +72,34 @@
 		copyTags(other);
 		for (Map.Entry<String, Element> pair : other.getElements()) {
 			addElement(pair.getKey(), pair.getValue());
-			
 		}
 	}
 	
 	/**
-	 * 
+	 * The evaluation should happen after style processing.
+	 * Normally this is called from the {@link RelationStyleHook}
+	 * Performs also diverse plausibility checks.
+	 * @param bbox tile boundary
 	 */
-	public void eval(){
-		evalWasCalled = true;
-		final String browseURL = toBrowseURL();
-		fromWays.clear();
-		viaWays.clear();
-		toWays.clear();
+	public void eval(Area bbox){
+		if (evalWasCalled){
+			log.error(messagePrefix,"internal error: eval() was already called");
+			fromWayIds.clear();
+			toWayIds.clear();
+			viaWayIds.clear();
+		}
 		if (getTag("type") == null){
-      log.info(messagePrefix, "type tag was removed, relation is ignored");				
+			// style removed the tag
+			log.info(messagePrefix, "type tag was removed, relation is ignored");				
 			valid = false;
 			return;
 		}
+		
+	    List<Way> fromWays = new ArrayList<>();
+	    List<Way> toWays = new ArrayList<>();
+	    List<Way> viaWays = new ArrayList<>();
+		evalWasCalled = true;
+		final String browseURL = toBrowseURL();
 		valid = true;
 		// find out what kind of restriction we have and to which vehicles it applies
 		exceptMask = RouteRestriction.EXCEPT_FOOT | RouteRestriction.EXCEPT_EMERGENCY;
@@ -108,34 +127,39 @@
 				valid = false;
 			}
 		}
-    if (specifc_type == null){
-				log.warn(messagePrefix, "no valid restriction tag found");				
-				valid = false;
-        return;
-    }
+		if (specifc_type == null){
+			// style removed the tag
+			log.info(messagePrefix, "no valid restriction tag found");				
+			valid = false;
+			return;
+		}
 		restriction = specifc_type.trim();
+		
 		messagePrefix = "Turn restriction (" + restriction + ") " + browseURL;
-		if(restriction.equals("no_left_turn") ||
-				   restriction.equals("no_right_turn") ||
-				   restriction.equals("no_straight_on") ||
-				   restriction.equals("no_u_turn") ||
-				   restriction.startsWith("no_turn") ||
-				   restriction.equals("no_entry") ||
-				   restriction.equals("no_exit") ) {
-			if(restriction.startsWith("no_turn"))
-				log.warn(messagePrefix, "has bad type '" + restriction + "' it should be of the form no_X_turn rather than no_turn_X");
-
-		}  else if(restriction.equals("only_left_turn") ||
-				restriction.equals("only_right_turn") ||
-				restriction.startsWith("only_straight") ||
-				restriction.startsWith("only_turn")) {
-			if(restriction.startsWith("only_turn"))
-				log.warn(messagePrefix, "has bad type '" + restriction + "' it should be of the form only_X_turn rather than only_turn_X");
-		} else {
+		if (supportedRestrictions.contains(restriction) == false){
 			log.warn(messagePrefix, "ignoring unsupported restriction type '" + restriction + "'");
 			valid = false;
 			return;
 		}
+		
+		String dirInfo = "";
+		if (restriction.contains("left"))
+			dirInfo += "l";
+		if (restriction.contains("right"))
+			dirInfo += "r";
+		if (restriction.contains("straight"))
+			dirInfo += "s";
+		if (restriction.endsWith("u_turn"))
+			dirInfo += "u";
+		if (dirInfo.length() > 1){
+			log.warn(messagePrefix, "ignoring unsupported restriction type '" + restriction + "'");
+			valid = false;
+			return;
+		} else if (dirInfo.length() == 1){
+			dirIndicator = dirInfo.charAt(0);
+		} else 
+			dirIndicator = '?';
+		
 		String type = getTag("type");
 		if (type.startsWith("restriction:")){
 			exceptMask = (byte) 0xff;
@@ -146,6 +170,7 @@
 				return;
 			}
 		}
+		
 		String except = getTag("except");
 		if(except != null) {
 			for(String vehicle : except.split("[,;]")) { // be nice
@@ -154,12 +179,6 @@
 			}
 		}
 		
-		// These tags are not loaded by default but if they exist issue a warning
-		String[] unsupportedTags = {
-		    "day_on",
-		    "day_off",
-		    "hour_on",
-		    "hour_off" };
 		for (String unsupportedTag : unsupportedTags) {
 			if (getTag(unsupportedTag) != null) {
 				log.warn(messagePrefix, "ignoring unsupported '" + unsupportedTag + "' tag");
@@ -271,13 +290,14 @@
 				log.warn(messagePrefix, "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' (" + toWay.toBrowseURL() + ") ways don't connect");
 				valid = false;
 			} else {
-				log.warn(messagePrefix, "lacks 'via' node (guessing it should be at", viaCoord.toOSMURL() + ", why don't you add it to the OSM data?)");				
+				if (fromPoints.get(0) != viaCoord && fromPoints.get(fromPoints.size()-1) != viaCoord ||
+						toPoints.get(0) != viaCoord && toPoints.get(toPoints.size()-1) != viaCoord){
+					log.warn(messagePrefix, "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' (" + toWay.toBrowseURL() + ") ways don't connect at an end point");
+					valid = false;
+				} else
+					log.warn(messagePrefix, "lacks 'via' node (guessing it should be at", viaCoord.toOSMURL() + ", why don't you add it to the OSM data?)");				
 			}
 		}
-		if(restriction == null) {
-			log.warn(messagePrefix, "lacks 'restriction' tag (e.g. no_left_turn)");
-			valid = false;
-		}
 
 		if(fromWays.isEmpty() ) {
 			log.warn(messagePrefix, "lacks 'from' way");
@@ -290,12 +310,12 @@
 		}
 
 		if ((fromWays.size() > 1 || toWays.size() > 1) && viaWays.isEmpty() == false){
-			log.warn(messagePrefix, "via way(s) are not supported with multiple from or to ways");
+			log.warn(messagePrefix, "'via' way(s) are not supported with multiple 'from' or 'to' ways");
 			valid = false;
 		}
 		if (toWays.size() == 1 && fromWays.size() == 1 && viaWays.isEmpty()){
 			if ("no_u_turn".equals(restriction) && fromWays.get(0).equals(toWays.get(0))){
-				log.warn(messagePrefix,"no_u_turn with equal 'from' and 'to' way is ignored");
+				log.warn(messagePrefix,"no_u_turn with equal 'from' and 'to' way and via node is ignored");
 				valid = false;
 			}
 		}
@@ -308,7 +328,9 @@
 					valid = false;
 				} else {
 					if (way.getPoints().get(0) == way.getPoints().get(way.getPoints().size()-1)){
-						log.warn(messagePrefix, "way", way.toBrowseURL(), "starts and ends at same node, this is not supported");
+						if (ways == toWays && dirIndicator != '?')
+							continue; // we try to determine the correct part in RoadNetwork 
+						log.warn(messagePrefix, "way", way.toBrowseURL(), "starts and ends at same node, don't konw which one to use");
 						valid = false;
 					}
 				}
@@ -316,15 +338,105 @@
 		}
 		if (!valid)
 			return;
+		if (viaPoints.isEmpty() == false)
+			viaCoord = viaPoints.get(0);
+		
+		if(viaCoord == null && viaWays.isEmpty()) {
+			valid = false;
+			return;
+		}
+		
+		viaPoints.clear();
+		Coord v1 = viaCoord;
+		Coord v2 = viaCoord;
 		if (viaWays.isEmpty() == false){
-			for (Way way:viaWays){
-				way.getPoints().get(0).setViaNodeOfRestriction(true);
-				way.getPoints().get(way.getPoints().size()-1).setViaNodeOfRestriction(true);
-				way.setViaWay(true);
+			v1 = viaWays.get(0).getPoints().get(0);
+			v2 = viaWays.get(0).getPoints().get(viaWays.get(0).getPoints().size()-1);
+		}
+		// check if all from ways are connected at the given via point or with the given via ways
+		for (Way fromWay : fromWays){
+			Coord e1 = fromWay.getPoints().get(0);
+			Coord e2 = fromWay.getPoints().get(fromWay.getPoints().size() - 1);
+			if (e1 == v1 || e2 == v1)
+				viaCoord = v1;
+			else if (e1 == v2 || e2 == v2)
+				viaCoord = v2;
+			else {
+				log.warn(messagePrefix, "'from' way", fromWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
+				valid = false;
+			} 
+		}
+		if (!valid)
+			return;
+		viaPoints.add(viaCoord);
+		// check if via ways are connected in the given order
+		for (int i = 0; i < viaWays.size();i++){
+			Way way = viaWays.get(i);
+			Coord v = viaPoints.get(viaPoints.size()-1);
+			if (way.getPoints().get(0) == v)
+				v2 = way.getPoints().get(way.getPoints().size()-1);
+			else if (way.getPoints().get(way.getPoints().size()-1) == v)
+				v2 = way.getPoints().get(0);
+			else {
+				log.warn(messagePrefix, "'via' way", way.toBrowseURL(), "doesn't start or end at",v.toDegreeString());
+				valid = false;
 			}
+			viaPoints.add(v2);
 		}
-		if (viaCoord != null) 
-			viaCoord.setViaNodeOfRestriction(true);
+		
+		// check if all via points are inside the bounding box
+		int countInside = 0;
+		for (Coord via: viaPoints){
+			if(bbox.contains(via))
+				++countInside;
+		}
+		if (countInside == 0)
+			valid = false;
+		else if (countInside > 0 && countInside < viaPoints.size()){
+			log.warn(messagePrefix,"via way crosses tile boundary. Don't know how to save that, ignoring it");
+			valid = false;
+		}
+		
+		if (!valid)
+			return;
+		// check if all to ways are connected to via point or last via way
+		Coord lastVia = viaPoints.get(viaPoints.size()-1);
+		for (Way toWay : toWays){
+			Coord e1 = toWay.getPoints().get(0);
+			Coord e2 = toWay.getPoints().get(toWay.getPoints().size() - 1);
+			if(e1 != lastVia && e2 != lastVia) {
+				log.warn(messagePrefix, "'to' way", toWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
+				valid = false;
+			} 
+		}
+		if (valid && !viaWays.isEmpty() && restriction.startsWith("only")){
+			log.warn(messagePrefix, "check: 'via' way(s) are used in",restriction,"restriction");
+		}
+		if (valid){
+			// make sure that via way(s) don't appear in the from or to lists 
+			for (Way w: viaWays){
+				if (fromWays.contains(w)){
+					log.warn(messagePrefix, "'via' way",w.toBrowseURL(),"appears also as 'from' way");
+					valid = false;
+				}
+				if (toWays.contains(w)){
+					log.warn(messagePrefix, "'via' way",w.toBrowseURL(),"appears also as 'to' way");
+					valid = false;
+				}
+			}
+		}
+		if (valid){
+			for (Way w: fromWays)
+				fromWayIds.add(w.getId());
+			for (Way w: toWays)
+				toWayIds.add(w.getId());
+			for (Way w: viaWays){
+				w.setViaWay(true);
+				viaWayIds.add(w.getId());
+			}
+			for (Coord v: viaPoints)
+				v.setViaNodeOfRestriction(true);
+		}
 	}
 
 	/** 
@@ -366,12 +478,12 @@
 		return true;			
 	}
 	
-	public boolean isFromWay(Way way) {
-		return fromWays.contains(way);
+	public boolean isFromWay(long wayId) {
+		return fromWayIds.contains(wayId);
 	}
 
-	public boolean isToWay(Way way) {
-		return toWays.contains(way);
+	public boolean isToWay(long wayId) {
+		return toWayIds.contains(wayId);
 	}
 
 	public void replaceViaCoord(Coord oldP, Coord newP) {
@@ -387,89 +499,9 @@
 		}
 	}
 	
-	public boolean isValid() {
-		if (!evalWasCalled){
-			log.warn("internal error: RestrictionRelation.isValid() is called before eval()");
-			eval();
-		}
-		if(!valid)
-			return false;
-		
-		if (viaPoints.isEmpty() == false)
-			viaCoord = viaPoints.get(0);
-		
-		if(viaCoord == null && viaWays.isEmpty()) {
-			valid = false;
-			return false;
-		}
-		
-		viaPoints.clear();
-		Coord v1 = viaCoord;
-		Coord v2 = viaCoord;
-		if (viaWays.isEmpty() == false){
-			v1 = viaWays.get(0).getPoints().get(0);
-			v2 = viaWays.get(0).getPoints().get(viaWays.get(0).getPoints().size()-1);
-		}
-		// check if all from ways are connected at the given via point or with the given via ways
-		for (Way fromWay : fromWays){
-			Coord e1 = fromWay.getPoints().get(0);
-			Coord e2 = fromWay.getPoints().get(fromWay.getPoints().size() - 1);
-			if (e1 == v1 || e2 == v1)
-				viaCoord = v1;
-			else if (e1 == v2 || e2 == v2)
-				viaCoord = v2;
-			else {
-				log.warn(messagePrefix, "'from' way", fromWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
-				valid = false;
-			} 
-		}
-		if (!valid)
-			return false;
-		viaPoints.add(viaCoord);
-		// check if via ways are connected in the given order
-		for (int i = 0; i < viaWays.size();i++){
-			Way way = viaWays.get(i);
-			Coord v = viaPoints.get(viaPoints.size()-1);
-			if (way.getPoints().get(0) == v)
-				v2 = way.getPoints().get(way.getPoints().size()-1);
-			else if (way.getPoints().get(way.getPoints().size()-1) == v)
-				v2 = way.getPoints().get(0);
-			else {
-				log.warn(messagePrefix, "'via' way", way.toBrowseURL(), "doesn't start or end at",v.toDegreeString());
-				valid = false;
-			}
-			viaPoints.add(v2);
-		}
-		if (!valid)
-			return false;
-		// check if all to ways are connected to via point or last via way
-		Coord lastVia = viaPoints.get(viaPoints.size()-1);
-		for (Way toWay : toWays){
-			Coord e1 = toWay.getPoints().get(0);
-			Coord e2 = toWay.getPoints().get(toWay.getPoints().size() - 1);
-			if(e1 != lastVia && e2 != lastVia) {
-				log.warn(messagePrefix, "'to' way", toWay.toBrowseURL(), "doesn't start or end at 'via' node or way");
-				valid = false;
-			} 
-		}
-		if (valid && !viaWays.isEmpty() && isOnlyXXXRestriction()){
-			log.warn(messagePrefix, "check: 'via' way(s) are used in",restriction,"restriction");
-		}
-		if (valid && viaWays.size() > 1){
-			log.warn(messagePrefix, "sorry, multiple via ways are not (yet) supported");
-			valid = false;
-		}
-		if (!valid)
-			return false;
-		for (Coord v: viaPoints)
-			v.setViaNodeOfRestriction(true);
-		return valid;
-	}
-
 	public void addRestriction(MapCollector collector, IdentityHashMap<Coord, CoordNode> nodeIdMap) {
 		if (!valid)
 			return;
-		
 	    List<CoordNode> viaNodes = new ArrayList<>();
 		for (Coord v: viaPoints){
 			CoordNode vn = nodeIdMap.get(v);
@@ -480,93 +512,46 @@
 			else 
 				viaNodes.add(vn);
 		}
-		List<NodeOnWay> fromNodes = new ArrayList<>(); 
-		for (Way fromWay: fromWays){
-			CoordNode fromNode = findNextNode(fromWay, viaNodes.get(0));
-			if (fromNode == null){
-				log.warn(messagePrefix, "can't find routable 'from' node on 'from' way",fromWay);
-				return;
-			}
-			fromNodes.add(new NodeOnWay(fromNode, fromWay));
+
+		if (viaNodes.size() > 6){
+			log.warn(messagePrefix,"has more than 6 via nodes, this is not supported");
+			return;
 		}
-		Coord currNode = viaNodes.get(0);
-		
-		for (Way viaWay: viaWays){
-			if (viaWay.getPoints().get(0).getId() == 0 || viaWay.getPoints().get(viaWay.getPoints().size()-1).getId() == 0){
-				log.error(messagePrefix, "'via' way", viaWay.toBrowseURL(), "doesn't start or end with CoordNode");
-				return;
-			}
-			Coord nextNode = null;
-			if (viaWay.getPoints().get(0) == currNode)
-				nextNode = viaWay.getPoints().get(viaWay.getPoints().size()-1);
-			else 
-				nextNode = viaWay.getPoints().get(0);
-			Coord co = findNextNode(viaWay, currNode);
-			if (nextNode != co){
-				if (co == null)
-					return;
-				log.warn(messagePrefix, "'via' way", viaWay.toBrowseURL(), "is also connected to other roads between end-points at",co.toDegreeString()); 
-				return;
-			}
-			currNode = nextNode;
-		} 
-		List<NodeOnWay> toNodes = new ArrayList<>(); 
-		for (Way toWay: toWays){
-			CoordNode toNode = findNextNode(toWay, currNode);
-			if (toNode == null){
-				log.warn(messagePrefix, "can't find routable 'to' node on 'to' way",toWay);
-				return;
-			}
-			toNodes.add(new NodeOnWay(toNode, toWay));
-		}
-		
-		if(restriction == null || fromNodes.isEmpty() || toNodes.isEmpty()) {
+		if(restriction == null){
 			log.error("internal error: can't add valid restriction relation", this.getId(), "type", restriction);
 			return;
 		}
-		
+		int addedRestrictions = 0;
 		GeneralRouteRestriction grr;
-		List<Long> viaWayIds = new ArrayList<>();
-		for (Way viaWay : viaWays)
-			viaWayIds.add(viaWay.getId());
 		if(restriction.startsWith("no_")){
-			for (NodeOnWay fromNode : fromNodes){
-				for (NodeOnWay toNode : toNodes){
+			for (long fromWayId : fromWayIds){
+				for (long toWayId : toWayIds){
 					grr = new GeneralRouteRestriction("not", exceptMask, messagePrefix);
-					grr.setFromNode(fromNode.node);
-					grr.setFromWayId(fromNode.way.getId());
-					grr.setToNode(toNode.node);
-					grr.setToWayId(toNode.way.getId());
+					grr.setFromWayId(fromWayId);
+					grr.setToWayId(toWayId);
 					grr.setViaNodes(viaNodes);
 					grr.setViaWayIds(viaWayIds);
-
-					int numAdded = collector.addRestriction(grr);
-					if (numAdded == 0){
-						return; // message was created before
-					}
-					if(restriction.startsWith("no_turn"))
-						log.warn(messagePrefix, "has bad type '" + restriction + "' it should be of the form no_X_turn rather than no_turn_X - I added the restriction anyway - blocks routing to way", toNode.way.toBrowseURL());
-					else 
-						log.info(messagePrefix, restriction, "added - blocks routing to way", toNode.way.toBrowseURL());
+					grr.setDirIndicator(dirIndicator);
+					addedRestrictions += collector.addRestriction(grr);
 				}
 			}
+			if (log.isInfoEnabled())
+				log.info(messagePrefix, restriction, "translated to",addedRestrictions,"img file restrictions");
 		}
 		else if(restriction.startsWith("only_")){
-			log.info(messagePrefix, restriction, "added - allows routing to way", toWays.get(0).toBrowseURL());
 			grr = new GeneralRouteRestriction("only", exceptMask, messagePrefix);
-			grr.setFromNode(fromNodes.get(0).node);
-			grr.setFromWayId(fromNodes.get(0).way.getId());
-			grr.setToNode(toNodes.get(0).node);
-			grr.setToWayId(toNodes.get(0).way.getId());
+			grr.setFromWayId(fromWayIds.get(0));
+			grr.setToWayId(toWayIds.get(0));
 			grr.setViaNodes(viaNodes);
 			grr.setViaWayIds(viaWayIds);
+			grr.setDirIndicator(dirIndicator);
 			int numAdded = collector.addRestriction(grr);
-			if (numAdded == 0){
-				return; // message was created before
-			}
+			if (numAdded > 0)
+				log.info(messagePrefix, restriction, "added - allows routing to way", toWayIds.get(0));
+
 		}
 		else {
-			log.warn(messagePrefix, "has unsupported type '" + restriction + "'");
+			log.error("mkgmap internal error: unknown restriction", restriction);
 		}
 	}
 
@@ -577,135 +562,135 @@
 	}
 
 	public String toString() {
-		return "[restriction = " + restriction + ", from = " + fromWays.get(0).toBrowseURL() + ", to = " + toWays.get(0).toBrowseURL() + ", via = " + viaCoord.toOSMURL() + "]";
+		String s = "[restriction id = " + getId() + "(" + restriction + ")";
+		if (!fromWayIds.isEmpty() && !toWayIds.isEmpty() && viaCoord != null )
+			s += ", from = " + fromWayIds.get(0) + ", to = " + toWayIds.get(0) + ", via = " + viaCoord.toOSMURL() + "]";
+		else 
+			s += "]";
+		return s;
 	}
 	
-	public boolean isOnlyXXXRestriction(){
-		return restriction.startsWith("only");
-	}
-	
 	/**
-	 * First next CoordNode on the way, starting search at start
-	 * @param way the way
-	 * @param currNode the start node (
-	 * @return the next node or null if none was found
+	 * @return true if restriction is usable
 	 */
-	private CoordNode findNextNode(Way way, Coord currNode){
-		List<Coord> points = way.getPoints();
-		if (points.get(0) == currNode){
-			for (int i = 1; i < points.size(); i++){
-				Coord co = points.get(i);
-				if (co.getId() != 0)
-					return (CoordNode)co;
-			}
-		} else if (points.get(points.size()-1) == currNode){
-			for (int i = points.size()-2; i >= 0; --i){
-				Coord co = points.get(i);
-				if (co.getId() != 0)
-					return (CoordNode)co;
-			}
-		} else 
-			log.error(messagePrefix,"way",way.toBrowseURL(),"doesn't have required node");
-			
-		return null;
+	public boolean isValid() {
+		assert evalWasCalled;
+		return valid;
 	}
 
-	/**
-	 * Check if the via node(s) of the restriction are all inside 
-	 * or on the bbox and if the restriction itself is valid. 
-	 * @param bbox
-	 * @return true if restriction is okay
-	 */
-	public boolean isValid(Area bbox) {
-		if (!isValid())
-			return false;
-		if (viaCoord != null && bbox.contains(viaCoord) == false)
-			return false;
-		int countInside = 0;
-		for (Way viaWay : viaWays){
-			if(bbox.contains(viaWay.getPoints().get(0)))
-				++countInside;
-			if(bbox.contains(viaWay.getPoints().get(viaWay.getPoints().size()-1)))
-				++countInside;
-		}
-		if (countInside > 0 && countInside < viaWays.size() * 2){
-			log.warn(messagePrefix,"via way crosses tile boundary. Don't know how to save that, ignoring it");
-			return false;
-		}
-		return true;
-	}
-
 	public List<Coord> getViaCoords() {
+		assert evalWasCalled;
 		return viaPoints;
 	}
 
-	public Set<Long> getConnectedWayIds(Coord via){
-		Set<Long> wayIds = new HashSet<>();
-		for (List<Way> ways : Arrays.asList(fromWays,viaWays,toWays)){
-			for (Way way : ways){
-				List<Coord> points = way.getPoints();
-				if (points.get(0) == via || points.get(points.size()-1) == via)
-					wayIds.add(way.getId());
-			}
-		}
-		return wayIds;
-	}
-	
+	/**
+	 * 
+	 * @return a Set with the OSM IDs of all ways used in the restriction 
+	 */
 	public Set<Long> getWayIds(){
+		assert evalWasCalled;
 		Set<Long> wayIds = new HashSet<>();
-		for (List<Way> ways : Arrays.asList(fromWays,viaWays,toWays)){
-			for (Way way : ways){
-				wayIds.add(way.getId());
-			}
-		}
+		wayIds.addAll(fromWayIds);
+		wayIds.addAll(viaWayIds);
+		wayIds.addAll(toWayIds);
 		return wayIds;
 	}
 	
-	public boolean replaceWay(Way way, Way nWay) {
+	/**
+	 * Replace 
+	 * @param oldWayId
+	 * @param newWayId
+	 * @return
+	 */
+	public boolean replaceWay(long oldWayId, long newWayId) {
+		assert evalWasCalled;
 		boolean matched = false;
-		for (List<Way> ways : Arrays.asList(fromWays,viaWays,toWays)){
+		for (List<Long> ways: Arrays.asList(fromWayIds, viaWayIds, toWayIds)){
 			for (int i = 0; i < ways.size(); i++){
-				if (ways.get(i) == way){
-					ways.set(i, nWay);
+				if (ways.get(i) == oldWayId){
+					ways.set(i, newWayId);
 					matched = true;
 				}
 			}
 		}
-		if (way.isViaWay())
-			nWay.setViaWay(true);
 		return matched;
 	}
 
-	// helper class 
-	private class NodeOnWay{
-		final CoordNode node;
-		final Way way;
-		public NodeOnWay(CoordNode node, Way way) {
-			this.node = node;
-			this.way = way;
-		}
+	/**
+	 * check if restriction is still valid if the way with the given id is not in the map
+	 * @param wayId
+	 * @return
+	 */
+	public boolean isValidWithoputWay(long wayId) {
+		assert evalWasCalled;
+		if (viaWayIds.contains(wayId))
+			return false;
+		fromWayIds.remove(wayId);
+		if (fromWayIds.isEmpty())
+			return false;
+		// else it must be a no_entry restriction which still is valid
+
+		toWayIds.remove(wayId);
+		if (toWayIds.isEmpty())
+			return false;
+		// else it must be a no_exit restriction which still is valid
+		return true;
 	}
 
 	/**
-	 * check if restriction is still valid if the given way is removed
+	 * A via way may be connected to other ways between the end points.
+	 * We have to create a complete path for that. 
 	 * @param way
-	 * @return
+	 * @param nodeIndices
 	 */
-	public boolean isValidWithoputWay(Way way) {
-		if (viaWays.contains(way))
-			return false;
-		if (fromWays.contains(way)){
-			fromWays.remove(way);
-			if (fromWays.isEmpty())
-				return false;
-			// else it must be a no_entry restriction which still is valid
+	public void updateViaWay(Way way, List<Integer> nodeIndices) {
+		if (!valid)
+			return;
+		if (viaWayIds.contains(way.getId()) == false)
+			return;
+		Coord first = way.getPoints().get(nodeIndices.get(0));
+		Coord last = way.getPoints().get(
+				nodeIndices.get(nodeIndices.size() - 1));
+		int posFirst = -1;
+		for (int i = 0; i < viaPoints.size(); i++) {
+			if (first == viaPoints.get(i)) {
+				posFirst = i;
+				break;
+			}
 		}
-		if (toWays.contains(way)){
-			toWays.remove(way);
-			if (toWays.isEmpty())
-				return false;
-			// else it must be a no_exit restriction which still is valid
+		int posLast = -1;
+		for (int i = 0; i < viaPoints.size(); i++) {
+			if (last == viaPoints.get(i)) {
+				posLast = i;
+				break;
+			}
 		}
-		return true;
+		if (posFirst < 0  || posLast < 0 || Math.abs(posLast-posFirst) > 1){
+			log.error(messagePrefix, "internal error: via way doesn't contain expected points");
+			valid = false;
+			return;
+		}
+		List<Coord> midPoints = new ArrayList<>();
+		for (int i = 1; i + 1 < nodeIndices.size(); i++) {
+			midPoints.add(way.getPoints().get(nodeIndices.get(i)));
+		}
+		if (posFirst < posLast)
+			viaPoints.addAll(posFirst + 1, midPoints); 
+		else {
+			Collections.reverse(midPoints);
+			viaPoints.addAll(posLast + 1, midPoints);
+		}
+		
+		int wayPos = viaWayIds.indexOf(way.getId());
+		for (int i = 0; i < midPoints.size(); i++){
+			viaWayIds.add(wayPos+1, way.getId());
+		}
+		if (viaPoints.size() != viaWayIds.size()+1){
+			log.error("internal error: number of via points and via ways no longer fits");
+			valid = false;
+		} else if (viaPoints.size() > 6){
+			log.warn(messagePrefix,"has more than 6 via nodes, this is not supported");
+			valid = false;
+		} 
 	}
 }
