24 Aug 2023

QGIS3 Virtual Layer & SQL: Calculation of Intersection Areas from (Segmented) Line Buffers and Polygon

Usecase: For a set of lines in one layer you would like to know the areas of (segmented) line buffers, that intersect with polygons from another layer. I.e., (segmented = with different buffer width segments) trail buffers, that intersect with wood patches. 

An inner buffer segment of, say 10 meters (5 meters to each side of the middle line) and an oute buffer segment, inbetween 5 and 10 meters offset from the middle line. 

 In QGIS Virtual Layers SQL you can not call Buffer function with specification of the end ("square", "flat", "round") and Buffer() will make round ends by default - so you need the workaround with ST_union() of single sided buffers to get the correct flat ends. 

Then, for the final calculations, all the feature's buffer polygons were merged into one polygon with outer ST_Union() call. 

The ST_difference() call is used to make the outer buffer segment by clipping the narrower ("Breite_Forst") from the wider buffer ("Breite_Forst"+"Breite_F_bef"). 

The final output will be to poylgons, one with the inner, narrower buffer, and one with the outer wider buffer, and the calculated areas for each polygon, and merged into one table with the UNION ALL statement.
SELECT 
	T.geom as geometry,
	ST_area(T.geom) AS Fl_Rod
FROM (
	SELECT
		ST_union(
			ST_union( 
			  intersection(st_SingleSidedBuffer(t.geometry,t.Breite_Forst/2,0), w.geometry),
			  intersection(st_SingleSidedBuffer(t.geometry,t.Breite_Forst/2,1), w.geometry)
			) 
		) AS geom
	FROM trails AS t, wood AS w
	UNION ALL 
	SELECT 
		ST_difference(
			ST_union(
				ST_union( 
				  intersection(st_SingleSidedBuffer(t.geometry,t.Breite_Forst/2+Breite_F_bef,0), w.geometry),
				  intersection(st_SingleSidedBuffer(t.geometry,t.Breite_Forst/2+Breite_F_bef,1), w.geometry)
				) 
			),
			ST_union(
				ST_union( 
				  intersection(st_SingleSidedBuffer(t.geometry,t.Breite_Forst/2,0), w.geometry),
				  intersection(st_SingleSidedBuffer(t.geometry,t.Breite_Forst/2,1), w.geometry)
				) 
			)
		) AS geom 
	FROM trails AS t, wood AS w    
) as T