Index: src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(revision 1131)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(working copy)
@@ -30,6 +30,7 @@
 import uk.me.parabola.imgfmt.app.CoordNode;
 import uk.me.parabola.imgfmt.app.Exit;
 import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.filters.LineMergeFilter;
 import uk.me.parabola.mkgmap.general.AreaClipper;
 import uk.me.parabola.mkgmap.general.Clipper;
 import uk.me.parabola.mkgmap.general.LineAdder;
@@ -66,6 +67,7 @@
 	private final String[] nameTagList;
 
 	private final MapCollector collector;
+	private List<MapLine> linesCollector = new ArrayList<MapLine>();
 
 	private Clipper clipper = Clipper.NULL_CLIPPER;
 	private Area bbox;
@@ -97,6 +99,7 @@
 	private final Rule relationRules;
 
 	private boolean ignoreMaxspeeds;
+	private boolean mergeLines;
 
 	class AccessMapping {
 		private final String type;
@@ -123,10 +126,7 @@
 
 	private LineAdder lineAdder = new LineAdder() {
 		public void add(MapLine element) {
-			if (element instanceof MapRoad)
-				collector.addRoad((MapRoad) element);
-			else
-				collector.addLine(element);
+			linesCollector.add(element);
 		}
 	};
 
@@ -138,6 +138,7 @@
 		nodeRules = style.getNodeRules();
 		relationRules = style.getRelationRules();
 		ignoreMaxspeeds = props.getProperty("ignore-maxspeeds") != null;
+		mergeLines = props.getProperty("merge-lines") != null;
 
 		LineAdder overlayAdder = style.getOverlays(lineAdder);
 		if (overlayAdder != null)
@@ -175,6 +176,22 @@
 			addShape(way, foundType);
 	}
 
+	public void postConvertWays() {
+		if (mergeLines) {
+			log.info("Start merging lines with " + linesCollector.size() + " lines.");
+			LineMergeFilter merger = new LineMergeFilter();
+			linesCollector = merger.merge(linesCollector);
+			log.info("After merging " + linesCollector.size() + " lines remain.");
+		}
+		for (MapLine element : linesCollector) {
+			if (element instanceof MapRoad)
+				collector.addRoad((MapRoad) element);
+			else
+				collector.addLine(element);
+		}
+		linesCollector = null;
+	}
+
 	/**
 	 * Takes a node (that has its own identity) and converts it from the OSM
 	 * type to the Garmin map type.
@@ -247,17 +264,16 @@
 		// Relations never resolve to a GType and so we ignore the return
 		// value.
 		relationRules.resolveType(relation);
+	}
 
-		if(relation instanceof RestrictionRelation) {
-			RestrictionRelation rr = (RestrictionRelation)relation;
-			if(rr.isValid()) {
-				List<RestrictionRelation> lrr = restrictions.get(rr.getViaCoord());
-				if(lrr == null) {
-					lrr = new ArrayList<RestrictionRelation>();
-					restrictions.put(rr.getViaCoord(), lrr);
-				}
-				lrr.add(rr);
+	public void convertRestrictionRelation(RestrictionRelation relation) {
+		if(relation.isValid()) {
+			List<RestrictionRelation> lrr = restrictions.get(relation.getViaCoord());
+			if(lrr == null) {
+				lrr = new ArrayList<RestrictionRelation>();
+				restrictions.put(relation.getViaCoord(), lrr);
 			}
+			lrr.add(relation);
 		}
 	}
 
Index: src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java	(revision 1131)
+++ src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java	(working copy)
@@ -447,7 +447,8 @@
 
 		coordMap = null;
 		for (Relation r : relationMap.values())
-			converter.convertRelation(r);
+			if (!(r instanceof RestrictionRelation))
+				converter.convertRelation(r);
 
 		for (Node n : nodeMap.values())
 			converter.convertNode(n);
@@ -462,11 +463,14 @@
 		for (Way w: wayMap.values())
 			converter.convertWay(w);
 
+		converter.postConvertWays();
+
 		wayMap = null;
 
 		RoadNetwork roadNetwork = mapper.getRoadNetwork();
 		for (Relation r : relationMap.values()) {
 			if(r instanceof RestrictionRelation) {
+				converter.convertRestrictionRelation((RestrictionRelation) r);
 				((RestrictionRelation)r).addRestriction(roadNetwork);
 			}
 		}
Index: src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java	(revision 1131)
+++ src/uk/me/parabola/mkgmap/reader/osm/OsmConverter.java	(working copy)
@@ -33,6 +33,8 @@
 	 */
 	public void convertWay(Way way);
 
+	public void postConvertWays();
+	
 	/**
 	 * Takes a node (that has its own identity) and converts it from the OSM
 	 * type to the Garmin map type.
@@ -54,6 +56,8 @@
 	 */
 	public void convertRelation(Relation relation);
 
