Hi Steve,

> If that comes up today, I can test it tonight. Thanks in advance.

A v4 patch was posted yesterday, here it is again.

Cheers,

Mark
diff --git a/src/uk/me/parabola/imgfmt/app/net/RoadDef.java b/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
index de87495..e6a187e 100644
--- a/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
+++ b/src/uk/me/parabola/imgfmt/app/net/RoadDef.java
@@ -555,6 +555,10 @@ public class RoadDef implements Comparable {
 		nod2Flags |= (speed << 1);
 	}
 
+	public int getRoadSpeed() {
+		return tabAInfo & 7;
+	}
+
 	public void setOneway() {
 		tabAInfo |= TABA_FLAG_ONEWAY;
 		netFlags |= NET_FLAG_ONEWAY;
diff --git a/src/uk/me/parabola/imgfmt/app/net/RouteNode.java b/src/uk/me/parabola/imgfmt/app/net/RouteNode.java
index 45d6010..c01f7a9 100644
--- a/src/uk/me/parabola/imgfmt/app/net/RouteNode.java
+++ b/src/uk/me/parabola/imgfmt/app/net/RouteNode.java
@@ -67,6 +67,7 @@ public class RouteNode implements Comparable<RouteNode> {
 	private final CoordNode coord;
 	private char latOff;
 	private char lonOff;
+	private List<RouteArc[]> throughRoutes;
 
 	// this is for setting destination class on arcs
 	// we're taking the maximum of roads this node is
@@ -295,18 +296,8 @@ public class RouteNode implements Comparable<RouteNode> {
 
 	private static boolean possiblySameRoad(RouteArc raa, RouteArc rab) {
 
-		if(raa == rab) {
-			// the arcs are the same object
-			return true;
-		}
-
 		RoadDef rda = raa.getRoadDef();
 		RoadDef rdb = rab.getRoadDef();
-		if(rda == rdb) {
-			// the arcs share the same RoadDef
-			return true;
-		}
-
 		boolean bothArcsNamed = false;
 		for(Label laba : rda.getLabels()) {
 			if(laba != null && laba.getOffset() != 0) {
@@ -395,17 +386,74 @@ public class RouteNode implements Comparable<RouteNode> {
 				// determine the outgoing arc that is likely to be the
 				// same road as the incoming arc
 				RouteArc outArc = null;
-				for(RouteArc oa : arcs) {
-					if(oa.getDest() != inArc.getSource()) {
-						// this arc is not going to the same node as
-						// inArc came from
-						if((oa.isForward() || !oa.getRoadDef().isOneway()) &&
-						   possiblySameRoad(inArc, oa)) {
-							outArc = oa;
+
+				if(throughRoutes != null) {
+					// through_route relations have the highest precedence
+					for(RouteArc[] pair : throughRoutes) {
+						if(pair[0] == inArc) {
+							outArc = pair[1];
+							log.info("Found through route from " + inArc.getRoadDef() + " to " + outArc.getRoadDef());
 							break;
 						}
 					}
 				}
+
+				if(outArc == null) {
+					// next, if oa has the same RoadDef as inArc, it's
+					// definitely the same road
+					for(RouteArc oa : arcs) {
+						if(oa.getDest() != inArc.getSource()) {
+							// this arc is not going to the same node as
+							// inArc came from
+							if(oa.getRoadDef() == inArc.getRoadDef()) {
+								outArc = oa;
+								break;
+							}
+						}
+					}
+				}
+
+				if(outArc == null) {
+					// next, although the RoadDefs don't match, use
+					// possiblySameRoad() to see if the road
+					// labels (names/refs) match
+					for(RouteArc oa : arcs) {
+						if(oa.getDest() != inArc.getSource()) {
+							// this arc is not going to the same node as
+							// inArc came from
+							if((oa.isForward() || !oa.getRoadDef().isOneway()) &&
+							   possiblySameRoad(inArc, oa)) {
+								outArc = oa;
+								break;
+							}
+						}
+					}
+				}
+
+				if(outArc == null) {
+					// last ditch attempt to find the outgoing arc -
+					// try and find a single arc that has the same
+					// road class and speed as the incoming arc
+					int inArcClass = inArc.getRoadDef().getRoadClass();
+					int inArcSpeed = inArc.getRoadDef().getRoadSpeed();
+					for(RouteArc oa : arcs) {
+						if(oa.getDest() != inArc.getSource() &&
+						   oa.getRoadDef().getRoadClass() == inArcClass &&
+						   oa.getRoadDef().getRoadSpeed() == inArcSpeed) {
+							if(outArc != null) {
+								// multiple arcs have the same road
+								// class as the incoming arc so don't
+								// use any of them as the outgoing arc
+								outArc = null;
+								break;
+							}
+							outArc = oa;
+						}
+					}
+					if(outArc != null)
+						log.info("Matched outgoing arc " + outArc.getRoadDef() + " to " + inArc.getRoadDef() + " using road class (" + inArcClass + ") and speed (" + inArcSpeed + ")"); 
+				}
+
 				// if we did not find the outgoing arc, give up with
 				// this incoming arc
 				if(outArc == null) {
@@ -449,12 +497,6 @@ public class RouteNode implements Comparable<RouteNode> {
 						continue;
 					}
 
-					if(possiblySameRoad(inArc, otherArc) ||
-					   possiblySameRoad(outArc, otherArc)) {
-						// not obviously a different road so give up
-						continue;
-					}
-
 					if(inArc.getRoadDef().isLinkRoad() &&
 					   otherArc.getRoadDef().isLinkRoad()) {
 						// it's a link road leaving a link road so
@@ -483,9 +525,12 @@ public class RouteNode implements Comparable<RouteNode> {
 						if((mask & ATH_OUTGOING) != 0 &&
 						   outToOtherDelta < minDiffBetweenOutgoingAndOtherArcs)
 							newHeading = outHeading + minDiffBetweenOutgoingAndOtherArcs;
-						else if((mask & ATH_INCOMING) != 0 &&
-								inToOtherDelta < minDiffBetweenIncomingAndOtherArcs)
-							newHeading = inHeading + minDiffBetweenIncomingAndOtherArcs;
+						if((mask & ATH_INCOMING) != 0 &&
+						   inToOtherDelta < minDiffBetweenIncomingAndOtherArcs) {
+							int nh = inHeading + minDiffBetweenIncomingAndOtherArcs;
+							if(nh > newHeading)
+								newHeading = nh;
+						}
 
 						if(newHeading > 180)
 							newHeading -= 360;
@@ -495,9 +540,12 @@ public class RouteNode implements Comparable<RouteNode> {
 						if((mask & ATH_OUTGOING) != 0 &&
 						   outToOtherDelta > -minDiffBetweenOutgoingAndOtherArcs)
 							newHeading = outHeading - minDiffBetweenOutgoingAndOtherArcs;
-						else if((mask & ATH_INCOMING) != 0 &&
-								inToOtherDelta > -minDiffBetweenIncomingAndOtherArcs)
-							newHeading = inHeading - minDiffBetweenIncomingAndOtherArcs;
+						if((mask & ATH_INCOMING) != 0 &&
+						   inToOtherDelta > -minDiffBetweenIncomingAndOtherArcs) {
+							int nh = inHeading - minDiffBetweenIncomingAndOtherArcs;
+							if(nh < newHeading)
+								newHeading = nh;
+						}
 
 						if(newHeading < -180)
 							newHeading += 360;
@@ -732,4 +780,34 @@ public class RouteNode implements Comparable<RouteNode> {
 			}
 		}
 	}
+
+	public void addThroughRoute(long roadIdA, long roadIdB) {
+		if(throughRoutes == null)
+			throughRoutes = new ArrayList<RouteArc[]>();
+		boolean success = false;
+		for(RouteArc arc1 : incomingArcs) {
+			if(arc1.getRoadDef().getId() == roadIdA) {
+				for(RouteArc arc2 : arcs) {
+					if(arc2.getRoadDef().getId() == roadIdB) {
+						throughRoutes.add(new RouteArc[] { arc1, arc2 });
+						success = true;
+						break;
+					}
+				}
+			}
+			else if(arc1.getRoadDef().getId() == roadIdB) {
+				for(RouteArc arc2 : arcs) {
+					if(arc2.getRoadDef().getId() == roadIdA) {
+						throughRoutes.add(new RouteArc[] { arc1, arc2 });
+						success = true;
+						break;
+					}
+				}
+			}
+		}
+		if(success)
+			log.info("Added through route between ways " + roadIdA + " and " + roadIdB + " at " + coord.toOSMURL());
+		else
+			log.warn("Failed to add through route between ways " + roadIdA + " and " + roadIdB + " at " + coord.toOSMURL() + " - perhaps they don't meet here?");
+	}
 }
diff --git a/src/uk/me/parabola/mkgmap/general/MapCollector.java b/src/uk/me/parabola/mkgmap/general/MapCollector.java
index 07b32d9..6ca5bac 100644
--- a/src/uk/me/parabola/mkgmap/general/MapCollector.java
+++ b/src/uk/me/parabola/mkgmap/general/MapCollector.java
@@ -73,4 +73,10 @@ public interface MapCollector {
 	 * @param exceptMask For exceptions eg. no-left-turn except for buses.
 	 */
 	public void addRestriction(CoordNode fromNode, CoordNode toNode, CoordNode viaNode, byte exceptMask);
+
+	/**
+	 * Add a through route to the map. 
+	 *
+	 */
+	public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB);
 }
diff --git a/src/uk/me/parabola/mkgmap/general/MapDetails.java b/src/uk/me/parabola/mkgmap/general/MapDetails.java
index a5707c5..30e638a 100644
--- a/src/uk/me/parabola/mkgmap/general/MapDetails.java
+++ b/src/uk/me/parabola/mkgmap/general/MapDetails.java
@@ -119,6 +119,10 @@ public class MapDetails implements MapCollector, MapDataSource {
 		roadNetwork.addRestriction(fromNode, toNode, viaNode, exceptMask);
 	}
 
+	public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) {
+		roadNetwork.addThroughRoute(junctionNodeId, roadIdA, roadIdB);
+	}
+
 	/**
 	 * Add the given point to the total bounds for the map.
 	 *
diff --git a/src/uk/me/parabola/mkgmap/general/RoadNetwork.java b/src/uk/me/parabola/mkgmap/general/RoadNetwork.java
index 6be2d0c..2740665 100644
--- a/src/uk/me/parabola/mkgmap/general/RoadNetwork.java
+++ b/src/uk/me/parabola/mkgmap/general/RoadNetwork.java
@@ -285,4 +285,10 @@ public class RoadNetwork {
 		vn.addRestriction(new RouteRestriction(fa, ta, exceptMask));
     }
 
+	public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) {
+		RouteNode node = nodes.get(junctionNodeId);
+		assert node != null :  "Can't find node with id " + junctionNodeId;
+
+		node.addThroughRoute(roadIdA, roadIdB);
+	}
 }
diff --git a/src/uk/me/parabola/mkgmap/main/StyleTester.java b/src/uk/me/parabola/mkgmap/main/StyleTester.java
index 998b195..cf994ae 100644
--- a/src/uk/me/parabola/mkgmap/main/StyleTester.java
+++ b/src/uk/me/parabola/mkgmap/main/StyleTester.java
@@ -713,6 +713,9 @@ public class StyleTester implements OsmConverter {
 
 		public void addRestriction(CoordNode fromNode, CoordNode toNode, CoordNode viaNode, byte exceptMask) {
 		}
+
+		public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) {
+		}
 	}
 
 	/**
@@ -753,6 +756,9 @@ public class StyleTester implements OsmConverter {
 		public void addRestriction(CoordNode fromNode, CoordNode toNode, CoordNode viaNode, byte exceptMask) {
 		}
 
+		public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) {
+		}
+
 		public long getStart() {
 			return start;
 		}
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
index 784f238..6de7738 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
@@ -22,6 +22,7 @@ import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.regex.Pattern;
 
@@ -80,6 +81,8 @@ public class StyledConverter implements OsmConverter {
 	// Coord corresponding to the restrictions' 'via' node
 	private final Map<Coord, List<RestrictionRelation>> restrictions = new IdentityHashMap<Coord, List<RestrictionRelation>>();
 
+	private final List<Relation> throughRouteRelations = new ArrayList<Relation>();
+
 	// originalWay associates Ways that have been created due to
 	// splitting or clipping with the Ways that they were derived
 	// from
@@ -386,6 +389,50 @@ public class StyledConverter implements OsmConverter {
 				rr.addRestriction(collector);
 			}
 		}
+
+		for(Relation relation : throughRouteRelations) {
+			Node node = null;
+			Way w1 = null;
+			Way w2 = null;
+			for(Map.Entry<String,Element> member : relation.getElements()) {
+				if(member.getValue() instanceof Node) {
+					if(node == null)
+						node = (Node)member.getValue();
+					else
+						log.warn("Through route relation " + relation.toBrowseURL() + " has more than 1 node");
+				}
+				else if(member.getValue() instanceof Way) {
+					Way w = (Way)member.getValue();
+					if(w1 == null)
+						w1 = w;
+					else if(w2 == null)
+						w2 = w;
+					else
+						log.warn("Through route relation " + relation.toBrowseURL() + " has more than 2 ways");
+				}
+			}
+
+			Coord junctionPoint = null;
+			Integer nodeId = null;
+			if(node == null)
+				log.warn("Through route relation " + relation.toBrowseURL() + " is missing the junction node");
+			else {
+				junctionPoint = node.getLocation();
+				if(bbox != null && !bbox.contains(junctionPoint)) {
+					// junction is outside of the tile - ignore it
+					continue;
+				}
+				nodeId = nodeIdMap.get(junctionPoint);
+				if(nodeId == null)
+					log.warn("Through route relation " + relation.toBrowseURL() + " junction node at " + junctionPoint.toOSMURL() + " is not a routing node");
+			}
+
+			if(w1 == null || w2 == null)
+				log.warn("Through route relation " + relation.toBrowseURL() + " should reference 2 ways that meet at the junction node");
+
+			if(nodeId != null && w1 != null && w2 != null)
+				collector.addThroughRoute(nodeId, w1.getId(), w2.getId());
+		}
 	}
 
 	/**
@@ -411,6 +458,9 @@ public class StyledConverter implements OsmConverter {
 				lrr.add(rr);
 			}
 		}
+		else if("through_route".equals(relation.getTag("type"))) {
+			throughRouteRelations.add(relation);
+		}
 	}
 
 	private void addLine(Way way, GType gt) {
diff --git a/src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java b/src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java
index dd5a54e..2d6e541 100644
--- a/src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java
+++ b/src/uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java
@@ -144,6 +144,10 @@ public class OverviewMapDataSource extends MapperBasedMapDataSource
 		getRoadNetwork().addRestriction(fromNode, toNode, viaNode, exceptMask);
 	}
 
+	public void addThroughRoute(long junctionNodeId, long roadIdA, long roadIdB) {
+		getRoadNetwork().addThroughRoute(junctionNodeId, roadIdA, roadIdB);
+	}
+
 	public int getShift() {
 		return 24 - (topBits - 1);
 	}
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to