diff --git a/src/main/java/com/conveyal/r5/labeling/SidewalkTraversalPermissionLabeler.java b/src/main/java/com/conveyal/r5/labeling/SidewalkTraversalPermissionLabeler.java index dd8c53e23..9c85525e2 100644 --- a/src/main/java/com/conveyal/r5/labeling/SidewalkTraversalPermissionLabeler.java +++ b/src/main/java/com/conveyal/r5/labeling/SidewalkTraversalPermissionLabeler.java @@ -1,6 +1,12 @@ package com.conveyal.r5.labeling; +import com.conveyal.osmlib.Way; +import com.conveyal.r5.streets.EdgeStore; + +import java.util.EnumMap; +import java.util.EnumSet; + /** * Traversal permission labeler that restricts walking on most driving ways (useful for networks with complete * sidewalks). Also includes permissions for the United States (see USTraversalPermissionLabeler). @@ -12,7 +18,80 @@ public class SidewalkTraversalPermissionLabeler extends TraversalPermissionLabel addPermissions("cycleway", "bicycle=yes;foot=yes"); addPermissions("trunk|primary|secondary|tertiary|unclassified|residential|living_street|road|service|track", "access=yes;foot=no"); // Note foot=no + } + + @Override + public RoadPermission getPermissions(Way way) { + EnumMap tree = getTreeForWay(way); + + applySpecificPermissions(tree, way); + + applyWheelchairPermissions(tree, way); + + EnumSet ret = EnumSet.noneOf(EdgeStore.EdgeFlag.class); + + Label walk = walk(tree, Node.FOOT); + Label bicycle = walk(tree, Node.BICYCLE); + Label car = walk(tree, Node.CAR); + Label wheelchair = walk(tree, Node.WHEELCHAIR); + if (walk == Label.YES && car == Label.NO) { + ret.add(EdgeStore.EdgeFlag.ALLOWS_PEDESTRIAN); + } else if (walk == Label.NO_THRU_TRAFFIC) { + ret.add(EdgeStore.EdgeFlag.NO_THRU_TRAFFIC_PEDESTRIAN); + } + if (wheelchair == Label.YES && car == Label.NO) { + ret.add(EdgeStore.EdgeFlag.ALLOWS_WHEELCHAIR); + } + + if (wheelchair == Label.LIMITED) { + ret.add(EdgeStore.EdgeFlag.LIMITED_WHEELCHAIR); + } + if (bicycle == Label.YES) { + ret.add(EdgeStore.EdgeFlag.ALLOWS_BIKE); + } else if (bicycle == Label.NO_THRU_TRAFFIC) { + ret.add(EdgeStore.EdgeFlag.NO_THRU_TRAFFIC_BIKE); + } + if (car == Label.YES) { + ret.add(EdgeStore.EdgeFlag.ALLOWS_CAR); + } else if (car == Label.NO_THRU_TRAFFIC) { + ret.add(EdgeStore.EdgeFlag.NO_THRU_TRAFFIC_CAR); + } + + + EnumSet forward = EnumSet.copyOf(ret); + EnumSet backward = EnumSet.copyOf(ret); + + applyDirectionalPermissions(way, forward, backward); + + // check for one-way streets. Note that leaf nodes will always be labeled and there is no unknown, + // so we need not traverse the tree + EnumMap dir = getDirectionalTree(way); + + //Backward edge + // you can traverse back if this is not one way or it is one way reverse + if (dir.get(Node.CAR) == OneWay.YES) backward.remove(EdgeStore.EdgeFlag.ALLOWS_CAR); + if (dir.get(Node.BICYCLE) == OneWay.YES) backward.remove(EdgeStore.EdgeFlag.ALLOWS_BIKE); + if (dir.get(Node.FOOT) == OneWay.YES) backward.remove(EdgeStore.EdgeFlag.ALLOWS_PEDESTRIAN); + + //Forward edge + // you can always forward traverse unless this is a rare reversed one-way street + if (dir.get(Node.CAR) == OneWay.REVERSE) forward.remove(EdgeStore.EdgeFlag.ALLOWS_CAR); + if (dir.get(Node.BICYCLE) == OneWay.REVERSE) forward.remove(EdgeStore.EdgeFlag.ALLOWS_BIKE); + if (dir.get(Node.FOOT) == OneWay.REVERSE) forward.remove(EdgeStore.EdgeFlag.ALLOWS_PEDESTRIAN); + + //This needs to be called after permissions were removed in directionalTree + //it is moved from directional tree since we can only remove permissions there + //but they need to be added also for example highway=residential;bicycle=no;oneway=yes;bicycle:left=opposite_lane + + //If oneway is reversed (oneway=-1) opposite bicycle permission also need to be since they are opposite rest of traffic + if (dir.get(Node.CAR) == OneWay.REVERSE){ + applyOppositeBicyclePermissions(way, forward); + } else { + applyOppositeBicyclePermissions(way, backward); + } + + return new RoadPermission(forward, backward); } } diff --git a/src/main/java/com/conveyal/r5/labeling/TraversalPermissionLabeler.java b/src/main/java/com/conveyal/r5/labeling/TraversalPermissionLabeler.java index dab3b482c..e11961bf6 100644 --- a/src/main/java/com/conveyal/r5/labeling/TraversalPermissionLabeler.java +++ b/src/main/java/com/conveyal/r5/labeling/TraversalPermissionLabeler.java @@ -145,7 +145,7 @@ public RoadPermission getPermissions(Way way) { * @param tree * @param way */ - private void applyWheelchairPermissions(EnumMap tree, Way way) { + void applyWheelchairPermissions (EnumMap tree, Way way) { if (way.hasTag("highway", "steps")) { applyLabel(Node.WHEELCHAIR, Label.NO, tree); } @@ -167,7 +167,7 @@ private void applyWheelchairPermissions(EnumMap tree, Way way) { * @param way * @param backward */ - private void applyOppositeBicyclePermissions(Way way, EnumSet backward) { + void applyOppositeBicyclePermissions (Way way, EnumSet backward) { String cyclewayLeftTagValue = way.getTag("cycleway:left"); String cyclewayRightTagValue = way.getTag("cycleway:right"); String cyclewayTagValue = way.getTag("cycleway"); @@ -197,8 +197,8 @@ private void applyOppositeBicyclePermissions(Way way, EnumSet forward, - EnumSet backward) { + void applyDirectionalPermissions (Way way, EnumSet forward, + EnumSet backward) { String cyclewayLeftTagValue = way.getTag("cycleway:left"); String cyclewayRightTagValue = way.getTag("cycleway:right"); @@ -228,7 +228,7 @@ public EnumSet getPermissions(Way way, boolean back) { } /** returns whether this node is permitted traversal anywhere in the hierarchy */ - private Label walk (EnumMap tree, Node node) { + Label walk (EnumMap tree, Node node) { do { //We need to return first labeled node not first yes node //Otherwise access=yes bicycle=no returns true for bicycle @@ -242,7 +242,7 @@ private Label walk (EnumMap tree, Node node) { } /** apply any specific permissions that may exist */ - private void applySpecificPermissions (EnumMap tree, Way way) { + void applySpecificPermissions (EnumMap tree, Way way) { // start from the root of the tree if (way.hasTag("access")) applyLabel(Node.ACCESS, Label.fromTag(way.getTag("access")), tree); if (way.hasTag("foot")) applyLabel(Node.FOOT, Label.fromTag(way.getTag("foot")), tree); @@ -398,7 +398,7 @@ protected EnumMap getDefaultTree () { } /** Get a directional tree (for use when labeling one-way streets) where every node is labeled bidirectional */ - private EnumMap getDirectionalTree (Way way) { + EnumMap getDirectionalTree (Way way) { EnumMap tree = new EnumMap<>(Node.class); // label all nodes as unknown