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