v2 of this patch not only enables remove-short-arcs by default when
routing is in use (as previously discussed on ML) but it also fixes some
problems in the way splitting code.

I would be grateful if people could test this patch because it could
possibly cure some routing failures.

Cheers,

Mark
diff --git a/resources/help/en/options b/resources/help/en/options
index 9bbfad7..ceb1921 100644
--- a/resources/help/en/options
+++ b/resources/help/en/options
@@ -182,11 +182,15 @@ Miscellaneous options:
 	in which they appear in the OSM input. Without this option,
 	the order in which the elements are processed is not defined.
 
---remove-short-arcs[=MinLength]
-	Merge nodes to remove short arcs that can cause routing
-	problems. If MinLength is specified (in metres), arcs shorter
-	than that length will be removed. If a length is not
-	specified, only zero-length arcs will be removed.
+--remove-short-arcs               (a)
+--remove-short-arcs=MinLength     (b)
+--remove-short-arcs=no            (c)
+	If routing is enabled, arcs shorter than 5m will be removed
+	to avoid routing problems. This behaviour can be modified with
+	this option. It has three variants:
+	(a) turn on short arc removal even if routing is not enabled.
+	(b) explicitly specify the minimum arc length (no 'm' suffix).
+	(c) completely disable short arc removal.
 
 --road-name-pois[=GarminCode]
 	Generate a POI for each named road. By default, the POIs'
diff --git a/src/uk/me/parabola/imgfmt/app/Coord.java b/src/uk/me/parabola/imgfmt/app/Coord.java
index 5462602..3e47df7 100644
--- a/src/uk/me/parabola/imgfmt/app/Coord.java
+++ b/src/uk/me/parabola/imgfmt/app/Coord.java
@@ -20,6 +20,7 @@ import java.util.Formatter;
 import java.util.Locale;
 
 import uk.me.parabola.imgfmt.Utils;
+import uk.me.parabola.imgfmt.app.net.RouteArc;
 
 /**
  * A point coordinate in unshifted map-units.
@@ -101,6 +102,11 @@ public class Coord implements Comparable<Coord> {
 		return latitude == other.latitude && longitude == other.longitude;
 	}
 
+	public boolean tooCloseTo(Coord other) {
+		return ((latitude == other.latitude && longitude == other.longitude) ||
+				!RouteArc.goodArcLength(quickDistance(other)));
+	}
+
 	/**
 	 * Distance to other point in meters.
 	 */
diff --git a/src/uk/me/parabola/imgfmt/app/net/RouteArc.java b/src/uk/me/parabola/imgfmt/app/net/RouteArc.java
index 1a0968d..ae2bf8b 100644
--- a/src/uk/me/parabola/imgfmt/app/net/RouteArc.java
+++ b/src/uk/me/parabola/imgfmt/app/net/RouteArc.java
@@ -193,6 +193,12 @@ public class RouteArc {
 		return (int) (l * factor);
 	}
 
