Hello,

So my post from a couple weeks ago was correct. You can have turn restrictions with via ways. Attached is a patch that does that and also implements the "More restriction exceptions <http://www.mkgmap.org.uk/pipermail/mkgmap-dev/2010q2/008330.html>" I posted yesterday.

I'd like to warn that this was a quite complex thing and I did not fully understand the relation structure in mkgmap so it may break other thinks. I needs to be reviewed by s.o. who knows how restriction relation works in mkgmap.

It has limitations as well:

* If the via ways gets split for routing (like in http://www.openstreetmap.org/browse/relation/275622 where via way http://www.openstreetmap.org/browse/way/41694496 gets split at http://www.openstreetmap.org/browse/node/62547613 because of an incoming ramp), the relation creation fails * I did not try with more than one via way but it probably just fails as well

Those again would need to be looked at by s.o. with better knowledge of how routing and restrictions works.

  Thanks,

N.
Index: uk/me/parabola/imgfmt/app/net/RouteRestriction.java
===================================================================
--- uk/me/parabola/imgfmt/app/net/RouteRestriction.java (revision 1647)
+++ uk/me/parabola/imgfmt/app/net/RouteRestriction.java (working copy)
@@ -14,6 +14,7 @@
        */
 package uk.me.parabola.imgfmt.app.net;
 
+import java.util.List;
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
 
 /**
@@ -35,19 +36,29 @@
        //private static final Logger log = 
Logger.getLogger(RouteRestriction.class);
 
        // size in bytes
-       private static final int SIZE = 11;
+       private static final int SIZE = 3;
 
-       // first three bytes of the header -- might specify the type of 
restriction
+       // first byte of the header -- might specify the type of restriction
        // and when it is active
-       private static final int HEADER = 0x004005;
+       private static final int HEADER = 0x05;
+       
+       // flags for the second byte
+       private byte flagByte;
 
+       public final static byte FLAG_PEDESTRIAN         = 0x02;
+       public final static byte FLAG_EMERGENCY         = 0x04;
+       public final static byte FLAG_EXCEPT_OTHER = 0x08;
+
+       // third byte (always 0?)
+       public final static byte THIRD_BYTE = 0x00;
+
+
        // To specifiy that a node is given by a relative offset instead
        // of an entry to Table B.
        private static final int F_INTERNAL = 0x8000;
 
        // the arcs
-       private final RouteArc from;
-       private final RouteArc to;
+       private final List<RouteArc> arcs;
 
        // offset in Table C
        private byte offsetSize;
@@ -57,14 +68,18 @@
        private boolean last;
 
        // mask that specifies which vehicle types the restriction doesn't 
apply to
-       private final byte exceptMask;
+       private final int exceptMask;
 
-       public final static byte EXCEPT_CAR                     = 0x01;
-       public final static byte EXCEPT_BUS                     = 0x02;
-       public final static byte EXCEPT_TAXI             = 0x04;
-       public final static byte EXCEPT_DELIVERY = 0x10;
-       public final static byte EXCEPT_BICYCLE = 0x20;
-       public final static byte EXCEPT_TRUCK           = 0x40;
+       public final static int EXCEPT_CAR                              = 
0x0001;
+       public final static int EXCEPT_BUS                              = 
0x0002;
+       public final static int EXCEPT_TAXI                      = 0x0004;
+       public final static int EXCEPT_DELIVERY  = 0x0010;
+       public final static int EXCEPT_BICYCLE          = 0x0020;
+       public final static int EXCEPT_TRUCK                    = 0x0040;
+       public final static int EXCEPT_PEDESTRIAN = 0x0100;
+       public final static int EXCEPT_EMERGENCY        = 0x0200;
+       
+       
 
        /**
         * Create a route restriction.
@@ -72,11 +87,12 @@
         * @param from The inverse arc of "from" arc.
         * @param to The "to" arc.
         */
-       public RouteRestriction(RouteArc from, RouteArc to, byte exceptMask) {
-               assert from.getSource().equals(to.getSource()) : "arcs in 
restriction don't meet";
-               this.from = from;
-               this.to = to;
+       public RouteRestriction(List<RouteArc> arcs, int exceptMask) {
+               //assert from.getSource().equals(to.getSource()) : "arcs in 
restriction don't meet";
+               // NAKOR_FIXME: not sure how to handle this with multiple arcs
+               this.arcs = arcs;
                this.exceptMask = exceptMask;
+               this.flagByte = 0;
        }
 
        private int calcOffset(RouteNode node, int tableOffset) {
@@ -93,34 +109,52 @@
         * @param tableOffset The offset in NOD 1 of the tables area.
         */
        public void write(ImgFileWriter writer, int tableOffset) {
-               int header = HEADER;
+               byte header = HEADER;
 
-               if(exceptMask != 0)
-                       header |= 0x0800;
+               writer.put(header);
+               if( (exceptMask & 0xFF) != 0)
+                       flagByte |= FLAG_EXCEPT_OTHER;
+               if( (exceptMask & EXCEPT_PEDESTRIAN) != 0)
+                       flagByte |= FLAG_PEDESTRIAN;
+               if( (exceptMask & EXCEPT_EMERGENCY) != 0)
+                       flagByte |= FLAG_EMERGENCY;
+               assert arcs.size()<=7 : "No more than 7 arcs supported on a 
turn restriction";
+               int arcsCount = arcs.size() << 5;
+               flagByte |= arcsCount;
 
-               writer.put3(header);
+               writer.put(flagByte);
 
-               if(exceptMask != 0)
-                       writer.put(exceptMask);
+               writer.put(THIRD_BYTE);
 
-               int[] offsets = new int[3];
+               if((exceptMask & 0xFF) != 0)
+                       writer.put((byte)exceptMask);
 
-               if (from.isInternal())
-                       offsets[0] = calcOffset(from.getDest(), tableOffset);
-               else
-                       offsets[0] = from.getIndexB();
-               offsets[1] = calcOffset(to.getSource(), tableOffset);
-               if (to.isInternal())
-                       offsets[2] = calcOffset(to.getDest(), tableOffset);
-               else
-                       offsets[2] = to.getIndexB();
+               int[] offsets = new int[arcs.size()+1];
 
+               int index =0;
+               
+               RouteArc fistArc=arcs.get(0);
+               if (fistArc.isInternal())
+                       offsets[index] = calcOffset(fistArc.getSource(), 
tableOffset);
+               else
+                       offsets[index] = fistArc.getIndexB();
+               index = index+1;
+               
+               for (RouteArc arc: arcs)
+               {
+                       if (arc.isInternal())
+                               offsets[index] = calcOffset(arc.getDest(), 
tableOffset);
+                       else
+                               offsets[index] = arc.getIndexB();
+                       index = index+1;
+               }
+
                for (int offset : offsets)
                        writer.putChar((char) offset);
 
-               writer.put(from.getIndexA());
-               writer.put(to.getIndexA());
-       }
+               for (RouteArc arc: arcs)
+                       writer.put(arc.getIndexA());
+       }
 
        /**
         * Write this restriction's offset within Table C into a node record.
@@ -146,6 +180,7 @@
         */
        public int getSize() {
                int size = SIZE;
+               size += 3*arcs.size() +2; //(2 bytes for nodes, 1 byte for ways 
with 1 more node than ways) 
                if(exceptMask != 0)
                        ++size;
                return size;
Index: uk/me/parabola/mkgmap/general/MapCollector.java
===================================================================
--- uk/me/parabola/mkgmap/general/MapCollector.java     (revision 1647)
+++ uk/me/parabola/mkgmap/general/MapCollector.java     (working copy)
@@ -16,6 +16,8 @@
        */
 package uk.me.parabola.mkgmap.general;
 
+import java.util.List;
+
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.imgfmt.app.CoordNode;
 
@@ -72,7 +74,7 @@
         * no left turn.
         * @param exceptMask For exceptions eg. no-left-turn except for buses.
         */
-       public void addRestriction(CoordNode fromNode, CoordNode toNode, 
CoordNode viaNode, byte exceptMask);
+       public void addRestriction(List<CoordNode> restrNodes, int exceptMask);
 
        /**
         * Add a through route to the map. 
Index: uk/me/parabola/mkgmap/general/MapDetails.java
===================================================================
--- uk/me/parabola/mkgmap/general/MapDetails.java       (revision 1647)
+++ uk/me/parabola/mkgmap/general/MapDetails.java       (working copy)
@@ -115,8 +115,8 @@
                addLine(road);
        }
 
-       public void addRestriction(CoordNode fromNode, CoordNode toNode, 
CoordNode viaNode, byte exceptMask) {
-               roadNetwork.addRestriction(fromNode, toNode, viaNode, 
exceptMask);
+       public void addRestriction(List<CoordNode> restrNodes, int exceptMask) {
+               roadNetwork.addRestriction(restrNodes, exceptMask);
        }
 
        public void addThroughRoute(long junctionNodeId, long roadIdA, long 
roadIdB) {
Index: uk/me/parabola/mkgmap/general/RoadNetwork.java
===================================================================
--- uk/me/parabola/mkgmap/general/RoadNetwork.java      (revision 1647)
+++ uk/me/parabola/mkgmap/general/RoadNetwork.java      (working copy)
@@ -264,23 +264,38 @@
                return boundary;
        }
 
-       public void addRestriction(CoordNode fromNode, CoordNode toNode, 
CoordNode viaNode, byte exceptMask) {
-               RouteNode fn = nodes.get(fromNode.getId());
-               RouteNode tn = nodes.get(toNode.getId());
-               RouteNode vn = nodes.get(viaNode.getId());
+       public void addRestriction(List<CoordNode> restrNodes, int exceptMask) {
+               ArrayList<RouteArc> arcs = new ArrayList<RouteArc>();
+       
+               // Initialize by getting the first node
+               RouteNode oldNode = nodes.get(restrNodes.get(0).getId());
+               assert oldNode != null : "can't locate RouteNode with id " + 
restrNodes.get(0).getId();
 
-               assert fn != null : "can't locate 'from' RouteNode with id " + 
fromNode.getId();
-               assert tn != null : "can't locate 'to' RouteNode with id " + 
toNode.getId();
-               assert vn != null : "can't locate 'via' RouteNode with id " + 
viaNode.getId();
+               // Creating arcs and restrictions on intermediate nodes
+               for (CoordNode restrNode: restrNodes.subList(1, 
restrNodes.size()-1) )
+               {
+                       RouteNode node = nodes.get(restrNode.getId());
+               
+                       assert node != null : "can't locate RouteNode with id " 
+ restrNode.getId();
 
-               RouteArc fa = vn.getArcTo(fn); // inverse arc gets used
-               RouteArc ta = vn.getArcTo(tn);
+                       RouteArc arc = oldNode.getArcTo(node); // inverse arc 
gets used
+                       assert arc != null : "unable to find arc from " + 
restrNode.getId();
+                       
+                       arcs.add(arc);
+                       node.addRestriction(new RouteRestriction(arcs, 
exceptMask));
+                       
+                       oldNode=node;
+               }
 
-               assert fa != null : "can't locate arc from 'via' node to 'from' 
node";
-               assert ta != null : "can't locate arc from 'via' node to 'to' 
node";
+               // Create arc to final node
+               CoordNode lastNode=restrNodes.get(restrNodes.size()-1);
+               RouteNode finalNode = nodes.get(lastNode.getId());
+       
+               assert finalNode != null : "can't locate RouteNode with id " + 
lastNode.getId();
 
-               vn.addRestriction(new RouteRestriction(fa, ta, exceptMask));
-               }
+               RouteArc finalArc = oldNode.getArcTo(finalNode); // inverse arc 
gets used
+               arcs.add(finalArc);
+       }
 
        public void addThroughRoute(long junctionNodeId, long roadIdA, long 
roadIdB) {
                RouteNode node = nodes.get(junctionNodeId);
Index: uk/me/parabola/mkgmap/main/StyleTester.java
===================================================================
--- uk/me/parabola/mkgmap/main/StyleTester.java (revision 1647)
+++ uk/me/parabola/mkgmap/main/StyleTester.java (working copy)
@@ -716,7 +716,7 @@
                        lines.add(road);
                }
 
-               public void addRestriction(CoordNode fromNode, CoordNode 
toNode, CoordNode viaNode, byte exceptMask) {
+               public void addRestriction(List<CoordNode> restrNodes, int 
exceptMask) {
                }
 
                public void addThroughRoute(long junctionNodeId, long roadIdA, 
long roadIdB) {
@@ -758,7 +758,7 @@
                        }
                }
 
-               public void addRestriction(CoordNode fromNode, CoordNode 
toNode, CoordNode viaNode, byte exceptMask) {
+               public void addRestriction(List<CoordNode> restrNodes, int 
exceptMask) {
                }
 
                public void addThroughRoute(long junctionNodeId, long roadIdA, 
long roadIdB) {
Index: uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
===================================================================
--- uk/me/parabola/mkgmap/osmstyle/StyledConverter.java (revision 1647)
+++ uk/me/parabola/mkgmap/osmstyle/StyledConverter.java (working copy)
@@ -468,16 +468,22 @@
                // Relations never resolve to a GType and so we ignore the 
return
                // value.
                relationRules.resolveType(relation, TypeResult.NULL_RESULT);
-
+               
+               log.info("Processing relation");
                if(relation instanceof RestrictionRelation) {
                        RestrictionRelation rr = (RestrictionRelation)relation;
                        if(rr.isValid()) {
-                               List<RestrictionRelation> lrr = 
restrictions.get(rr.getViaCoord());
-                               if(lrr == null) {
-                                       lrr = new 
ArrayList<RestrictionRelation>();
-                                       restrictions.put(rr.getViaCoord(), lrr);
-                               }
-                               lrr.add(rr);
+                               List<Coord> Coords=rr.getViaCoords();
+                               for (Coord coord: Coords)
+                               {
+                                       List<RestrictionRelation> lrr = 
restrictions.get(coord);
+                                       if(lrr == null) {
+                                               lrr = new 
ArrayList<RestrictionRelation>();
+                                               restrictions.put(coord, lrr);
+                                               log.info("Adding relation to 
map");
+                                       }
+                                       lrr.add(rr);
+                               }
                        }
                }
                else if("through_route".equals(relation.getTag("type"))) {
Index: uk/me/parabola/mkgmap/reader/osm/RestrictionRelation.java
===================================================================
--- uk/me/parabola/mkgmap/reader/osm/RestrictionRelation.java   (revision 1647)
+++ uk/me/parabola/mkgmap/reader/osm/RestrictionRelation.java   (working copy)
@@ -24,14 +24,14 @@
                 private Way fromWay;
                 private Way toWay;
                 private Way viaWay;
-               private Coord viaCoord;
+               private ArrayList<Coord> viaCoords = new ArrayList<Coord>();
                 private final String restriction;
 
                 private CoordNode fromNode;
                 private CoordNode toNode;
                 private CoordNode viaNode;
                 private final List<CoordNode> otherNodes = new 
ArrayList<CoordNode>();
-       private byte exceptMask;
+               private int exceptMask;
                 private String messagePrefix;
 
        /**
@@ -55,8 +55,8 @@
 
                        Coord location = null;
 
-                       if(viaCoord != null)
-                               location = viaCoord;
+                       if(viaCoords.size()>0)
+                               location = viaCoords.get(0);
                        else if(fromWay != null && fromWay.getPoints().size() > 
0)
                                location = fromWay.getPoints().get(0);
                        else if(toWay != null && toWay.getPoints().size() > 0)
@@ -92,14 +92,17 @@
                                        fromWay = (Way)el;
                        }
                        else if("via".equals(role)) {
-                               if(viaCoord != null || viaWay != null) {
+                               if(viaCoords.size()>0 || viaWay != null) {
                                        log.warn(messagePrefix + "has extra 
'via' member " + el.toBrowseURL());
                                }
                                else if(el instanceof Node) {
-                                       viaCoord = ((Node)el).getLocation();
+                                       viaCoords.add(((Node)el).getLocation());
                                }
                                else if(el instanceof Way) {
                                        viaWay = (Way)el;
+                                       List<Coord> 
points=((Way)el).getPoints();
+                                       viaCoords.add(points.get(0));
+                                       
viaCoords.add(points.get(points.size()-1));
                                }
                                else {
                                        log.warn(messagePrefix + "'via' member 
" + el.toBrowseURL() + " is not a node or way");
@@ -148,6 +151,10 @@
                                        exceptMask |= 
RouteRestriction.EXCEPT_BICYCLE;
                                else if(e.equals("hgv") || e.equals("truck"))
                                        exceptMask |= 
RouteRestriction.EXCEPT_TRUCK;
+                               else if(e.equals("emergency"))
+                                       exceptMask |= 
RouteRestriction.EXCEPT_EMERGENCY;
+                               else if(e.equals("pedestrian"))
+                                       exceptMask |= 
RouteRestriction.EXCEPT_PEDESTRIAN;
                                else
                                        log.warn(messagePrefix + "ignoring 
unsupported vehicle class '" + e + "' in turn restriction exception");
                        }
@@ -166,8 +173,8 @@
                return viaWay;
        }
 
-       public Coord getViaCoord() {
-               return viaCoord;
+       public List<Coord> getViaCoords() {
+               return viaCoords;
        }
 
        public void setFromNode(CoordNode fromNode) {
@@ -187,10 +194,12 @@
                        log.warn(messagePrefix + restriction + " 'via' node 
redefined from " +
                                         this.viaNode.toOSMURL() + " to " + 
viaNode.toOSMURL());
                this.viaNode = viaNode;
+               if (otherNodes.indexOf(viaNode)==-1)
+                       otherNodes.add(viaNode);
        }
 
        public void addOtherNode(CoordNode otherNode) {
-               otherNodes.add(otherNode);
+               //otherNodes.add(otherNode);
                log.debug(messagePrefix + restriction + " adding 'other' node " 
+ otherNode.toOSMURL());
        }
 
@@ -213,14 +222,14 @@
                if(fromWay == null || toWay == null)
                        return false;
 
-               if(viaCoord == null && viaWay == null) {
+               if(viaCoords.size() == 0 && viaWay == null) {
                        List<Coord>fromPoints = fromWay.getPoints();
                        List<Coord>toPoints = toWay.getPoints();
                        for(Coord fp : fromPoints) {
                                for(Coord tp : toPoints) {
                                        if(fp.equals(tp)) {
-                                               if(viaCoord == null) {
-                                                       viaCoord = fp;
+                                               if(viaCoords.size() == 0) {
+                                                       viaCoords.add(fp);
                                                }
                                                else {
                                                        log.warn(messagePrefix 
+ "lacks 'via' node and the 'from' (" + fromWay.toBrowseURL() + ") and 'to' (" 
+ toWay.toBrowseURL() + ") ways connect in more than one place");
@@ -230,15 +239,15 @@
                                }
                        }
 
-                       if(viaCoord == null) {
+                       if(viaCoords.size()==0) {
                                log.warn(messagePrefix + "lacks 'via' node and 
the 'from' (" + fromWay.toBrowseURL() + ") and 'to' (" + toWay.toBrowseURL() + 
") ways don't connect");
                                return false;
                        }
 
-                       log.warn(messagePrefix + "lacks 'via' node (guessing it 
should be at " + viaCoord.toOSMURL() + ", why don't you add it to the OSM 
data?)");
+                       log.warn(messagePrefix + "lacks 'via' node (guessing it 
should be at " + viaCoords.get(0).toOSMURL() + ", why don't you add it to the 
OSM data?)");
                }
 
-               Coord v1 = viaCoord;
+               Coord v1 = viaCoords.get(0);
                Coord v2 = null;
 
                if(viaWay != null) {
@@ -262,17 +271,17 @@
                        result = false;
                }
 
-               if (result && viaWay != null) {
+               /*if (result && viaWay != null) {
                        log.warn(messagePrefix + "sorry, 'via' ways are not 
supported - ignoring restriction");
                        result = false;
-               }
+               }*/
 
                return result;
        }
 
        public void addRestriction(MapCollector collector) {
 
-               if(restriction == null || viaNode == null || fromNode == null 
|| toNode == null) {
+               if(restriction == null || (viaNode == null && viaWay == null) 
|| fromNode == null || toNode == null) {
                        // restriction must have some error (reported earlier)
                        return;
                }
@@ -282,7 +291,22 @@
                         restriction.equals("no_straight_on") ||
                         restriction.equals("no_u_turn") ||
                         restriction.startsWith("no_turn")) {
-                       collector.addRestriction(fromNode, toNode, viaNode, 
exceptMask);
+                       ArrayList<CoordNode> nodes = new ArrayList<CoordNode>();
+                       nodes.add(fromNode);
+                       if (viaWay!=null)
+                       {
+                               nodes.addAll(otherNodes);       
+                       }
+                       else if (viaNode!=null) {
+                               nodes.add(viaNode);
+                       }
+                       nodes.add(toNode);
+                       log.info ("Creating relation with " +nodes.size()+" 
nodes");
+                       for (Coord node :nodes)
+                       {
+                               log.info ("     " +node.toOSMURL());
+                       }
+                       collector.addRestriction(nodes, exceptMask);
                        if(restriction.startsWith("no_turn"))
                                log.warn(messagePrefix + "has bad type '" + 
restriction + "' it should be of the form no_X_turn rather than no_turn_X - I 
added the restriction anyway - blocks routing to way " + toWay.toBrowseURL());
                        else
@@ -297,7 +321,11 @@
                        log.info(messagePrefix + restriction + " added - allows 
routing to way " + toWay.toBrowseURL());
                        for(CoordNode otherNode : otherNodes) {
                                log.info(messagePrefix + restriction + "        
blocks routing to node " + otherNode.toOSMURL());
-                               collector.addRestriction(fromNode, otherNode, 
viaNode, exceptMask);
+                               ArrayList<CoordNode> nodes = new 
ArrayList<CoordNode>();
+                               nodes.add(fromNode);
+                               nodes.add(viaNode);
+                               nodes.add(otherNode);
+                               collector.addRestriction(nodes, exceptMask);
                        }
                }
                else {
@@ -312,6 +340,6 @@
        }
 
        public String toString() {
-               return "[restriction = " + restriction + ", from = " + 
fromWay.toBrowseURL() + ", to = " + toWay.toBrowseURL() + ", via = " + 
viaCoord.toOSMURL() + "]";
+               return "[restriction = " + restriction + ", from = " + 
fromWay.toBrowseURL() + ", to = " + toWay.toBrowseURL() + ", via = " + 
viaCoords.get(0).toOSMURL() + "]";
        }
 }
Index: uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java
===================================================================
--- uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java    
(revision 1647)
+++ uk/me/parabola/mkgmap/reader/overview/OverviewMapDataSource.java    
(working copy)
@@ -18,6 +18,7 @@
 
 import java.io.FileNotFoundException;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import uk.me.parabola.imgfmt.FormatException;
@@ -140,8 +141,8 @@
                addLine(road);
        }
 
-       public void addRestriction(CoordNode fromNode, CoordNode toNode, 
CoordNode viaNode, byte exceptMask) {
-               getRoadNetwork().addRestriction(fromNode, toNode, viaNode, 
exceptMask);
+       public void addRestriction(List<CoordNode> restrNodes, int exceptMask) {
+               getRoadNetwork().addRestriction(restrNodes, exceptMask);
        }
 
        public void addThroughRoute(long junctionNodeId, long roadIdA, long 
roadIdB) {
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to