13 Dec 2022

QGIS3: Virtual Layers & Spatialite/SQLite/SQL Queries - Intersecting Lines With Polygons

SQL and Spatialite make super effective table and geometry operations possible. With the implemantation of Virtual Layers, QGIS has now a built in functionality to run such queries very easily and without the need for preparation of databases. The below SQL snippet, i.e., can be used to intersect features of a line and a polygon layer, and calculate the summed segment lengths for each single polygon. The usecase here was, that I needed to know the cummulated lengths of trail crossing single parcels.

SELECT 
  t.Name AS Trail_Name,
  g.GNR AS Parcel_NR,
  SUM(LENGTH(INTERSECTION(t.geometry, g.geometry))) AS SUM_L_inP,
  COLLECT(INTERSECTION(t.geometry, g.geometry)) as geom
FROM Trails AS t JOIN Parcels AS g ON INTERSECTS(t.geometry, g.geometry)
GROUP BY g.GNR

9 Sept 2022

QGIS REGEX Expression to Find Last Vaue of an XML/Html Image Source of the Description Field of a KML File

if(
regexp_substr(description, 'img src="!?.*img src="(.*)"') = '',
regexp_substr(description, 'img src="(.*)"'), 
regexp_substr(description, 'img src="!?.*img src="(.*)"') 
)

7 Jul 2022

GDAL: Bash Script for Converting All GPKG-Files From Directory To GPX-Format

Since lately QGIS (QGIS 3.12) comes equipped with a nice tool ("Split Vector Layers"), that will split your layers based on an attribute and ame your files accordingly. Th only drawback is, that you can not choose different output format - so you'll need to go with the only possibility, namely the GPKG-format. Now, I rather needed GPX files and had to find a way of converting the gpkg-files in batch mode. This I achieved by writing a small bash script looping over the files with GDAL's ogr2ogr command, and convert each file to GPX.

#!/bin/bash ## first two lines and last line prevent whitspace problems in filenames (see: https://unix.stackexchange.com/questions/9496/looping-through-files-with-spaces-in-the-names ## then loop over all files with gpkg extension an convert to gpx format preserving the old filename! ## the script would throw an error and discard attribute fields for all fieldnames that do not match the GPX XML definition (name, cmt, etc…). ## if you dont put the GPX_USE_EXTENSION=YES paramter.. ## with <-t_srs epsg:4326=""> the target CRS, to which the input coordinates will be transformed, is given.. OIFS="$IFS" IFS=$'\n' for f in *.gpkg do ogr2ogr -f GPX -dsco GPX_USE_EXTENSIONS=YES -t_srs EPSG:4326 -overwrite ${f%.*}.gpx $f done IFS="$OIFS" read -p "Hit [Enter] to exit..."

9 Jun 2022

QGIS 3: Symbology with Geometry Generator - Draw One Convex Hull For All Features With Same Attribute

I have a layer named "Trails" with an attribute "Trail ID", which contains unique, consecutive Feature/Trail IDs and an attribute "Schwierigkeit" (trail difficulty). For all features with the value "black" for the attribute "Schwierigkeit" I want to render one convex hull. The below code will select the last element of all the features in the layer and apply the code for drawing the polygon only once. The first
array_foreach()
in the code will create an array of all features (series generated from 1 to feature count number). Over this array, the second array_foreach() will apply the geometry function on each element that meets the condition of the
array_filter()
function. The
collect_geometries()
function finally puts all those single geometries within the resulting array into one multiline geometry, for which I then draw the hull. The purpose of this procedure, is to check if the trails in my dataset show a spatial aggregation according to their trail difficulty..

if($id = maximum($id),
convex_hull(
collect_geometries(
with_variable('my_arr', 
array_foreach(
generate_series(1,  layer_property( 'trails', 'feature_count'), 1),
get_feature('trails', 'Trail ID', @element)
),
array_foreach(
array_filter(@my_arr, attribute(@element, 'Schwierigkeit')='black') , geometry(@element)))))
, NULL)

28 Feb 2022

QGIS 3: Geometry Generator Expression for Points at Line Intersections

A solution for symbolizing line intersections between the current layer's features and another layer's features ('Tracks Subset=Detail'). The
generate_series
is used with an
aggregate
which yields the number if features in the other layer used for the intersection. The
array_foreach
iterates over all features of the other layer and intersects each line with the input layer's current feature. The
array_filter
is needed to filter out the epmty geometries that could result after the intersection. If you wouldn't do this, the code would break when calling
collect_geometries
, which is needed to finally convert the array of geometries into a valid, digestible geometry collection, fed into the geometry generator with checking Point/Multi-POint as geometry type..
with_variable ('my_series', generate_series(1, aggregate(layer:='Tracks Subset=Detail', aggregate:='max', expression:="id")),
	collect_geometries(
		array_filter(
		array_foreach(@my_series, if(is_empty_or_null( 
			intersection(geometry(get_feature('Tracks Subset=Detail', 'id', @element)),
			$geometry)), 'x', intersection(geometry(get_feature('Tracks Subset=Detail', 'id', @element)),
			$geometry))
			), 
		@element != 'x'
	)
  )
)