# Buffering with obstacles

I want to analyse parks for their reachability by foot, and I thought of doing that with a buffer around the parks (more than 300 in total). Now the problem is, that in cities usually there are boundaries that cant be crossed or only at very specific spots. So I would like to create a buffer that is limited by these boundaries, but where they are open, it should still expand according to the maximum distance given to the buffer. I think it can be easily understood from the picture below. I'd need the polygons for further analyses like the amount of people living in the parks vicinity.

Any tips on how to approach that?

• You're looking for travel distances instead of usual buffers. Those require a network to literally run on.
– Erik
Mar 24, 2021 at 15:57

There are two possibility that come to mind.

The first is to use isochrone instead of buffer (there numerous online service that will calculate them for you, some of them are discussed here). As isochrone are calculated using street network the result will account for uncrossable boundaries. the problems with this solution are:

• Pedestrian can wander outside of the street network (think crossing a plazza diagonally or walking on grass where there are no really a path) introducing some error
• Isochrone are generally calculated from a point while your park may not have an obvious entrance point if they are not fenced (if they are relatively small a point in the center could work)

The second solution is to use a cost distance analysis where your cost raster is set to 1 for walkable area and to no data for obstacle effectively preventing crossing. The advantage of this approach is that you are not constrain by the street network and get a model that's closer to real foot walking, the difficulty is the creation of the cost raster by identifying all non accessible area for pedestrian.

• Nice icon (probably a new one) =) Mar 24, 2021 at 16:34
• Finally, the map cost distance worked very nicely for my purpose. And, as i had access to a complete surface coverage layer, it was even possible to assign different costs to different surfaces, making my model much more precise than i wanted it to be! So thanks! You showed me a tool which will come in handy more often i think ;). Jun 2, 2021 at 14:16

EDIT : Faster processing direcly with geometries

From :

To :

With (description in the code comments) :

``````def buffer_dist(lyr_input, distance: int):
"""Create a buffer from the lyr_input at distance"""
result = processing.run(
"native:buffer",
{
"INPUT": lyr_input,
"DISTANCE": distance,
"SEGMENTS": 30,
"END_CAP_STYLE": 0,
"JOIN_STYLE": 0,
"MITER_LIMIT": 2,
"DISSOLVE": False,
"OUTPUT": 'TEMPORARY_OUTPUT'
}
)
return result["OUTPUT"]

def diff(lyr_input, lyr_overlay):
"""Make a diffence between lyr_input and lyr_overlay"""
result = processing.run(
"native:difference",
{
"INPUT": lyr_input,
"OVERLAY": lyr_overlay,
"OUTPUT": "TEMPORARY_OUTPUT"
}
)
return result["OUTPUT"]

# init the start layer, can be points, lines, polygons
# layer named in my QGIS project: "start"
lyr_start = QgsProject.instance().mapLayersByName("start")[0]
# init layer with obstacles, in my case a line layer
# layer named in my QGIS project: "obstacle"
lyr_obstacle = QgsProject.instance().mapLayersByName("obstacle")[0]
# if layer with obstacles is a line layer, create a small buffer around
lyr_obstacle_buffered = buffer_dist(lyr_obstacle, 1)
# set the walking distance
walking_distance = 100

result = lyr_start
# to each loop, add 1 unit until walking_distance
for i in range(walking_distance):
# add a buffer of 1 unit
result = buffer_dist(result, 1)
# make a buffer at 0 units to make the geometry valid
result = buffer_dist(result, 0)
# make a difference between the buffer and the obstacles
result = diff(result, lyr_obstacle_buffered)

# finally, add result in the project
``````

Fast version :

``````# init the start layer, can be points, lines, polygons
# layer named in my QGIS project: "start"
lyr_start = QgsProject.instance().mapLayersByName("start")[0]
# init layer with obstacles, in my case a line layer
# layer named in my QGIS project: "obstacle"
lyr_obstacle = QgsProject.instance().mapLayersByName("obstacle")[0]
# set the walking distance
walking_distance = 100
# create a red transparent rubberband to display result
rubber = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry)
rubber.setFillColor(QColor(255, 0, 0, 200))

# create the obstacle buffer
for i, obstacle_feat in enumerate(lyr_obstacle.getFeatures()):
# first loop, create the buffer from first line
if i == 0:
obstacles = obstacle_feat.geometry().buffer(1.1, 30)
# for the next loops, combine the buffer with the previous obstacles geometry
else:
obstacles = obstacles.combine(obstacle_feat.geometry().buffer(1.1, 30))

# iterate over start layer features
for start_feat in lyr_start.getFeatures():
# init walking_buff
walking_buff = start_feat.geometry()
# to each loop, add 1 unit until walking_distance
for j in range(walking_distance):
# add a buffer of 1 unit
walking_buff = walking_buff.buffer(1, 30)
# make the geometry valid
walking_buff = walking_buff.makeValid()
# make a difference between the buffer and the obstacles
walking_buff = walking_buff.difference(obstacles)
# add walking buffer to the rubberband