I förra inlägget skapade jag ett ganska enkelt men utbyggbart skript för anpassade funktioner i uttrycksbyggaren. I detta inlägg bygger jag vidare på detta och lägger till funktioner som använder externa pythonbibliotek.
Jag försöker samla funktioner som jag använder när jag skapar layouter så att framför allt koordinathantering och ”grid” blir så enkelt som möjligt att skapa.
Jag har sedan tidigare funktioner för att skapa enkla och fullständiga UTM koordinater med kilometersiffror och upphöjda indexsiffror. Nästa steg är MGRS bigram. Om du inte känner till MGRS så är det ett sätt att med bokstäver identifiera koordinatrutor om 100 x 100 km, samt erbjuda ett förenklat sätt att rapportera koordinater med varierande noggrannhet.
För detta behöver jag kunna ange dessa bokstäver vid gränserna mellan dessa 100 kilometerrutor. Jag tror inte jag kan lösa allt med ett enda rutnät, men två borde räcka. Jag börjar att skapa ett förskjutet kilometernät som korsar axlarna mitt emellan kilometermarkeringarna.
Jag vill inte rita ut några linjer, utan endast ha etiketter. Villkoret för att rita ut etiketter är att koordinaten axeln vid 99.5 eller 00.5 kilometer, vilket är enkelt att filtrera i uttrycksbyggaren, men det är lika enkelt i en pythonfunktion. Min funktion behöver därför minst ha @grid_number variabeln som indata. Jag behöver även veta var koordinatlinjen skär kartramen, det vill säga för horisontella linjer så behöver jag veta minsta och största x-koordinaten för dataramen.
Detta löser jag genom att skicka med x_min eller x_max, respektive y_min eller y_max i funktioner, beroende på om jag vill ha svar för sidorna uppe till vänster eller nere till höger.
I uttrycksbyggaren kan jag göra detta med den inbyggda variabeln map_extent, för att få exakta utsträckningen för kartramen. Jag har arbetet med QGIS 3.9 när jag gjorde detta, och när jag senare testar i 3.8 så kan jag inte hitta variabeln @map_extent för kartelement. Det är sannolikt så att variabeln inte är tillgänglig här förrän 3.10 släpps. Det går att komma runt detta, men vi är bara en dryg månad bort, så det får vara. Men det är skönt att ha något att se fram emot…
När jag tänker efter så behöver jag faktiskt veta vilken axel som @grid_number refererar till också. Annars så vet jag ju inte vilken av x- respektive y-koordinaterna för utsträckningen som skall användas som komplement.
Mitt funktionsanrop skulle därmed kunna se ut såhär.
MGRS_Bigram(@grid_number, @grid_axis, x_min( @map_extent ), y_max( @map_extent ))
Och en enkel (ej fullständig) pythonfunktion skulle kunna se ut såhär.
@qgsfunction(ars='auto', group='Mina Koordinater') def MGRS_Bigram(koordinat, axel, x_varde, y_varde, feature, parent): """ Denna funktion skickar tillbaka aktuellt MGRS bigram för koordinatsiffror. """ k_string = str(int(koordinat)) if k_string[-5:-2] in ["005", "995"]: return "XX" else: return ""
Funktionen är som tidigare definierad i gruppen ”Mina Koordinater” och tar fyra variabler som ingångsvärde, förutom de standardiserade variablerna feature och parent.
Som tidigare gör jag om koordinaten till heltal och därefter till text. Texten testas sedan om de tre siffrorna näst, näst längst till höger är 005 eller 995, vilket skulle betyda att det är koordinater närmast jämna 100-tal kilometer.
Om det är det, så returneras för tillfället ’XX’ och om det inte är det så returneras en tom sträng. Resultatet är uppmuntrande och det är därför dags att gå vidare med nästa steg.
För att räkna fram MGRS koordinater så kommer jag att använda ett externt pythonbibliotek som skapats av Boundless. Det heter mgrspy och finns att ladda ner med ”pip” eller via pypi.org.
Katalogen mgrspy placerar jag direkt i min QGIS profil i python katalogen. Den finns med andra ord på samma plats som katalogen expressions.
I min pythonfunktion kan jag nu importera mgrs-funktionerna från detta bibliotek, direkt i början av funktionsfilen.
from mgrspy import mgrs
Det som jag behöver för att kunna använda funktionerna är koordinater i oprojicerad lat, long. Vilket betyder att min funktion behöver en variabel till, nämligen den projektion som används. Annars kan jag inte säkert omvandla projicerade koordinater till lat/long.
MGRS_Bigram(@grid_number, @grid_axis, @map_crs, x_min( @map_extent ), y_max( @map_extent ))
Det blir fortfarande inte bombsäkert, då hela funktionen förutsätter att koordinaterna är angivna i kartramens projicerade koordinatsystem. Det finns vad jag känner till ingen variabel för valt koordinatsystem i rutnätsinställningarna. Det får jag nog ta och undersöka närmare en annan gång.
För att hämta mgrs, så måste först en punkt fastställas där linjen skär axeln. Därefter skall den punkten transformeras om till lat/long, och därefter kan mgrsfunktionen anropas. Den såhär långt fungerande funktionen ser ut enligt nedan.
@qgsfunction(ars='auto', group='Mina Koordinater') def MGRS_Bigram(koordinat, axel, koordinatsystem, x_varde, y_varde, feature, parent): """ Denna funktion skickar tillbaka aktuellt MGRS bigram för koordinatsiffror. """ k_string = str(int(koordinat)) oproj = QgsCoordinateReferenceSystem(koordinatsystem) proj = QgsCoordinateReferenceSystem("EPSG:4326") skapalatlon = QgsCoordinateTransform(oproj, proj, QgsProject.instance()) if k_string[-5:-2] in ["005", "995"]: if axel=="x": latlon_punkt = skapalatlon.transform(koordinat, y_varde) else: latlon_punkt = skapalatlon.transform(x_varde, koordinat) mgrstext = mgrs.toMgrs(latlon_punkt.y(), latlon_punkt.x()) return mgrstext[3:5] else: return ""
Det som tillkommit är ett transformeringsobjekt, från projektets crs till lat/long, samt transformeringen beroende på om koordinaten skär x- eller y-axeln och slutligen anrop av mgrsfunktionen och returnerandet av två bokstäver på kända positioner i textsträngen.
Just nu har kartan bara ett problem kvar att fixa, nämligen att släcka utritningen av de felaktiga bigrammen till höger och i nederkant, samt att lägga till ett nytt exakt likadant rutnät för dessa sidor, något modifierat. När det är gjort så ser kartan ut såhär.
Därmed tror jag att jag är nöjd för tillfället. Mina tidigare funktioner har krävt dubbelt så många MGRS rutnät, så en halvering är ganska bra. Nästa steg blir att försöka hitta ett sätt att reducera det till endast ett. Detta tror jag dock kommer bli svårare för närvarande, då QGIS inte har en variabel för om det är höger eller vänster y-axel som koordinatsiffran anger.