Index: doc/styles/internal-tags.txt
===================================================================
--- doc/styles/internal-tags.txt	(revision 4728)
+++ doc/styles/internal-tags.txt	(working copy)
@@ -138,6 +138,7 @@
 | Tag | Description     
 | +mkgmap:skipSizeFilter+  | If set to +true+ the line or polygon will pass the size filter, no matter what size it has    
 | +mkgmap:highest-resolution-only+  | If set to +true+ the object will only be added for the highest resolution configured in the element type definition.
+| +mkgmap:nooverlap+  | If set to a positive integer the object will not be included if it is a routable way and overlaps another routable way with a lower mkgmap:nooverlap value (default 0) with access that allows a superset of its traffic. If the two ways have the same value and access, it is indeterminate which gets deleted. The maximum value is 127.
 | +mkgmap:execute_finalize_rules+  | If set to +true+ mkgmap will execute the finalize rules even if no object is created fot the element.
 | +mkgmap:numbers+  | If set to +false+ for a node or way mkgmap will ignore the object in the calculations for the --housenumber option   
 | +mkgmap:drawLevel+  | Set to a number from 1 to 100. Overrides the polygon area that is used by --order-by-decreasing-area. 1..50 are larger than typical polygons and be overwritten by them, 51..100 are smaller and will show. Higher drawLevels will show over lower values.
Index: src/uk/me/parabola/imgfmt/app/net/RoadDef.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/RoadDef.java	(revision 4728)
+++ src/uk/me/parabola/imgfmt/app/net/RoadDef.java	(working copy)
@@ -126,6 +126,7 @@
 	private boolean roundabout;
 	private boolean synthesised;
 	private boolean flareCheck;
+	private byte deleteIfOverlapping = 0;
 	private Set<String> messageIssued;
 
 	private final List<Offset> rgnOffsets = new ArrayList<>();
@@ -853,4 +854,12 @@
 		return lenInMeter;
 	}
 	
+	public int deleteIfOverlapping() {
+		return deleteIfOverlapping;
+	}
+
+	public void setDeleteIfOverlapping(int value) {
+		deleteIfOverlapping = (byte) Math.min(Math.max(value,0), 127);
+	}
+
 }
Index: src/uk/me/parabola/imgfmt/app/net/RouteNode.java
===================================================================
--- src/uk/me/parabola/imgfmt/app/net/RouteNode.java	(revision 4728)
+++ src/uk/me/parabola/imgfmt/app/net/RouteNode.java	(working copy)
@@ -680,9 +680,42 @@
 					continue;
 				if(arci.getDest() == arcj.getDest() &&
 				   arci.getLength() == arcj.getLength() &&
-				   arci.getPointsHash() == arcj.getPointsHash() &&
-				   !rdi.messagePreviouslyIssued("Similar arcs")) {
-					log.diagnostic("Similar arcs " + rdi + " and " + rdj + " found at " + coord.toOSMURL());
+				   arci.getPointsHash() == arcj.getPointsHash()) {
+					int deleteIfOverlappingI = rdi.deleteIfOverlapping();
+					int deleteIfOverlappingJ = rdj.deleteIfOverlapping();
+					int accessI = rdi.getAccess();
+					int accessJ = rdj.getAccess();
+					boolean onewayI = rdi.isOneway();
+					boolean onewayJ = rdj.isOneway();
+					if ((deleteIfOverlappingJ > 0) && (deleteIfOverlappingJ >= deleteIfOverlappingI) && ((accessI & accessJ) == accessJ) && (!onewayI || onewayI == onewayJ || accessJ == 1)) {
+						if (!rdj.messagePreviouslyIssued("Removing arc"))
+							log.info("Removing arc " + rdj + " similar to " + rdi + " found at " + coord.toOSMURL());
+						arcs.remove(j--);
+					}
+					else if ((deleteIfOverlappingI > 0) && (deleteIfOverlappingI >= deleteIfOverlappingJ) && ((accessI & accessJ) == accessI) && (!onewayJ || onewayI == onewayJ || accessI == 1)) {
+						if (!rdi.messagePreviouslyIssued("Removing arc"))
+							log.info("Removing arc " + rdi + " similar to " + rdj + " found at " + coord.toOSMURL());
+						arcs.remove(i--);
+						break;
+					}
+					else if ((deleteIfOverlappingJ > 0) && ((accessI & accessJ) == accessJ) && (!onewayI || onewayI == onewayJ || accessJ == 1)) {
+						if (!rdj.messagePreviouslyIssued("Removing arc"))
+							log.info("Removing arc " + rdj + " similar to " + rdi + " found at " + coord.toOSMURL());
+						arcs.remove(j--);
+					}
+					else if ((deleteIfOverlappingI > 0) && ((accessI & accessJ) == accessI) && (!onewayJ || onewayI == onewayJ || accessI == 1)) {
+						if (!rdi.messagePreviouslyIssued("Removing arc"))
+							log.info("Removing arc " + rdi + " similar to " + rdj + " found at " + coord.toOSMURL());
+						arcs.remove(i--);
+						break;
+					}
+					else if ((deleteIfOverlappingI > 0) || (deleteIfOverlappingJ > 0)) {
+						if (!rdi.messagePreviouslyIssued("Similar arcs"))
+							log.diagnostic("Similar arcs " + rdi + " (access " + accessI + "," + (onewayI ? "one way" : "two way") + ") and " + rdj + " (access " + accessJ + "," + (onewayJ ? "one way" : "two way") + ") found at " + coord.toOSMURL());
+					}
+					else if (!rdi.messagePreviouslyIssued("Similar arcs")) {
+						log.diagnostic("Similar arcs " + rdi + " and " + rdj + " found at " + coord.toOSMURL());
+					}
 				}
 			}
 		}
