Identifying polygons that intersect with another layer using QGIS?
There is a possibility using a "Virtual Layer" through Layer > Add Layer > Add/Edit Virtual Layer...
Let's assume we have three features in 'vegetation'
and four in 'treatment'
accordingly, see image below.
With the following Query, it is possible to add a field to the attribute layer of the vegetation layer to indicate if any part of the polygon has been treated (overlaps with a treatment layer).
SELECT vegetation.*,
(CASE
WHEN vegetation.id IN
(SELECT vegetation.id
FROM vegetation, treatment
WHERE st_intersection(vegetation.geometry, treatment.geometry) IS NOT NULL)
THEN '1'
ELSE '0'
END) AS Is_Treated
FROM vegetation
The output Virtual Layer will maintain initial attributes and geometries and add an additional field representing overlaps.
Additionally, you may extend your output layer as was earlier suggested by @spatialthoughts with several lines
SELECT vegetation.*,
(CASE
WHEN vegetation.id IN
(SELECT vegetation.id
FROM vegetation, treatment
WHERE st_intersection(vegetation.geometry, treatment.geometry) IS NOT NULL)
THEN '1'
ELSE '0'
END) AS Is_Treated,
SUM(st_intersection(vegetation.geometry, treatment.geometry) IS NOT NULL) AS Intersections
FROM vegetation, treatment
GROUP BY vegetation.id
Now, the output Virtual Layer will look as following
References:
- Chapter 8. PostGIS Reference | 8.5. Geometry Accessors
- Counting attributes from line intersections with polygons on QGIS?
- Understanding Join Attributes by Location in QGIS?
You can do this using Aggregate function. Add a new field "isTreated"
in the 'vegetation'
layer with an expression like below:
if(aggregate(layer:='treatment',
aggregate:='count',
expression:=fid,
filter:=intersects($geometry, geometry(@parent))
) > 0,
1, 0)
The aggregate function returns number of features from the 'treatment'
layer that are intersecting. As you are only interested whether they intersect at least 1 feature, you can add the if condition to assign 0
or 1
.
See my post about aggregate functions in QGIS to learn more https://spatialthoughts.com/2019/04/12/summary-aggregation-qgis/
A possible performance improvement for large amounts of features, and a slight improvement in readability:
SELECT DISTINCT
a.*,
CASE WHEN b.id
THEN 1
ELSE 0
END AS "isTreated" -- but, better to avoid camelCase as column names
FROM vegetation AS a
LEFT JOIN
treatment AS b
ON ST_Intersects(a.geometry, b.geometry)
;
The LEFT JOIN
will select all rows in the left hand table for the join, matching the condition or not; b.id
will be NULL
if a row has no match in the right hand table, and the CASE
filters accordingly. The DISTINCT
makes sure there will only be one row per match.