Index: src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java	(revision 1379)
+++ src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java	(working copy)
@@ -172,7 +172,7 @@
 		writer.put(getPoiDisplayFlags());
 
 		writer.put3(displayPriority);
-		writer.putInt(0x110301);
+		writer.putInt(0x170401);
 
 		writer.putChar((char) 1);
 		writer.put((byte) 0);
Index: src/uk/me/parabola/mkgmap/build/MapBuilder.java
===================================================================
--- src/uk/me/parabola/mkgmap/build/MapBuilder.java	(revision 1379)
+++ src/uk/me/parabola/mkgmap/build/MapBuilder.java	(working copy)
@@ -110,7 +110,7 @@
 	private boolean	poiAddresses = true;
 	private int		poiDisplayFlags;
 	private boolean sortRoads = true;
-	private static final double FILTER_DISTANCE = 2.6;
+	private static final double FILTER_DISTANCE = 1.3;
 	private boolean enableLineCleanFilters = true;
 	private boolean makePOIIndex = false;
 	private int routeCenterBoundaryType = 0;
Index: src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java	(revision 1379)
+++ src/uk/me/parabola/mkgmap/osmstyle/ActionRule.java	(working copy)
@@ -52,7 +52,7 @@
 		this.type = null;
 	}
 
-	public GType resolveType(Element el) {
+	public GType resolveType(Element el, GType pre) {
 		if (expression == null || expression.eval(el)) {
 			for (Action a : actions)
 				a.perform(el);
Index: src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java	(revision 1379)
+++ src/uk/me/parabola/mkgmap/osmstyle/ExpressionRule.java	(working copy)
@@ -28,22 +28,22 @@
  * @author Steve Ratcliffe
  */
 public class ExpressionRule implements Rule {
-	private final Op exression;
+	private final Op expression;
 	private final GType gtype;
 
-	public ExpressionRule(Op exression, GType gtype) {
-		this.exression = exression;
+	public ExpressionRule(Op expression, GType gtype) {
+		this.expression = expression;
 		this.gtype = gtype;
 	}
 
-	public GType resolveType(Element el) {
-		if (exression.eval(el))
+	public GType resolveType(Element el, GType pre) {
+		if (expression.eval(el))
 			return gtype;
 
 		return null;
 	}
 
 	public String toString() {
-		return exression.toString() + ' ' + gtype;
+		return expression.toString() + ' ' + gtype;
 	}
 }
Index: src/uk/me/parabola/mkgmap/osmstyle/FixedRule.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/FixedRule.java	(revision 1379)
+++ src/uk/me/parabola/mkgmap/osmstyle/FixedRule.java	(working copy)
@@ -32,7 +32,7 @@
 		this.gtype = gtype;
 	}
 
-	public GType resolveType(Element el) {
+	public GType resolveType(Element el, GType pre) {
 		return gtype;
 	}
 
Index: src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java	(revision 1379)
+++ src/uk/me/parabola/mkgmap/osmstyle/RuleSet.java	(working copy)
@@ -63,14 +63,14 @@
 		return rules.entrySet();
 	}
 
-	public GType resolveType(Element el) {
+	public GType resolveType(Element el, GType pre) {
 		GType foundType = null;
 		for (String tagKey : el) {
 			Rule rule = rules.get(tagKey);
 			if (rule != null) {
-				GType type = rule.resolveType(el);
+				GType type = rule.resolveType(el, pre);
 				if (type != null) {
-					if (foundType == null || type.isBetterPriority(foundType)) {
+					if ((foundType == null || type.isBetterPriority(foundType)) && (pre == null || pre.isBetterPriority(type))) {
 						foundType = type;
 					}
 				}
Index: src/uk/me/parabola/mkgmap/osmstyle/SequenceRule.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/SequenceRule.java	(revision 1379)
+++ src/uk/me/parabola/mkgmap/osmstyle/SequenceRule.java	(working copy)
@@ -34,9 +34,9 @@
 public class SequenceRule implements Rule, Iterable<Rule> {
 	private final List<Rule> ruleList = new ArrayList<Rule>();
 
-	public GType resolveType(Element el) {
+	public GType resolveType(Element el, GType pre) {
 		for (Rule r : ruleList) {
-			GType type = r.resolveType(el);
+			GType type = r.resolveType(el, pre);
 			if (type != null)
 				return type;
 		}
Index: src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(revision 1379)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(working copy)
@@ -20,6 +20,7 @@
 import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Properties;
 import java.util.regex.Pattern;
@@ -260,26 +261,48 @@
 			foundType = makeGTypeFromTags(way);
 			if(foundType == null)
 				return;
+			if (!foundType.isProcessingOnly()){
+				if (foundType.getFeatureKind() == GType.POLYLINE) {
+					if(foundType.isRoad())
+						addRoad(way, foundType);
+					else
+						addLine(way, foundType);
+				}
+				else
+					addShape(way, foundType);
+			}
 		}
 		else {
 			preConvertRules(way);
 
-			foundType = wayRules.resolveType(way);
-			if (foundType == null)
-				return;
 
-			postConvertRules(way, foundType);
-		}
+			do {
+				foundType = wayRules.resolveType(way, foundType);
+				if (foundType == null)
+					return;
+  
+				postConvertRules(way, foundType);
 
-		if (foundType.getFeatureKind() == GType.POLYLINE) {
-		    if(foundType.isRoad() &&
-			   !MapElement.hasExtendedType(foundType.getType()))
-				addRoad(way, foundType);
-		    else
-				addLine(way, foundType);
+				if (!foundType.isProcessingOnly()){
+					if (foundType.getFeatureKind() == GType.POLYLINE) {
+						if(foundType.isRoad()) {
+							if(foundType.isFinal())
+								addRoad(way, foundType);    
+							else
+								addRoad(way.duplicate(), foundType);
+							}
+						else {
+							if(foundType.isFinal())
+								addLine(way, foundType);
+							else
+								addLine(way.duplicate(), foundType);
+							}
+					}
+					else
+						addShape(way, foundType);
+				}
+			} while (!foundType.isFinal());
 		}
-		else
-			addShape(way, foundType);
 	}
 
 	/**
@@ -295,18 +318,23 @@
 			foundType = makeGTypeFromTags(node);
 			if(foundType == null)
 				return;
+			if (!foundType.isProcessingOnly())
+				addPoint(node, foundType);
 		}
 		else {
 			preConvertRules(node);
 
-			foundType = nodeRules.resolveType(node);
-			if (foundType == null)
-				return;
+			do {
+				foundType = nodeRules.resolveType(node, foundType);
+				if (foundType == null)
+					return;
 
-			postConvertRules(node, foundType);
+				postConvertRules(node, foundType);
+
+				if (!foundType.isProcessingOnly())
+					addPoint(node, foundType);
+			} while (!foundType.isFinal());
 		}
-
-		addPoint(node, foundType);
 	}
 
 	/**
@@ -360,10 +388,29 @@
 	 * @param relation The relation to convert.
 	 */
 	public void convertRelation(Relation relation) {
-		// Relations never resolve to a GType and so we ignore the return
-		// value.
-		relationRules.resolveType(relation);
 
+		// If the relation resolves to a GType of a way then add that way to the map
+		preConvertRules(relation);
+		GType foundType = relationRules.resolveType(relation,null);
+		if (foundType != null) {
+			postConvertRules(relation, foundType);
+			List<Element> elements = relation.getElements();
+			// Extract all the ways that belong to the relation
+			List<Way> ways = new ArrayList<Way>(elements.size());
+			for (Element el : elements) {
+				if (el instanceof Way)
+					addWayToListAndChainIfPossible(ways, (Way) el, foundType.isRoad()); // care about oneways if it is a road
+			}
+
+			for (Way w : ways) {
+				w.setName(relation.getName());
+			    if (foundType.isRoad())
+			    	addRoad(w, foundType);
+			    else
+			    	addLine(w, foundType);
+			}
+		} 
+	
 		if(relation instanceof RestrictionRelation) {
 			RestrictionRelation rr = (RestrictionRelation)relation;
 			if(rr.isValid()) {
@@ -377,6 +424,135 @@
 		}
 	}
 
+	
+		private void addWayToListAndChainIfPossible(List<Way> ways, Way newWay, boolean careAboutOneways) {
+		outer_loop: for (;;) {
+			List<Coord> newWayCoords = newWay.getPoints();
+			int newWayNumPoints = newWayCoords.size();
+			if (newWayNumPoints == 0) return;
+	
+			Coord newWayFirstCoord = newWayCoords.get(0);
+			Coord newWayLastCoord = newWayCoords.get(newWayNumPoints-1);
+	
+			ListIterator<Way> listIterator = ways.listIterator();
+			while (listIterator.hasNext()) {
+				Way existantWay = listIterator.next();
+				List<Coord> existantWayCoords = existantWay.getPoints();
+				int existantWayNumPoints = existantWayCoords.size();
+				if (existantWayNumPoints == 0) continue;
+	
+				Coord existantWayFirstCoord = existantWayCoords.get(0);
+				Coord existantWayLastCoord = existantWayCoords.get(existantWayNumPoints-1);
+	
+				// Test coordinates to see whether two way can be chained together
+				// If they are chained together the only tag we will copy is the oneway tag (if we care about them).
+				// Access tags will have to be set by the relation!
+				// TODO: Handle the oneway=-1 tag in a useful way, now it prevents chaining of the ways.
+	
+				// Both ways share the same first point. So the new way is connected in reverse, but if we care about oneways
+				// then only if none of them is one.
+				if (existantWayFirstCoord.equals(newWayFirstCoord) 
+					&& (!careAboutOneways || (!existantWay.isBoolTag("oneway") && !newWay.isBoolTag("oneway")))) {
+	
+					Way replacementWay = new Way(existantWay.getId());
+
+					// Add points of new way in reverse
+					ListIterator<Coord> newWayCoordIterator = newWayCoords.listIterator(newWayNumPoints);
+					while (newWayCoordIterator.hasPrevious()) {
+						replacementWay.addPoint(newWayCoordIterator.previous());
+					}
+					// And of the existant way in order (starting from the second point)
+					ListIterator<Coord> existantWayCoordIterator = existantWayCoords.listIterator(1);
+					while (existantWayCoordIterator.hasNext()) {
+						replacementWay.addPoint(existantWayCoordIterator.next());
+					}
+					// Remove the existant way that was chained to the new way and start the search again.
+					listIterator.remove();
+					newWay = replacementWay;
+					continue outer_loop;
+				// The last point of the existant way is the same as the first point of the new way, so they are
+				// connected in order, but if we care about oneways then only if they either both have the oneway tag or both have not.
+				} else if (existantWayLastCoord.equals(newWayFirstCoord)
+					&& (!careAboutOneways || !(existantWay.isBoolTag("oneway") ^ newWay.isBoolTag("oneway")))) {
+	
+					Way replacementWay = new Way(existantWay.getId());
+					if (careAboutOneways) {
+						String onewayValue = existantWay.getTag("oneway");
+						if (onewayValue != null)
+							replacementWay.addTag("oneway",onewayValue);
+					}
+
+					// Add points of existant way in order
+					ListIterator<Coord> existantWayCoordIterator = existantWayCoords.listIterator();
+					while (existantWayCoordIterator.hasNext()) {
+						replacementWay.addPoint(existantWayCoordIterator.next());
+					}
+					// And of the new way also in order (starting from the second point)
+					ListIterator<Coord> newWayCoordIterator = newWayCoords.listIterator(1);
+					while (newWayCoordIterator.hasNext()) {
+						replacementWay.addPoint(newWayCoordIterator.next());
+					}
+					// Remove the existant way that was chained to the new way and start the search again.
+					listIterator.remove();
+					newWay = replacementWay;
+					continue outer_loop;
+				// The first point of the existant way is the same as the last point of the new way, so connect them,
+				// but starting with the new way and if we care about oneways then only if they either both have the
+				// oneway tag or both have not.
+				} else if (existantWayFirstCoord.equals(newWayLastCoord)
+					&& (!careAboutOneways || (!(existantWay.isBoolTag("oneway") ^ newWay.isBoolTag("oneway"))))) {
+	
+					Way replacementWay = new Way(existantWay.getId());
+					if (careAboutOneways) {
+						String onewayValue = existantWay.getTag("oneway");
+						if (onewayValue != null)
+							replacementWay.addTag("oneway",onewayValue);
+					}
+
+					// Add points of the new way in order
+					ListIterator<Coord> newWayCoordIterator = newWayCoords.listIterator();
+					while (newWayCoordIterator.hasNext()) {
+						replacementWay.addPoint(newWayCoordIterator.next());
+					}
+					// And of the existant way also in order (starting from the second point)
+					ListIterator<Coord> existantWayCoordIterator = existantWayCoords.listIterator(1);
+					while (existantWayCoordIterator.hasNext()) {
+						replacementWay.addPoint(existantWayCoordIterator.next());
+					}
+					// Remove the existant way that was chained to the new way and start the search again.
+					listIterator.remove();
+					newWay = replacementWay;
+					continue outer_loop;
+				// The last points of the existant and the new way are the same. So the new way is connected in reverse,
+				// but if we care about oneways than only if neither of them has the oneway tag set.
+				} else if (existantWayLastCoord.equals(newWayLastCoord)
+					&& (!careAboutOneways || (!existantWay.isBoolTag("oneway") && !newWay.isBoolTag("oneway")))) {
+	
+					Way replacementWay = new Way(existantWay.getId());
+
+					// Add points of existant way in order
+					ListIterator<Coord> existantWayCoordIterator = existantWayCoords.listIterator();
+					while (existantWayCoordIterator.hasNext()) {
+						replacementWay.addPoint(existantWayCoordIterator.next());
+					}
+					// And of the new way in reverse (starting from the second last point)
+					ListIterator<Coord> newWayCoordIterator = newWayCoords.listIterator(newWayNumPoints-1);
+					while (newWayCoordIterator.hasPrevious()) {
+						replacementWay.addPoint(newWayCoordIterator.previous());
+					}
+					// Remove the existant way that was chained to the new way and start the search again.
+					listIterator.remove();
+					newWay = replacementWay;
+					continue outer_loop;
+				}
+			}
+			// If we get here no way was found anymore that we could chain to. Add the way and return.
+			ways.add(newWay);
+			return;
+		}
+	}
+
+	
 	private void addLine(Way way, GType gt) {
 		List<Coord> wayPoints = way.getPoints();
 		List<Coord> points = new ArrayList<Coord>(wayPoints.size());
@@ -419,7 +595,7 @@
 
 		clipper.clipShape(shape, collector);
 		
-		GType pointType = nodeRules.resolveType(way);
+		GType pointType = nodeRules.resolveType(way, null);
 		
 		if(pointType != null)
 			shape.setPoiType(pointType.getType());
Index: src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java	(revision 1379)
+++ src/uk/me/parabola/mkgmap/osmstyle/TypeReader.java	(working copy)
@@ -23,6 +23,9 @@
 	}
 
 	public GType readType(TokenScanner ts) {
+
+		GType gt;
+
 		// We should have a '[' to start with
 		Token t = ts.nextToken();
 		if (t == null || t.getType() == TokType.EOF)
@@ -34,33 +37,73 @@
 
 		ts.skipSpace();
 		String type = ts.nextValue();
-		if (!Character.isDigit(type.charAt(0)))
-			throw new SyntaxException(ts, "Garmin type number must be first.  Saw '" + type + '\'');
+		if (Character.isDigit(type.charAt(0))) {
 
-		log.debug("gtype", type);
-		GType gt = new GType(kind, type);
+			log.debug("gtype", type);
+			gt = new GType(kind, type);
+			gt.setProcessingAndConversion();
 
-		while (!ts.isEndOfFile()) {
-			ts.skipSpace();
-			String w = ts.nextValue();
-			if (w.equals("]"))
-				break;
+			while (!ts.isEndOfFile()) {
+				ts.skipSpace();
+				String w = ts.nextValue();
+				if (w.equals("]"))
+					break;
 
-			if (w.equals("level")) {
-				setLevel(ts, gt);
-			} else if (w.equals("resolution")) {
-				setResolution(ts, gt);
-			} else if (w.equals("default_name")) {
-				gt.setDefaultName(nextValue(ts));
-			} else if (w.equals("road_class")) {
-				gt.setRoadClass(nextIntValue(ts));
-			} else if (w.equals("road_speed")) {
-				gt.setRoadSpeed(nextIntValue(ts));
-			} else if (w.equals("copy")) {
-				// reserved word.  not currently used
-			} else {
-				throw new SyntaxException(ts, "Unrecognised type command '" + w + '\'');
+				if (w.equals("level")) {
+					setLevel(ts, gt);
+				} else if (w.equals("resolution")) {
+					setResolution(ts, gt);
+				} else if (w.equals("default_name")) {
+					gt.setDefaultName(nextValue(ts));
+				} else if (w.equals("road_class")) {
+					gt.setRoadClass(nextIntValue(ts));
+				} else if (w.equals("road_speed")) {
+					gt.setRoadSpeed(nextIntValue(ts));
+				} else if (w.equals("copy")) {
+					// reserved word.  not currently used
+				} else if (w.equals("continue")) {
+					gt.setContinue();
+				} else if (w.equals("stop")) {
+					gt.setFinal();
+				} else {
+					throw new SyntaxException(ts, "Unrecognised type command '" + w + '\'');
+				}
 			}
+
+		} else if (type.equals("continue")) {
+
+			gt = new GType(kind, "0");
+			gt.setContinue();
+			gt.setProcessingOnly();
+
+			while (!ts.isEndOfFile()) {
+				ts.skipSpace();
+				String w = ts.nextValue();
+				if (w.equals("]")) {
+					break;
+				} else {
+					throw new SyntaxException(ts, "Unrecognised type command '" + w + '\'');
+				}
+			}
+
+		} else if (type.equals("stop")) {
+
+			gt = new GType(kind, "0");
+			gt.setFinal();
+			gt.setProcessingOnly();
+
+			while (!ts.isEndOfFile()) {
+				ts.skipSpace();
+				String w = ts.nextValue();
+				if (w.equals("]")) {
+					break;
+				} else {
+					throw new SyntaxException(ts, "Unrecognised type command '" + w + '\'');
+				}
+			}
+
+		} else {
+			throw new SyntaxException(ts, "Garmin type number must be first.  Saw '" + type + '\'');
 		}
 
 		gt.fixLevels(levels);
Index: src/uk/me/parabola/mkgmap/reader/osm/GType.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/GType.java	(revision 1379)
+++ src/uk/me/parabola/mkgmap/reader/osm/GType.java	(working copy)
@@ -39,6 +39,10 @@
 	private static int nextPriority = 1;
 	private static final int PRIORITY_PUSH = 100000;
 
+	// control flag, whether this is an empty dummy element
+	// for processing rules
+	private boolean RuleWithoutConversion = false;
+
 	private final int featureKind;
 	private final int type;
 
@@ -58,6 +62,11 @@
 
 	private boolean road;
 
+	// control flag, whether this element defines
+	// the final conversion, or whether we shall search
+	// for further matching elements
+	private boolean FinalElement = true;
+	
 	public GType(int featureKind, String type) {
 		priority = nextPriority();
 		this.featureKind = featureKind;
@@ -190,7 +199,7 @@
 		return road;
 	}
 
-	public static void push() {
+	public void setFinal() {		FinalElement = true;	}		public void setContinue() {		FinalElement = false;	}		public boolean isFinal() {		return FinalElement;	}		public void setProcessingOnly() {		RuleWithoutConversion = true;	}		public void setProcessingAndConversion() {		RuleWithoutConversion = false;	}		public boolean isProcessingOnly() {		return RuleWithoutConversion;	}	public static void push() {
 		nextPriority += PRIORITY_PUSH;
 	}
 
Index: src/uk/me/parabola/mkgmap/reader/osm/Rule.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/Rule.java	(revision 1379)
+++ src/uk/me/parabola/mkgmap/reader/osm/Rule.java	(working copy)
@@ -29,7 +29,8 @@
 	 * represent it.
 	 *
 	 * @param el The element as read from an OSM xml file in 'tag' format.
+	 * @param pre The previous garmin type generated from the element.
 	 * @return Enough information to represent this as a garmin type.
 	 */
-	public GType resolveType(Element el);
+	public GType resolveType(Element el, GType pre);
 }
