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
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev