Det finns massor med verktyg och instrument för att mäta en vägs kurvradie. Jag tänker i detta inlägg testa om jag kan använda lite matte och QGIS för att beräkna en kurvradie från tre godtyckliga punkter på kurvan.
Målet är att direkt i QGIS och en ansluten GNSS kunna skapa en linje med tre brytpunkter, som sedan automatiskt räknar ut kurvans radie, med mera. I förlängningen så skulle jag vilja att det även fungerar i QField, men jag tror att detta kan bli lite svårare då jag kommer att använda anpassade Python-funktioner i mina uttryck. Men läs vidare så skall det nog lösa sig det också.
Det finns flera källor på Internet om hur man beräknar cirklar på olika sätt, men inget som jag hittar är speciellt enkelt att ta till sig. Däremot hittar jag en artikel av Thomas Lingefjärd (länk) där han tacksamt nog presenterat en del Python kod som jag direkt kan anpassa och använda i ett uttryck.
Jag väljer att skapa en funktion som tar tre koordinatpar som indata. Det hade nog gått att skicka hela linjen, men på detta sätt är jag lite mer fri att använda uttrycket i andra sammanhang (tror jag).
Vill man sätta sig in i matten så kan man följa artikeln (länk tidigare) men det handlar i stor om trigonometri och Pythagoras sats.
Resultatet som skickas tillbaka från funktionen är en array med ett koordinatpar och en radie.
Indata i lagret är ett linjelager. I attributtabellen så har jag även valt att lägga till ett attribut ”radie” som ställs in att beräknas automatiskt.
I formulärdesignen så görs fältet ”radie” om så att det inte går att redigera (General/Editable) och ett anpassat uttryck används som ”Default value”. Jag har även valt att uppdatera fältet vid redigering (Defaults/Apply default value on update).
För att stilsätta lagret så använder jag även en geometrigenerator och den andra delen av den anpassade Pythonfunktionen.
I geometrigeneratorn så används en liknande funktion som för uppdateringen av radie-fältet. Här hämtas däremot den första posten i funktionens resultat, som i sig är en array. Denna array, som består av ett koordinatpar med cirkelns beräknade centrum, används tillsammans med radien för att generera en cirkel.
Avslutningsvis skapas även en etikett i cirkelns mitt som skriver ut radiens mått.
Om man har väldigt många objekt i lagret så vill man kanske undvika överdrivet många beräkningar. Då kan man skapa attribut för centrum_x och centrum_y och beräkna dessa när linjen skapas, så slipper man några beräkningar dynamiskt.
Funktionerna är lagrade ”per installation” och inte i projektet. Detta gör att det är problematiskt att flytta med funktionen till exempelvis QField eller MerginMaps i en mobil. Det hade underlättat om varit möjligt att lagra dessa funktioner i projektet också.
För att göra funktionen ”mobil” så behöver jag skriva om Pythonkoden till QGIS uttryck…
with_variable('temp', -- Create Temp Variable
x(point_n($geometry,2)) ^ 2 + y(point_n($geometry,2)) ^ 2,
with_variable('bc', -- Create bc Variable
(x(point_n($geometry,1)) ^ 2 + y(point_n($geometry,1)) ^ 2 - @temp )/2,
with_variable('cd', -- Create cd Variable
(@temp - x(point_n($geometry,3)) ^ 2 - y(point_n($geometry,3)) ^ 2 ) / 2,
with_variable('det', -- Create det Variable
(x(point_n($geometry,1)) - x(point_n($geometry,2))) * (y(point_n($geometry,2)) - y(point_n($geometry,3))) - (x(point_n($geometry,2)) - x(point_n($geometry,3))) * (y(point_n($geometry,1)) - y(point_n($geometry,2))),
-- Maybe some error handeling here
with_variable('cx', -- Create circle center x variable
( @bc * (y(point_n($geometry,2)) - y(point_n($geometry,3))) - @cd * (y(point_n($geometry,1)) - y(point_n($geometry,2)))) / @det,
with_variable('cy', -- Create circle center y variable
((x(point_n($geometry,1)) - x(point_n($geometry,2))) * @cd - (x(point_n($geometry,2)) - x(point_n($geometry,3))) * @bc) / @det,
-- Calculate Radius
sqrt((@cx - x(point_n($geometry,1))) ^ 2 + (@cy - y(point_n($geometry,1))) ^ 2)
))))))
Ovanstående uttryck motsvarar Pythonfunktionen där radien beräknas. För att beräkna cirkelns centrumkoordinater (cx, cy) så behöver man inte all kod, utan det går att förenkla. Annars kan man helt enkelt använda variablerna @cx och @cy i stället för sqrt(…) raden.
Detta uttryck kan användas i formulärinställningarna som ”default” och här generera värden för radie, centrum_x och centrum_y. Dessa värden kan sedan användas i stilarna med geometrigeneratorer för att uppnå samma resultat som tidigare med Python.
Nu är lagret mobilt!
När jag läser in projekt och databas i QField så kan jag skapa linjer (med tre punkter) och radie, center_x och center_y kommer att genereras automatiskt. Resultatet syns sedan direkt i appen…
Perfekt!
Jag är nöjd med resultatet av detta arbete och nu skall jag bara paketera detta på något smart sätt så att jag kan dela med mig av projektet på QGIS ”hub” (hämta här).
1 svar på ”Mäta kurvradier med GNSS”