CoursesGIS Basics — A Complete Introduction10.4 Distance and Cost Surfaces
Module 10: Raster Analysis

10.4 Distance and Cost Surfaces

From straight-line proximity rasters to cost-weighted least-cost paths.

Lesson 53 of 100·17 min read

Key takeaways

  • A distance surface gives every cell its distance to the nearest feature.
  • A cost surface encodes how expensive movement through each cell is.
  • Least-cost paths combine both to find the "easiest" route through a landscape.

Introduction

Continuous-surface questions often need continuous-surface answers. How far from the nearest road is every point in the park? What route minimises elevation gain, vegetation density, and water crossings? Distance and cost surfaces answer these at raster scale.

Euclidean distance surface

Every cell gets the distance (in metres or CRS units) to the nearest source feature.

GDAL

Shell
gdal_proximity.py roads.tif dist.tif -values 1 -distunits GEO

Python

Python
from scipy.ndimage import distance_transform_edt

Earth Engine

JavaScript
var dist = roads.distance(50000, 'meters');

Uses: buffers-as-continuous-values, service-area gradient maps, habitat proximity metrics.

Cost surface

A cost surface assigns each cell a cost per unit distance reflecting how hard movement through it is:

  • Steep slope → high cost.
  • Dense vegetation → high cost.
  • Open road → low cost.
  • Water → impassable (infinite) or very high.

Combine inputs linearly or through a weighted sum:

Python
cost = 1.0 + 2.0 * slope_normalised + 5.0 * water_mask

Scale each input to a comparable range (0–1 or class scores) before summing; otherwise a raw variable dominates.

Cost-distance / accumulated-cost surface

Accumulated cost from a source to every cell — i.e., the least-cost distance on a cost-weighted raster. Uses an algorithm similar to Dijkstra's but on a grid.

Python
1from skimage.graph import route_through_array
2[object Object]
3[object Object]
4

Tools:

  • GRASS r.cost, r.walk.
  • ArcGIS Spatial Analyst Cost Distance.
  • QGIS Least-cost path.
  • Python: scikit-image route_through_array, pyrouting (network-based).

Least-cost path

From the accumulated-cost surface, back-trace from a destination to a source along the gradient — the path of minimum accumulated cost.

Applications:

  • Wildlife corridor design.
  • Utility line routing.
  • Logistics through unstructured terrain.
  • Pedestrian routing where no network data exists.

Anisotropic cost

Some costs depend on direction of travel. Classic example: climbing uphill vs going downhill has different energy costs per metre. Tobler's hiking function:

$$v = 6 e^{-3.5 |s + 0.05|}$$

(where s is slope, returns km/h). GRASS's r.walk implements this.

Euclidean vs network vs cost surface

MethodProsCons
EuclideanSimple, fastIgnores obstacles
NetworkRealistic for roadsRequires network data
Cost surfaceWorks off-roadMore input data needed

Choose based on data availability and realism required.

Multi-source / multi-destination

"Distance to the nearest of many sources":

Python
1all_sources = roads_mask | schools_mask | hospitals_mask
2distance = distance_transform_edt(~all_sources) * cell_size

Time surfaces

Convert cost surface (per-cell minutes) into an accumulated time surface. Gives you walking-time isochrones ("everywhere within 30 min"), useful where no road network exists or you want to include terrain.

Pitfalls

  • Diagonal vs straight connectivity — allowing diagonal movement vs only cardinal (4 vs 8 neighbours) subtly changes distances. Use fully_connected=True for 8-way.
  • Resolution — coarse cells underestimate distance (diagonals are discretised).
  • Cost weighting — arbitrary weights yield arbitrary paths; calibrate with real observations if possible.
  • Barriers — model impassable features with very high cost rather than nodata to allow paths to route around.

Self-check exercises

1. You need "distance to the nearest road" as a raster across a 100 × 100 km area. Which tool / approach?

gdal_proximity.py on a rasterised road mask, at the same resolution and CRS as your analysis raster. For a metric CRS at 30 m resolution, this takes seconds. In Earth Engine, roads.distance(50000) is the equivalent. Always use a projected CRS to get metre distances.

2. Why use a cost surface instead of straight-line distance for wildlife corridor analysis?

Wildlife movement depends on habitat quality, not geometric distance. A river, a highway, or dense human development may be effectively impassable despite being geographically short. A cost surface encoding these constraints produces corridors that real animals can use — Euclidean paths might cross a highway that no animal would.

3. A least-cost path in your analysis clings unrealistically to one cell column. What's likely wrong?

(1) Diagonal movement isn't enabled (fully_connected=True). (2) Cost weights are too extreme (one variable dominates, forcing paths along a narrow ridge). (3) Resolution is too coarse — real paths "see" obstacles differently at different scales. (4) Source / destination points may have been snapped into a no-data or infinite-cost cell.

Summary

  • Distance surfaces are proximity-as-raster.
  • Cost surfaces encode variable movement difficulty per cell.
  • Accumulated-cost + back-trace yields least-cost paths.
  • Tobler's hiking function and anisotropic costs model realistic movement.

Further reading

  • Tobler, W. (1993) — Three presentations on geographical analysis and modeling.
  • GRASS r.cost, r.walk documentation.
  • Quantitative Methods in Landscape Ecology — Turner & Gardner.
  • scikit-image route_through_array documentation.