v2 - sans syntax error

---------

Bloody typical, you wait around for ages hoping for a new routing
capability to be added to mkgmap and then two come along on
the same day.

I've been trying to discover how unpavedness is encoded for at least 6
months. Every now and again, I return to think about it some more.
Check and re-check the same old data structures. Very
frustrating, no progress. Damn those cunning bastards at Garmin....

However, a month or two ago, I discovered that Table C contains more
than just turn restrictions. I still don't know many of it's little
secrets but, today, having exhausted all other possibilities, I finally
twigged that Table C contains the key to understanding "unpavedness".
Gotcha!

The attached patch allows you to add either unpaved=yes/true/1 or
paved=no/false/0 to a way and then it will be ignored for routing
purposes when the GPS has been told to avoid unpaved roads.

Not sure if those are the best tags to use - any thoughts?

BTW - the unpaved road line type 0x0a has nothing to do with
unpavedness, it's just a routable way that gets drawn as a dashed line
(default rendering).

Feedback, etc.

Mark
diff --git a/src/uk/me/parabola/imgfmt/app/net/RoadDef.java b/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
index 7323017..2642211 100644
--- a/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
+++ b/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
@@ -122,6 +122,7 @@ public class RoadDef implements Comparable {
 
 	private City city;
 	private Zip zip;
+	private boolean paved = true;
 	private boolean roundabout;
 	private boolean linkRoad;
 	private boolean synthesised;
@@ -586,6 +587,14 @@ public class RoadDef implements Comparable {
 		return city;
 	}
 
+	public boolean paved() {
+		return paved;
+	}
+
+	public void paved(boolean p) {
+		paved = p;
+	}
+
 	public void setRoundabout(boolean r) {
 		roundabout = r;
 	}
diff --git a/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java b/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java
index a4134c4..931778c 100644
--- a/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java
+++ b/src/uk/me/parabola/imgfmt/app/net/RouteCenter.java
@@ -49,6 +49,9 @@ public class RouteCenter {
 		this.tabB = tabB;
 		this.tabC = new TableC();
 
+		// let Table C know how many unpaved arcs there are
+		tabC.numUnpavedArcs(tabA.numUnpavedArcs());
+
 		log.info("new RouteCenter at " + centralPoint.toDegreeString() +
 				 ", nodes: " + nodes.size()	+ " tabA: " + tabA.size() +
 				 " tabB: " + tabB.size());
@@ -106,7 +109,7 @@ public class RouteCenter {
 		writer.position(tablesOffset);
 
 		// Write the tables header
-		writer.put(tabC.getSizeBytes());
+		writer.put(tabC.getFormat());
 		writer.put3(centralPoint.getLongitude());
 		writer.put3(centralPoint.getLatitude());
 		writer.put(tabA.getNumberOfItems());
diff --git a/src/uk/me/parabola/imgfmt/app/net/TableA.java b/src/uk/me/parabola/imgfmt/app/net/TableA.java
index a0c87ee..bc57844 100644
--- a/src/uk/me/parabola/imgfmt/app/net/TableA.java
+++ b/src/uk/me/parabola/imgfmt/app/net/TableA.java
@@ -16,6 +16,7 @@
  */
 package uk.me.parabola.imgfmt.app.net;
 
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
@@ -37,10 +38,15 @@ public class TableA {
 	// This table's start position relative to the start of NOD 1
 	private int offset;
 
-	private final LinkedHashMap<Arc,Integer> arcs = new LinkedHashMap<Arc,Integer>();
+	// arcs for paved ways
+	private final HashMap<Arc,Integer> pavedArcs = new LinkedHashMap<Arc,Integer>();
+	// arcs for unpaved ways
+	private final HashMap<Arc,Integer> unpavedArcs = new LinkedHashMap<Arc,Integer>();
 
 	private static int count;
 
+	private boolean frozen = false; // true when no more arcs should be added
+
 	public TableA() {
 		log.debug("creating TableA", count);
 		count++;
@@ -88,24 +94,42 @@ public class TableA {
 	 * the table fulfills the size constraint.
 	 */
 	public void addArc(RouteArc arc) {
+		assert !frozen : "trying to add arc to Table A after it has been frozen";
 		Arc narc = new Arc(arc);
 		int i;
-		if (!arcs.containsKey(narc)) {
-			i = arcs.size();
-			arcs.put(narc, i);
-			log.debug("added arc", count, narc, i);
+		if(arc.getRoadDef().paved()) {
+			if (!pavedArcs.containsKey(narc)) {
+				i = pavedArcs.size();
+				pavedArcs.put(narc, i);
+				log.debug("added paved arc", count, narc, i);
+			}
+		}
+		else {
+			if (!unpavedArcs.containsKey(narc)) {
+				i = unpavedArcs.size();
+				unpavedArcs.put(narc, i);
+				log.debug("added unpaved arc", count, narc, i);
+			}
 		}
 	}
 
 	/**
-	 * Retrieve an arc's index.
+	 * Retrieve an arc's index (unpaved arcs are all before the paved arcs)
 	 */
 	public byte getIndex(RouteArc arc) {
-		log.debug("getting index", arc);
+		frozen = true;
 		Arc narc = new Arc(arc);
-		assert arcs.containsKey(narc):
+		int i;
+		if(arc.getRoadDef().paved()) {
+			assert pavedArcs.containsKey(narc):
+			"Trying to read Table A index for non-registered arc: " + count + " " + narc;
+			i = unpavedArcs.size() + pavedArcs.get(narc);
+		}
+		else {
+			assert unpavedArcs.containsKey(narc):
 			"Trying to read Table A index for non-registered arc: " + count + " " + narc;
-		int i = arcs.get(narc);
+			i = unpavedArcs.get(narc);
+		}
 		assert i < 0x100 : "Table A index too large: " + narc;
 		return (byte) i;
 	}
@@ -118,7 +142,11 @@ public class TableA {
 	 * the network.
 	 */
 	public int size() {
-		return arcs.size();
+		return unpavedArcs.size() + pavedArcs.size();
+	}
+
+	public int numUnpavedArcs() {
+		return unpavedArcs.size();
 	}
 
 	/**
@@ -130,8 +158,8 @@ public class TableA {
 	 * it isn't too large.
 	 */
 	public byte getNumberOfItems() {
-		assert arcs.size() < 0x100 : "Table A too large";
-		return (byte) arcs.size();
+		assert size() < 0x100 : "Table A too large";
+		return (byte)size();
 	}
 
 	/**
@@ -140,7 +168,7 @@ public class TableA {
 	 */
 	public void write(ImgFileWriter writer) {
 		offset = writer.position();
-		int size = arcs.size() * ITEM_SIZE;		
+		int size = size() * ITEM_SIZE;		
 		log.debug("tab a offset", offset, "tab a size", size);
 	
 		for (int i = 0; i < size; i++)
@@ -152,19 +180,27 @@ public class TableA {
 	 */
 	public void writePost(ImgFileWriter writer) {
 		writer.position(offset);
-		for (Arc arc : arcs.keySet()) {
-			// write the table A entries.  Consists of a pointer to net
-			// followed by 2 bytes of class and speed flags and road restrictions.
-			log.debug("writing Table A entry", arcs.get(arc));
-			int pos = arc.roadDef.getOffsetNet1();
-			int access = arc.roadDef.getTabAAccess();
-			// top bits of access go into net1 offset
-			final int ACCESS_TOP_BITS = 0xc000;
-			pos |= (access & ACCESS_TOP_BITS) << 8;
-			access &= ~ACCESS_TOP_BITS;
-			writer.put3(pos);
-			writer.put((byte) arc.roadDef.getTabAInfo());
-			writer.put((byte) access);
+		// unpaved arcs first
+		for (Arc arc : unpavedArcs.keySet()) {
+			writePost(writer, arc);
 		}
+		// followed by the paved arcs
+		for (Arc arc : pavedArcs.keySet()) {
+			writePost(writer, arc);
+		}
+	}
+
+	public void writePost(ImgFileWriter writer, Arc arc) {
+		// write the table A entries.  Consists of a pointer to net
+		// followed by 2 bytes of class and speed flags and road restrictions.
+		int pos = arc.roadDef.getOffsetNet1();
+		int access = arc.roadDef.getTabAAccess();
+		// top bits of access go into net1 offset
+		final int ACCESS_TOP_BITS = 0xc000;
+		pos |= (access & ACCESS_TOP_BITS) << 8;
+		access &= ~ACCESS_TOP_BITS;
+		writer.put3(pos);
+		writer.put((byte) arc.roadDef.getTabAInfo());
+		writer.put((byte) access);
 	}
 }
diff --git a/src/uk/me/parabola/imgfmt/app/net/TableC.java b/src/uk/me/parabola/imgfmt/app/net/TableC.java
index 5cd9992..17be303 100644
--- a/src/uk/me/parabola/imgfmt/app/net/TableC.java
+++ b/src/uk/me/parabola/imgfmt/app/net/TableC.java
@@ -31,23 +31,33 @@ public class TableC {
 
 	private final List<RouteRestriction> restrictions = new ArrayList<RouteRestriction>();
 
+	private int numUnpavedArcs = 0;
+
+	public void numUnpavedArcs(int nua) {
+		numUnpavedArcs = nua;
+	}
+
 	/**
 	 * Write the table including size field.
 	 */
 	public void write(ImgFileWriter writer, int tablesOffset) {
 		if (restrictions.isEmpty()) {
+			if(numUnpavedArcs > 0)
+				writer.put((byte)numUnpavedArcs);
 			writer.put((byte) 0);
-			return;
-		} else {
+		}
+		else {
 			byte b = getSizeBytes();
 			assert size < (1 << 8*b);
 			if (b == 1)
 				writer.put((byte) size);
 			else
 				writer.putChar((char) size);
+			for (RouteRestriction restr : restrictions)
+				restr.write(writer, tablesOffset);
+			if(numUnpavedArcs > 0)
+				writer.put((byte)numUnpavedArcs);
 		}
-		for (RouteRestriction restr : restrictions)
-			restr.write(writer, tablesOffset);
 	}
 
 	/**
@@ -85,4 +95,11 @@ public class TableC {
 		for (RouteRestriction restr : restrictions)
 			restr.setOffsetSize(b);
 	}
+
+	public byte getFormat() {
+		byte format = getSizeBytes();
+		if(numUnpavedArcs > 0)
+			format |= 0x08;
+		return format;
+	}
 }
diff --git a/src/uk/me/parabola/mkgmap/general/MapRoad.java b/src/uk/me/parabola/mkgmap/general/MapRoad.java
index c540a69..d887099 100644
--- a/src/uk/me/parabola/mkgmap/general/MapRoad.java
+++ b/src/uk/me/parabola/mkgmap/general/MapRoad.java
@@ -72,6 +72,10 @@ public class MapRoad extends MapLine {
 		this.roadDef.setToll();
 	}
 
+	public void paved(boolean p) {
+		this.roadDef.paved(p);
+	}
+
 	public void showOSMBrowseURL() {
 		this.roadDef.showOSMBrowseURL();
 	}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
index fbff7e0..db2178e 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
@@ -1426,6 +1426,11 @@ public class StyledConverter implements OsmConverter {
 		if(way.isBoolTag("toll"))
 			road.setToll();
 
+		// assume road is paved unless unpaved tag is true or paved
+		// tag is false, in which case, consider road as unpaved
+		if(way.isBoolTag("unpaved") || way.isNotBoolTag("paved"))
+			road.paved(false);
+
 		Way origWay = originalWay.get(way);
 		if(origWay == null)
 			origWay = way;
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to