TL;DR: I'm trying to calculate the forested area of nature reserves. For this I have two partially overlapping datasets (reserves and forests). My approach is a union and consecutive spatial join of conntaining forest areas, that fails because forests that share a boundary with the reserve are not recognized.
A) Is this due to the definition of "contains"?
B) If yes, isn't this definition of "contains" flawed or should at least be made transparent in the docs?
C) Are there alternatives (in QGIS) to join on polygons that interior but with touching borders?
I uploaded test datasets: reserves.gpkg and forest.gpkg and reserve_union_forest.gpkg (as suggested in a comment).
In detail: To calculate the forested area of nature reserves my approach was
- Union reserves and forests => waldreservate_union_wald.gpkg
- Delete non matching polygons (areas that are outside reserves or that are not forest)
- Calculate area of remaining polygons
- => waldreservate_union_wald.gpkg clean (only forests within reserves) with attribute forest_area_ha
- Calculate total forest area within each reserve: Join attributes by location (summary) with contains and calculate summary sum on attribute forest_area_ha
- => waldreservate_forest_area_ha.gpkg with attribute forest_area_ha_sum
This however gives me a lot of NULL values, since all forest polygons that share the border with the reserve polygon are not considered contained (see image at the end of post), despite being inside the polygon (the forest polygons originate from a union). Only forest area that is completely within (not bordering) the reserve is recognized. I ensured that this is not due to imprecisions caused by different CRS or projections.
The QGIS doc on contain is unspecific regarding points that are directly ON the polygon border (touch). It only specifies behavior for interior or exterior points, but not borderline.
Contain: Returns 1 (true) if and only if no points of b lie in the exterior of a, and at least one point of the interior of b lies in the interior of a. In the picture, no circle is returned, but the rectangle would be if you would look for it the other way around, as it contains circle 1 completely. This is the opposite of are within.
The illustrations within this question on spatial relations in QGIS suggests, borderline is "contained", and I'd prefer this behavior, but my results suggest otherwise: The polygons that I created using Union should have exactly the same border as their "parent polygons" (the polygons used to cut them) OR should be in their interior. But they don't show up as contained.
I tested other spatial relations, but they do cause other problems:
intersect, gives me forest areas of neighboring reserves that share the border. Meaning: intersect handles borderline as TRUE (as opposed to contain). Also, if I couldn't be sure (because of previos Union) that no polygons partially overlap, this would also include partially overlapping polygons.
overlap gives me correct results for polygons that are contained and touching but leaves out areas (forest) that are completely overlapping (equal) to the parent polygon (reserve). This behavior is described in the docs ("... but are not completely contained by each other").
all others (touch, cross, equal, disjoint) are not applicable to my case
according to docs, are within is the opposite of "contained" (NOT exterior and NOT touching), so it might work, but I'd have to switch Base Layer (reserves) and Join Layer (forests) and hence couldn't caluclate the summarized area of forest in reserves anymore.
Maybe I'm not seeing something, so before I raise an issue to the QGIS developers, I'm wondering:
- isn't it completely unintuitive that the results of a union are not "contained" in their parent polygons?
- isn't this use case a perfect example of why "contain" should be TRUE when points are interior OR borderline (the behaviour of contain should be changed?!) or there should be distinct relations (contains with/without shared points)?
- ... shouldn't at least the docs be updated to make this behavior transparent (FALSE when points are exterior OR borderline/shared)?
- there is no spatial join relation available, that does what I want?!
I checked in the ArcGIS Pro Doc without testing. They differentiate between three cases ("contained"/"completely contained"/"contains clementini"), where "contains clementini" omits results that are only borderline/on boundary - this suggests to me, that they apparently have the suggested behavior implemented (contained = [no exterior points] AND [at least one interior OR borderline/on boundary point]
).
I can work around this by:
- defining a minor buffer
- spatial join (summary) with contain in the buffered layered
- joining the resulting summaries via ID back to the original unbuffered layer
Or:
- spatial join (summary) with overlap
- spatial join (summary) with equal
- write both results into one new field
But both seem circumstancial and dirty to me.
Example image of reserve (selected in red) containing a lot of forest (green) that is not recognized (Flaeche_ha_Wald_sum = NULL) because all forest polygons share borders with the reserve.
union
probably created a vertex that is considered outside of the original shape because of floating point accuracy. You can try joining on the polygon centroid instead.ST_contains
here? I guess this part "An important subtlety of this definition is that A does not contain its boundary, but A does contain itself." is what should tell me that basically the boundary of A is already defined as "exterior" (hence causing points of B being there violating the first condition of the previous doc sentence).