+	public void convertRestrictionRelation(RestrictionRelation relation);
+
 	/**
 	 * Set the bounding box for this map.  This should be set before any other
 	 * elements are converted if you want to use it.
Index: src/uk/me/parabola/mkgmap/filters/LineMergeFilter.java
===================================================================
--- src/uk/me/parabola/mkgmap/filters/LineMergeFilter.java	(revision 0)
+++ src/uk/me/parabola/mkgmap/filters/LineMergeFilter.java	(revision 0)
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2009 Johann Gail
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ * 
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ * 
+ * Author: Johann Gail
+ */
+ 
+package uk.me.parabola.mkgmap.filters;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import uk.me.parabola.imgfmt.app.Coord;
+import uk.me.parabola.log.Logger;
+import uk.me.parabola.mkgmap.general.MapLine;
+import uk.me.parabola.mkgmap.general.MapRoad;
+import uk.me.parabola.util.MultiHashMap;
+
+public class LineMergeFilter{
+	private static final Logger log = Logger.getLogger(LineMergeFilter.class);
+
+	MultiHashMap<Coord, MapLine> startPoints = new MultiHashMap<Coord, MapLine>();
+	MultiHashMap<Coord, MapLine> endPoints = new MultiHashMap<Coord, MapLine>();
+
+	public LineMergeFilter() {}
+
+	private boolean areSimilar(MapLine line1, MapLine line2) {
+		// Tests whether the lines are in those respects similar that allow them to be merged
+		if (line1.getType() != line2.getType())
+			return false;
+
+		if (line1.getMinResolution() != line2.getMinResolution() || line1.getMaxResolution() != line2.getMaxResolution())
+			return false;
+		
+		String name1 = line1.getName();
+		String name2 = line2.getName();
+
+		if ((name1 == null && name2 != null) || (name1 != null && name2 == null))
+			return false;
+		if (name1 != null && name2 != null && !name1.equals(name2))
+			return false;
+
+		String ref1 = line1.getRef();
+		String ref2 = line2.getRef();
+
+		if ((ref1 == null && ref2 != null) || (ref1 != null && ref2 == null))
+			return false;
+		if (ref1 != null && ref2 != null && !ref1.equals(ref2))
+			return false;
+
+		if ((line1.isHighway() != line2.isHighway()))
+			return false;
+
+		if (line1.isRoad() != line2.isRoad())
+			return false;
+		
+		if (!line1.isRoad() && !line2.isRoad())
+			// if both lines are not roads the comparison is finished here
+			return true;
+
+		// From here on dealing with roads
+		MapRoad road1 = (MapRoad) line1;
+		MapRoad road2 = (MapRoad) line2;
+
+		if (road1.isDirection() != road2.isDirection())
+			return false;
+
+		if (road1.getRoadClass() != road2.getRoadClass())
+			return false;
+
+		if (road1.getSpeed() != road2.getSpeed())
+			return false;
+
+		if (road1.isOneway() != road2.isOneway())
+			return false;
+
+		if (road1.isToll() != road2.isToll())
+			return false;
+
+		if (road1.getAccess() != road2.getAccess())
+			return false;
+
+		if (road1.isUnknownAccess08() != road2.isUnknownAccess08())
+			return false;
+
+		if (road1.isNoThroughRouting() != road2.isNoThroughRouting())
+			return false;
+
+		return true;
+	}
+	
+	private void addLine(MapLine line) {
+		List<Coord> points = line.getPoints();
+		startPoints.add(points.get(0), line);
+		endPoints.add(points.get(points.size()-1), line);
+	}
+	
+	private void mergeLines(MapLine line1, MapLine line2) {
+		// Removes the first line,
+		// Merges the points in the second one
+		List<Coord> points1 = line1.getPoints();
+		List<Coord> points2 = line2.getPoints();
+		// remove line1 from startPoints and endPoints
+		startPoints.remove(points1.get(0), line1);
+		endPoints.remove(points1.get(points1.size()-1), line1);
+		// replace start point of line2 with start point of line1
+		startPoints.remove(points2.get(0), line2);
+		startPoints.add(points1.get(0), line2);
+		line2.insertPointsAtStart(points1);
+	}
+
+	private void mergeLinesReverse2nd(MapLine line1, MapLine line2) {
+		// Removes the first line,
+		// Merges the points in the second one
+		List<Coord> points1 = line1.getPoints();
+		List<Coord> points2 = line2.getPoints();
+		// remove line1 from startPoints and endPoints
+		startPoints.remove(points1.get(0), line1);
+		endPoints.remove(points1.get(points1.size()-1), line1);
+		// replace start point of line2 with start point of line1 (after reversal)
+		startPoints.remove(points2.get(0), line2);
+		Collections.reverse(points1);
+		startPoints.add(points1.get(0), line2);
+		line2.insertPointsAtStart(points1);
+	}
+	
+	private void addPointsAtStart(MapLine line, List<Coord> additionalPoints) {
+		log.info("merged lines before " + line.getName());
+		List<Coord> points = line.getPoints();
+		startPoints.remove(points.get(0), line);
+		line.insertPointsAtStart(additionalPoints);
+		startPoints.add(points.get(0), line);
+	}
+
+	private void addPointsAtEnd(MapLine line, List<Coord> additionalPoints) {
+		log.info("merged lines after " + line.getName());
+		List<Coord> points = line.getPoints();
+		endPoints.remove(points.get(points.size()-1), line);
+		line.insertPointsAtEnd(additionalPoints);
+		endPoints.add(points.get(points.size()-1), line);
+	}
+
+	public List<MapLine> merge(List<MapLine> lines) {
+		outer_loop: for (MapLine line : lines) {
+			List<Coord> points = line.getPoints();
+			Coord start = points.get(0); 
+			Coord end = points.get(points.size()-1); 
+
+			// Search for start point in hashlist 
+			// (can the end of current line connect to an existing line?)
+			for (MapLine line2 : startPoints.get(end)) {
+				if (areSimilar(line,line2)) {
+					addPointsAtStart(line2, points);
+					// Search for endpoint in hashlist
+					// (if the other end (=start of line =start of line2) could be connected to an existing line,
+					//  both lines have to be merged and one of them dropped)
+					for (MapLine line1 : endPoints.get(start)) {
+						if (areSimilar(line2,line1) && !line2.equals(line1)) // don't make a closed loop a double loop
+						{
+							mergeLines(line1, line2);
+							continue outer_loop;
+						}
+					}
+					continue outer_loop;
+				}
+			}
+
+			// Search for endpoint in hashlist
+			// (can the start of current line connect to an existing line?)
+			for (MapLine line2 : endPoints.get(start)) {
+				if (areSimilar(line,line2)) {
+					addPointsAtEnd(line2, points);
+					continue outer_loop;
+				}
+			}
+
+			if (!line.isDirection()) {
+				// if the direction doesn't matter, try also merging with one line reversed
+				for (MapLine line2 : startPoints.get(start)) {
+					if (areSimilar(line,line2)) {
+						Collections.reverse(points);
+						addPointsAtStart(line2, points);
+						// Search for endpoint in hashlist
+						// (if the other end (=end of line =end of line2) could be connected to an existing line,
+						//  both lines have to be merged and one of them dropped)
+						for (MapLine line1 : endPoints.get(end)) {
+							if (areSimilar(line2,line1) && !line2.equals(line1)) // don't make a closed loop a double loop
+							{
+								mergeLinesReverse2nd(line1, line2);
+								continue outer_loop;
+							}
+						}
+						continue outer_loop;
+					}
+				}
+
+				// Search for endpoint in hashlist
+				// (can the end of current line connect to an existing line?)
+				for (MapLine line2 : endPoints.get(end)) {
+					if (areSimilar(line,line2)) {
+						Collections.reverse(points);
+						addPointsAtEnd(line2, points);
+						continue outer_loop;
+					}
+				}
+			}
+
+			// No match, just add line to hashmaps
+			addLine(line);
+		}
+
+		// Each line has one and only one start point, so getting all lines out of the start point map will retrieve all of them
+		ArrayList<MapLine> mergedLines = new ArrayList<MapLine>(lines.size());
+		for (List<MapLine> lineList : startPoints.values()) {
+			mergedLines.addAll(lineList);
+		}
+		return mergedLines;
+	}
+}
Index: src/uk/me/parabola/mkgmap/general/MapRoad.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/MapRoad.java	(revision 1131)
+++ src/uk/me/parabola/mkgmap/general/MapRoad.java	(working copy)
@@ -36,6 +36,13 @@
 public class MapRoad extends MapLine {
 
 	private final RoadDef roadDef;
+	int roadClass = 0;
+	int speed = 0;
+	boolean oneway = false;
+	boolean toll = false;
+	boolean[] access;
+	boolean unknownAccess08 = false;
+	boolean noThroughRouting = false;
 
 	public MapRoad(long id, MapLine line) {
 		super(line);
@@ -57,34 +64,69 @@
 	}
 
 	public void setRoadClass(int roadClass) {
+		this.roadClass = roadClass;
 		this.roadDef.setRoadClass(roadClass);
 	}
 
+	public int getRoadClass() {
+		return roadClass;
+	}
+
 	public void setSpeed(int speed) {
+		this.speed = speed;
 		this.roadDef.setSpeed(speed);
 	}
 
+	public int getSpeed() {
+		return speed;
+	}
+
 	public void setOneway() {
+		this.oneway = true;
 		this.roadDef.setOneway();
 	}
 
+	public boolean isOneway() {
+		return oneway;
+	}
+
 	public void setToll() {
+		this.toll = true;
 		this.roadDef.setToll();
 	}
 
+	public boolean isToll() {
+		return toll;
+	}
+
 	// XXX: currently passing PolishMapSource-internal format
 	public void setAccess(boolean[] access) {
+		this.access = access;
 		this.roadDef.setAccess(access);
 	}
 
+	public boolean[] getAccess() {
+		return access;
+	}
+
 	public void setUnknownAccess08() {
+		this.unknownAccess08 = true;
 		this.roadDef.setUnknownAccess08();
 	}
 
+	public boolean isUnknownAccess08() {
+		return unknownAccess08;
+	}
+
 	public void setNoThroughRouting() {
+		this.noThroughRouting = true;
 		this.roadDef.setNoThroughRouting();
 	}
 
+	public boolean isNoThroughRouting() {
+		return noThroughRouting;
+	}
+
 	public void setStartsWithNode(boolean s) {
 		this.roadDef.setStartsWithNode(s);
 	}
Index: src/uk/me/parabola/mkgmap/general/MapLine.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/MapLine.java	(revision 1131)
+++ src/uk/me/parabola/mkgmap/general/MapLine.java	(working copy)
@@ -59,8 +59,13 @@
 		if (this.points != null)
 			log.warn("overwriting points");
 		assert points != null : "trying to set null points";
+		assert points.size() != 0 : "trying to set points with zero length";
 
 		this.points = points;
+		testForConsecutivePoints(points);
+	}
+	
+	public void testForConsecutivePoints(List<Coord> points) {
 		Coord last = null;
 		for (Coord co : points) {
 			if (last != null && last.equals(co))
@@ -70,6 +75,18 @@
 		}
 	}
 
