Repository: graphhopper/graphhopper
Pull request #1892 (2020-02-06 21:01:24)

highway=path and bicycle=yes should not get speed for pushing section
See https://discuss.graphhopper.com/t/bike-profil-highway-pathpath-and-bicycle-yes-should-not-get-speed-for-pushing-section/5148

ratrun: There is a difference to bicycle=designated, here we expect 18km/h, which is the cycleway speed. This seems correct to me. If you feel 14km/h is too much for bicycle=yes, what would you suggest?
karussell: > If you feel 14km/h is too much for bicycle=yes, what would you suggest?

For footway and bicycle=yes this is too much IMO. Maybe 10? Or maybe I have the wrong situation in mind. Isn't it like for that sign?

![image](https://user-images.githubusercontent.com/129644/75032893-e831b780-54a9-11ea-9f25-9fdee8f31d48.png)

ratrun: Yes, the sign is correct. I reduced the speed for this classification to 10 km/h as suggested.

Patch:
diff --git a/core/src/main/java/com/graphhopper/GraphHopper.java b/core/src/main/java/com/graphhopper/GraphHopper.java
index c6c7b8808..17b80ada2 100644
--- a/core/src/main/java/com/graphhopper/GraphHopper.java
+++ b/core/src/main/java/com/graphhopper/GraphHopper.java
@@ -1020,6 +1020,9 @@ public class GraphHopper implements GraphHopperAPI {
             Graph graph = ghStorage;
             if (chPreparationHandler.isEnabled() && !disableCH) {
                 if (algorithmFactory instanceof CHRoutingAlgorithmFactory) {
+                    if (hints.has(Routing.BLOCK_AREA))
+                        throw new IllegalArgumentException("When CH is enabled the " + Parameters.Routing.BLOCK_AREA + " cannot be specified");
+
                     CHProfile chProfile = ((CHRoutingAlgorithmFactory) algorithmFactory).getCHProfile();
                     weighting = chProfile.getWeighting();
                     graph = ghStorage.getCHGraph(chProfile);
@@ -1030,7 +1033,8 @@ public class GraphHopper implements GraphHopperAPI {
                 checkNonChMaxWaypointDistance(points);
                 weighting = createWeighting(hints, encoder, turnCostProvider);
                 if (hints.has(Routing.BLOCK_AREA))
-                    weighting = new BlockAreaWeighting(weighting, createBlockArea(points, hints, DefaultEdgeFilter.allEdges(encoder)));
+                    weighting = new BlockAreaWeighting(weighting, GraphEdgeIdFinder.createBlockArea(ghStorage, locationIndex,
+                            points, hints, DefaultEdgeFilter.allEdges(encoder)));
             }
             ghRsp.addDebugInfo("tmode:" + tMode.toString());
 
@@ -1049,6 +1053,9 @@ public class GraphHopper implements GraphHopperAPI {
                 return Collections.emptyList();
 
             QueryGraph queryGraph = QueryGraph.lookup(graph, qResults);
+            if (weighting instanceof BlockAreaWeighting)
+                ((BlockAreaWeighting) weighting).setQueryGraph(queryGraph);
+
             int maxVisitedNodesForRequest = hints.getInt(Routing.MAX_VISITED_NODES, routingConfig.getMaxVisitedNodes());
             if (maxVisitedNodesForRequest > routingConfig.getMaxVisitedNodes())
                 throw new IllegalArgumentException("The max_visited_nodes parameter has to be below or equal to:" + routingConfig.getMaxVisitedNodes());
@@ -1112,17 +1119,6 @@ public class GraphHopper implements GraphHopperAPI {
         return new ChangeGraphHelper(graph, locationIndex);
     }
 
-    private GraphEdgeIdFinder.BlockArea createBlockArea(List<GHPoint> points, HintsMap hints, EdgeFilter edgeFilter) {
-        String blockAreaStr = hints.get(Parameters.Routing.BLOCK_AREA, "");
-        GraphEdgeIdFinder.BlockArea blockArea = new GraphEdgeIdFinder(ghStorage, locationIndex).
-                parseBlockArea(blockAreaStr, edgeFilter, hints.getDouble(Routing.BLOCK_AREA + ".edge_id_max_area", 1000 * 1000));
-        for (GHPoint p : points) {
-            if (blockArea.contains(p))
-                throw new IllegalArgumentException("Request with " + Routing.BLOCK_AREA + " contained query point " + p + ". This is not allowed.");
-        }
-        return blockArea;
-    }
-
     private void checkIfPointsAreInBounds(List<GHPoint> points) {
         BBox bounds = ghStorage.getBounds();
         for (int i = 0; i < points.size(); i++) {
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 efb50d354..e1e52f447 100644
--- a/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/BikeCommonFlagEncoder.java
@@ -335,12 +335,13 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
         // Under certain conditions we need to increase the speed of pushing sections to the speed of a "highway=cycleway"
         if (way.hasTag("highway", pushingSectionsHighways)
                 && ((way.hasTag("foot", "yes") && way.hasTag("segregated", "yes"))
-                || way.hasTag("bicycle", "designated") || way.hasTag("bicycle", "official")))
+                || (way.hasTag("bicycle", intendedValues))))
             highwaySpeed = getHighwaySpeed("cycleway");
 
         String s = way.getTag("surface");
+        Integer surfaceSpeed = 0;
         if (!Helper.isEmpty(s)) {
-            Integer surfaceSpeed = surfaceSpeeds.get(s);
+            surfaceSpeed = surfaceSpeeds.get(s);
             if (surfaceSpeed != null) {
                 speed = surfaceSpeed;
                 // boost handling for good surfaces but avoid boosting if pushing section
@@ -366,24 +367,24 @@ abstract public class BikeCommonFlagEncoder extends AbstractFlagEncoder {
         }
 
         // Until now we assumed that the way is no pushing section
-        // Now we check that, but only in case that our speed is bigger compared to the PUSHING_SECTION_SPEED
+        // Now we check that, but only in case that our speed computed so far is bigger compared to the PUSHING_SECTION_SPEED
         if (speed > PUSHING_SECTION_SPEED
                 && (way.hasTag("highway", pushingSectionsHighways) || way.hasTag("bicycle", "dismount"))) {
             if (!way.hasTag("bicycle", intendedValues)) {
                 // Here we set the speed for pushing sections and set speed for steps as even lower:
-                if (way.hasTag("highway", "steps"))
-                    speed = PUSHING_SECTION_SPEED / 2;
-                else
-                    speed = PUSHING_SECTION_SPEED;
-            } else if (way.hasTag("bicycle", "designated") || way.hasTag("bicycle", "official")) {
+                speed = way.hasTag("highway", "steps") ? PUSHING_SECTION_SPEED / 2 : PUSHING_SECTION_SPEED;
+            } else if (way.hasTag("bicycle", "designated") || way.hasTag("bicycle", "official") ||
+                    way.hasTag("segregated", "yes") || way.hasTag("bicycle", "yes")) {
                 // Here we handle the cases where the OSM tagging results in something similar to "highway=cycleway"
-                speed = highwaySpeeds.get("cycleway");
-            } else {
-                speed = PUSHING_SECTION_SPEED;
+                if (way.hasTag("segregated", "yes"))
+                    speed = highwaySpeeds.get("cycleway");
+                else
+                    speed = way.hasTag("bicycle", "yes") ? 10 : highwaySpeeds.get("cycleway");
+
+                // overwrite our speed again in case we have a valid surface speed and if it is smaller as computed so far
+                if ((surfaceSpeed > 0) && (surfaceSpeed < speed))
+                    speed = surfaceSpeed;
             }
-            // Increase speed in case of segregated
-            if (speed <= PUSHING_SECTION_SPEED && way.hasTag("segregated", "yes"))
-                speed = PUSHING_SECTION_SPEED * 2;
         }
         return speed;
     }
diff --git a/core/src/main/java/com/graphhopper/routing/weighting/BlockAreaWeighting.java b/core/src/main/java/com/graphhopper/routing/weighting/BlockAreaWeighting.java
index d912800d1..0b2e2df97 100644
--- a/core/src/main/java/com/graphhopper/routing/weighting/BlockAreaWeighting.java
+++ b/core/src/main/java/com/graphhopper/routing/weighting/BlockAreaWeighting.java
@@ -1,5 +1,6 @@
 package com.graphhopper.routing.weighting;
 
+import com.graphhopper.routing.querygraph.QueryGraph;
 import com.graphhopper.storage.GraphEdgeIdFinder;
 import com.graphhopper.util.EdgeIteratorState;
 
@@ -15,6 +16,11 @@ public class BlockAreaWeighting extends AbstractAdjustedWeighting {
         this.blockArea = blockArea;
     }
 
+    public BlockAreaWeighting setQueryGraph(QueryGraph queryGraph) {
+        blockArea.setQueryGraph(queryGraph);
+        return this;
+    }
+
     @Override
     public double calcEdgeWeight(EdgeIteratorState edgeState, boolean reverse) {
         if (blockArea.intersects(edgeState))
diff --git a/core/src/main/java/com/graphhopper/storage/GraphEdgeIdFinder.java b/core/src/main/java/com/graphhopper/storage/GraphEdgeIdFinder.java
index 5e5ead977..c38c31c4d 100644
--- a/core/src/main/java/com/graphhopper/storage/GraphEdgeIdFinder.java
+++ b/core/src/main/java/com/graphhopper/storage/GraphEdgeIdFinder.java
@@ -17,14 +17,14 @@
  */
 package com.graphhopper.storage;
 
-import com.graphhopper.coll.GHBitSet;
+import com.carrotsearch.hppc.cursors.IntCursor;
 import com.graphhopper.coll.GHIntHashSet;
-import com.graphhopper.coll.GHTBitSet;
+import com.graphhopper.routing.querygraph.QueryGraph;
 import com.graphhopper.routing.util.EdgeFilter;
+import com.graphhopper.routing.util.HintsMap;
 import com.graphhopper.storage.index.LocationIndex;
-import com.graphhopper.storage.index.QueryResult;
-import com.graphhopper.util.BreadthFirstSearch;
 import com.graphhopper.util.EdgeIteratorState;
+import com.graphhopper.util.Parameters;
 import com.graphhopper.util.PointList;
 import com.graphhopper.util.shapes.Polygon;
 import com.graphhopper.util.shapes.*;
@@ -32,6 +32,7 @@ import org.locationtech.jts.algorithm.RectangleLineIntersector;
 import org.locationtech.jts.geom.*;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import static com.graphhopper.util.shapes.BBox.toEnvelope;
@@ -43,6 +44,7 @@ import static com.graphhopper.util.shapes.BBox.toEnvelope;
  */
 public class GraphEdgeIdFinder {
 
+    private final static int P_RADIUS = 5;
     private final Graph graph;
     private final LocationIndex locationIndex;
 
@@ -51,97 +53,53 @@ public class GraphEdgeIdFinder {
         this.locationIndex = locationIndex;
     }
 
-    /**
-     * This method fills the edgeIds hash with edgeIds found close (exact match) to the specified point
-     */
-    public void findClosestEdgeToPoint(GHIntHashSet edgeIds, GHPoint point, EdgeFilter filter) {
-        findClosestEdge(edgeIds, point.getLat(), point.getLon(), filter);
-    }
-
-    /**
-     * This method fills the edgeIds hash with edgeIds found close (exact match) to the specified lat,lon
-     */
-    public void findClosestEdge(GHIntHashSet edgeIds, double lat, double lon, EdgeFilter filter) {
-        QueryResult qr = locationIndex.findClosest(lat, lon, filter);
-        if (qr.isValid())
-            edgeIds.add(qr.getClosestEdge().getEdge());
-    }
-
     /**
      * This method fills the edgeIds hash with edgeIds found inside the specified shape
      */
     public void findEdgesInShape(final GHIntHashSet edgeIds, final Shape shape, EdgeFilter filter) {
-        GHPoint center = shape.getCenter();
-        QueryResult qr = locationIndex.findClosest(center.getLat(), center.getLon(), filter);
-        // TODO: this is suboptimal and will be fixed in #1324
-        if (!qr.isValid())
-            throw new IllegalArgumentException("Shape '" + shape + "' does not cover graph. Center: " + center);
-
-        if (shape.contains(qr.getSnappedPoint().lat, qr.getSnappedPoint().lon))
-            edgeIds.add(qr.getClosestEdge().getEdge());
-
-        final boolean isPolygon = shape instanceof Polygon;
-
-        BreadthFirstSearch bfs = new BreadthFirstSearch() {
-            final NodeAccess na = graph.getNodeAccess();
-            final Shape localShape = shape;
-
-            @Override
-            protected GHBitSet createBitSet() {
-                return new GHTBitSet();
-            }
-
+        locationIndex.query(shape.getBounds(), new LocationIndex.EdgeVisitor(graph.createEdgeExplorer(filter)) {
             @Override
-            protected boolean goFurther(int nodeId) {
-                if (isPolygon) return isInsideBBox(nodeId);
-
-                return localShape.contains(na.getLatitude(nodeId), na.getLongitude(nodeId));
-            }
-
-            @Override
-            protected boolean checkAdjacent(EdgeIteratorState edge) {
-                int adjNodeId = edge.getAdjNode();
-
-                if (localShape.contains(na.getLatitude(adjNodeId), na.getLongitude(adjNodeId))) {
+            public void onEdge(EdgeIteratorState edge, int nodeA, int nodeB) {
+                if (shape.intersects(edge.fetchWayGeometry(3).makeImmutable()))
                     edgeIds.add(edge.getEdge());
-                    return true;
-                }
-                return isPolygon && isInsideBBox(adjNodeId);
             }
-
-            private boolean isInsideBBox(int nodeId) {
-                BBox bbox = localShape.getBounds();
-                double lat = na.getLatitude(nodeId);
-                double lon = na.getLongitude(nodeId);
-                return lat <= bbox.maxLat && lat >= bbox.minLat && lon <= bbox.maxLon && lon >= bbox.minLon;
-            }
-        };
-        bfs.start(graph.createEdgeExplorer(filter), qr.getClosestNode());
+        });
     }
 
     /**
      * This method fills the edgeIds hash with edgeIds found inside the specified geometry
      */
-    public void fillEdgeIDs(GHIntHashSet edgeIds, Geometry geometry, EdgeFilter filter) {
+    public void fillEdgeIDs(final GHIntHashSet edgeIds, final Geometry geometry, EdgeFilter filter) {
         if (geometry instanceof Point) {
-            GHPoint point = GHPoint.create((Point) geometry);
-            findClosestEdgeToPoint(edgeIds, point, filter);
+            Point p = (Point) geometry;
+            findEdgesInShape(edgeIds, new Circle(p.getY(), p.getX(), P_RADIUS), filter);
         } else if (geometry instanceof LineString) {
-            PointList pl = PointList.fromLineString((LineString) geometry);
-            // TODO do map matching or routing
-            int lastIdx = pl.size() - 1;
-            if (pl.size() >= 2) {
-                double meanLat = (pl.getLatitude(0) + pl.getLatitude(lastIdx)) / 2;
-                double meanLon = (pl.getLongitude(0) + pl.getLongitude(lastIdx)) / 2;
-                findClosestEdge(edgeIds, meanLat, meanLon, filter);
-            }
+            locationIndex.query(BBox.fromEnvelope(geometry.getEnvelopeInternal()), new LocationIndex.EdgeVisitor(graph.createEdgeExplorer(filter)) {
+                @Override
+                public void onEdge(EdgeIteratorState edge, int nodeA, int nodeB) {
+                    if (geometry.intersects(edge.fetchWayGeometry(3).toLineString(false)))
+                        edgeIds.add(edge.getEdge());
+                }
+            });
         } else if (geometry instanceof MultiPoint) {
             for (Coordinate coordinate : geometry.getCoordinates()) {
-                findClosestEdge(edgeIds, coordinate.y, coordinate.x, filter);
+                findEdgesInShape(edgeIds, new Circle(coordinate.y, coordinate.x, P_RADIUS), filter);
             }
         }
     }
 
+    public static GraphEdgeIdFinder.BlockArea createBlockArea(Graph graph, LocationIndex locationIndex,
+                                                              List<GHPoint> points, HintsMap hints, EdgeFilter edgeFilter) {
+        String blockAreaStr = hints.get(Parameters.Routing.BLOCK_AREA, "");
+        GraphEdgeIdFinder.BlockArea blockArea = new GraphEdgeIdFinder(graph, locationIndex).
+                parseBlockArea(blockAreaStr, edgeFilter, hints.getDouble(Parameters.Routing.BLOCK_AREA + ".edge_id_max_area", 1000 * 1000));
+        for (GHPoint p : points) {
+            if (blockArea.contains(p))
+                throw new IllegalArgumentException("Request with " + Parameters.Routing.BLOCK_AREA + " contained query point " + p + ". This is not allowed.");
+        }
+        return blockArea;
+    }
+
     /**
      * This method reads the blockAreaString and creates a Collection of Shapes or a set of found edges if area is small enough.
      *
@@ -162,9 +120,9 @@ public class GraphEdgeIdFinder {
                 // always add the shape as we'll need this for virtual edges and for debugging.
                 if (splittedObject.length > 4) {
                     final Polygon polygon = Polygon.parsePoints(objectAsString);
-                    blockArea.add(polygon);
+                    GHIntHashSet blockedEdges = blockArea.add(polygon);
                     if (polygon.calculateArea() <= useEdgeIdsUntilAreaSize)
-                        findEdgesInShape(blockArea.blockedEdges, polygon, filter);
+                        findEdgesInShape(blockedEdges, polygon, filter);
                 } else if (splittedObject.length == 4) {
                     final BBox bbox = BBox.parseTwoPoints(objectAsString);
                     final RectangleLineIntersector cachedIntersector = new RectangleLineIntersector(toEnvelope(bbox));
@@ -174,22 +132,24 @@ public class GraphEdgeIdFinder {
                             return BBox.intersects(cachedIntersector, pointList);
                         }
                     };
-                    blockArea.add(preparedBBox);
+                    GHIntHashSet blockedEdges = blockArea.add(preparedBBox);
                     if (bbox.calculateArea() <= useEdgeIdsUntilAreaSize)
-                        findEdgesInShape(blockArea.blockedEdges, preparedBBox, filter);
+                        findEdgesInShape(blockedEdges, preparedBBox, filter);
                 } else if (splittedObject.length == 3) {
                     double lat = Double.parseDouble(splittedObject[0]);
                     double lon = Double.parseDouble(splittedObject[1]);
                     int radius = Integer.parseInt(splittedObject[2]);
                     Circle circle = new Circle(lat, lon, radius);
-                    blockArea.add(circle);
+                    GHIntHashSet blockedEdges = blockArea.add(circle);
                     if (circle.calculateArea() <= useEdgeIdsUntilAreaSize)
-                        findEdgesInShape(blockArea.blockedEdges, circle, filter);
+                        findEdgesInShape(blockedEdges, circle, filter);
 
                 } else if (splittedObject.length == 2) {
                     double lat = Double.parseDouble(splittedObject[0]);
                     double lon = Double.parseDouble(splittedObject[1]);
-                    findClosestEdge(blockArea.blockedEdges, lat, lon, filter);
+                    Circle circle = new Circle(lat, lon, P_RADIUS);
+                    GHIntHashSet blockedEdges = blockArea.add(circle);
+                    findEdgesInShape(blockedEdges, circle, filter);
                 } else {
                     throw new IllegalArgumentException(objectAsString + " at index " + i + " need to be defined as lat,lon "
                             + "or as a circle lat,lon,radius or rectangular lat1,lon1,lat2,lon2");
@@ -203,20 +163,35 @@ public class GraphEdgeIdFinder {
      * This class handles edges and areas where access should be blocked.
      */
     public static class BlockArea {
-        final GHIntHashSet blockedEdges = new GHIntHashSet();
-        final List<Shape> blockedShapes = new ArrayList<>();
-        private final NodeAccess na;
+        private final List<GHIntHashSet> edgesList = new ArrayList<>();
+        private final List<Shape> blockedShapes = new ArrayList<>();
+        private NodeAccess na;
+        private final int baseEdgeCount;
+        private boolean prepared;
 
         public BlockArea(Graph g) {
+            baseEdgeCount = g.getAllEdges().length();
             na = g.getNodeAccess();
         }
 
-        public void add(int edgeId) {
-            blockedEdges.addAll(edgeId);
+        public boolean hasCachedEdgeIds(int shapeIndex) {
+            return !edgesList.get(shapeIndex).isEmpty();
+        }
+
+        public String toString(int shapeIndex) {
+            List<Integer> returnList = new ArrayList<>();
+            for (IntCursor intCursor : edgesList.get(shapeIndex)) {
+                returnList.add(intCursor.value);
+            }
+            Collections.sort(returnList);
+            return returnList.toString();
         }
 
-        public void add(Shape shape) {
+        public GHIntHashSet add(Shape shape) {
             blockedShapes.add(shape);
+            GHIntHashSet set = new GHIntHashSet();
+            edgesList.add(set);
+            return set;
         }
 
         public final boolean contains(GHPoint point) {
@@ -231,15 +206,19 @@ public class GraphEdgeIdFinder {
          * @return true if the specified edgeState is part of this BlockArea
          */
         public final boolean intersects(EdgeIteratorState edgeState) {
-            if (!blockedEdges.isEmpty() && blockedEdges.contains(edgeState.getEdge())) {
-                return true;
-            }
-
-            // compromise: mostly avoid expensive fetchWayGeometry which isn't yet fast for being used in Weighting.calc
-            BBox bbox = BBox.fromPoints(na.getLatitude(edgeState.getBaseNode()), na.getLongitude(edgeState.getBaseNode()),
-                    na.getLatitude(edgeState.getAdjNode()), na.getLongitude(edgeState.getAdjNode()));
             PointList pointList = null;
-            for (Shape shape : blockedShapes) {
+            for (int shapeIdx = 0; shapeIdx < blockedShapes.size(); shapeIdx++) {
+                GHIntHashSet blockedEdges = edgesList.get(shapeIdx);
+                // blockedEdges acts as cache that is only useful when filled and for non-virtual edges
+                if (!blockedEdges.isEmpty() && edgeState.getEdge() < baseEdgeCount) {
+                    if (blockedEdges.contains(edgeState.getEdge()))
+                        return true;
+                    continue;
+                }
+
+                // compromise: mostly avoid expensive fetchWayGeometry which isn't yet fast for being used in Weighting.calc
+                BBox bbox = createBBox(na, edgeState);
+                Shape shape = blockedShapes.get(shapeIdx);
                 if (shape.getBounds().intersects(bbox)) {
                     if (pointList == null)
                         pointList = edgeState.fetchWayGeometry(3).makeImmutable();
@@ -249,5 +228,19 @@ public class GraphEdgeIdFinder {
             }
             return false;
         }
+
+        public BlockArea setQueryGraph(QueryGraph queryGraph) {
+            if (prepared)
+                throw new IllegalStateException("setGraph cannot be called multiple times");
+
+            prepared = true;
+            na = queryGraph.getNodeAccess();
+            return this;
+        }
+    }
+
+    private static BBox createBBox(NodeAccess na, EdgeIteratorState edgeState) {
+        return BBox.fromPoints(na.getLatitude(edgeState.getBaseNode()), na.getLongitude(edgeState.getBaseNode()),
+                na.getLatitude(edgeState.getAdjNode()), na.getLongitude(edgeState.getAdjNode()));
     }
 }
\ No newline at end of file
diff --git a/web-bundle/src/main/java/com/graphhopper/resources/IsochroneResource.java b/web-bundle/src/main/java/com/graphhopper/resources/IsochroneResource.java
index 7e399968e..78dced27b 100644
--- a/web-bundle/src/main/java/com/graphhopper/resources/IsochroneResource.java
+++ b/web-bundle/src/main/java/com/graphhopper/resources/IsochroneResource.java
@@ -9,10 +9,13 @@ import com.graphhopper.isochrone.algorithm.Isochrone;
 import com.graphhopper.json.geo.JsonFeature;
 import com.graphhopper.routing.querygraph.QueryGraph;
 import com.graphhopper.routing.util.*;
+import com.graphhopper.routing.weighting.BlockAreaWeighting;
 import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Graph;
+import com.graphhopper.storage.GraphEdgeIdFinder;
 import com.graphhopper.storage.index.LocationIndex;
 import com.graphhopper.storage.index.QueryResult;
+import com.graphhopper.util.Parameters;
 import com.graphhopper.util.StopWatch;
 import com.graphhopper.util.shapes.GHPoint;
 import org.locationtech.jts.geom.*;
@@ -29,10 +32,7 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
 
 import static com.graphhopper.routing.weighting.TurnCostProvider.NO_TURN_COST_PROVIDER;
 
@@ -74,9 +74,8 @@ public class IsochroneResource {
         if (!encodingManager.hasEncoder(vehicle))
             throw new IllegalArgumentException("vehicle not supported:" + vehicle);
 
-        if (respType != null && !respType.equalsIgnoreCase("json") && !respType.equalsIgnoreCase("geojson")) {
+        if (respType != null && !respType.equalsIgnoreCase("json") && !respType.equalsIgnoreCase("geojson"))
             throw new IllegalArgumentException("Format not supported:" + respType);
-        }
 
         FlagEncoder encoder = encodingManager.getEncoder(vehicle);
         EdgeFilter edgeFilter = DefaultEdgeFilter.allEdges(encoder);
@@ -93,6 +92,9 @@ public class IsochroneResource {
 
         // todo: isochrones with turn costs ?
         Weighting weighting = graphHopper.createWeighting(hintsMap, encoder, NO_TURN_COST_PROVIDER);
+        if (hintsMap.has(Parameters.Routing.BLOCK_AREA))
+            weighting = new BlockAreaWeighting(weighting, GraphEdgeIdFinder.createBlockArea(graph, locationIndex,
+                    Collections.singletonList(point), hintsMap, DefaultEdgeFilter.allEdges(encoder)));
         Isochrone isochrone = new Isochrone(queryGraph, weighting, reverseFlow);
 
         if (distanceInMeter > 0) {
diff --git a/web-bundle/src/main/java/com/graphhopper/resources/SPTResource.java b/web-bundle/src/main/java/com/graphhopper/resources/SPTResource.java
index ccef84596..6a669d9e0 100644
--- a/web-bundle/src/main/java/com/graphhopper/resources/SPTResource.java
+++ b/web-bundle/src/main/java/com/graphhopper/resources/SPTResource.java
@@ -5,8 +5,10 @@ import com.graphhopper.isochrone.algorithm.Isochrone;
 import com.graphhopper.routing.profiles.*;
 import com.graphhopper.routing.querygraph.QueryGraph;
 import com.graphhopper.routing.util.*;
+import com.graphhopper.routing.weighting.BlockAreaWeighting;
 import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.Graph;
+import com.graphhopper.storage.GraphEdgeIdFinder;
 import com.graphhopper.storage.index.LocationIndex;
 import com.graphhopper.storage.index.QueryResult;
 import com.graphhopper.util.*;
@@ -24,10 +26,7 @@ import java.io.BufferedWriter;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import static com.graphhopper.routing.weighting.TurnCostProvider.NO_TURN_COST_PROVIDER;
 
@@ -81,6 +80,10 @@ public class SPTResource {
 
         // todo: /spt with turn costs ?
         Weighting weighting = graphHopper.createWeighting(hintsMap, encoder, NO_TURN_COST_PROVIDER);
+        if (hintsMap.has(Parameters.Routing.BLOCK_AREA))
+            weighting = new BlockAreaWeighting(weighting, GraphEdgeIdFinder.createBlockArea(graph, locationIndex,
+                    Collections.singletonList(point), hintsMap, DefaultEdgeFilter.allEdges(encoder)));
+
         Isochrone isochrone = new Isochrone(queryGraph, weighting, reverseFlow);
 
         if (distanceInMeter > 0) {


Test patch:
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 19c2f6c9b..2fb8d461a 100644
--- a/core/src/test/java/com/graphhopper/routing/util/BikeFlagEncoderTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/BikeFlagEncoderTest.java
@@ -65,6 +65,10 @@ public class BikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
         assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
 
+        way.clearTags();
+        way.setTag("highway", "path");
+        assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
+
         way.clearTags();
         way.setTag("highway", "secondary");
         way.setTag("bicycle", "dismount");
@@ -74,33 +78,36 @@ public class BikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         way.clearTags();
         way.setTag("highway", "footway");
         way.setTag("bicycle", "yes");
-        assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
+        assertEquals(10, encoder.getSpeed(way));
         assertPriority(PREFER.getValue(), way);
         way.setTag("segregated", "no");
-        assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
+        assertEquals(10 , encoder.getSpeed(way));
         assertPriority(PREFER.getValue(), way);
         way.setTag("segregated", "yes");
-        assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
+        assertEquals(18, encoder.getSpeed(way));
         assertPriority(PREFER.getValue(), way);
 
         way.clearTags();
         way.setTag("highway", "footway");
         way.setTag("surface", "paved");
         way.setTag("bicycle", "yes");
-        assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
+        assertEquals(10, encoder.getSpeed(way));
+        way.setTag("surface", "cobblestone");
+        assertEquals(8, encoder.getSpeed(way));
         assertPriority(PREFER.getValue(), way);
         way.setTag("segregated", "yes");
-        assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
+        way.setTag("surface", "paved");
+        assertEquals(18, encoder.getSpeed(way));
         assertPriority(PREFER.getValue(), way);
 
         way.clearTags();
         way.setTag("highway", "platform");
         way.setTag("surface", "paved");
         way.setTag("bicycle", "yes");
-        assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
+        assertEquals(10, encoder.getSpeed(way));
         assertPriority(PREFER.getValue(), way);
         way.setTag("segregated", "yes");
-        assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
+        assertEquals(18, encoder.getSpeed(way));
         assertPriority(PREFER.getValue(), way);
 
         way.clearTags();
@@ -140,18 +147,18 @@ public class BikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         assertPriority(VERY_NICE.getValue(), way);
 
         way.setTag("bicycle", "yes");
-        assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
+        assertEquals(10, encoder.getSpeed(way));
         assertPriority(PREFER.getValue(), way);
 
         way.setTag("segregated", "yes");
-        assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
+        assertEquals(cyclewaySpeed, encoder.getSpeed(way));
         assertPriority(PREFER.getValue(), way);
 
         way.setTag("surface", "unpaved");
-        assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
+        assertEquals(14, encoder.getSpeed(way));
 
         way.setTag("surface", "paved");
-        assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
+        assertEquals(cyclewaySpeed, encoder.getSpeed(way));
 
         way.clearTags();
         way.setTag("highway", "path");
@@ -238,7 +245,7 @@ public class BikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
         way.clearTags();
         way.setTag("highway", "path");
         way.setTag("surface", "ground");
-        assertEquals(4, encoder.getSpeed(way));
+        assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
         assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
 
         way.clearTags();
diff --git a/core/src/test/java/com/graphhopper/routing/weighting/BlockAreaWeightingTest.java b/core/src/test/java/com/graphhopper/routing/weighting/BlockAreaWeightingTest.java
index dc06c6073..214a50927 100644
--- a/core/src/test/java/com/graphhopper/routing/weighting/BlockAreaWeightingTest.java
+++ b/core/src/test/java/com/graphhopper/routing/weighting/BlockAreaWeightingTest.java
@@ -1,11 +1,18 @@
 package com.graphhopper.routing.weighting;
 
+import com.graphhopper.coll.GHIntHashSet;
+import com.graphhopper.routing.querygraph.QueryGraph;
 import com.graphhopper.routing.util.CarFlagEncoder;
+import com.graphhopper.routing.util.EdgeFilter;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.FlagEncoder;
-import com.graphhopper.storage.Graph;
 import com.graphhopper.storage.GraphBuilder;
 import com.graphhopper.storage.GraphEdgeIdFinder;
+import com.graphhopper.storage.GraphHopperStorage;
+import com.graphhopper.storage.index.LocationIndex;
+import com.graphhopper.storage.index.LocationIndexTree;
+import com.graphhopper.storage.index.QueryResult;
+import com.graphhopper.util.EdgeIterator;
 import com.graphhopper.util.EdgeIteratorState;
 import com.graphhopper.util.shapes.Circle;
 import org.junit.Before;
@@ -20,7 +27,7 @@ public class BlockAreaWeightingTest {
 
     private FlagEncoder encoder = new CarFlagEncoder();
     private EncodingManager em;
-    private Graph graph;
+    private GraphHopperStorage graph;
 
     @Before
     public void setUp() {
@@ -40,7 +47,8 @@ public class BlockAreaWeightingTest {
         BlockAreaWeighting instance = new BlockAreaWeighting(new FastestWeighting(encoder), bArea);
         assertEquals(94.35, instance.calcEdgeWeight(edge, false), .01);
 
-        bArea.add(0);
+        GHIntHashSet set = bArea.add(null);
+        set.add(0);
         instance = new BlockAreaWeighting(new FastestWeighting(encoder), bArea);
         assertEquals(Double.POSITIVE_INFINITY, instance.calcEdgeWeight(edge, false), .01);
     }
@@ -62,10 +70,27 @@ public class BlockAreaWeightingTest {
         assertEquals(94.35, instance.calcEdgeWeight(edge, false), .01);
     }
 
-
     @Test
-    public void testNullGraph() {
-        // TODO is there an equivalent to check?
-        // BlockAreaWeighting weighting = new BlockAreaWeighting(new FastestWeighting(encoder));
+    public void testBlockVirtualEdges_QueryGraph() {
+        GraphEdgeIdFinder.BlockArea bArea = new GraphEdgeIdFinder.BlockArea(graph);
+        // add base graph edge to fill caches and trigger edgeId cache search (without virtual edges)
+        GHIntHashSet set = bArea.add(new Circle(0.0025, 0.0025, 1));
+        set.add(0);
+
+        LocationIndex index = new LocationIndexTree(graph, graph.getDirectory()).prepareIndex();
+        QueryResult qr = index.findClosest(0.005, 0.005, EdgeFilter.ALL_EDGES);
+        QueryGraph queryGraph = QueryGraph.lookup(graph, qr);
+        bArea.setQueryGraph(queryGraph);
+
+        BlockAreaWeighting instance = new BlockAreaWeighting(new FastestWeighting(encoder), bArea);
+        EdgeIterator iter = queryGraph.createEdgeExplorer().setBaseNode(qr.getClosestNode());
+        int blockedEdges = 0, totalEdges = 0;
+        while (iter.next()) {
+            if (Double.isInfinite(instance.calcEdgeWeight(iter, false)))
+                blockedEdges++;
+            totalEdges++;
+        }
+        assertEquals(1, blockedEdges);
+        assertEquals(2, totalEdges);
     }
 }
\ No newline at end of file
diff --git a/core/src/test/java/com/graphhopper/storage/GraphEdgeIdFinderTest.java b/core/src/test/java/com/graphhopper/storage/GraphEdgeIdFinderTest.java
index e943535d9..3b4af4a78 100644
--- a/core/src/test/java/com/graphhopper/storage/GraphEdgeIdFinderTest.java
+++ b/core/src/test/java/com/graphhopper/storage/GraphEdgeIdFinderTest.java
@@ -17,7 +17,6 @@
  */
 package com.graphhopper.storage;
 
-import com.graphhopper.coll.GHIntHashSet;
 import com.graphhopper.routing.util.*;
 import com.graphhopper.storage.index.LocationIndex;
 import com.graphhopper.storage.index.LocationIndexTree;
@@ -59,14 +58,12 @@ public class GraphEdgeIdFinderTest {
 
         GraphEdgeIdFinder graphFinder = new GraphEdgeIdFinder(graph, locationIndex);
         GraphEdgeIdFinder.BlockArea blockArea = graphFinder.parseBlockArea("0.01,0.005,1", DefaultEdgeFilter.allEdges(encoder), 1000 * 1000);
-        assertEquals("[0]", blockArea.blockedEdges.toString());
-        assertFalse(blockArea.blockedShapes.isEmpty());
+        assertEquals("[0]", blockArea.toString(0));
 
         // big area => no edgeIds are collected up-front
         graphFinder = new GraphEdgeIdFinder(graph, locationIndex);
         blockArea = graphFinder.parseBlockArea("0,0,1000", DefaultEdgeFilter.allEdges(encoder), 1000 * 1000);
-        assertEquals("[]", blockArea.blockedEdges.toString());
-        assertFalse(blockArea.blockedShapes.isEmpty());
+        assertFalse(blockArea.hasCachedEdgeIds(0));
     }
 
     @Test
@@ -114,15 +111,17 @@ public class GraphEdgeIdFinderTest {
         // big value => the polygon is small => force edgeId optimization
         double area = 500_000L * 500_000L;
         GraphEdgeIdFinder.BlockArea blockArea = graphFinder.parseBlockArea("2.1,1, -1.1,2, 2,3", DefaultEdgeFilter.allEdges(encoder), area);
-        GHIntHashSet blockedEdges = new GHIntHashSet();
-        blockedEdges.addAll(1, 2, 6, 7, 11, 12);
-        assertEquals(blockedEdges, blockArea.blockedEdges);
+        assertEquals("[1, 2, 6, 7, 11, 12]", blockArea.toString(0));
         assertEdges(graph, "[1, 2, 6, 7, 11, 12]", blockArea);
 
         // small value => same polygon is now "large" => do not pre-calculate edgeId set => check only geometries
         blockArea = graphFinder.parseBlockArea("2.1,1, 0.9,3, 0.9,2, -0.3,0", DefaultEdgeFilter.allEdges(encoder), 1000 * 1000);
-        assertEquals("[]", blockArea.blockedEdges.toString());
+        assertFalse(blockArea.hasCachedEdgeIds(0));
         assertEdges(graph, "[0, 1, 4, 5, 6, 7, 9, 10]", blockArea);
+
+        blockArea = graphFinder.parseBlockArea("1.5,3,100000", DefaultEdgeFilter.allEdges(encoder), area);
+        assertEquals("[2, 7]", blockArea.toString(0));
+        assertEdges(graph, "[2, 7]", blockArea);
     }
 
     private void assertEdges(Graph g, String assertSetContent, GraphEdgeIdFinder.BlockArea blockArea) {
diff --git a/core/src/test/java/com/graphhopper/storage/change/ChangeGraphHelperTest.java b/core/src/test/java/com/graphhopper/storage/change/ChangeGraphHelperTest.java
index 837d4d896..11054b017 100644
--- a/core/src/test/java/com/graphhopper/storage/change/ChangeGraphHelperTest.java
+++ b/core/src/test/java/com/graphhopper/storage/change/ChangeGraphHelperTest.java
@@ -72,7 +72,7 @@ public class ChangeGraphHelperTest {
         ChangeGraphHelper instance = new ChangeGraphHelper(graph, locationIndex);
         JsonFeatureCollection collection = Jackson.newObjectMapper().readValue(reader, JsonFeatureCollection.class);
         long updates = instance.applyChanges(encodingManager, collection.getFeatures());
-        assertEquals(2, updates);
+        assertEquals(3, updates);
 
         // assert changed speed and access
         double newSpeed = GHUtility.getEdge(graph, 0, 1).get(avSpeedEnc);
diff --git a/core/src/test/resources/com/graphhopper/storage/change/overlaydata1.json b/core/src/test/resources/com/graphhopper/storage/change/overlaydata1.json
index ee7dd2b70..05ffa679a 100644
--- a/core/src/test/resources/com/graphhopper/storage/change/overlaydata1.json
+++ b/core/src/test/resources/com/graphhopper/storage/change/overlaydata1.json
@@ -17,7 +17,7 @@
         {
             "id": "2",
             "type": "Feature",
-            "bbox": [-0.01, -0.01, 0.015, 0.005],
+            "bbox": [-0.01, -0.01, 0.005, 0.005],
             "properties": {
                 "access": false,
                 "assert_nodes": [3, 4]
diff --git a/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java b/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
index 39ec09736..ebad3dace 100644
--- a/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
+++ b/reader-osm/src/test/java/com/graphhopper/GraphHopperIT.java
@@ -499,12 +499,10 @@ public class GraphHopperIT {
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
         assertEquals(12173, rsp.getBest().getDistance(), 1);
 
-        // TODO after #1324 this will work and should block both roads and return 12173m, currently it still routes
-        //  through one of the roads due to "disconnected" roads
-        req.getHints().put(Routing.BLOCK_AREA, "49.981502,11.51762,80");
+        req.getHints().put(Routing.BLOCK_AREA, "49.980868,11.516397,150");
         rsp = hopper.route(req);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
-        assertEquals(7383, rsp.getBest().getDistance(), 1);
+        assertEquals(12173, rsp.getBest().getDistance(), 1);
 
         // block by edge IDs -> i.e. use small rectangular area
         req.getHints().put(Routing.BLOCK_AREA, "49.981875,11.515818,49.979522,11.521407");
@@ -519,8 +517,7 @@ public class GraphHopperIT {
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
         assertEquals(1807, rsp.getBest().getDistance(), 1);
 
-        // block point 49.985759,11.50687
-        req.getHints().put(Routing.BLOCK_AREA, "50.018274,11.492558");
+        req.getHints().put(Routing.BLOCK_AREA, "50.018277,11.492336");
         rsp = hopper.route(req);
         assertFalse(rsp.getErrors().toString(), rsp.hasErrors());
         assertEquals(3363, rsp.getBest().getDistance(), 1);
diff --git a/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java b/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java
index 60d9f2b7a..faca74397 100644
--- a/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java
+++ b/reader-osm/src/test/java/com/graphhopper/routing/RoutingAlgorithmWithOSMIT.java
@@ -401,8 +401,7 @@ public class RoutingAlgorithmWithOSMIT {
     public void testKremsBikeRelation() {
         List<OneRun> list = new ArrayList<>();
         list.add(new OneRun(48.409523, 15.602394, 48.375466, 15.72916, 12491, 159));
-        // 3109m is better as cyclepath is used
-        list.add(new OneRun(48.410061, 15.63951, 48.411386, 15.604899, 3112, 87));
+        list.add(new OneRun(48.410061, 15.63951, 48.411386, 15.604899, 3077, 79));
         list.add(new OneRun(48.412294, 15.62007, 48.398306, 15.609667, 3965, 94));
 
         runAlgo(testCollector, DIR + "/krems.osm.gz", "target/krems-gh",
diff --git a/web/src/test/java/com/graphhopper/http/resources/IsochroneResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/IsochroneResourceTest.java
index 28ca470c4..72a8c3b9e 100644
--- a/web/src/test/java/com/graphhopper/http/resources/IsochroneResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/IsochroneResourceTest.java
@@ -34,6 +34,7 @@ import org.locationtech.jts.geom.GeometryFactory;
 import javax.ws.rs.core.Response;
 import java.io.File;
 
+import static com.graphhopper.util.Parameters.Routing.BLOCK_AREA;
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertEquals;
@@ -64,7 +65,7 @@ public class IsochroneResourceTest {
     @Test
     public void requestByTimeLimit() {
         Response rsp = app.client().target("http://localhost:8080/isochrone")
-                .queryParam("point","42.531073,1.573792")
+                .queryParam("point", "42.531073,1.573792")
                 .queryParam("time_limit", 5 * 60)
                 .queryParam("buckets", 2)
                 .queryParam("type", "geojson")
@@ -85,7 +86,7 @@ public class IsochroneResourceTest {
     @Test
     public void requestByDistanceLimit() {
         Response rsp = app.client().target("http://localhost:8080/isochrone")
-                .queryParam("point","42.531073,1.573792")
+                .queryParam("point", "42.531073,1.573792")
                 .queryParam("distance_limit", 3_000)
                 .queryParam("buckets", 2)
                 .queryParam("type", "geojson")
@@ -106,7 +107,7 @@ public class IsochroneResourceTest {
     @Test
     public void requestReverseFlow() {
         Response rsp = app.client().target("http://localhost:8080/isochrone")
-                .queryParam("point","42.531073,1.573792")
+                .queryParam("point", "42.531073,1.573792")
                 .queryParam("reverse_flow", true)
                 .queryParam("time_limit", 5 * 60)
                 .queryParam("buckets", 2)
@@ -137,7 +138,7 @@ public class IsochroneResourceTest {
     @Test
     public void requestWithShortest() {
         Response rsp = app.client().target("http://localhost:8080/isochrone")
-                .queryParam("point","42.509644,1.540554")
+                .queryParam("point", "42.509644,1.540554")
                 .queryParam("time_limit", 130)
                 .queryParam("buckets", 1)
                 .queryParam("weighting", "shortest")
@@ -155,7 +156,7 @@ public class IsochroneResourceTest {
         assertTrue(polygon0.getCoordinates().length < 185);
 
         rsp = app.client().target("http://localhost:8080/isochrone")
-                .queryParam("point","42.509644,1.540554")
+                .queryParam("point", "42.509644,1.540554")
                 .queryParam("time_limit", 130)
                 .queryParam("buckets", 1)
                 .queryParam("weighting", "fastest")
@@ -165,7 +166,7 @@ public class IsochroneResourceTest {
         polygon0 = featureCollection.getFeatures().get(0).getGeometry();
         assertTrue(polygon0.getCoordinates().length >= 190);
     }
-    
+
     @Test
     public void requestJsonBadType() {
         Response response = app.client().target("http://localhost:8080/isochrone?point=42.531073,1.573792&time_limit=130&type=xml")
@@ -176,8 +177,31 @@ public class IsochroneResourceTest {
 
         assertEquals(message, "Format not supported:xml");
     }
-    
-    
+
+    @Test
+    public void requestWithBlockArea() {
+        Response rsp = app.client().target("http://localhost:8080/isochrone")
+                .queryParam("point", "42.531073,1.573792")
+                .queryParam("time_limit", 5 * 60)
+                .queryParam("buckets", 2)
+                .queryParam("type", "geojson")
+                .queryParam(BLOCK_AREA, "42.558067,1.589429,100")
+                .request().buildGet().invoke();
+        JsonFeatureCollection featureCollection = rsp.readEntity(JsonFeatureCollection.class);
+
+        assertEquals(2, featureCollection.getFeatures().size());
+        Geometry polygon0 = featureCollection.getFeatures().get(0).getGeometry();
+        Geometry polygon1 = featureCollection.getFeatures().get(1).getGeometry();
+
+        assertTrue(polygon0.contains(geometryFactory.createPoint(new Coordinate(1.587224, 42.5386))));
+        assertFalse(polygon0.contains(geometryFactory.createPoint(new Coordinate(1.589756, 42.558012))));
+
+        assertFalse(polygon1.contains(geometryFactory.createPoint(new Coordinate(1.589756, 42.558012))));
+        assertFalse(polygon1.contains(geometryFactory.createPoint(new Coordinate(1.635246, 42.53841))));
+
+        assertTrue(polygon1.contains(geometryFactory.createPoint(new Coordinate(1.58864, 42.554582))));
+    }
+
     @Test
     public void requestJsonWithType() {
         Response response = app.client().target("http://localhost:8080/isochrone?point=42.531073,1.573792&time_limit=130&type=json")
@@ -186,7 +210,7 @@ public class IsochroneResourceTest {
         assertTrue(json.has("polygons"));
         assertTrue(json.has("info"));
     }
-    
+
     @Test
     public void requestJsonNoType() {
         Response response = app.client().target("http://localhost:8080/isochrone?point=42.531073,1.573792&time_limit=130")