+
+	public static boolean goodArcLength(double len) {
+		int l = convertMeters(len);
+		return l > 0 && l < (1 << 14);
+	}
+
 	public void write(ImgFileWriter writer) {
 		offset = writer.position();
 		if(log.isDebugEnabled())
diff --git a/src/uk/me/parabola/mkgmap/general/RoadNetwork.java b/src/uk/me/parabola/mkgmap/general/RoadNetwork.java
index 0c45d68..f76b4b1 100644
--- a/src/uk/me/parabola/mkgmap/general/RoadNetwork.java
+++ b/src/uk/me/parabola/mkgmap/general/RoadNetwork.java
@@ -105,8 +105,8 @@ public class RoadNetwork {
 					log.error("Road " + road.getRoadDef().getName() + " (OSM id " + road.getRoadDef().getId() + ") contains consecutive identical nodes - routing will be broken");
 					log.error("  " + co.toOSMURL());
 				}
-				else if(arcLength == 0) {
-					log.error("Road " + road.getRoadDef().getName() + " (OSM id " + road.getRoadDef().getId() + ") contains zero length arc");
+				else if(!RouteArc.goodArcLength(arcLength)) {
+					log.error("Road " + road.getRoadDef().getName() + " (OSM id " + road.getRoadDef().getId() + ") contains a bad arc of length " + String.format("%.2f", arcLength) + "m");
 					log.error("  " + co.toOSMURL());
 				}
 
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
index 2a549f8..19beb66 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
@@ -468,9 +468,9 @@ public class StyledConverter implements OsmConverter {
 							// now split the way at the next point to
 							// limit the region that has restricted
 							// access
-							if(!p.equals(p1) &&
+							if(!p.tooCloseTo(p1) &&
 							   ((i + 2) == points.size() ||
-								!p1.equals(points.get(i + 2)))) {
+								!p1.tooCloseTo(points.get(i + 2)))) {
 								Way tail = splitWayAt(way, i + 1);
 								// recursively process tail of way
 								addRoad(tail, gt);
@@ -531,8 +531,8 @@ public class StyledConverter implements OsmConverter {
 							// first point in the way
 							if(p1 instanceof CoordPOI &&
 							   i > 0 &&
-							   !p.equals(points.get(i - 1)) &&
-							   !p.equals(p1)) {
+							   !p.tooCloseTo(points.get(i - 1)) &&
+							   !p.tooCloseTo(p1)) {
 								Way tail = splitWayAt(way, i);
 								// recursively process tail of road
 								addRoad(tail, gt);
@@ -622,7 +622,7 @@ public class StyledConverter implements OsmConverter {
 
 						// start at point before intersection point
 						// check that splitting there will not produce
-						// a zero length arc - if it does try the
+						// a short arc - if it does try the
 						// previous point(s)
 						int splitI = p2I - 1;
 						while(splitI > p1I &&
@@ -632,7 +632,7 @@ public class StyledConverter implements OsmConverter {
 						}
 
 						if(splitI == p1I) {
-							log.warn("Splitting looped way " + getDebugName(way) + " would make a zero length arc, so it will have to be pruned");
+							log.warn("Splitting looped way " + getDebugName(way) + " would make a short arc, so it will have to be pruned");
 							do {
 								log.warn("  Pruning point[" + p2I + "]");
 								wayPoints.remove(p2I);
@@ -647,7 +647,7 @@ public class StyledConverter implements OsmConverter {
 								// loop back and prune it
 							} while(p2I > p1I &&
 									(p2I + 1) == numPointsInWay &&
-									p1.equals(wayPoints.get(p2I)));
+									p1.tooCloseTo(wayPoints.get(p2I)));
 						}
 						else {
 							// split the way before the second point
@@ -686,7 +686,7 @@ public class StyledConverter implements OsmConverter {
 			Coord p = points.get(i);
 			if(p.getHighwayCount() > 1) {
 				// point is going to be a node
-				if(candidate.equals(p))
+				if(candidate.tooCloseTo(p))
 					return false;
 				// no need to test further
 				break;
@@ -697,7 +697,7 @@ public class StyledConverter implements OsmConverter {
 			Coord p = points.get(i);
 			if(p.getHighwayCount() > 1) {
 				// point is going to be a node
-				if(candidate.equals(p))
+				if(candidate.tooCloseTo(p))
 					return false;
 				// no need to test further
 				break;
diff --git a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
index e350483..28a037f 100644
--- a/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
+++ b/src/uk/me/parabola/mkgmap/reader/osm/xml/Osm5XmlHandler.java
@@ -107,8 +107,13 @@ class Osm5XmlHandler extends DefaultHandler {
 		ignoreBounds = props.getProperty("ignore-osm-bounds", false);
 		routing = props.containsKey("route");
 		String rsa = props.getProperty("remove-short-arcs", null);
-		if(rsa != null)
-			minimumArcLength = (rsa.length() > 0)? Double.parseDouble(rsa) : 0.0;
+		final double MIN_ALLOWED_ARC_LENGTH = 5.0;
+		if("no".equals(rsa))
+			minimumArcLength = null;
+		else if(rsa != null)
+			minimumArcLength = (rsa.length() > 0)? Double.parseDouble(rsa) : MIN_ALLOWED_ARC_LENGTH;
+		else if(routing)
+			minimumArcLength = MIN_ALLOWED_ARC_LENGTH;
 		else
 			minimumArcLength = null;
 		frigRoundabouts = props.getProperty("frig-roundabouts");
@@ -500,6 +505,7 @@ class Osm5XmlHandler extends DefaultHandler {
 		Map<Coord, Integer> arcCounts = new IdentityHashMap<Coord, Integer>();
 		int numWaysDeleted = 0;
 		int numNodesMerged = 0;
+		log.info("Removing short arcs (min arc length = " + minArcLength + "m)");
 		log.info("Removing short arcs - counting arcs");
 		for(Way w : wayMap.values()) {
 			List<Coord> points = w.getPoints();
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to