4

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?

The buffer doesnt pass the linar object, but at openingsit passes through

1
  • 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

3 Answers 3

4

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.

2
  • 1
    Nice icon (probably a new one) =)
    – Taras
    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 ;).
    – Sev_Zide
    Jun 2, 2021 at 14:16
4

EDIT : Faster processing direcly with geometries

From :

start configuration

To :

result

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
QgsProject.instance().addMapLayer(result)

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
    rubber.addGeometry(walking_buff, lyr_start.crs())
2

An alternative technique using standard spatial analyst tools in Arcpro or ArcMap is to use the Euclidean distance tool and set the lines as barriers and a maximum distance. This would create such a dataset

Euclidean distance raster

Then using the CON tool convert all distances below your threshold distance to 1 and everything else 0 or nodata. In the example below all cells less than 4Km away are coded up as 1 (light brown).

Distance

No code or network analysis required and could easily be bundled up in a model.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.