Spatial relations

A spatial relation (or spatial predicate) is a yes-or-no question about two geometries: does A contain B? Do they touch? Selection by location, summary by location and every join by location depend on one. The relations are defined in the OGC Simple Features standard, and the same set appears, with nearly the same names, in most GIS software: as tick boxes in QGIS, as functions in spatial SQL (ST_Intersects, ST_Contains, … in PostGIS and in GeoPackage/SpatiaLite), as predicate= in GeoPandas. ArcGIS’s Select Layer By Location uses its own names and adds some, such as have their center in.

Interior, boundary and exterior

Each relation is defined by how the interior, boundary and exterior of A and B meet (the dimensionally extended nine-intersection model, DE-9IM).

GeometryInteriorBoundary
Pointthe point itselfnone
Linethe line without its two end pointsthe two end points
Polygonthe area inside the outlinethe outline

Everything else is the exterior. The boundary causes most surprises: a point lying exactly on a polygon’s outline is not inside it.

The relations

QGISSQL”A … B” is true whenDirection
intersectST_IntersectsA and B have at least one point in common, interior or boundarysymmetric
disjointST_DisjointA and B have no point in common: the opposite of intersectsymmetric
containST_Containsno part of B lies outside A, and their interiors meetA contains B = B is within A
are withinST_Withinno part of A lies outside B, and their interiors meetA is within B = B contains A
equalST_EqualsA and B are the same shape: each lies within the othersymmetric
touchST_TouchesA and B meet only at their boundaries; their interiors do not meetsymmetric
overlapST_OverlapsA and B have the same dimension (two polygons, two lines), share part of their interiors, and each also has a part outside the othersymmetric
crossST_Crossestheir interiors meet, but in something of lower dimension: a line passing in and out of a polygon, two lines crossing at a pointsymmetric

Spatial SQL also has ST_Covers and ST_CoveredBy: like contain and within, but a B lying only on A’s boundary counts too. The QGIS dialogs do not offer them.

Reading the QGIS dialog

QGIS’s location tools read as a sentence: [features in the first layer] [relation] [features in the second layer]. In Join attributes by location (summary):

Join to features in roder — where the features contain — by comparing to boliger

asks for each rode which dwellings it contains. Ticking are within instead asks whether a rode lies within a dwelling point. That is never true, so every rode gets a count of 0, without any warning. Ticking several boxes means or: a feature is matched if any of the ticked relations holds.

First layerSecond layerRelation
zonespointscontain or intersect
pointszonesare within or intersect
zoneslines (roads, streams)intersect: any part in the zone; contain: the whole line in the zone; cross: passes through the zone’s outline
zonespolygons (buildings, fields)intersect: any part in the zone; contain: wholly in the zone; overlap: partly in the zone
polygonspolygons of the same layertouch: the neighbours

Points on a border

Two square zones, A and B, side by side, and four points: one inside A, one on the border between A and B, one on A’s outer edge and one outside both. In QGIS 4.2.2, Join attributes by location (summary) with the zones as the first layer gives:

Pointintersectcontaintouch
inside AAA—
on the border between A and BA and BneitherA and B
on A’s outer edgeAnoneA
outside both———

So intersect counts a point on a shared border in both zones, and contain counts it in none: either way the counts no longer add up to the number of points. Touch finds exactly the points on borders, which makes it a check.

With real coordinates, exact border positions are rare. None of Copenhagen’s 349,743 dwelling address points lies on the border of a rode, kvarter or bydel, and intersect and contain give the same counts (example data). The choice matters when points lie on lines by construction: points snapped to a road centre line or a plot boundary, or coordinates rounded to whole metres counted in a grid whose edges lie on whole metres.

Polygons across zone borders

A building or field that crosses a zone border intersects and overlaps both zones and is within neither. Counted with intersect it is counted twice; with contain it is not counted at all. The choices:

  • assign it to one zone: the zone it overlaps most (Join attributes by location, one-to-one, largest overlap), or the zone that contains a point placed inside it;
  • split it at the border and share its values by area (overlay, then area-weighting);
  • count it in every zone it touches, and say that the totals add up to more than the whole.

Coordinates must match exactly

Equal and touch hold only when coordinates match exactly. Two layers digitised separately rarely share their boundaries exactly. Neighbours that should touch either overlap by a few centimetres or leave a thin gap, so touch finds nothing and overlap finds pairs that are really neighbours. A tolerance helps: in SQL ST_DWithin, in QGIS a small buffer or a distance-based tool.

Related: selection by location, summary by location, Modifiable areal unit problem.