Repository: graphhopper/graphhopper
Pull request #1811 (2019-12-02 13:15:06)

Remove FlagEncoder.getAnnotation
This removes the method and also a bit the ability to customize such annotations, but if this is really needed we can introduce it later. (There will follow up channges where we add warnings for fords and tolls.)

When multiple bike vehicles are used, this change will also reduce bit usage by 8 bits as it does no longer store the way type and paved/unpaved boolean in a separate EncodedValue but relies on `RoadClass` and could rely on `Surface`.

It also introduces a "ford warning" in all cases, so that we can switch defaults to handle #236 later (not in this PR)


Patch:
diff --git a/core/src/main/java/com/graphhopper/reader/ReaderElement.java b/core/src/main/java/com/graphhopper/reader/ReaderElement.java
index aaf5ff720..db6f3582b 100644
--- a/core/src/main/java/com/graphhopper/reader/ReaderElement.java
+++ b/core/src/main/java/com/graphhopper/reader/ReaderElement.java
@@ -136,7 +136,7 @@ public abstract class ReaderElement {
     /**
      * Check that a given tag has one of the specified values.
      */
-    public final boolean hasTag(String key, Set<String> values) {
+    public final boolean hasTag(String key, Collection<String> values) {
         return values.contains(getTag(key, ""));
     }
 
@@ -144,7 +144,7 @@ public abstract class ReaderElement {
      * Check a number of tags in the given order for the any of the given values. Used to parse
      * hierarchical access restrictions
      */
-    public boolean hasTag(List<String> keyList, Set<String> values) {
+    public boolean hasTag(List<String> keyList, Collection<String> values) {
         for (String key : keyList) {
             if (values.contains(getTag(key, "")))
                 return true;
diff --git a/core/src/main/java/com/graphhopper/routing/InstructionsFromEdges.java b/core/src/main/java/com/graphhopper/routing/InstructionsFromEdges.java
index 02dd8f491..1aa209920 100644
--- a/core/src/main/java/com/graphhopper/routing/InstructionsFromEdges.java
+++ b/core/src/main/java/com/graphhopper/routing/InstructionsFromEdges.java
@@ -17,7 +17,7 @@
  */
 package com.graphhopper.routing;
 
-import com.graphhopper.routing.profiles.BooleanEncodedValue;
+import com.graphhopper.routing.profiles.*;
 import com.graphhopper.routing.util.DefaultEdgeFilter;
 import com.graphhopper.routing.util.FlagEncoder;
 import com.graphhopper.routing.weighting.Weighting;
@@ -27,6 +27,8 @@ import com.graphhopper.storage.NodeAccess;
 import com.graphhopper.util.*;
 import com.graphhopper.util.shapes.GHPoint;
 
+import static com.graphhopper.routing.util.EncodingManager.getKey;
+
 /**
  * This class calculates instructions from the edges in a Path.
  *
@@ -46,6 +48,11 @@ public class InstructionsFromEdges implements Path.EdgeVisitor {
     private final EdgeExplorer crossingExplorer;
     private final BooleanEncodedValue roundaboutEnc;
     private final BooleanEncodedValue accessEnc;
+    private final BooleanEncodedValue getOffBikeEnc;
+    private final EnumEncodedValue<RouteNetwork> bikeRouteEnc;
+    private final EnumEncodedValue<RoadClass> roadClassEnc;
+    private final EnumEncodedValue<RoadEnvironment> roadEnvEnc;
+
     /*
      * We need three points to make directions
      *
@@ -81,33 +88,40 @@ public class InstructionsFromEdges implements Path.EdgeVisitor {
 
     private final int MAX_U_TURN_DISTANCE = 35;
 
-    public InstructionsFromEdges(Graph graph, Weighting weighting,
-                                 BooleanEncodedValue roundaboutEnc,
+    public InstructionsFromEdges(Graph graph, Weighting weighting, EncodedValueLookup evLookup,
                                  Translation tr, InstructionList ways) {
-        this.weighting = weighting;
         this.encoder = weighting.getFlagEncoder();
-        this.accessEnc = this.encoder.getAccessEnc();
-        this.roundaboutEnc = roundaboutEnc;
+        this.weighting = weighting;
+        this.accessEnc = evLookup.getBooleanEncodedValue(getKey(encoder.toString(), "access"));
+        this.roundaboutEnc = evLookup.getBooleanEncodedValue(Roundabout.KEY);
+
+        // both EncodedValues are optional and only used when bike encoders are added
+        String key = getKey("bike", RouteNetwork.EV_SUFFIX);
+        this.bikeRouteEnc = evLookup.hasEncodedValue(key) ? evLookup.getEnumEncodedValue(key, RouteNetwork.class) : null;
+        this.getOffBikeEnc = evLookup.hasEncodedValue(GetOffBike.KEY) ? evLookup.getBooleanEncodedValue(GetOffBike.KEY) : null;
+
+        this.roadClassEnc = evLookup.getEnumEncodedValue(RoadClass.KEY, RoadClass.class);
+        this.roadEnvEnc = evLookup.getEnumEncodedValue(RoadEnvironment.KEY, RoadEnvironment.class);
         this.nodeAccess = graph.getNodeAccess();
         this.tr = tr;
         this.ways = ways;
         prevNode = -1;
         prevInRoundabout = false;
         prevName = null;
-        outEdgeExplorer = graph.createEdgeExplorer(DefaultEdgeFilter.outEdges(this.encoder));
-        crossingExplorer = graph.createEdgeExplorer(DefaultEdgeFilter.allEdges(this.encoder));
+        outEdgeExplorer = graph.createEdgeExplorer(DefaultEdgeFilter.outEdges(encoder));
+        crossingExplorer = graph.createEdgeExplorer(DefaultEdgeFilter.allEdges(encoder));
     }
 
     /**
      * @return the list of instructions for this path.
      */
-    public static InstructionList calcInstructions(Path path, Graph graph, Weighting weighting, BooleanEncodedValue roundaboutEnc, final Translation tr) {
+    public static InstructionList calcInstructions(Path path, Graph graph, Weighting weighting, EncodedValueLookup evLookup, final Translation tr) {
         final InstructionList ways = new InstructionList(tr);
         if (path.isFound()) {
             if (path.getSize() == 0) {
                 ways.add(new FinishInstruction(graph.getNodeAccess(), path.getEndNode()));
             } else {
-                path.forEveryEdge(new InstructionsFromEdges(graph, weighting, roundaboutEnc, tr, ways));
+                path.forEveryEdge(new InstructionsFromEdges(graph, weighting, evLookup, tr, ways));
             }
         }
         return ways;
@@ -143,7 +157,19 @@ public class InstructionsFromEdges implements Path.EdgeVisitor {
         }
 
         String name = edge.getName();
-        InstructionAnnotation annotation = encoder.getAnnotation(flags, tr);
+        InstructionAnnotation annotation = InstructionAnnotation.EMPTY;
+        if (getOffBikeEnc != null) {
+            // only for bikes do
+            if (edge.get(roadClassEnc) == RoadClass.CYCLEWAY
+                    || bikeRouteEnc != null && edge.get(bikeRouteEnc) != RouteNetwork.OTHER) {
+                // for backward compatibility
+                annotation = new InstructionAnnotation(0, tr.tr("cycleway"));
+            } else if (edge.get(getOffBikeEnc)) {
+                annotation = new InstructionAnnotation(1, tr.tr("off_bike"));
+            }
+        } else if (edge.get(roadEnvEnc) == RoadEnvironment.FORD) {
+            annotation = new InstructionAnnotation(1, tr.tr("way_contains_ford"));
+        }
 
         if ((prevName == null) && (!isRoundabout)) // very first instruction (if not in Roundabout)
         {
diff --git a/core/src/main/java/com/graphhopper/routing/InstructionsOutgoingEdges.java b/core/src/main/java/com/graphhopper/routing/InstructionsOutgoingEdges.java
index cbd03f0ea..8868bb9ab 100644
--- a/core/src/main/java/com/graphhopper/routing/InstructionsOutgoingEdges.java
+++ b/core/src/main/java/com/graphhopper/routing/InstructionsOutgoingEdges.java
@@ -18,8 +18,8 @@
 package com.graphhopper.routing;
 
 import com.graphhopper.routing.profiles.BooleanEncodedValue;
-import com.graphhopper.routing.profiles.MaxSpeed;
 import com.graphhopper.routing.profiles.DecimalEncodedValue;
+import com.graphhopper.routing.profiles.MaxSpeed;
 import com.graphhopper.routing.util.DataFlagEncoder;
 import com.graphhopper.routing.util.FlagEncoder;
 import com.graphhopper.storage.IntsRef;
@@ -57,19 +57,14 @@ import java.util.List;
  */
 class InstructionsOutgoingEdges {
 
-    final EdgeIteratorState prevEdge;
-    final EdgeIteratorState currentEdge;
-
+    private final EdgeIteratorState prevEdge;
+    private final EdgeIteratorState currentEdge;
     // Outgoing edges that we would be allowed to turn on
-    final List<EdgeIteratorState> allowedOutgoingEdges;
-
+    private final List<EdgeIteratorState> allowedOutgoingEdges;
     // All outgoing edges, including oneways in the wrong direction
-    final List<EdgeIteratorState> allOutgoingEdges;
-
-    final FlagEncoder encoder;
-    final BooleanEncodedValue accessEnc;
-    final DecimalEncodedValue speedEnc;
-    final NodeAccess nodeAccess;
+    private final List<EdgeIteratorState> allOutgoingEdges;
+    private final DecimalEncodedValue speedEnc;
+    private final NodeAccess nodeAccess;
 
     public InstructionsOutgoingEdges(EdgeIteratorState prevEdge,
                                      EdgeIteratorState currentEdge,
@@ -81,8 +76,7 @@ class InstructionsOutgoingEdges {
                                      int adjNode) {
         this.prevEdge = prevEdge;
         this.currentEdge = currentEdge;
-        this.encoder = encoder;
-        this.accessEnc = encoder.getAccessEnc();
+        BooleanEncodedValue accessEnc = encoder.getAccessEnc();
         this.speedEnc = (encoder instanceof DataFlagEncoder) ? encoder.getDecimalEncodedValue(MaxSpeed.KEY) : encoder.getAverageSpeedEnc();
         this.nodeAccess = nodeAccess;
 
diff --git a/core/src/main/java/com/graphhopper/routing/profiles/DefaultEncodedValueFactory.java b/core/src/main/java/com/graphhopper/routing/profiles/DefaultEncodedValueFactory.java
index be704d425..a36fbfbd8 100644
--- a/core/src/main/java/com/graphhopper/routing/profiles/DefaultEncodedValueFactory.java
+++ b/core/src/main/java/com/graphhopper/routing/profiles/DefaultEncodedValueFactory.java
@@ -34,6 +34,8 @@ public class DefaultEncodedValueFactory implements EncodedValueFactory {
         // creating the Country EV is done while SpatialRuleIndex is created and not here
         if (Roundabout.KEY.equals(name)) {
             enc = Roundabout.create();
+        } else if (GetOffBike.KEY.equals(name)) {
+            enc = GetOffBike.create();
         } else if (RoadClass.KEY.equals(name)) {
             enc = new EnumEncodedValue<>(RoadClass.KEY, RoadClass.class);
         } else if (RoadClassLink.KEY.equals(name)) {
diff --git a/core/src/main/java/com/graphhopper/routing/profiles/GetOffBike.java b/core/src/main/java/com/graphhopper/routing/profiles/GetOffBike.java
new file mode 100644
index 000000000..babef4101
--- /dev/null
+++ b/core/src/main/java/com/graphhopper/routing/profiles/GetOffBike.java
@@ -0,0 +1,9 @@
+package com.graphhopper.routing.profiles;
+
+public class GetOffBike {
+    public static final String KEY = "get_off_bike";
+
+    public static BooleanEncodedValue create() {
+        return new SimpleBooleanEncodedValue(KEY, false);
+    }
+}
diff --git a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
index 5438bb655..cff636576 100644
--- a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
@@ -228,11 +228,6 @@ public abstract class AbstractFlagEncoder implements FlagEncoder {
         return 0;
     }
 
-    @Override
-    public InstructionAnnotation getAnnotation(IntsRef edgeFlags, Translation tr) {
-        return InstructionAnnotation.EMPTY;
-    }
-
     /**
      * Sets default flags with specified access.
      */
diff --git a/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java
index d353e6cd0..b5439c139 100644
--- a/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java
@@ -40,10 +40,7 @@ import static com.graphhopper.routing.util.PriorityCode.*;
  * @author ratrun
  */
 abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
-    /**
-     * Reports whether this edge is unpaved.
-     */
-    public static final int K_UNPAVED = 100;
+
     protected static final int PUSHING_SECTION_SPEED = 4;
     // Pushing section highways are parts where you need to get off your bike and push it (German: Schiebestrecke)
     protected final HashSet<String> pushingSectionsHighways = new HashSet<>();
@@ -57,8 +54,6 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
     private final Map<String, Integer> highwaySpeeds = new HashMap<>();
     protected boolean speedTwoDirections;
     DecimalEncodedValue priorityEnc;
-    private BooleanEncodedValue unpavedEnc;
-    private IntEncodedValue wayTypeEnc;
     // Car speed limit which switches the preference from UNCHANGED to AVOID_IF_POSSIBLE
     private int avoidSpeedLimit;
     EnumEncodedValue<RouteNetwork> bikeRouteEnc;
@@ -212,8 +207,6 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
         // first two bits are reserved for route handling in superclass
         super.createEncodedValues(registerNewEncodedValue, prefix, index);
         registerNewEncodedValue.add(avgSpeedEnc = new UnsignedDecimalEncodedValue(getKey(prefix, "average_speed"), speedBits, speedFactor, speedTwoDirections));
-        registerNewEncodedValue.add(unpavedEnc = new SimpleBooleanEncodedValue(getKey(prefix, "paved"), false));
-        registerNewEncodedValue.add(wayTypeEnc = new UnsignedIntEncodedValue(getKey(prefix, "waytype"), 2, false));
         registerNewEncodedValue.add(priorityEnc = new UnsignedDecimalEncodedValue(getKey(prefix, "priority"), 3, PriorityCode.getFactor(1), false));
 
         bikeRouteEnc = getEnumEncodedValue(getKey("bike", EV_SUFFIX), RouteNetwork.class);
@@ -324,7 +317,6 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
         if (!access.isFerry()) {
             wayTypeSpeed = applyMaxSpeed(way, wayTypeSpeed);
             handleSpeed(edgeFlags, way, wayTypeSpeed);
-            handleBikeRelated(edgeFlags, way, priorityFromRelation != null && priorityFromRelation > UNCHANGED.getValue());
         } else {
             double ferrySpeed = getFerrySpeed(way);
             handleSpeed(edgeFlags, way, ferrySpeed);
@@ -398,48 +390,6 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
         return speed;
     }
 
-    @Override
-    public InstructionAnnotation getAnnotation(IntsRef edgeFlags, Translation tr) {
-        int paveType = 0; // paved
-        if (unpavedEnc.getBool(false, edgeFlags))
-            paveType = 1; // unpaved
-
-        int wayType = wayTypeEnc.getInt(false, edgeFlags);
-        String wayName = getWayName(paveType, wayType, tr);
-        return new InstructionAnnotation(0, wayName);
-    }
-
-    String getWayName(int pavementType, int wayType, Translation tr) {
-        String pavementName = "";
-        if (pavementType == 1)
-            pavementName = tr.tr("unpaved");
-
-        String wayTypeName = "";
-        switch (wayType) {
-            case 0:
-                wayTypeName = "";
-                break;
-            case 1:
-                wayTypeName = tr.tr("off_bike");
-                break;
-            case 2:
-                wayTypeName = tr.tr("cycleway");
-                break;
-            case 3:
-                wayTypeName = tr.tr("small_way");
-                break;
-        }
-
-        if (pavementName.isEmpty()) {
-            if (wayType == 0 || wayType == 3)
-                return "";
-            return wayTypeName;
-        } else if (wayTypeName.isEmpty())
-            return pavementName;
-        else
-            return wayTypeName + ", " + pavementName;
-    }
-
     /**
      * In this method we prefer cycleways or roads with designated bike access and avoid big roads
      * or roads with trams or pedestrian.
@@ -562,46 +512,6 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
         }
     }
 
-    /**
-     * Handle surface and wayType encoding
-     */
-    void handleBikeRelated(IntsRef edgeFlags, ReaderWay way, boolean partOfCycleRelation) {
-        String surfaceTag = way.getTag("surface");
-        String highway = way.getTag("highway");
-        String trackType = way.getTag("tracktype");
-
-        // Populate unpavedBit
-        if ("track".equals(highway) && !"grade1".equals(trackType)
-                || "path".equals(highway) && surfaceTag == null
-                || unpavedSurfaceTags.contains(surfaceTag)) {
-            unpavedEnc.setBool(false, edgeFlags, true);
-        }
-
-        WayType wayType;
-        if (roadValues.contains(highway))
-            wayType = WayType.ROAD;
-        else
-            wayType = WayType.OTHER_SMALL_WAY;
-
-        boolean isPushingSection = isPushingSection(way);
-        if (isPushingSection && !partOfCycleRelation || "steps".equals(highway))
-            wayType = WayType.PUSHING_SECTION;
-
-        if (way.hasTag("bicycle", intendedValues)) {
-            if (isPushingSection && !way.hasTag("bicycle", "designated"))
-                wayType = WayType.OTHER_SMALL_WAY;
-            else if (wayType == WayType.OTHER_SMALL_WAY || wayType == WayType.PUSHING_SECTION)
-                wayType = WayType.CYCLEWAY;
-        } else if ("cycleway".equals(highway))
-            wayType = WayType.CYCLEWAY;
-
-        wayTypeEnc.setInt(false, edgeFlags, wayType.getValue());
-    }
-
-    boolean isPushingSection(ReaderWay way) {
-        return way.hasTag("highway", pushingSectionsHighways) || way.hasTag("railway", "platform") || way.hasTag("bicycle", "dismount");
-    }
-
     protected void handleSpeed(IntsRef edgeFlags, ReaderWay way, double speed) {
         avgSpeedEnc.setDecimal(false, edgeFlags, speed);
 
@@ -633,11 +543,11 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
         }
     }
 
-    protected void setHighwaySpeed(String highway, int speed) {
+    void setHighwaySpeed(String highway, int speed) {
         highwaySpeeds.put(highway, speed);
     }
 
-    protected int getHighwaySpeed(String key) {
+    int getHighwaySpeed(String key) {
         return highwaySpeeds.get(key);
     }
 
@@ -661,28 +571,11 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
         return PriorityWeighting.class.isAssignableFrom(feature);
     }
 
-    public void setAvoidSpeedLimit(int limit) {
+    void setAvoidSpeedLimit(int limit) {
         avoidSpeedLimit = limit;
     }
 
-    protected void setSpecificClassBicycle(String subkey) {
+    void setSpecificClassBicycle(String subkey) {
         classBicycleKey = "class:bicycle:" + subkey;
     }
-
-    private enum WayType {
-        ROAD(0),
-        PUSHING_SECTION(1),
-        CYCLEWAY(2),
-        OTHER_SMALL_WAY(3);
-
-        private final int value;
-
-        private WayType(int value) {
-            this.value = value;
-        }
-
-        public int getValue() {
-            return value;
-        }
-    }
 }
diff --git a/core/src/main/java/com/graphhopper/routing/util/BikeFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/BikeFlagEncoder.java
index 67c84a12a..777748efc 100644
--- a/core/src/main/java/com/graphhopper/routing/util/BikeFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/BikeFlagEncoder.java
@@ -75,13 +75,6 @@ public class BikeFlagEncoder extends BikeCommonFlagEncoder {
         return 2;
     }
 
-    @Override
-    boolean isPushingSection(ReaderWay way) {
-        String highway = way.getTag("highway");
-        String trackType = way.getTag("tracktype");
-        return super.isPushingSection(way) || "track".equals(highway) && trackType != null && !"grade1".equals(trackType);
-    }
-
     @Override
     public String toString() {
         return "bike";
diff --git a/core/src/main/java/com/graphhopper/routing/util/DataFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/DataFlagEncoder.java
index 7a4182022..9dcfd0130 100644
--- a/core/src/main/java/com/graphhopper/routing/util/DataFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/DataFlagEncoder.java
@@ -203,15 +203,6 @@ public class DataFlagEncoder extends AbstractFlagEncoder {
         return GenericWeighting.class.isAssignableFrom(feature);
     }
 
-    @Override
-    public InstructionAnnotation getAnnotation(IntsRef flags, Translation tr) {
-        if (roadEnvironmentEnc.getEnum(false, flags) == RoadEnvironment.FORD) {
-            return new InstructionAnnotation(1, tr.tr("way_contains_ford"));
-        }
-
-        return super.getAnnotation(flags, tr);
-    }
-
     @Override
     public int getVersion() {
         return 4;
diff --git a/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java b/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java
index 5819b9c05..988cafbaf 100644
--- a/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java
+++ b/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java
@@ -320,10 +320,15 @@ public class EncodingManager implements EncodedValueLookup {
             }
 
             for (AbstractFlagEncoder encoder : flagEncoderList) {
-                if (encoder instanceof BikeCommonFlagEncoder && !em.hasEncodedValue(getKey("bike", RouteNetwork.EV_SUFFIX))) {
-                    _addRelationTagParser(new OSMBikeNetworkTagParser());
-                } else if (encoder instanceof FootFlagEncoder && !em.hasEncodedValue(getKey("foot", RouteNetwork.EV_SUFFIX))) {
-                    _addRelationTagParser(new OSMFootNetworkTagParser());
+                if (encoder instanceof BikeCommonFlagEncoder) {
+                    if (!em.hasEncodedValue(getKey("bike", RouteNetwork.EV_SUFFIX)))
+                        _addRelationTagParser(new OSMBikeNetworkTagParser());
+                    if (!em.encodedValueMap.containsKey(GetOffBike.KEY))
+                        _addEdgeTagParser(new OSMGetOffBikeParser(), false, false);
+
+                } else if (encoder instanceof FootFlagEncoder) {
+                    if (!em.hasEncodedValue(getKey("foot", RouteNetwork.EV_SUFFIX)))
+                        _addRelationTagParser(new OSMFootNetworkTagParser());
                 }
 
                 em.addEncoder(encoder);
diff --git a/core/src/main/java/com/graphhopper/routing/util/FlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/FlagEncoder.java
index 10178613d..5bc2f9409 100644
--- a/core/src/main/java/com/graphhopper/routing/util/FlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/FlagEncoder.java
@@ -60,11 +60,6 @@ public interface FlagEncoder extends EncodedValueLookup {
      */
     boolean supports(Class<?> feature);
 
-    /**
-     * @return additional cost or warning information for an instruction like ferry or road charges.
-     */
-    InstructionAnnotation getAnnotation(IntsRef intsRef, Translation tr);
-
     /**
      * @return true if already registered in an EncodingManager
      */
diff --git a/core/src/main/java/com/graphhopper/routing/util/RacingBikeFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/RacingBikeFlagEncoder.java
index bd81ce890..2fd25bf57 100644
--- a/core/src/main/java/com/graphhopper/routing/util/RacingBikeFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/RacingBikeFlagEncoder.java
@@ -144,16 +144,6 @@ public class RacingBikeFlagEncoder extends BikeCommonFlagEncoder {
         }
     }
 
-    @Override
-    boolean isPushingSection(ReaderWay way) {
-        String highway = way.getTag("highway");
-        String trackType = way.getTag("tracktype");
-        return way.hasTag("highway", pushingSectionsHighways)
-                || way.hasTag("railway", "platform")
-                || way.hasTag("bicycle", "dismount")
-                || "track".equals(highway) && trackType != null && !"grade1".equals(trackType);
-    }
-
     @Override
     boolean isSacScaleAllowed(String sacScale) {
         // for racing bike it is only allowed if empty
diff --git a/core/src/main/java/com/graphhopper/routing/util/parsers/OSMGetOffBikeParser.java b/core/src/main/java/com/graphhopper/routing/util/parsers/OSMGetOffBikeParser.java
new file mode 100644
index 000000000..ba4c762a1
--- /dev/null
+++ b/core/src/main/java/com/graphhopper/routing/util/parsers/OSMGetOffBikeParser.java
@@ -0,0 +1,47 @@
+package com.graphhopper.routing.util.parsers;
+
+import com.graphhopper.reader.ReaderWay;
+import com.graphhopper.routing.profiles.BooleanEncodedValue;
+import com.graphhopper.routing.profiles.EncodedValue;
+import com.graphhopper.routing.profiles.EncodedValueLookup;
+import com.graphhopper.routing.profiles.GetOffBike;
+import com.graphhopper.routing.util.EncodingManager;
+import com.graphhopper.storage.IntsRef;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * This parser scans different OSM tags to identify ways where a cyclist has to get off her bike.
+ */
+public class OSMGetOffBikeParser implements TagParser {
+
+    private final HashSet<String> pushBikeHighwayTags = new HashSet<>();
+    private final List<String> accepted = Arrays.asList("designated", "yes");
+    private final BooleanEncodedValue offBikeEnc;
+
+    public OSMGetOffBikeParser() {
+        offBikeEnc = GetOffBike.create();
+        pushBikeHighwayTags.add("path");
+        // pushBikeHighwayTags.add("steps"); special handling
+        pushBikeHighwayTags.add("footway");
+        pushBikeHighwayTags.add("pedestrian");
+        pushBikeHighwayTags.add("platform");
+    }
+
+    @Override
+    public void createEncodedValues(EncodedValueLookup lookup, List<EncodedValue> registerNewEncodedValue) {
+        registerNewEncodedValue.add(offBikeEnc);
+    }
+
+    @Override
+    public IntsRef handleWayTags(IntsRef edgeFlags, ReaderWay way, EncodingManager.Access access, IntsRef relationFlags) {
+        String highway = way.getTag("highway");
+        if (!way.hasTag("bicycle", accepted) && (pushBikeHighwayTags.contains(highway) || way.hasTag("railway", "platform"))
+                || "steps".equals(highway) || way.hasTag("bicycle", "dismount")) {
+            offBikeEnc.setBool(false, edgeFlags, true);
+        }
+        return edgeFlags;
+    }
+}
diff --git a/core/src/main/java/com/graphhopper/util/PathMerger.java b/core/src/main/java/com/graphhopper/util/PathMerger.java
index 5fab95154..10c7b96e7 100644
--- a/core/src/main/java/com/graphhopper/util/PathMerger.java
+++ b/core/src/main/java/com/graphhopper/util/PathMerger.java
@@ -21,6 +21,7 @@ import com.graphhopper.PathWrapper;
 import com.graphhopper.routing.InstructionsFromEdges;
 import com.graphhopper.routing.Path;
 import com.graphhopper.routing.profiles.BooleanEncodedValue;
+import com.graphhopper.routing.profiles.EncodedValueLookup;
 import com.graphhopper.routing.profiles.Roundabout;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.weighting.Weighting;
@@ -90,7 +91,7 @@ public class PathMerger {
         return this;
     }
 
-    public void doWork(PathWrapper altRsp, List<Path> paths, EncodingManager encodingManager, Translation tr) {
+    public void doWork(PathWrapper altRsp, List<Path> paths, EncodedValueLookup evLookup, Translation tr) {
         int origPoints = 0;
         long fullTimeInMillis = 0;
         double fullWeight = 0;
@@ -100,7 +101,6 @@ public class PathMerger {
         InstructionList fullInstructions = new InstructionList(tr);
         PointList fullPoints = PointList.EMPTY;
         List<String> description = new ArrayList<>();
-        BooleanEncodedValue roundaboutEnc = encodingManager.getBooleanEncodedValue(Roundabout.KEY);
         for (int pathIndex = 0; pathIndex < paths.size(); pathIndex++) {
             Path path = paths.get(pathIndex);
             if (!path.isFound()) {
@@ -112,7 +112,7 @@ public class PathMerger {
             fullDistance += path.getDistance();
             fullWeight += path.getWeight();
             if (enableInstructions) {
-                InstructionList il = InstructionsFromEdges.calcInstructions(path, graph, weighting, roundaboutEnc, tr);
+                InstructionList il = InstructionsFromEdges.calcInstructions(path, graph, weighting, evLookup, tr);
 
                 if (!il.isEmpty()) {
                     fullInstructions.addAll(il);
@@ -137,7 +137,7 @@ public class PathMerger {
                 }
 
                 fullPoints.add(tmpPoints);
-                altRsp.addPathDetails(PathDetailsFromEdges.calcDetails(path, encodingManager, weighting, requestedPathDetails, pathBuilderFactory, origPoints));
+                altRsp.addPathDetails(PathDetailsFromEdges.calcDetails(path, evLookup, weighting, requestedPathDetails, pathBuilderFactory, origPoints));
                 origPoints = fullPoints.size();
             }
 
diff --git a/core/src/main/java/com/graphhopper/util/PathSimplification.java b/core/src/main/java/com/graphhopper/util/PathSimplification.java
index 31e84a4b4..87db5a25b 100644
--- a/core/src/main/java/com/graphhopper/util/PathSimplification.java
+++ b/core/src/main/java/com/graphhopper/util/PathSimplification.java
@@ -125,8 +125,7 @@ public class PathSimplification {
 
         simplify(pathWrapper.getPoints(), partitions, douglasPeucker);
         assertConsistencyOfPathDetails(pathWrapper.getPathDetails());
-        if (enableInstructions)
-            assertConsistencyOfInstructions(pathWrapper.getInstructions(), pathWrapper.getPoints().size());
+        assertConsistencyOfInstructions(pathWrapper.getInstructions(), pathWrapper.getPoints().size());
         return pointList;
     }
 
diff --git a/core/src/main/java/com/graphhopper/util/details/PathDetailsFromEdges.java b/core/src/main/java/com/graphhopper/util/details/PathDetailsFromEdges.java
index 0cc0ca688..0cf9a9b41 100644
--- a/core/src/main/java/com/graphhopper/util/details/PathDetailsFromEdges.java
+++ b/core/src/main/java/com/graphhopper/util/details/PathDetailsFromEdges.java
@@ -18,7 +18,7 @@
 package com.graphhopper.util.details;
 
 import com.graphhopper.routing.Path;
-import com.graphhopper.routing.util.EncodingManager;
+import com.graphhopper.routing.profiles.EncodedValueLookup;
 import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.util.EdgeIteratorState;
 
@@ -55,11 +55,11 @@ public class PathDetailsFromEdges implements Path.EdgeVisitor {
      * @param pathBuilderFactory Generates the relevant PathBuilders
      * @return List of PathDetails for this Path
      */
-    public static Map<String, List<PathDetail>> calcDetails(Path path, EncodingManager encodingManager, Weighting weighting,
+    public static Map<String, List<PathDetail>> calcDetails(Path path, EncodedValueLookup evLookup, Weighting weighting,
                                                             List<String> requestedPathDetails, PathDetailsBuilderFactory pathBuilderFactory, int previousIndex) {
         if (!path.isFound() || requestedPathDetails.isEmpty())
             return Collections.emptyMap();
-        List<PathDetailsBuilder> pathBuilders = pathBuilderFactory.createPathDetailsBuilders(requestedPathDetails, encodingManager, weighting);
+        List<PathDetailsBuilder> pathBuilders = pathBuilderFactory.createPathDetailsBuilders(requestedPathDetails, evLookup, weighting);
         if (pathBuilders.isEmpty())
             return Collections.emptyMap();
 
diff --git a/reader-gtfs/src/main/java/com/graphhopper/reader/gtfs/TripFromLabel.java b/reader-gtfs/src/main/java/com/graphhopper/reader/gtfs/TripFromLabel.java
index b711b3b4d..6d33ac6e4 100644
--- a/reader-gtfs/src/main/java/com/graphhopper/reader/gtfs/TripFromLabel.java
+++ b/reader-gtfs/src/main/java/com/graphhopper/reader/gtfs/TripFromLabel.java
@@ -27,7 +27,6 @@ import com.graphhopper.PathWrapper;
 import com.graphhopper.Trip;
 import com.graphhopper.gtfs.fare.Fares;
 import com.graphhopper.routing.InstructionsFromEdges;
-import com.graphhopper.routing.profiles.Roundabout;
 import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Graph;
 import com.graphhopper.util.*;
@@ -357,7 +356,7 @@ class TripFromLabel {
         } else {
             InstructionList instructions = new InstructionList(tr);
             InstructionsFromEdges instructionsFromEdges = new InstructionsFromEdges(graph,
-                    weighting, weighting.getFlagEncoder().getBooleanEncodedValue(Roundabout.KEY), tr, instructions);
+                    weighting, weighting.getFlagEncoder(), tr, instructions);
             int prevEdgeId = -1;
             for (int i = 1; i < path.size(); i++) {
                 if (path.get(i).edge.edgeType != GtfsStorage.EdgeType.HIGHWAY) {


Test patch:
diff --git a/core/src/test/java/com/graphhopper/routing/PathTest.java b/core/src/test/java/com/graphhopper/routing/PathTest.java
index 83d5402e7..00e72095e 100644
--- a/core/src/test/java/com/graphhopper/routing/PathTest.java
+++ b/core/src/test/java/com/graphhopper/routing/PathTest.java
@@ -46,13 +46,11 @@ public class PathTest {
     private final FlagEncoder encoder = new CarFlagEncoder();
     private final DataFlagEncoder dataFlagEncoder = new DataFlagEncoder();
     private final EncodingManager carManager = EncodingManager.create(encoder);
-    private final BooleanEncodedValue carManagerRoundabout = carManager.getBooleanEncodedValue(Roundabout.KEY);
     private final BooleanEncodedValue carAccessEnc = encoder.getAccessEnc();
     private final DecimalEncodedValue carAvSpeedEnv = encoder.getAverageSpeedEnc();
     private final EncodingManager dataFlagManager = new EncodingManager.Builder().add(dataFlagEncoder).build();
     private final IntsRef edgeFlags = dataFlagManager.createEdgeFlags();
     private final EncodingManager mixedEncoders = EncodingManager.create(new CarFlagEncoder(), new FootFlagEncoder());
-    private final BooleanEncodedValue mixedManagerRoundabout = mixedEncoders.getBooleanEncodedValue(Roundabout.KEY);
     private final TranslationMap trMap = TranslationMapTest.SINGLETON;
     private final Translation tr = trMap.getWithFallBack(Locale.US);
     private final RoundaboutGraph roundaboutGraph = new RoundaboutGraph();
@@ -89,7 +87,7 @@ public class PathTest {
         Path path = extractPath(g, weighting, e1);
         // 0-1-2
         assertPList(Helper.createPointList(0, 0.1, 8, 1, 9, 1, 1, 0.1, 10, 1, 11, 1, 2, 0.1), path.calcPoints());
-        InstructionList instr = InstructionsFromEdges.calcInstructions(path, path.graph, weighting, carManagerRoundabout, tr);
+        InstructionList instr = InstructionsFromEdges.calcInstructions(path, path.graph, weighting, carManager, tr);
         Instruction tmp = instr.get(0);
         assertEquals(3000.0, tmp.getDistance(), 0.0);
         assertEquals(504000L, tmp.getTime());
@@ -122,7 +120,7 @@ public class PathTest {
         e1.parent = new SPTEntry(edge1.getEdge(), 1, 1);
         e1.parent.parent = new SPTEntry(-1, 0, 1);
         path = extractPath(g, weighting, e1);
-        instr = InstructionsFromEdges.calcInstructions(path, path.graph, weighting, carManagerRoundabout, tr);
+        instr = InstructionsFromEdges.calcInstructions(path, path.graph, weighting, carManager, tr);
 
         tmp = instr.get(0);
         assertEquals(1000.0, tmp.getDistance(), 0);
@@ -149,7 +147,7 @@ public class PathTest {
         // 2-1-0
         assertPList(Helper.createPointList(2, 0.1, 11, 1, 10, 1, 1, 0.1, 9, 1, 8, 1, 0, 0.1), path.calcPoints());
 
-        instr = InstructionsFromEdges.calcInstructions(path, path.graph, weighting, carManagerRoundabout, tr);
+        instr = InstructionsFromEdges.calcInstructions(path, path.graph, weighting, carManager, tr);
         tmp = instr.get(0);
         assertEquals(2000.0, tmp.getDistance(), 0);
         assertEquals(144000L, tmp.getTime());
@@ -205,7 +203,7 @@ public class PathTest {
         FastestWeighting weighting = new FastestWeighting(encoder);
         Path path = extractPath(g, weighting, e1);
 
-        InstructionList il = InstructionsFromEdges.calcInstructions(path, path.graph, weighting, carManagerRoundabout, tr);
+        InstructionList il = InstructionsFromEdges.calcInstructions(path, path.graph, weighting, carManager, tr);
         Instruction nextInstr0 = il.find(-0.001, 0.0, 1000);
         assertEquals(Instruction.CONTINUE_ON_STREET, nextInstr0.getSign());
 
@@ -237,7 +235,7 @@ public class PathTest {
                     .calcPath(1, 8);
             assertTrue(p.isFound());
             assertEquals("[1, 2, 3, 4, 5, 8]", p.calcNodes().toString());
-            InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+            InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
             // Test instructions
             List<String> tmpList = getTurnDescriptions(wayList);
             assertEquals(Arrays.asList("continue onto MainStreet 1 2",
@@ -252,7 +250,7 @@ public class PathTest {
             // case of continuing a street through a roundabout
             p = new Dijkstra(roundaboutGraph.g, weighting, TraversalMode.NODE_BASED).
                     calcPath(1, 7);
-            wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+            wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
             tmpList = getTurnDescriptions(wayList);
             assertEquals(Arrays.asList("continue onto MainStreet 1 2",
                     "At roundabout, take exit 2 onto MainStreet 4 7",
@@ -274,7 +272,7 @@ public class PathTest {
         Path p = new Dijkstra(roundaboutGraph.g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(2, 8);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
         List<String> tmpList = getTurnDescriptions(wayList);
         assertEquals(Arrays.asList("At roundabout, take exit 3 onto 5-8",
                 "arrive at destination"),
@@ -291,7 +289,7 @@ public class PathTest {
         Path p = new Dijkstra(roundaboutGraph.g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(6, 8);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
         List<String> tmpList = getTurnDescriptions(wayList);
         assertEquals(Arrays.asList("continue onto 3-6",
                 "At roundabout, take exit 3 onto 5-8",
@@ -426,7 +424,7 @@ public class PathTest {
         Path p = new Dijkstra(roundaboutGraph.g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(1, 8);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
         List<String> tmpList = getTurnDescriptions(wayList);
         assertEquals(Arrays.asList("continue onto MainStreet 1 2",
                 "At roundabout, take exit 2 onto 5-8",
@@ -473,6 +471,7 @@ public class PathTest {
         // roundabout
         EdgeIteratorState tmpEdge;
         tmpEdge = g.edge(3, 9, 2, false).setName("3-9");
+        BooleanEncodedValue carManagerRoundabout = carManager.getBooleanEncodedValue(Roundabout.KEY);
         carManagerRoundabout.setBool(false, tmpEdge.getFlags(), true);
         tmpEdge.setFlags(tmpEdge.getFlags());
         tmpEdge = g.edge(9, 10, 2, false).setName("9-10");
@@ -505,7 +504,7 @@ public class PathTest {
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(6, 11);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManager, tr);
         List<String> tmpList = getTurnDescriptions(wayList);
         assertEquals(Arrays.asList("At roundabout, take exit 1 onto MainStreet 1 11",
                 "arrive at destination"),
@@ -522,7 +521,7 @@ public class PathTest {
         Path p = new Dijkstra(roundaboutGraph.g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(1, 8);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
         List<String> tmpList = getTurnDescriptions(wayList);
         assertEquals(Arrays.asList("continue onto MainStreet 1 2",
                 "At roundabout, take exit 1 onto 5-8",
@@ -541,7 +540,7 @@ public class PathTest {
         Path p = new Dijkstra(roundaboutGraph.g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(4, 11);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
 
         // Contain only start and finish instruction, no CONTINUE
         assertEquals(2, wayList.size());
@@ -554,7 +553,7 @@ public class PathTest {
         Path p = new Dijkstra(roundaboutGraph.g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(10, 12);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
 
         // Contain only start and finish instruction
         assertEquals(2, wayList.size());
@@ -586,7 +585,7 @@ public class PathTest {
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(1, 4);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManager, tr);
 
         assertEquals(3, wayList.size());
         assertEquals(-7, wayList.get(1).getSign());
@@ -615,7 +614,7 @@ public class PathTest {
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(4, 3);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManager, tr);
 
         // no turn instruction for entering the highway
         assertEquals(2, wayList.size());
@@ -644,7 +643,7 @@ public class PathTest {
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(1, 3);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManager, tr);
 
         assertEquals(3, wayList.size());
         // TODO this should be a keep_right
@@ -674,7 +673,7 @@ public class PathTest {
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(4, 3);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManager, tr);
 
         assertEquals(3, wayList.size());
         assertEquals(2, wayList.get(1).getSign());
@@ -702,7 +701,7 @@ public class PathTest {
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(1, 4);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManager, tr);
 
         assertEquals(3, wayList.size());
         assertEquals(-7, wayList.get(1).getSign());
@@ -732,7 +731,7 @@ public class PathTest {
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(4, 1);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManager, tr);
 
         assertEquals(3, wayList.size());
         assertEquals(-1, wayList.get(1).getSign());
@@ -768,7 +767,7 @@ public class PathTest {
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(1, 4);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManager, tr);
 
         assertEquals(3, wayList.size());
         assertEquals(Instruction.U_TURN_LEFT, wayList.get(1).getSign());
@@ -804,7 +803,7 @@ public class PathTest {
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(1, 6);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManager, tr);
 
         assertEquals(3, wayList.size());
         assertEquals(Instruction.U_TURN_RIGHT, wayList.get(1).getSign());
@@ -817,7 +816,7 @@ public class PathTest {
         Path p = new Dijkstra(roundaboutGraph.g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(11, 13);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
 
         // Contain start, turn, and finish instruction
         assertEquals(3, wayList.size());
@@ -848,7 +847,7 @@ public class PathTest {
         GenericWeighting weighting = new GenericWeighting(dataFlagEncoder, new HintsMap());
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED).calcPath(1, 3);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, dataFlagManager, tr);
         assertEquals(3, wayList.size());
     }
 
@@ -859,7 +858,7 @@ public class PathTest {
         Path p = new Dijkstra(roundaboutGraph.g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(12, 16);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
 
         // Contain start, turn, and finish instruction
         assertEquals(3, wayList.size());
@@ -890,7 +889,7 @@ public class PathTest {
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(1, 2);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, carManager, tr);
 
         assertEquals(3, wayList.size());
         assertEquals(Instruction.TURN_SLIGHT_RIGHT, wayList.get(1).getSign());
@@ -903,7 +902,7 @@ public class PathTest {
         Path p = new Dijkstra(roundaboutGraph.g, weighting, TraversalMode.NODE_BASED)
                 .calcPath(16, 19);
         assertTrue(p.isFound());
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedManagerRoundabout, tr);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, p.graph, weighting, mixedEncoders, tr);
 
         // Contain start, and finish instruction
         assertEquals(2, wayList.size());
@@ -1020,11 +1019,12 @@ public class PathTest {
         }
 
         public void setRoundabout(boolean clockwise) {
+            BooleanEncodedValue mixedRoundabout = mixedEncoders.getBooleanEncodedValue(Roundabout.KEY);
             for (FlagEncoder encoder : mixedEncoders.fetchEdgeEncoders()) {
                 BooleanEncodedValue accessEnc = encoder.getAccessEnc();
                 for (EdgeIteratorState edge : roundaboutEdges) {
                     edge.set(accessEnc, clockwise).setReverse(accessEnc, !clockwise);
-                    mixedManagerRoundabout.setBool(false, edge.getFlags(), true);
+                    mixedRoundabout.setBool(false, edge.getFlags(), true);
                     edge.setFlags(edge.getFlags());
                 }
             }
diff --git a/core/src/test/java/com/graphhopper/routing/util/AbstractBikeFlagEncoderTester.java b/core/src/test/java/com/graphhopper/routing/util/AbstractBikeFlagEncoderTester.java
index 5d0b2cc53..98b7e3ab1 100644
--- a/core/src/test/java/com/graphhopper/routing/util/AbstractBikeFlagEncoderTester.java
+++ b/core/src/test/java/com/graphhopper/routing/util/AbstractBikeFlagEncoderTester.java
@@ -77,16 +77,6 @@ public abstract class AbstractBikeFlagEncoderTester {
         return avSpeedEnc.getDecimal(false, flags);
     }
 
-    protected String getWayTypeFromFlags(ReaderWay way) {
-        return getWayTypeFromFlags(way, encodingManager.createRelationFlags());
-    }
-
-    protected String getWayTypeFromFlags(ReaderWay way, IntsRef relationFlags) {
-        IntsRef flags = encodingManager.handleWayTags(way, new EncodingManager.AcceptWay().put(encoder.toString(), WAY), relationFlags);
-        Translation enMap = SINGLETON.getWithFallBack(Locale.UK);
-        return encoder.getAnnotation(flags, enMap).getMessage();
-    }
-
     @Test
     public void testAccess() {
         ReaderWay way = new ReaderWay(1);
@@ -315,108 +305,6 @@ public abstract class AbstractBikeFlagEncoderTester {
         assertPriority(PREFER.getValue(), way);
     }
 
-    @Test
-    public void testHandleCommonWayTags() {
-        ReaderWay way = new ReaderWay(1);
-        String wayType;
-
-        way.setTag("highway", "steps");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike", wayType);
-
-        way.setTag("highway", "footway");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike", wayType);
-
-        way.setTag("highway", "footway");
-        way.setTag("surface", "pebblestone");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike", wayType);
-
-        way.setTag("highway", "residential");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("", wayType);
-        assertPriority(PREFER.getValue(), way);
-
-        way.clearTags();
-        way.setTag("highway", "residential");
-        way.setTag("bicycle", "yes");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "residential");
-        way.setTag("bicycle", "designated");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "track");
-        way.setTag("bicycle", "designated");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("cycleway, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "cycleway");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("cycleway", wayType);
-        assertPriority(VERY_NICE.getValue(), way);
-
-        way.setTag("surface", "grass");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("cycleway, unpaved", wayType);
-
-        way.setTag("surface", "asphalt");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("cycleway", wayType);
-        assertPriority(VERY_NICE.getValue(), way);
-
-        way.setTag("highway", "footway");
-        way.setTag("bicycle", "yes");
-        way.setTag("surface", "grass");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("small way, unpaved", wayType);
-
-        way.setTag("bicycle", "designated");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("cycleway, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "footway");
-        way.setTag("bicycle", "yes");
-        way.setTag("surface", "grass");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("small way, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("railway", "platform");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "track");
-        way.setTag("railway", "platform");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "secondary");
-        way.setTag("bicycle", "dismount");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "platform");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "platform");
-        way.setTag("bicycle", "yes");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("", wayType);
-    }
-
     @Test
     public void testService() {
         ReaderWay way = new ReaderWay(1);
diff --git a/core/src/test/java/com/graphhopper/routing/util/BikeFlagEncoderTest.java b/core/src/test/java/com/graphhopper/routing/util/BikeFlagEncoderTest.java
index 66c64bb35..19c2f6c9b 100644
--- a/core/src/test/java/com/graphhopper/routing/util/BikeFlagEncoderTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/BikeFlagEncoderTest.java
@@ -282,44 +282,6 @@ public class BikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         assertEquals(18, encoder.getSpeed(way));
     }
 
-    @Test
-    public void testHandleWayTags() {
-        ReaderWay way = new ReaderWay(1);
-        String wayType;
-        way.setTag("highway", "track");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("small way, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "path");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "path");
-        way.setTag("surface", "grass");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "path");
-        way.setTag("surface", "concrete");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "track");
-        way.setTag("foot", "yes");
-        way.setTag("surface", "paved");
-        way.setTag("tracktype", "grade1");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("", wayType);
-
-        way.setTag("tracktype", "grade2");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike, unpaved", wayType);
-    }
-
     @Test
     public void testWayAcceptance() {
         ReaderWay way = new ReaderWay(1);
@@ -478,50 +440,6 @@ public class BikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         osmRel.setTag("route", "bicycle");
         osmRel.setTag("network", "lcn");
         assertPriority(PREFER.getValue(), osmWay, osmRel);
-
-        // A footway is not of waytype get off the bike in case that it is part of a cycle route
-        osmRel.clearTags();
-        osmWay.clearTags();
-        osmWay.setTag("highway", "footway");
-        osmWay.setTag("surface", "grass");
-
-        // First tests without a cycle route relation, this is a get off the bike
-        IntsRef relFlags = encodingManager.handleRelationTags(osmRel, encodingManager.createRelationFlags());
-        String wayType = getWayTypeFromFlags(osmWay, relFlags);
-        assertEquals("get off the bike, unpaved", wayType);
-
-        // now as part of a cycle route relation
-        osmRel.setTag("type", "route");
-        osmRel.setTag("route", "bicycle");
-        osmRel.setTag("network", "lcn");
-        relFlags = encodingManager.handleRelationTags(osmRel, encodingManager.createRelationFlags());
-        wayType = getWayTypeFromFlags(osmWay, relFlags);
-        assertEquals("small way, unpaved", wayType);
-
-        // steps are still shown as get off the bike
-        osmWay.clearTags();
-        osmWay.setTag("highway", "steps");
-        relFlags = encodingManager.handleRelationTags(osmRel, encodingManager.createRelationFlags());
-        wayType = getWayTypeFromFlags(osmWay, relFlags);
-        assertEquals("get off the bike", wayType);
-
-        // Test for highway=platform.
-        osmRel.clearTags();
-        osmWay.clearTags();
-        osmWay.setTag("highway", "platform");
-
-        // First tests without a cycle route relation, this is a get off the bike
-        relFlags = encodingManager.handleRelationTags(osmRel, encodingManager.createRelationFlags());
-        wayType = getWayTypeFromFlags(osmWay, relFlags);
-        assertEquals("get off the bike", wayType);
-
-        // now as part of a cycle route relation
-        osmRel.setTag("type", "route");
-        osmRel.setTag("route", "bicycle");
-        osmRel.setTag("network", "lcn");
-        relFlags = encodingManager.handleRelationTags(osmRel, encodingManager.createRelationFlags());
-        wayType = getWayTypeFromFlags(osmWay, relFlags);
-        assertEquals("", wayType);
     }
 
     @Test
diff --git a/core/src/test/java/com/graphhopper/routing/util/DataFlagEncoderTest.java b/core/src/test/java/com/graphhopper/routing/util/DataFlagEncoderTest.java
index 82fb0e4fb..de3f987a7 100644
--- a/core/src/test/java/com/graphhopper/routing/util/DataFlagEncoderTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/DataFlagEncoderTest.java
@@ -132,18 +132,6 @@ public class DataFlagEncoderTest {
         assertTrue(edge.get(roadEnvironmentEnc) == RoadEnvironment.BRIDGE);
     }
 
-    @Test
-    public void testFord() {
-        ReaderWay osmWay = new ReaderWay(0);
-        osmWay.setTag("highway", "unclassified");
-        osmWay.setTag("ford", "yes");
-        IntsRef flags = encodingManager.handleWayTags(osmWay, map, relFlags);
-        EdgeIteratorState edge = GHUtility.createMockedEdgeIteratorState(0, flags);
-        assertEquals("ford", edge.get(roadEnvironmentEnc).toString());
-        assertTrue(edge.get(roadEnvironmentEnc) == RoadEnvironment.FORD);
-        assertTrue(encoder.getAnnotation(edge.getFlags(), TranslationMapTest.SINGLETON.get("en")).getMessage().contains("ford"));
-    }
-
     @Test
     public void testHighwaySpeed() {
         PMap map = new PMap();
diff --git a/core/src/test/java/com/graphhopper/routing/util/MountainBikeFlagEncoderTest.java b/core/src/test/java/com/graphhopper/routing/util/MountainBikeFlagEncoderTest.java
index 7f0472bc9..90eace9f2 100644
--- a/core/src/test/java/com/graphhopper/routing/util/MountainBikeFlagEncoderTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/MountainBikeFlagEncoderTest.java
@@ -101,54 +101,6 @@ public class MountainBikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         assertTrue(encoder.getAccess(way).canSkip());
     }
 
-    @Test
-    public void testHandleWayTags() {
-        ReaderWay way = new ReaderWay(1);
-        String wayType;
-
-        way.setTag("highway", "track");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("small way, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "path");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("small way, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "path");
-        way.setTag("surface", "grass");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("small way, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "path");
-        way.setTag("surface", "concrete");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "track");
-        way.setTag("foot", "yes");
-        way.setTag("surface", "paved");
-        way.setTag("tracktype", "grade1");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "track");
-        way.setTag("foot", "yes");
-        way.setTag("surface", "paved");
-        way.setTag("tracktype", "grade2");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("small way, unpaved", wayType);
-
-        way.clearTags();
-        way.setTag("highway", "pedestrian");
-        wayType = getWayTypeFromFlags(way);
-        assertEquals("get off the bike", wayType);
-    }
-
     @Test
     public void testHandleWayTagsInfluencedByRelation() {
         ReaderWay osmWay = new ReaderWay(1);
@@ -160,7 +112,6 @@ public class MountainBikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         IntsRef flags = encodingManager.handleWayTags(osmWay, accessMap, relFlags);
         assertEquals(18, encoder.getSpeed(flags), 1e-1);
         assertPriority(PriorityCode.PREFER.getValue(), osmWay);
-        assertEquals("small way, unpaved", getWayTypeFromFlags(osmWay));
 
         // relation code is PREFER
         osmRel.setTag("route", "bicycle");
@@ -169,7 +120,6 @@ public class MountainBikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         flags = encodingManager.handleWayTags(osmWay, accessMap, relFlags);
         assertEquals(18, encoder.getSpeed(flags), 1e-1);
         assertPriority(PriorityCode.PREFER.getValue(), osmWay);
-        assertEquals("small way, unpaved", getWayTypeFromFlags(osmWay));
 
         // relation code is PREFER
         osmRel.setTag("network", "rcn");
@@ -197,7 +147,6 @@ public class MountainBikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         flags = encodingManager.handleWayTags(osmWay, accessMap, relFlags);
         assertEquals(18, encoder.getSpeed(flags), 1e-1);
         assertPriority(PriorityCode.PREFER.getValue(), osmWay);
-        assertEquals("", getWayTypeFromFlags(osmWay));
     }
 
     // Issue 407 : Always block kissing_gate execpt for mountainbikes
diff --git a/core/src/test/java/com/graphhopper/routing/util/RacingBikeFlagEncoderTest.java b/core/src/test/java/com/graphhopper/routing/util/RacingBikeFlagEncoderTest.java
index 01645dd24..75073d7ad 100644
--- a/core/src/test/java/com/graphhopper/routing/util/RacingBikeFlagEncoderTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/RacingBikeFlagEncoderTest.java
@@ -130,7 +130,6 @@ public class RacingBikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         ReaderWay osmWay = new ReaderWay(1);
         osmWay.setTag("highway", "track");
         assertEquals(PUSHING_SECTION_SPEED / 2, getSpeedFromFlags(osmWay), 1e-1);
-        assertEquals("small way, unpaved", getWayTypeFromFlags(osmWay, encodingManager.createRelationFlags()));
 
         // relation code is PREFER
         ReaderRelation osmRel = new ReaderRelation(1);
@@ -138,9 +137,6 @@ public class RacingBikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         osmRel.setTag("network", "lcn");
         IntsRef flags = assertPriority(AVOID_AT_ALL_COSTS.getValue(), osmWay, osmRel);
         assertEquals(2, encoder.getSpeed(flags), 1e-1);
-        IntsRef relFlags = encodingManager.handleRelationTags(osmRel, encodingManager.createRelationFlags());
-        assertEquals("small way, unpaved", getWayTypeFromFlags(osmWay, relFlags));
-
         // relation code is OUTSTANDING NICE but as unpaved, the speed is still PUSHING_SECTION_SPEED/2
         osmRel.setTag("network", "icn");
         flags = assertPriority(AVOID_AT_ALL_COSTS.getValue(), osmWay, osmRel);
@@ -155,16 +151,12 @@ public class RacingBikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         osmWay.setTag("tracktype", "grade1");
         flags = assertPriority(PREFER.getValue(), osmWay, osmRel);
         assertEquals(20, encoder.getSpeed(flags), 1e-1);
-        relFlags = encodingManager.handleRelationTags(osmRel, encodingManager.createRelationFlags());
-        assertEquals("cycleway", getWayTypeFromFlags(osmWay, relFlags));
 
         // Now we assume bicycle=yes, and unpaved as part of a cycle relation
         osmWay.setTag("tracktype", "grade2");
         osmWay.setTag("bicycle", "yes");
         flags = assertPriority(AVOID_AT_ALL_COSTS.getValue(), osmWay, osmRel);
         assertEquals(10, encoder.getSpeed(flags), 1e-1);
-        relFlags = encodingManager.handleRelationTags(osmRel, encodingManager.createRelationFlags());
-        assertEquals("small way, unpaved", getWayTypeFromFlags(osmWay, relFlags));
 
         // Now we assume bicycle=yes, and unpaved not part of a cycle relation
         osmWay.clearTags();
@@ -172,16 +164,12 @@ public class RacingBikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         osmWay.setTag("tracktype", "grade3");
         flags = assertPriority(AVOID_AT_ALL_COSTS.getValue(), osmWay);
         assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(flags), 1e-1);
-        relFlags = encodingManager.handleRelationTags(new ReaderRelation(1), encodingManager.createRelationFlags());
-        assertEquals("get off the bike, unpaved", getWayTypeFromFlags(osmWay, relFlags));
 
         // Now we assume bicycle=yes, and tracktype = null
         osmWay.clearTags();
         osmWay.setTag("highway", "track");
         flags = assertPriority(AVOID_AT_ALL_COSTS.getValue(), osmWay);
         assertEquals(2, encoder.getSpeed(flags), 1e-1);
-        relFlags = encodingManager.handleRelationTags(new ReaderRelation(1), encodingManager.createRelationFlags());
-        assertEquals("small way, unpaved", getWayTypeFromFlags(osmWay, relFlags));
     }
 
     @Test
diff --git a/core/src/test/java/com/graphhopper/routing/util/parsers/OSMGetOffBikeParserTest.java b/core/src/test/java/com/graphhopper/routing/util/parsers/OSMGetOffBikeParserTest.java
new file mode 100644
index 000000000..9aa50d326
--- /dev/null
+++ b/core/src/test/java/com/graphhopper/routing/util/parsers/OSMGetOffBikeParserTest.java
@@ -0,0 +1,97 @@
+package com.graphhopper.routing.util.parsers;
+
+import com.graphhopper.reader.ReaderRelation;
+import com.graphhopper.reader.ReaderWay;
+import com.graphhopper.routing.profiles.BooleanEncodedValue;
+import com.graphhopper.routing.profiles.EnumEncodedValue;
+import com.graphhopper.routing.profiles.GetOffBike;
+import com.graphhopper.routing.profiles.RoadClass;
+import com.graphhopper.routing.util.BikeFlagEncoder;
+import com.graphhopper.routing.util.EncodingManager;
+import com.graphhopper.storage.IntsRef;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class OSMGetOffBikeParserTest {
+
+    private EncodingManager em = EncodingManager.start().add(new BikeFlagEncoder()).build();
+    private BooleanEncodedValue offBikeEnc = em.getBooleanEncodedValue(GetOffBike.KEY);
+    private EnumEncodedValue<RoadClass> roadClassEnc = em.getEnumEncodedValue(RoadClass.KEY, RoadClass.class);
+
+    @Test
+    public void testHandleCommonWayTags() {
+        ReaderWay way = new ReaderWay(1);
+        way.setTag("highway", "steps");
+        assertTrue(isGetOffBike(way));
+
+        way.setTag("highway", "footway");
+        assertTrue(isGetOffBike(way));
+
+        way.setTag("highway", "footway");
+        way.setTag("surface", "pebblestone");
+        assertTrue(isGetOffBike(way));
+
+        way.setTag("highway", "residential");
+        assertFalse(isGetOffBike(way));
+
+        way = new ReaderWay(1);
+        way.setTag("highway", "residential");
+        way.setTag("bicycle", "yes");
+        assertFalse(isGetOffBike(way));
+
+        way = new ReaderWay(1);
+        way.setTag("highway", "cycleway");
+        assertEquals(getRoadClass(way), RoadClass.CYCLEWAY);
+
+        way.setTag("highway", "footway");
+        way.setTag("surface", "grass");
+        assertTrue(isGetOffBike(way));
+        way.setTag("bicycle", "yes");
+        assertFalse(isGetOffBike(way));
+        way.setTag("bicycle", "designated");
+        assertFalse(isGetOffBike(way));
+
+        way = new ReaderWay(1);
+        way.setTag("railway", "platform");
+        assertTrue(isGetOffBike(way));
+
+        way = new ReaderWay(1);
+        way.setTag("highway", "secondary");
+        way.setTag("bicycle", "dismount");
+        assertTrue(isGetOffBike(way));
+
+        way = new ReaderWay(1);
+        way.setTag("highway", "platform");
+        way.setTag("bicycle", "yes");
+        assertFalse(isGetOffBike(way));
+
+        way = new ReaderWay(1);
+        way.setTag("highway", "track");
+        way.setTag("foot", "yes");
+        assertFalse(isGetOffBike(way));
+
+        way = new ReaderWay(1);
+        way.setTag("highway", "pedestrian");
+        assertTrue(isGetOffBike(way));
+
+        way = new ReaderWay(1);
+        way.setTag("highway", "path");
+        way.setTag("surface", "concrete");
+        assertTrue(isGetOffBike(way));
+
+        way = new ReaderWay(1);
+        way.setTag("highway", "track");
+        assertFalse(isGetOffBike(way));
+    }
+
+    private RoadClass getRoadClass(ReaderWay way) {
+        IntsRef edgeFlags = em.handleWayTags(way, new EncodingManager.AcceptWay().put("bike", EncodingManager.Access.WAY), em.createRelationFlags());
+        return roadClassEnc.getEnum(false, edgeFlags);
+    }
+
+    private boolean isGetOffBike(ReaderWay way) {
+        IntsRef edgeFlags = em.handleWayTags(way, new EncodingManager.AcceptWay().put("bike", EncodingManager.Access.WAY), em.createRelationFlags());
+        return offBikeEnc.getBool(false, edgeFlags);
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/graphhopper/util/InstructionListTest.java b/core/src/test/java/com/graphhopper/util/InstructionListTest.java
index 29fa361db..dcda7b3ca 100644
--- a/core/src/test/java/com/graphhopper/util/InstructionListTest.java
+++ b/core/src/test/java/com/graphhopper/util/InstructionListTest.java
@@ -47,13 +47,11 @@ public class InstructionListTest {
     private final TraversalMode tMode = TraversalMode.NODE_BASED;
     private EncodingManager carManager;
     private FlagEncoder carEncoder;
-    private BooleanEncodedValue roundaboutEnc;
 
     @Before
     public void setUp() {
         carEncoder = new CarFlagEncoder();
         carManager = EncodingManager.create(carEncoder);
-        roundaboutEnc = carManager.getBooleanEncodedValue(Roundabout.KEY);
     }
 
     private List<String> getTurnDescriptions(InstructionList instructionList) {
@@ -117,12 +115,12 @@ public class InstructionListTest {
 
         ShortestWeighting weighting = new ShortestWeighting(carEncoder);
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED).calcPath(0, 10);
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, trMap.getWithFallBack(Locale.US));
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, trMap.getWithFallBack(Locale.US));
         List<String> tmpList = getTurnDescriptions(wayList);
         assertEquals(Arrays.asList("continue onto 0-1", "turn right onto 1-4", "turn left onto 7-8", "arrive at destination"),
                 tmpList);
 
-        wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, trMap.getWithFallBack(Locale.GERMAN));
+        wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, trMap.getWithFallBack(Locale.GERMAN));
         tmpList = getTurnDescriptions(wayList, trMap.getWithFallBack(Locale.GERMAN));
         assertEquals(Arrays.asList("dem Straßenverlauf von 0-1 folgen", "rechts abbiegen auf 1-4", "links abbiegen auf 7-8", "Ziel erreicht"),
                 tmpList);
@@ -146,7 +144,7 @@ public class InstructionListTest {
         assertEquals(42000, p.getDistance(), 1e-2);
         assertEquals(IntArrayList.from(6, 7, 8, 5, 2), p.calcNodes());
 
-        wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, trMap.getWithFallBack(Locale.US));
+        wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, trMap.getWithFallBack(Locale.US));
         tmpList = getTurnDescriptions(wayList);
         assertEquals(Arrays.asList("continue onto 6-7", "turn left onto 5-8", "arrive at destination"),
                 tmpList);
@@ -156,7 +154,7 @@ public class InstructionListTest {
 
         // special case of identical start and end
         p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED).calcPath(0, 0);
-        wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, trMap.getWithFallBack(Locale.US));
+        wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, trMap.getWithFallBack(Locale.US));
         assertEquals(1, wayList.size());
         assertEquals("arrive at destination", wayList.get(0).getTurnDescription(trMap.getWithFallBack(Locale.US)));
     }
@@ -187,13 +185,13 @@ public class InstructionListTest {
         ShortestWeighting weighting = new ShortestWeighting(carEncoder);
         Path p = new Dijkstra(g, weighting, tMode).calcPath(2, 3);
 
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, usTR);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, usTR);
         List<String> tmpList = getTurnDescriptions(wayList);
         assertEquals(Arrays.asList("continue onto 2-4", "turn slight right onto 3-4", "arrive at destination"),
                 tmpList);
 
         p = new Dijkstra(g, weighting, tMode).calcPath(3, 5);
-        wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, usTR);
+        wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, usTR);
         tmpList = getTurnDescriptions( wayList);
         assertEquals(Arrays.asList("continue onto 3-4", "keep right onto 4-5", "arrive at destination"),
                 tmpList);
@@ -226,7 +224,7 @@ public class InstructionListTest {
 
         ShortestWeighting weighting = new ShortestWeighting(carEncoder);
         Path p = new Dijkstra(g, weighting, tMode).calcPath(2, 3);
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, usTR);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, usTR);
         List<String> tmpList = getTurnDescriptions( wayList);
         assertEquals(Arrays.asList("continue onto street", "turn right onto street", "arrive at destination"), tmpList);
     }
@@ -255,7 +253,7 @@ public class InstructionListTest {
 
         ShortestWeighting weighting = new ShortestWeighting(carEncoder);
         Path p = new Dijkstra(g, weighting, tMode).calcPath(1, 3);
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, usTR);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, usTR);
         List<String> tmpList = getTurnDescriptions( wayList);
         assertEquals(Arrays.asList("continue", "arrive at destination"), tmpList);
     }
@@ -284,7 +282,7 @@ public class InstructionListTest {
 
         ShortestWeighting weighting = new ShortestWeighting(carEncoder);
         Path p = new Dijkstra(g, weighting, tMode).calcPath(1, 3);
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, usTR);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, usTR);
         List<String> tmpList = getTurnDescriptions( wayList);
         assertEquals(Arrays.asList("continue", "arrive at destination"), tmpList);
     }
@@ -294,7 +292,7 @@ public class InstructionListTest {
         Graph g = new GraphBuilder(carManager).create();
         ShortestWeighting weighting = new ShortestWeighting(carEncoder);
         Path p = new Dijkstra(g, weighting, tMode).calcPath(0, 1);
-        InstructionList il = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, usTR);
+        InstructionList il = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, usTR);
         assertEquals(0, il.size());
     }
 
@@ -326,7 +324,7 @@ public class InstructionListTest {
 
         ShortestWeighting weighting = new ShortestWeighting(carEncoder);
         Path p = new Dijkstra(g, weighting, tMode).calcPath(1, 5);
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, usTR);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, usTR);
 
         // query on first edge, get instruction for second edge
         assertEquals("2-3", wayList.find(15.05, 10, 1000).getName());
diff --git a/core/src/test/java/com/graphhopper/util/PathSimplificationTest.java b/core/src/test/java/com/graphhopper/util/PathSimplificationTest.java
index 755c72230..38aab5302 100644
--- a/core/src/test/java/com/graphhopper/util/PathSimplificationTest.java
+++ b/core/src/test/java/com/graphhopper/util/PathSimplificationTest.java
@@ -140,7 +140,7 @@ public class PathSimplificationTest {
         // Path is: [0 0-1, 3 1-4, 6 4-7, 9 7-8, 11 8-9, 10 9-10]
         ShortestWeighting weighting = new ShortestWeighting(carEncoder);
         Path p = new Dijkstra(g, weighting, tMode).calcPath(0, 10);
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager.getBooleanEncodedValue(Roundabout.KEY), usTR);
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, usTR);
         Map<String, List<PathDetail>> details = PathDetailsFromEdges.calcDetails(p, carManager, weighting,
                 Arrays.asList(AVERAGE_SPEED), new PathDetailsBuilderFactory(), 0);
 
diff --git a/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java b/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
index e6210200a..b21ab6a70 100644
--- a/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
+++ b/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
@@ -820,10 +820,10 @@ public class GraphHopperIT {
 
         PathWrapper arsp = rsp.getBest();
         assertEquals(6932.2, arsp.getDistance(), .1);
-        assertEquals(106, arsp.getPoints().getSize());
+        assertEquals(105, arsp.getPoints().getSize());
 
         InstructionList il = arsp.getInstructions();
-        assertEquals(22, il.size());
+        assertEquals(21, il.size());
 
         assertEquals("continue onto Obere Landstraße", il.get(0).getTurnDescription(tr));
         assertEquals("get off the bike", il.get(0).getAnnotation().getMessage());
@@ -840,8 +840,8 @@ public class GraphHopperIT {
         assertEquals("keep left onto Austraße", il.get(11).getTurnDescription(tr));
         assertEquals("keep left onto Rechte Kremszeile", il.get(12).getTurnDescription(tr));
         //..
-        assertEquals("turn right onto Treppelweg", il.get(18).getTurnDescription(tr));
-        assertEquals("cycleway", il.get(18).getAnnotation().getMessage());
+        assertEquals("turn right onto Treppelweg", il.get(17).getTurnDescription(tr));
+        assertEquals("cycleway", il.get(17).getAnnotation().getMessage());
     }
 
     @Test
diff --git a/web-bundle/src/test/java/com/graphhopper/util/gpx/GpxFromInstructionsTest.java b/web-bundle/src/test/java/com/graphhopper/util/gpx/GpxFromInstructionsTest.java
index 430dfd1c1..1aa5cd0f8 100644
--- a/web-bundle/src/test/java/com/graphhopper/util/gpx/GpxFromInstructionsTest.java
+++ b/web-bundle/src/test/java/com/graphhopper/util/gpx/GpxFromInstructionsTest.java
@@ -55,14 +55,12 @@ public class GpxFromInstructionsTest {
 
     private EncodingManager carManager;
     private FlagEncoder carEncoder;
-    private BooleanEncodedValue roundaboutEnc;
     private TranslationMap trMap;
 
     @Before
     public void setUp() {
         carEncoder = new CarFlagEncoder();
         carManager = EncodingManager.create(carEncoder);
-        roundaboutEnc = carManager.getBooleanEncodedValue(Roundabout.KEY);
         trMap = new TranslationMap().doImport();
     }
 
@@ -92,7 +90,7 @@ public class GpxFromInstructionsTest {
 
         ShortestWeighting weighting = new ShortestWeighting(carEncoder);
         Path p = new Dijkstra(g, weighting, TraversalMode.NODE_BASED).calcPath(1, 5);
-        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, roundaboutEnc, trMap.getWithFallBack(Locale.US));
+        InstructionList wayList = InstructionsFromEdges.calcInstructions(p, g, weighting, carManager, trMap.getWithFallBack(Locale.US));
         PointList points = p.calcPoints();
         assertEquals(4, wayList.size());
 
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
index a9b917335..147c88f83 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
@@ -128,19 +128,6 @@ public class RouteResourceTest {
         assertTrue("distance wasn't correct:" + distance, distance < 970);
     }
 
-    @Test
-    public void testQueryWithoutInstructions() {
-        final Response response = app.client().target("http://localhost:8080/route?point=42.554851,1.536198&point=42.510071,1.548128&instructions=false").request().buildGet().invoke();
-        assertEquals(200, response.getStatus());
-        JsonNode json = response.readEntity(JsonNode.class);
-        JsonNode infoJson = json.get("info");
-        assertFalse(infoJson.has("errors"));
-        JsonNode path = json.get("paths").get(0);
-        double distance = path.get("distance").asDouble();
-        assertTrue("distance wasn't correct:" + distance, distance > 9000);
-        assertTrue("distance wasn't correct:" + distance, distance < 9500);
-    }
-
     @Test
     public void testQueryWithStraightVia() {
         // Note, in general specifying pass_through does not work with CH, but this is an example where it works