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