Index: src/uk/me/parabola/mkgmap/general/MapRoad.java
===================================================================
--- src/uk/me/parabola/mkgmap/general/MapRoad.java	(revision 4728)
+++ src/uk/me/parabola/mkgmap/general/MapRoad.java	(working copy)
@@ -208,7 +208,6 @@
 
 	public void resetImgData() {
 		roadDef.resetImgData();
-		
 	}
 	
 	public int countNodes() {
@@ -220,5 +219,8 @@
 		return n;
 	}
 
-	
+	public void setDeleteIfOverlapping(int value) {
+		roadDef.setDeleteIfOverlapping(value);
+	}
+
 }
Index: src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(revision 4728)
+++ src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java	(working copy)
@@ -214,7 +214,7 @@
 			countryAbbr = countryAbbr.toUpperCase();
 			
 		checkRoundabouts = props.getProperty("check-roundabouts",false);
-		reportDeadEnds = (props.getProperty("report-dead-ends") != null) ? props.getProperty("report-dead-ends", 1) : 0;  
+		reportDeadEnds = (props.getProperty("report-dead-ends") != null) ? props.getProperty("report-dead-ends", 1) : 0;
 		prefixSuffixFilter = new PrefixSuffixFilter(props);
 
 		lineAdder = line -> {
@@ -580,7 +580,7 @@
 		return false;
 	}
 
-	private static final short TK_ONEWAY = TagDict.getInstance().xlate("oneway"); 
+	private static final short TK_ONEWAY = TagDict.getInstance().xlate("oneway");
 
 	/** One type result for nodes to avoid recreating one for each node. */ 
 	private NodeTypeResult nodeTypeResult = new NodeTypeResult();
@@ -1324,13 +1324,13 @@
 		if (element.tagIsLikeYes(TKM_HIGHEST_RES_ONLY)){
 			ms.setMinResolution(ms.getMaxResolution());
 		}
-		
+
 		if (ms instanceof MapLine && element.tagIsLikeYes(TKM_SKIP_SIZE_FILTER)){
 			((MapLine)ms).setSkipSizeFilter(true);
 		}
 		
 		// Now try to get some address info for POIs
-		
+
 		String country      = element.getTag(TKM_COUNTRY);
 		String region       = element.getTag(TKM_REGION);
 		String city         = element.getTag(TKM_CITY);
@@ -1856,6 +1856,15 @@
 			road.skipAddToNOD(true);
 		}
 		
+		String noOverlap = way.getTag("mkgmap:nooverlap");
+		if (noOverlap != null) {
+			try {
+				road.setDeleteIfOverlapping(Integer.parseInt(noOverlap));
+			}
+			catch (NumberFormatException e ) {
+			}
+		}
+
 		boolean doFlareCheck = true;
 		
 		if (cw.isRoundabout()){
