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