+	public void insertPointsAtStart(List<Coord> additionalPoints) {
+		testForConsecutivePoints(additionalPoints);
+		points.addAll(0, additionalPoints);
+		points.remove(additionalPoints.size()-1);	//End node exists now twice
+	}
+
+	public void insertPointsAtEnd(List<Coord> additionalPoints) {
+		testForConsecutivePoints(additionalPoints);
+		points.remove(points.size()-1); 
+		points.addAll(additionalPoints);
+	}
+
 	public boolean isDirection() {
 		return direction;
 	}
Index: src/uk/me/parabola/util/MultiHashMap.java
===================================================================
--- src/uk/me/parabola/util/MultiHashMap.java	(revision 0)
+++ src/uk/me/parabola/util/MultiHashMap.java	(revision 0)
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2009 Johann Gail
+ * 
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ * 
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ * 
+ * 
+ * Author: Johann Gail
+ */
+
+package uk.me.parabola.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+
+public class MultiHashMap<K,V> extends LinkedHashMap<K,List<V>> {
+
+	/**
+	* the empty list to be returned when there is key without values.
+	*/
+	private List<V> emptyList = Collections.unmodifiableList(new ArrayList<V>(0));
+
+	public MultiHashMap() {
+		super();
+	}
+
+	public MultiHashMap(int initialCapacity) {
+		super(initialCapacity);
+	}
+
+	/**
+	* Returns the list of values associated with the given key.
+	*
+	* @param o the key to get the values for.
+	* @return a list of values for the given keys or the empty list of no such
+	*         value exist.
+	*/
+	public List<V> get(K key) {
+		List<V> result = super.get(key);
+		return result == null ? emptyList : result;
+	}
+
+
+	public V add(K key, V value )
+	{
+	    
+	    List<V> values = super.get(key);
+	    if (values == null ) {
+	        values = new LinkedList<V>();
+	        super.put( key, values );
+	    }
+	    
+	    boolean results = values.add(value);
+	    
+	    return ( results ? value : null );
+	}
+
+	public V remove(K key, V value )
+	{
+	    
+	    List<V> values = super.get(key);
+	    if (values == null )
+			return null;
+	
+	    values.remove(value);
+		
+		if (values.size() == 0)
+			super.remove(values);
+
+		return value;
+	}
+}
+
Index: resources/help/en/options
===================================================================
--- resources/help/en/options	(revision 1131)
+++ resources/help/en/options	(working copy)
@@ -151,7 +151,13 @@
 	number used in the overview map and tdb file.  The default
 	number is 63240000.
 	
+Optimization options:
 
+--merge-lines
+	Try to merge lines. This helps the simplify filter to straighten out
+	longer chunks at lower zoom levels. Decreases file size more.
+	Increases paint speed at low zoom levels
+
 Miscellaneous options:
 
 --max-jobs[=number]
