Repository: graphhopper/graphhopper
Pull request #808 (2016-09-27 07:21:46)

adding unpaved and compacted to badSurfaceSpeedMap
there is many roads with surface unpaved and compacted, at least in Russia
example 
https://graphhopper.com/maps/?point=58.1353%2C52.6624&point=58.219602%2C53.183345&locale=ru-RU&vehicle=car&weighting=fastest&elevation=true&use_miles=false&layer=Omniscale

highway=secondary with surface=unpaved
https://www.openstreetmap.org/way/418251922


Patch:
diff --git a/core/src/main/java/com/graphhopper/routing/AStar.java b/core/src/main/java/com/graphhopper/routing/AStar.java
index f41626316..fe264d947 100644
--- a/core/src/main/java/com/graphhopper/routing/AStar.java
+++ b/core/src/main/java/com/graphhopper/routing/AStar.java
@@ -147,7 +147,8 @@ public class AStar extends AbstractRoutingAlgorithm {
 
     @Override
     protected Path extractPath() {
-        return new Path(graph, flagEncoder).setWeight(currEdge.weight).setSPTEntry(currEdge).extract();
+        return new Path(graph, weighting).
+                setWeight(currEdge.weight).setSPTEntry(currEdge).extract();
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/AStarBidirection.java b/core/src/main/java/com/graphhopper/routing/AStarBidirection.java
index ef9478570..dfc096f76 100644
--- a/core/src/main/java/com/graphhopper/routing/AStarBidirection.java
+++ b/core/src/main/java/com/graphhopper/routing/AStarBidirection.java
@@ -153,7 +153,7 @@ public class AStarBidirection extends AbstractBidirAlgo {
 
     @Override
     protected Path createAndInitPath() {
-        bestPath = new PathBidirRef(graph, flagEncoder);
+        bestPath = new PathBidirRef(graph, flagEncoder, weighting);
         return bestPath;
     }
 
diff --git a/core/src/main/java/com/graphhopper/routing/AbstractRoutingAlgorithm.java b/core/src/main/java/com/graphhopper/routing/AbstractRoutingAlgorithm.java
index a83f4e8f7..0b279e7b1 100644
--- a/core/src/main/java/com/graphhopper/routing/AbstractRoutingAlgorithm.java
+++ b/core/src/main/java/com/graphhopper/routing/AbstractRoutingAlgorithm.java
@@ -118,7 +118,7 @@ public abstract class AbstractRoutingAlgorithm implements RoutingAlgorithm {
     }
 
     protected Path createEmptyPath() {
-        return new Path(graph, flagEncoder);
+        return new Path(graph, weighting);
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/AlternativeRoute.java b/core/src/main/java/com/graphhopper/routing/AlternativeRoute.java
index e118e7af8..1daece99b 100644
--- a/core/src/main/java/com/graphhopper/routing/AlternativeRoute.java
+++ b/core/src/main/java/com/graphhopper/routing/AlternativeRoute.java
@@ -423,7 +423,7 @@ public class AlternativeRoute implements RoutingAlgorithm {
 
                         // plateaus.add(new PlateauInfo(altName, plateauEdges));
                         if (sortBy < worstSortBy || alternatives.size() < maxPaths) {
-                            Path path = new PathBidirRef(graph, flagEncoder).
+                            Path path = new PathBidirRef(graph, flagEncoder, weighting).
                                     setSPTEntryTo(toSPTEntry).setSPTEntry(fromSPTEntry).
                                     setWeight(weight);
                             path.extract();
diff --git a/core/src/main/java/com/graphhopper/routing/Dijkstra.java b/core/src/main/java/com/graphhopper/routing/Dijkstra.java
index c8583f365..5fa2dec6a 100644
--- a/core/src/main/java/com/graphhopper/routing/Dijkstra.java
+++ b/core/src/main/java/com/graphhopper/routing/Dijkstra.java
@@ -122,7 +122,8 @@ public class Dijkstra extends AbstractRoutingAlgorithm {
         if (currEdge == null || !finished())
             return createEmptyPath();
 
-        return new Path(graph, flagEncoder).setWeight(currEdge.weight).setSPTEntry(currEdge).extract();
+        return new Path(graph, weighting).
+                setWeight(currEdge.weight).setSPTEntry(currEdge).extract();
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/DijkstraBidirectionRef.java b/core/src/main/java/com/graphhopper/routing/DijkstraBidirectionRef.java
index 2b126e2b5..8cc391a4b 100644
--- a/core/src/main/java/com/graphhopper/routing/DijkstraBidirectionRef.java
+++ b/core/src/main/java/com/graphhopper/routing/DijkstraBidirectionRef.java
@@ -101,7 +101,7 @@ public class DijkstraBidirectionRef extends AbstractBidirAlgo {
 
     @Override
     protected Path createAndInitPath() {
-        bestPath = new PathBidirRef(graph, flagEncoder);
+        bestPath = new PathBidirRef(graph, flagEncoder, weighting);
         return bestPath;
     }
 
diff --git a/core/src/main/java/com/graphhopper/routing/DijkstraOneToMany.java b/core/src/main/java/com/graphhopper/routing/DijkstraOneToMany.java
index 20c9991a3..ef0d3ee93 100644
--- a/core/src/main/java/com/graphhopper/routing/DijkstraOneToMany.java
+++ b/core/src/main/java/com/graphhopper/routing/DijkstraOneToMany.java
@@ -76,7 +76,7 @@ public class DijkstraOneToMany extends AbstractRoutingAlgorithm {
 
     @Override
     public Path extractPath() {
-        PathNative p = new PathNative(graph, flagEncoder, parents, edgeIds);
+        PathNative p = new PathNative(graph, flagEncoder, weighting, parents, edgeIds);
         if (endNode >= 0)
             p.setWeight(weights[endNode]);
         p.setFromNode(fromNode);
diff --git a/core/src/main/java/com/graphhopper/routing/Path.java b/core/src/main/java/com/graphhopper/routing/Path.java
index 641dec9d0..2e42aa772 100644
--- a/core/src/main/java/com/graphhopper/routing/Path.java
+++ b/core/src/main/java/com/graphhopper/routing/Path.java
@@ -19,6 +19,7 @@ package com.graphhopper.routing;
 
 import com.graphhopper.routing.util.DefaultEdgeFilter;
 import com.graphhopper.routing.util.FlagEncoder;
+import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Graph;
 import com.graphhopper.storage.NodeAccess;
 import com.graphhopper.storage.SPTEntry;
@@ -54,6 +55,7 @@ public class Path {
     protected SPTEntry sptEntry;
     protected int endNode = -1;
     private List<String> description;
+    protected Weighting weighting;
     private FlagEncoder encoder;
     private boolean found;
     private int fromNode = -1;
@@ -61,11 +63,12 @@ public class Path {
     private double weight;
     private NodeAccess nodeAccess;
 
-    public Path(Graph graph, FlagEncoder encoder) {
+    public Path(Graph graph, Weighting weighting) {
         this.weight = Double.MAX_VALUE;
         this.graph = graph;
         this.nodeAccess = graph.getNodeAccess();
-        this.encoder = encoder;
+        this.weighting = weighting;
+        this.encoder = weighting.getFlagEncoder();
         this.edgeIds = new TIntArrayList();
     }
 
@@ -73,7 +76,7 @@ public class Path {
      * Populates an unextracted path instances from the specified path p.
      */
     Path(Path p) {
-        this(p.graph, p.encoder);
+        this(p.graph, p.weighting);
         weight = p.weight;
         edgeIds = new TIntArrayList(p.edgeIds);
         sptEntry = p.sptEntry;
@@ -182,9 +185,11 @@ public class Path {
 
         extractSW.start();
         SPTEntry goalEdge = sptEntry;
+        int prevEdge = EdgeIterator.NO_EDGE;
         setEndNode(goalEdge.adjNode);
         while (EdgeIterator.Edge.isValid(goalEdge.edge)) {
-            processEdge(goalEdge.edge, goalEdge.adjNode);
+            processEdge(goalEdge.edge, goalEdge.adjNode, prevEdge);
+            prevEdge = goalEdge.edge;
             goalEdge = goalEdge.parent;
         }
 
@@ -215,35 +220,21 @@ public class Path {
     /**
      * Calls getDistance and adds the edgeId.
      */
-    protected void processEdge(int edgeId, int adjNode) {
+    protected void processEdge(int edgeId, int adjNode, int prevEdgeId) {
         EdgeIteratorState iter = graph.getEdgeIteratorState(edgeId, adjNode);
-        double dist = iter.getDistance();
-        distance += dist;
-        // TODO calculate time based on weighting -> weighting.calcMillis
-        time += calcMillis(iter, false);
+        distance += iter.getDistance();
+        time += weighting.calcMillis(iter, false, prevEdgeId);
         addEdge(edgeId);
     }
 
     /**
      * Calculates the time in millis for the specified distance in meter and speed (in km/h) via
      * flags.
+     *
+     * @deprecated use Weighting
      */
-    protected long calcMillis(EdgeIteratorState edge, boolean revert) {
-        long flags = edge.getFlags();
-        if (revert && !encoder.isBackward(flags)
-                || !revert && !encoder.isForward(flags))
-            throw new IllegalStateException("Calculating time should not require to read speed from edge in wrong direction. "
-                    + "Reverse:" + revert + ", fwd:" + encoder.isForward(flags) + ", bwd:" + encoder.isBackward(flags));
-
-        double speed = revert ? encoder.getReverseSpeed(flags) : encoder.getSpeed(flags);
-        if (Double.isInfinite(speed) || Double.isNaN(speed) || speed < 0)
-            throw new IllegalStateException("Invalid speed stored in edge! " + speed);
-
-        if (speed == 0)
-            throw new IllegalStateException("Speed cannot be 0 for unblocked edge, use access properties to mark edge blocked! Should only occur for shortest path calculation. See #242.");
-
-        double distance = edge.getDistance();
-        return (long) (distance * 3600 / speed);
+    protected long calcMillis(EdgeIteratorState edge, boolean reverse) {
+        return weighting.calcMillis(edge, reverse, EdgeIterator.NO_EDGE);
     }
 
     /**
@@ -564,7 +555,8 @@ public class Path {
                 }
                 double newDist = edge.getDistance();
                 prevInstruction.setDistance(newDist + prevInstruction.getDistance());
-                prevInstruction.setTime(calcMillis(edge, false) + prevInstruction.getTime());
+                prevInstruction.setTime(weighting.calcMillis(edge, false, EdgeIterator.NO_EDGE)
+                        + prevInstruction.getTime());
             }
         });
 
diff --git a/core/src/main/java/com/graphhopper/routing/PathBidirRef.java b/core/src/main/java/com/graphhopper/routing/PathBidirRef.java
index d22c2ff50..ccfa422e1 100644
--- a/core/src/main/java/com/graphhopper/routing/PathBidirRef.java
+++ b/core/src/main/java/com/graphhopper/routing/PathBidirRef.java
@@ -18,6 +18,7 @@
 package com.graphhopper.routing;
 
 import com.graphhopper.routing.util.FlagEncoder;
+import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Graph;
 import com.graphhopper.storage.SPTEntry;
 import com.graphhopper.util.EdgeIterator;
@@ -32,8 +33,8 @@ public class PathBidirRef extends Path {
     protected SPTEntry edgeTo;
     private boolean switchWrapper = false;
 
-    public PathBidirRef(Graph g, FlagEncoder encoder) {
-        super(g, encoder);
+    public PathBidirRef(Graph g, FlagEncoder encoder, Weighting weighting) {
+        super(g, weighting);
     }
 
     PathBidirRef(PathBidirRef p) {
@@ -70,9 +71,11 @@ public class PathBidirRef extends Path {
             edgeTo = ee;
         }
 
+        int prevEdge = EdgeIterator.NO_EDGE;
         SPTEntry currEdge = sptEntry;
         while (EdgeIterator.Edge.isValid(currEdge.edge)) {
-            processEdge(currEdge.edge, currEdge.adjNode);
+            processEdge(currEdge.edge, currEdge.adjNode, prevEdge);
+            prevEdge = currEdge.edge;
             currEdge = currEdge.parent;
         }
         setFromNode(currEdge.adjNode);
@@ -81,7 +84,7 @@ public class PathBidirRef extends Path {
         int tmpEdge = currEdge.edge;
         while (EdgeIterator.Edge.isValid(tmpEdge)) {
             currEdge = currEdge.parent;
-            processEdge(tmpEdge, currEdge.adjNode);
+            processEdge(tmpEdge, currEdge.adjNode, currEdge.edge);
             tmpEdge = currEdge.edge;
         }
         setEndNode(currEdge.adjNode);
diff --git a/core/src/main/java/com/graphhopper/routing/PathNative.java b/core/src/main/java/com/graphhopper/routing/PathNative.java
index 310969d8a..e0e50b326 100644
--- a/core/src/main/java/com/graphhopper/routing/PathNative.java
+++ b/core/src/main/java/com/graphhopper/routing/PathNative.java
@@ -18,6 +18,7 @@
 package com.graphhopper.routing;
 
 import com.graphhopper.routing.util.FlagEncoder;
+import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Graph;
 import com.graphhopper.util.EdgeIterator;
 
@@ -31,8 +32,8 @@ public class PathNative extends Path {
     private final int[] parentNodes;
     private final int[] parentEdges;
 
-    public PathNative(Graph g, FlagEncoder encoder, int[] parentNodes, int[] parentEdges) {
-        super(g, encoder);
+    public PathNative(Graph g, FlagEncoder encoder, Weighting weighting, int[] parentNodes, int[] parentEdges) {
+        super(g, weighting);
         this.parentNodes = parentNodes;
         this.parentEdges = parentEdges;
     }
@@ -44,13 +45,15 @@ public class PathNative extends Path {
     public Path extract() {
         if (endNode < 0)
             return this;
-
+        
+        int prevEdge = EdgeIterator.NO_EDGE;        
         while (true) {
             int edgeId = parentEdges[endNode];
             if (!EdgeIterator.Edge.isValid(edgeId))
                 break;
 
-            processEdge(edgeId, endNode);
+            processEdge(edgeId, endNode, prevEdge);
+            prevEdge = edgeId;
             endNode = parentNodes[endNode];
         }
         reverseOrder();
diff --git a/core/src/main/java/com/graphhopper/routing/ch/Path4CH.java b/core/src/main/java/com/graphhopper/routing/ch/Path4CH.java
index 7e7f8385e..eb255a425 100644
--- a/core/src/main/java/com/graphhopper/routing/ch/Path4CH.java
+++ b/core/src/main/java/com/graphhopper/routing/ch/Path4CH.java
@@ -19,8 +19,10 @@ package com.graphhopper.routing.ch;
 
 import com.graphhopper.routing.PathBidirRef;
 import com.graphhopper.routing.util.FlagEncoder;
+import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Graph;
 import com.graphhopper.util.CHEdgeIteratorState;
+import com.graphhopper.util.EdgeIterator;
 
 /**
  * Recursivly unpack shortcuts.
@@ -32,13 +34,13 @@ import com.graphhopper.util.CHEdgeIteratorState;
 public class Path4CH extends PathBidirRef {
     private final Graph routingGraph;
 
-    public Path4CH(Graph routingGraph, Graph baseGraph, FlagEncoder encoder) {
-        super(baseGraph, encoder);
+    public Path4CH(Graph routingGraph, Graph baseGraph, FlagEncoder encoder, Weighting weighting) {
+        super(baseGraph, encoder, weighting);
         this.routingGraph = routingGraph;
     }
 
     @Override
-    protected final void processEdge(int tmpEdge, int endNode) {
+    protected final void processEdge(int tmpEdge, int endNode, int prevEdgeId) {
         // Shortcuts do only contain valid weight so first expand before adding
         // to distance and time
         expandEdge((CHEdgeIteratorState) routingGraph.getEdgeIteratorState(tmpEdge, endNode), false);
@@ -46,10 +48,8 @@ public class Path4CH extends PathBidirRef {
 
     private void expandEdge(CHEdgeIteratorState mainEdgeState, boolean reverse) {
         if (!mainEdgeState.isShortcut()) {
-            double dist = mainEdgeState.getDistance();
-            distance += dist;
-            long flags = mainEdgeState.getFlags();
-            time += calcMillis(mainEdgeState, reverse);
+            distance += mainEdgeState.getDistance();
+            time += weighting.calcMillis(mainEdgeState, reverse, EdgeIterator.NO_EDGE);
             addEdge(mainEdgeState.getEdge());
             return;
         }
diff --git a/core/src/main/java/com/graphhopper/routing/ch/PreparationWeighting.java b/core/src/main/java/com/graphhopper/routing/ch/PreparationWeighting.java
index 25e97e213..e937edeb4 100644
--- a/core/src/main/java/com/graphhopper/routing/ch/PreparationWeighting.java
+++ b/core/src/main/java/com/graphhopper/routing/ch/PreparationWeighting.java
@@ -52,6 +52,11 @@ public class PreparationWeighting implements Weighting {
         return userWeighting.calcWeight(edgeState, reverse, prevOrNextEdgeId);
     }
 
+    @Override
+    public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
+        return userWeighting.calcMillis(edgeState, reverse, prevOrNextEdgeId);
+    }
+
     @Override
     public FlagEncoder getFlagEncoder() {
         return userWeighting.getFlagEncoder();
diff --git a/core/src/main/java/com/graphhopper/routing/ch/PrepareContractionHierarchies.java b/core/src/main/java/com/graphhopper/routing/ch/PrepareContractionHierarchies.java
index ea91eb86f..89328100d 100644
--- a/core/src/main/java/com/graphhopper/routing/ch/PrepareContractionHierarchies.java
+++ b/core/src/main/java/com/graphhopper/routing/ch/PrepareContractionHierarchies.java
@@ -678,7 +678,7 @@ public class PrepareContractionHierarchies extends AbstractAlgoPreparation imple
 
             @Override
             protected Path createAndInitPath() {
-                bestPath = new Path4CH(graph, graph.getBaseGraph(), flagEncoder);
+                bestPath = new Path4CH(graph, graph.getBaseGraph(), flagEncoder, weighting);
                 return bestPath;
             }
 
@@ -715,7 +715,7 @@ public class PrepareContractionHierarchies extends AbstractAlgoPreparation imple
 
             @Override
             protected Path createAndInitPath() {
-                bestPath = new Path4CH(graph, graph.getBaseGraph(), flagEncoder);
+                bestPath = new Path4CH(graph, graph.getBaseGraph(), flagEncoder, weighting);
                 return bestPath;
             }
 
diff --git a/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java
index d9e4a7722..d66576a73 100644
--- a/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java
@@ -34,6 +34,9 @@ import java.util.*;
 public class CarFlagEncoder extends AbstractFlagEncoder {
     protected final Map<String, Integer> trackTypeSpeedMap = new HashMap<String, Integer>();
     protected final Set<String> badSurfaceSpeedMap = new HashSet<String>();
+
+    // This value determines the maximal possible on roads with bad surfaces
+    protected int badSurfaceSpeed;
     /**
      * A map which associates string to speed. Get some impression:
      * http://www.itoworld.com/map/124#fullscreen
@@ -100,6 +103,11 @@ public class CarFlagEncoder extends AbstractFlagEncoder {
         badSurfaceSpeedMap.add("dirt");
         badSurfaceSpeedMap.add("ground");
         badSurfaceSpeedMap.add("grass");
+        badSurfaceSpeedMap.add("unpaved");
+        badSurfaceSpeedMap.add("compacted");
+
+        // limit speed on bad surfaces to 30 km/h
+        badSurfaceSpeed = 30;
 
         maxPossibleSpeed = 140;
 
@@ -230,9 +238,7 @@ public class CarFlagEncoder extends AbstractFlagEncoder {
             double speed = getSpeed(way);
             speed = applyMaxSpeed(way, speed);
 
-            // limit speed to max 30 km/h if bad surface
-            if (speed > 30 && way.hasTag("surface", badSurfaceSpeedMap))
-                speed = 30;
+            speed = applyBadSurfaceSpeed(way, speed);
 
             flags = setSpeed(flags, speed);
 
@@ -312,6 +318,17 @@ public class CarFlagEncoder extends AbstractFlagEncoder {
         else
             return "destination: " + str;
     }
+    /**
+     * @param way:   needed to retrieve tags
+     * @param speed: speed guessed e.g. from the road type or other tags
+     * @return The assumed speed
+     */
+    protected double applyBadSurfaceSpeed(ReaderWay way, double speed) {
+        // limit speed if bad surface
+        if (badSurfaceSpeed > 0 && speed > badSurfaceSpeed && way.hasTag("surface", badSurfaceSpeedMap))
+            speed = badSurfaceSpeed;
+        return speed;
+    }
 
     @Override
     public String toString() {
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 ac43e25bc..83d517005 100644
--- a/core/src/main/java/com/graphhopper/routing/util/DataFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/DataFlagEncoder.java
@@ -448,9 +448,7 @@ public class DataFlagEncoder extends AbstractFlagEncoder {
 
     @Override
     public double getSpeed(long flags) {
-        // TODO fix Path.calcMillis(Path.java:255)
-        // use pluggable weighting.calcMillis but include reverse somehow
-        return 50;
+        throw new UnsupportedOperationException("Calculate speed via more customizable Weighting.calcMillis method");
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/TurnCostEncoder.java b/core/src/main/java/com/graphhopper/routing/util/TurnCostEncoder.java
index fadc4f1b2..d0d05d8f0 100644
--- a/core/src/main/java/com/graphhopper/routing/util/TurnCostEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/TurnCostEncoder.java
@@ -45,8 +45,7 @@ public interface TurnCostEncoder {
     long getTurnFlags(boolean restricted, double costs);
 
     /**
-     * whether turn costs nor turn restrictions will be encoded by this encoder, should be used for
-     * pedestrians
+     * No turn costs will be enabled by this encoder, should be used for pedestrians
      */
     class NoTurnCostsEncoder implements TurnCostEncoder {
 
diff --git a/core/src/main/java/com/graphhopper/routing/weighting/AbstractAdjustedWeighting.java b/core/src/main/java/com/graphhopper/routing/weighting/AbstractAdjustedWeighting.java
index 058399023..c712fb9da 100644
--- a/core/src/main/java/com/graphhopper/routing/weighting/AbstractAdjustedWeighting.java
+++ b/core/src/main/java/com/graphhopper/routing/weighting/AbstractAdjustedWeighting.java
@@ -19,6 +19,7 @@ package com.graphhopper.routing.weighting;
 
 import com.graphhopper.routing.util.FlagEncoder;
 import com.graphhopper.routing.util.HintsMap;
+import com.graphhopper.util.EdgeIteratorState;
 
 /**
  * The AdjustedWeighting wraps another Weighting.
@@ -34,6 +35,11 @@ public abstract class AbstractAdjustedWeighting implements Weighting {
         this.superWeighting = superWeighting;
     }
 
+    @Override
+    public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
+        return superWeighting.calcMillis(edgeState, reverse, prevOrNextEdgeId);
+    }
+
     /**
      * Returns the flagEncoder of the superWeighting. Usually we do not have a Flagencoder here.
      */
diff --git a/core/src/main/java/com/graphhopper/routing/weighting/AbstractWeighting.java b/core/src/main/java/com/graphhopper/routing/weighting/AbstractWeighting.java
index 4ed8950f2..55ddc7dd2 100644
--- a/core/src/main/java/com/graphhopper/routing/weighting/AbstractWeighting.java
+++ b/core/src/main/java/com/graphhopper/routing/weighting/AbstractWeighting.java
@@ -19,6 +19,7 @@ package com.graphhopper.routing.weighting;
 
 import com.graphhopper.routing.util.FlagEncoder;
 import com.graphhopper.routing.util.HintsMap;
+import com.graphhopper.util.EdgeIteratorState;
 
 /**
  * @author Peter Karich
@@ -34,18 +35,21 @@ public abstract class AbstractWeighting implements Weighting {
             throw new IllegalStateException("Not a valid name for a Weighting: " + getName());
     }
 
-    static final boolean isValidName(String name) {
-        if (name == null || name.isEmpty())
-            return false;
+    @Override
+    public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
+        long flags = edgeState.getFlags();
+        if (reverse && !flagEncoder.isBackward(flags)
+                || !reverse && !flagEncoder.isForward(flags))
+            throw new IllegalStateException("Calculating time should not require to read speed from edge in wrong direction. "
+                    + "Reverse:" + reverse + ", fwd:" + flagEncoder.isForward(flags) + ", bwd:" + flagEncoder.isBackward(flags));
 
-        return name.matches("[\\|_a-z]+");
-    }
+        double speed = reverse ? flagEncoder.getReverseSpeed(flags) : flagEncoder.getSpeed(flags);
+        if (Double.isInfinite(speed) || Double.isNaN(speed) || speed < 0)
+            throw new IllegalStateException("Invalid speed stored in edge! " + speed);
+        if (speed == 0)
+            throw new IllegalStateException("Speed cannot be 0 for unblocked edge, use access properties to mark edge blocked! Should only occur for shortest path calculation. See #242.");        
 
-    /**
-     * Replaces all characters which are not numbers, characters or underscores with underscores
-     */
-    public static String weightingToFileName(Weighting w) {
-        return w.toString().toLowerCase().replaceAll("\\|", "_");
+        return (long) (edgeState.getDistance() * 3600 / speed);
     }
 
     @Override
@@ -76,6 +80,20 @@ public abstract class AbstractWeighting implements Weighting {
         return toString().equals(other.toString());
     }
 
+    static final boolean isValidName(String name) {
+        if (name == null || name.isEmpty())
+            return false;
+
+        return name.matches("[\\|_a-z]+");
+    }
+
+    /**
+     * Replaces all characters which are not numbers, characters or underscores with underscores
+     */
+    public static String weightingToFileName(Weighting w) {
+        return w.toString().toLowerCase().replaceAll("\\|", "_");
+    }
+
     @Override
     public String toString() {
         return getName() + "|" + flagEncoder;
diff --git a/core/src/main/java/com/graphhopper/routing/weighting/GenericWeighting.java b/core/src/main/java/com/graphhopper/routing/weighting/GenericWeighting.java
index a96576560..03bf29c49 100644
--- a/core/src/main/java/com/graphhopper/routing/weighting/GenericWeighting.java
+++ b/core/src/main/java/com/graphhopper/routing/weighting/GenericWeighting.java
@@ -35,6 +35,7 @@ public class GenericWeighting extends AbstractWeighting {
      */
     protected final static double SPEED_CONV = 3.6;
     private final double headingPenalty;
+    private final long headingPenaltyMillis;
     private final double maxSpeed;
     private final DataFlagEncoder gEncoder;
     private final double[] speedArray;
@@ -44,6 +45,7 @@ public class GenericWeighting extends AbstractWeighting {
         super(encoder);
         gEncoder = encoder;
         headingPenalty = cMap.getDouble(Routing.HEADING_PENALTY, Routing.DEFAULT_HEADING_PENALTY);
+        headingPenaltyMillis = Math.round(headingPenalty * 1000);
 
         speedArray = gEncoder.getHighwaySpeedMap(cMap.getMap("highways", Double.class));
         double tmpSpeed = 0;
@@ -64,46 +66,57 @@ public class GenericWeighting extends AbstractWeighting {
     }
 
     @Override
-    public double calcWeight(EdgeIteratorState edge, boolean reverse, int prevOrNextEdgeId) {
+    public double calcWeight(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
         // handle oneways and removed edges via subnetwork removal (existing and allowed highway tags but 'island' edges)
         if (reverse) {
-            if (!gEncoder.isBackward(edge, accessType))
+            if (!gEncoder.isBackward(edgeState, accessType))
                 return Double.POSITIVE_INFINITY;
-        } else if (!gEncoder.isForward(edge, accessType))
+        } else if (!gEncoder.isForward(edgeState, accessType))
             return Double.POSITIVE_INFINITY;
 
+        long time = calcMillis(edgeState, reverse, prevOrNextEdgeId);
+        if (time == Long.MAX_VALUE)
+            return Double.POSITIVE_INFINITY;
+        return time;
+    }
+
+    @Override
+    public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
         // TODO to avoid expensive reverse flags include oneway accessibility
         // but how to include e.g. maxspeed as it depends on direction? Does highway depend on direction?
         // reverse = edge.isReverse()? !reverse : reverse;
-        int highwayVal = gEncoder.getHighway(edge);
+        int highwayVal = gEncoder.getHighway(edgeState);
         double speed = speedArray[highwayVal];
         if (speed < 0)
-            throw new IllegalStateException("speed was negative? " + edge.getEdge() + ", highway:" + highwayVal + ", reverse:" + reverse);
+            throw new IllegalStateException("speed was negative? " + edgeState.getEdge()
+                    + ", highway:" + highwayVal + ", reverse:" + reverse);
         if (speed == 0)
-            return Double.POSITIVE_INFINITY;
+            return Long.MAX_VALUE;
 
         // TODO inner city guessing -> lit, maxspeed <= 50, residential etc => create new encoder.isInnerCity(edge)
         // See #472 use edge.getDouble((encoder), K_MAXSPEED_MOTORVEHICLE_FORWARD, _default) or edge.getMaxSpeed(...) instead?
         // encoder could be made optional via passing to EdgeExplorer
-        double maxspeed = gEncoder.getMaxspeed(edge, accessType, reverse);
+        double maxspeed = gEncoder.getMaxspeed(edgeState, accessType, reverse);
         if (maxspeed > 0 && speed > maxspeed)
             speed = maxspeed;
 
-        double time = edge.getDistance() / speed * SPEED_CONV;
+        // TODO test performance difference for rounding
+        long timeInMillis = (long) (edgeState.getDistance() / speed * SPEED_CONV);
 
         // add direction penalties at start/stop/via points
-        boolean unfavoredEdge = edge.getBool(EdgeIteratorState.K_UNFAVORED_EDGE, false);
+        boolean unfavoredEdge = edgeState.getBool(EdgeIteratorState.K_UNFAVORED_EDGE, false);
         if (unfavoredEdge)
-            time += headingPenalty;
-
-        if (time < 0)
-            throw new IllegalStateException("Some problem with weight calculation: time:" + time + ", speed:" + speed);
+            timeInMillis += headingPenaltyMillis;
 
         // TODO avoid a certain (or multiple) bounding boxes (less efficient for just a few edges) or a list of edgeIDs (not good for large areas)
         // bbox.contains(nodeAccess.getLatitude(edge.getBaseNode()), nodeAccess.getLongitude(edge.getBaseNode())) time+=avoidPenalty;
         // TODO surfaces can reduce average speed
         // TODO prefer or avoid bike and hike routes
-        return time;
+        if (timeInMillis < 0)
+            throw new IllegalStateException("Some problem with weight calculation: time:"
+                    + timeInMillis + ", speed:" + speed);
+
+        return timeInMillis;
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/weighting/TurnWeighting.java b/core/src/main/java/com/graphhopper/routing/weighting/TurnWeighting.java
index ae2b89d0d..ed8484413 100644
--- a/core/src/main/java/com/graphhopper/routing/weighting/TurnWeighting.java
+++ b/core/src/main/java/com/graphhopper/routing/weighting/TurnWeighting.java
@@ -86,6 +86,26 @@ public class TurnWeighting implements Weighting {
         return weight + turnCosts;
     }
 
+    @Override
+    public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
+        long millis = superWeighting.calcMillis(edgeState, reverse, prevOrNextEdgeId);
+        if (prevOrNextEdgeId == EdgeIterator.NO_EDGE)
+            return millis;
+
+        // TODO for now assume turn costs are returned in milliseconds?
+        // should we also separate weighting vs. time for turn? E.g. a fast but dangerous turn - is this common?
+        long turnCostsInMillis;
+        if (reverse)
+            turnCostsInMillis = (long) calcTurnWeight(edgeState.getEdge(), edgeState.getBaseNode(), prevOrNextEdgeId);
+        else
+            turnCostsInMillis = (long) calcTurnWeight(prevOrNextEdgeId, edgeState.getBaseNode(), edgeState.getEdge());
+
+        return millis + turnCostsInMillis;
+    }
+
+    /**
+     * This method calculates the turn weight separately.
+     */
     public double calcTurnWeight(int edgeFrom, int nodeVia, int edgeTo) {
         long turnFlags = turnCostExt.getTurnCostFlags(edgeFrom, nodeVia, edgeTo);
         if (turnCostEncoder.isTurnRestricted(turnFlags))
diff --git a/core/src/main/java/com/graphhopper/routing/weighting/Weighting.java b/core/src/main/java/com/graphhopper/routing/weighting/Weighting.java
index d0deed657..b77e29cc1 100644
--- a/core/src/main/java/com/graphhopper/routing/weighting/Weighting.java
+++ b/core/src/main/java/com/graphhopper/routing/weighting/Weighting.java
@@ -37,6 +37,11 @@ public interface Weighting {
     double getMinWeight(double distance);
 
     /**
+     * This method calculates the weighting a certain edgeState should be associated. E.g. a high
+     * value indicates that the edge should be avoided. Make sure that this method is very fast and
+     * optimized as this is called potentially millions of times for one route or a lot more for
+     * nearly any preprocessing phase.
+     *
      * @param edgeState        the edge for which the weight should be calculated
      * @param reverse          if the specified edge is specified in reverse direction e.g. from the reverse
      *                         case of a bidirectional search.
@@ -46,9 +51,14 @@ public interface Weighting {
      * +Infinity. Make sure your method does not return NaN which can e.g. occur for 0/0.
      */
     double calcWeight(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId);
-    
-//    double calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId);
-    
+
+    /**
+     * This method calculates the time taken (in milli seconds) for the specified edgeState and
+     * optionally include the turn costs (in seconds) of the previous (or next) edgeId via
+     * prevOrNextEdgeId. Typically used for post-processing and on only a few thausend edges.
+     */
+    long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId);
+
     FlagEncoder getFlagEncoder();
 
     String getName();
diff --git a/core/src/main/java/com/graphhopper/util/Helper.java b/core/src/main/java/com/graphhopper/util/Helper.java
index 5587a0f2c..1d5613f82 100644
--- a/core/src/main/java/com/graphhopper/util/Helper.java
+++ b/core/src/main/java/com/graphhopper/util/Helper.java
@@ -88,11 +88,15 @@ public class Helper {
     }
 
     public static int countBitValue(int maxTurnCosts) {
-        double val = Math.log(maxTurnCosts) / Math.log(2);
-        int intVal = (int) val;
-        if (val == intVal)
-            return intVal;
-        return intVal + 1;
+        if (maxTurnCosts < 0)
+            throw new IllegalArgumentException("maxTurnCosts cannot be negative " + maxTurnCosts);
+
+        int counter = 0;
+        while (maxTurnCosts > 0) {
+            maxTurnCosts >>= 1;
+            counter++;
+        }
+        return counter++;
     }
 
     public static void loadProperties(Map<String, String> map, Reader tmpReader) throws IOException {


Test patch:
diff --git a/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java b/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java
index 0e013f572..98d4a7183 100644
--- a/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java
+++ b/core/src/main/java/com/graphhopper/routing/weighting/FastestWeighting.java
@@ -36,11 +36,13 @@ public class FastestWeighting extends AbstractWeighting {
      */
     protected final static double SPEED_CONV = 3.6;
     private final double headingPenalty;
+    private final long headingPenaltyMillis;
     private final double maxSpeed;
 
     public FastestWeighting(FlagEncoder encoder, PMap pMap) {
         super(encoder);
         headingPenalty = pMap.getDouble(Routing.HEADING_PENALTY, Routing.DEFAULT_HEADING_PENALTY);
+        headingPenaltyMillis = Math.round(headingPenalty * 1000);
         maxSpeed = encoder.getMaxSpeed() / SPEED_CONV;
     }
 
@@ -69,6 +71,17 @@ public class FastestWeighting extends AbstractWeighting {
         return time;
     }
 
+    @Override
+    public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
+        // TODO move this to AbstractWeighting?
+        long time = 0;
+        boolean unfavoredEdge = edgeState.getBool(EdgeIteratorState.K_UNFAVORED_EDGE, false);
+        if (unfavoredEdge)
+            time += headingPenaltyMillis;
+
+        return time + super.calcMillis(edgeState, reverse, prevOrNextEdgeId);
+    }
+
     @Override
     public String getName() {
         return "fastest";
diff --git a/core/src/test/java/com/graphhopper/routing/AbstractRoutingAlgorithmTester.java b/core/src/test/java/com/graphhopper/routing/AbstractRoutingAlgorithmTester.java
index ac6938009..4cdc7d1ad 100644
--- a/core/src/test/java/com/graphhopper/routing/AbstractRoutingAlgorithmTester.java
+++ b/core/src/test/java/com/graphhopper/routing/AbstractRoutingAlgorithmTester.java
@@ -764,6 +764,13 @@ public abstract class AbstractRoutingAlgorithmTester {
                 return edgeState.getDistance() * 0.8;
             }
 
+            private final Weighting tmpW = new FastestWeighting(carEncoder);
+
+            @Override
+            public long calcMillis(EdgeIteratorState edgeState, boolean reverse, int prevOrNextEdgeId) {
+                return tmpW.calcMillis(edgeState, reverse, prevOrNextEdgeId);
+            }
+
             @Override
             public boolean matches(HintsMap map) {
                 throw new UnsupportedOperationException("Not supported");
diff --git a/core/src/test/java/com/graphhopper/routing/PathBidirRefTest.java b/core/src/test/java/com/graphhopper/routing/PathBidirRefTest.java
index 45209e811..08df055f2 100644
--- a/core/src/test/java/com/graphhopper/routing/PathBidirRefTest.java
+++ b/core/src/test/java/com/graphhopper/routing/PathBidirRefTest.java
@@ -21,6 +21,7 @@ import com.graphhopper.routing.util.DefaultEdgeFilter;
 import com.graphhopper.routing.util.EdgeFilter;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.FlagEncoder;
+import com.graphhopper.routing.weighting.FastestWeighting;
 import com.graphhopper.storage.Graph;
 import com.graphhopper.storage.GraphBuilder;
 import com.graphhopper.storage.SPTEntry;
@@ -47,7 +48,7 @@ public class PathBidirRefTest {
     public void testExtract() {
         Graph g = createGraph();
         g.edge(1, 2, 10, true);
-        PathBidirRef pw = new PathBidirRef(g, carEncoder);
+        PathBidirRef pw = new PathBidirRef(g, carEncoder, new FastestWeighting(carEncoder));
         EdgeExplorer explorer = g.createEdgeExplorer(carOutEdges);
         EdgeIterator iter = explorer.setBaseNode(1);
         iter.next();
@@ -67,7 +68,7 @@ public class PathBidirRefTest {
         EdgeExplorer explorer = g.createEdgeExplorer(carOutEdges);
         EdgeIterator iter = explorer.setBaseNode(1);
         iter.next();
-        PathBidirRef pw = new PathBidirRef(g, carEncoder);
+        PathBidirRef pw = new PathBidirRef(g, carEncoder, new FastestWeighting(carEncoder));
         pw.sptEntry = new SPTEntry(iter.getEdge(), 2, 10);
         pw.sptEntry.parent = new SPTEntry(EdgeIterator.NO_EDGE, 1, 0);
 
diff --git a/core/src/test/java/com/graphhopper/routing/PathTest.java b/core/src/test/java/com/graphhopper/routing/PathTest.java
index 5655cb634..4971bba01 100644
--- a/core/src/test/java/com/graphhopper/routing/PathTest.java
+++ b/core/src/test/java/com/graphhopper/routing/PathTest.java
@@ -18,6 +18,7 @@
 package com.graphhopper.routing;
 
 import com.graphhopper.routing.util.*;
+import com.graphhopper.routing.weighting.FastestWeighting;
 import com.graphhopper.routing.weighting.ShortestWeighting;
 import com.graphhopper.storage.*;
 import com.graphhopper.util.*;
@@ -42,7 +43,7 @@ public class PathTest {
     @Test
     public void testFound() {
         GraphHopperStorage g = new GraphBuilder(carManager).create();
-        Path p = new Path(g, encoder);
+        Path p = new Path(g, new FastestWeighting(encoder));
         assertFalse(p.isFound());
         assertEquals(0, p.getDistance(), 1e-7);
         assertEquals(0, p.calcNodes().size());
@@ -53,7 +54,7 @@ public class PathTest {
     public void testTime() {
         FlagEncoder tmpEnc = new Bike2WeightFlagEncoder();
         GraphHopperStorage g = new GraphBuilder(new EncodingManager(tmpEnc)).create();
-        Path p = new Path(g, tmpEnc);
+        Path p = new Path(g, new FastestWeighting(tmpEnc));
         long flags = tmpEnc.setSpeed(tmpEnc.setReverseSpeed(tmpEnc.setAccess(0, true, true), 10), 15);
         EdgeIteratorState edge = GHUtility.createMockedEdgeIteratorState(100000, flags);
                 
@@ -76,7 +77,7 @@ public class PathTest {
         EdgeIteratorState edge2 = g.edge(2, 1).setDistance(2000).setFlags(encoder.setProperties(50, true, true));
         edge2.setWayGeometry(Helper.createPointList(11, 1, 10, 1));
 
-        Path path = new Path(g, encoder);
+        Path path = new Path(g, new FastestWeighting(encoder));
         SPTEntry e1 = new SPTEntry(edge2.getEdge(), 2, 1);
         e1.parent = new SPTEntry(edge1.getEdge(), 1, 1);
         e1.parent.parent = new SPTEntry(-1, 0, 1);
@@ -102,7 +103,7 @@ public class PathTest {
 
         // force minor change for instructions
         edge2.setName("2");
-        path = new Path(g, encoder);
+        path = new Path(g, new FastestWeighting(encoder));
         e1 = new SPTEntry(edge2.getEdge(), 2, 1);
         e1.parent = new SPTEntry(edge1.getEdge(), 1, 1);
         e1.parent.parent = new SPTEntry(-1, 0, 1);
@@ -126,7 +127,7 @@ public class PathTest {
         assertEquals(path.calcPoints().size() - 1, lastIndex);
 
         // now reverse order
-        path = new Path(g, encoder);
+        path = new Path(g, new FastestWeighting(encoder));
         e1 = new SPTEntry(edge1.getEdge(), 0, 1);
         e1.parent = new SPTEntry(edge2.getEdge(), 1, 1);
         e1.parent.parent = new SPTEntry(-1, 2, 1);
@@ -175,7 +176,7 @@ public class PathTest {
         edge4.setWayGeometry(Helper.createPointList());
         edge4.setName("Street 4");
 
-        Path path = new Path(g, encoder);
+        Path path = new Path(g, new FastestWeighting(encoder));
         SPTEntry e1 = new SPTEntry(edge4.getEdge(), 4, 1);
         e1.parent = new SPTEntry(edge3.getEdge(), 3, 1);
         e1.parent.parent = new SPTEntry(edge2.getEdge(), 2, 1);
diff --git a/core/src/test/java/com/graphhopper/routing/util/CarFlagEncoderTest.java b/core/src/test/java/com/graphhopper/routing/util/CarFlagEncoderTest.java
index d3c7f8171..41e6dc880 100644
--- a/core/src/test/java/com/graphhopper/routing/util/CarFlagEncoderTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/CarFlagEncoderTest.java
@@ -278,6 +278,13 @@ public class CarFlagEncoderTest {
         encoded = encoder.handleWayTags(way, allowed, 0);
         assertEquals(20, encoder.getSpeed(encoded), 1e-1);
 
+        way.clearTags();
+        way.setTag("highway", "secondary");
+        way.setTag("surface", "compacted");
+        allowed = encoder.acceptWay(way);
+        encoded = encoder.handleWayTags(way, allowed, 0);
+        assertEquals(30, encoder.getSpeed(encoded), 1e-1);
+
         try {
             encoder.setSpeed(0, -1);
             assertTrue(false);
@@ -555,4 +562,12 @@ public class CarFlagEncoderTest {
         assertTrue(em.getEncoder("bike").isBackward(edgeFlags));
         assertTrue(em.getEncoder("bike").isForward(edgeFlags));
     }
+    @Test
+    public void testApplyBadSurfaceSpeed() {
+        ReaderWay way = new ReaderWay(1);
+        way.setTag("highway", "secondary");
+        way.setTag("surface", "unpaved");
+        assertEquals(30, encoder.applyBadSurfaceSpeed(way, 90), 1e-1);
+
+    }
 }
diff --git a/core/src/test/java/com/graphhopper/routing/weighting/FastestWeightingTest.java b/core/src/test/java/com/graphhopper/routing/weighting/FastestWeightingTest.java
index 8d8836275..d66bbb1f3 100644
--- a/core/src/test/java/com/graphhopper/routing/weighting/FastestWeightingTest.java
+++ b/core/src/test/java/com/graphhopper/routing/weighting/FastestWeightingTest.java
@@ -18,9 +18,14 @@
 package com.graphhopper.routing.weighting;
 
 import com.graphhopper.routing.VirtualEdgeIteratorState;
+import com.graphhopper.routing.util.Bike2WeightFlagEncoder;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.FlagEncoder;
+import com.graphhopper.storage.GraphBuilder;
+import com.graphhopper.storage.GraphHopperStorage;
 import com.graphhopper.util.EdgeIterator;
+import com.graphhopper.util.EdgeIteratorState;
+import com.graphhopper.util.GHUtility;
 import com.graphhopper.util.Helper;
 import com.graphhopper.util.PMap;
 import com.graphhopper.util.Parameters;
@@ -45,7 +50,8 @@ public class FastestWeightingTest {
 
     @Test
     public void testWeightWrongHeading() {
-        Weighting instance = new FastestWeighting(encoder, new PMap().put(Parameters.Routing.HEADING_PENALTY, "100"));
+        Weighting instance = new FastestWeighting(encoder, new PMap().
+                put(Parameters.Routing.HEADING_PENALTY, "100"));
         VirtualEdgeIteratorState virtEdge = new VirtualEdgeIteratorState(0, 1, 1, 2, 10,
                 encoder.setProperties(10, true, true), "test", Helper.createPointList(51, 0, 51, 1));
         double time = instance.calcWeight(virtEdge, false, 0);
@@ -75,4 +81,19 @@ public class FastestWeightingTest {
         // 0 / 0 returns NaN but calcWeight should not return NaN!
         assertEquals(1.0 / 0, instance.calcWeight(createMockedEdgeIteratorState(0, encoder.setProperties(0, true, true)), false, EdgeIterator.NO_EDGE), 1e-8);
     }
+
+    @Test
+    public void testTime() {
+        FlagEncoder tmpEnc = new Bike2WeightFlagEncoder();
+        GraphHopperStorage g = new GraphBuilder(new EncodingManager(tmpEnc)).create();
+        Weighting w = new FastestWeighting(tmpEnc);
+
+        long flags = tmpEnc.setSpeed(tmpEnc.setReverseSpeed(tmpEnc.setAccess(0, true, true), 10), 15);
+        EdgeIteratorState edge = GHUtility.createMockedEdgeIteratorState(100000, flags);
+
+        assertEquals(375 * 60 * 1000, w.calcMillis(edge, false, EdgeIterator.NO_EDGE));
+        assertEquals(600 * 60 * 1000, w.calcMillis(edge, true, EdgeIterator.NO_EDGE));
+
+        g.close();
+    }
 }
diff --git a/core/src/test/java/com/graphhopper/util/HelperTest.java b/core/src/test/java/com/graphhopper/util/HelperTest.java
index c3768c5ce..76b740af7 100644
--- a/core/src/test/java/com/graphhopper/util/HelperTest.java
+++ b/core/src/test/java/com/graphhopper/util/HelperTest.java
@@ -47,7 +47,12 @@ public class HelperTest {
 
     @Test
     public void testCountBitValue() throws Exception {
-        assertEquals(2, Helper.countBitValue(4));
+        assertEquals(1, Helper.countBitValue(1));
+        assertEquals(2, Helper.countBitValue(2));
+        assertEquals(2, Helper.countBitValue(3));
+        assertEquals(3, Helper.countBitValue(4));
+        assertEquals(3, Helper.countBitValue(7));
+        assertEquals(4, Helper.countBitValue(8));
         assertEquals(5, Helper.countBitValue(20));
     }