I förra inlägget så var det vanliga projicerade koordinater, som blivit enklare att få till snyggt i senare QGIS versioner. Nu är det dags att återbesöka MGRS, eller Military Grid Reference System, som är en rapporteringsmetod för koordinater i UTM.
Syftet är kort och gott att förenkla och snabba upp, göra det enhetligt oavsett plats på jorden, samt att hantera osäkra positioner.
För att använda MGRS så behöver man dock referenser på sina kartor. Referenserna är till de bokstavspar som används för att referera till 100 km rutor i ett UTM nät. Bokstäverna ersätter alla värdesiffror högre än 99’999 och därmed så ser även siffrorna för öst och nord lika dana ut oavsett hur långt från ekvatorn man befinner sig.
Bokstäverna följer en standard och det finns funktioner i pythonbibliotek som kan användas för att automatiskt ta reda på MGRS positionen för en position i latitud och longitud, och därmed från vilket koordinatsystem som helst med hjälp av transformationer.
Mgrs.py kommer inte med i QGIS när man installerar, men det finns med i flera plugin. Däremot så är det inte säkert att det går att anropa biblioteket som standard från python-konsolen. Det kommer att synas i kod längre ner hur man bär sig åt. Jag kommer att använda biblioteket som följer med i ett plugin med namn ”Lat Lon Tools”.
Detta verktyg är suveränt för att enkelt hantera flera vanliga koordinatformat. Det finns även funktioner för konverteringar av tabeller med MGRS till punkter, samt att lägga till MGRS till tabellen för olika vektorlager. Men tillägget kan så väldigt mycket mer så kolla gärna själv.
För att kunna använda MGRS i mina layouter så behöver jag en anpassad funktion som sköter anrop och beräkningar mot pythonbiblioteket.
I funktionen importeras mgrs.py funktionen toMgrs(), som är den enda jag egentligen behöver för detta. Notera även att det är en lite längre referens till biblioteket då den inte finns lagrad i ”root” katalogen för python i profilen, utan i plugin-katalogen för Lat Lon Tools.
Jag inleder med en övergripande convert_mgrs() funktion som jag sedan använder i flera användarfunktioner. Den tar tre parametrar. X koordinat och Y koordinat, samt EPSG för koordinaterna. Funktionen toMgrs() vill ha koordinater i decimala grader, så det funktionen i huvudsak gör är att skapa en punkt och transformera över punkten från valfritt koordinatsystem till just latitud och longitud. Svaret som funktionen skickar tillbaka är sedan en MGRS textsträng med 15 tecken beräknad av funktionen toMgrs().
def convert_mgrs(source_x, source_y, source_epsg):
crsSrc = QgsCoordinateReferenceSystem(source_epsg)
crsDst = QgsCoordinateReferenceSystem(4326)
xform = QgsCoordinateTransform(crsSrc, crsDst,QgsProject.instance())
pt = xform.transform(source_x,source_y)
full_mgrs = toMgrs(pt[1], pt[0])
return full_mgrs
Övriga funktioner plockar sedan delar av denna sträng och skickar dessa tillbaka till användaren.
I dessa funktioner så finns även hjälptexter för uttrycken som skapas.
@qgsfunction(args='auto', group='LatLonTools', handlesnull=True)
def gzd(source_x, source_y, source_epsg, feature, parent):
"""
Calculates the MGRS Grid Zone Designator (GZD) from decimal longitude (x) and latitude (y).
<h2>Example usage:</h2>
<ul>
<li>gzd(14.9, 57.1, 4326) -> 33V</li>
</ul>
If inputing coordinates in other CRS include that EPSG code instead of 4326.
<h2>Example usage:</h2>
<ul>
<li>gzd(495951, 6393118, 3006) -> 33V</li>
</ul>
"""
return convert_mgrs(source_x, source_y, source_epsg)[:3]
Ovan är exempel på en funktion som returnerar de tre första tecknen i strängen, som består av UTM zonens ”GZD” eller Grid Zone Designator.
I Uttrycksbyggaren kan jag nu skapa uttryck med dessa funktioner och enkelt få de MGRS delar jag behöver från inmatade koordinater.
För att inte behöva skriva in koordinater manuellt i uttrycken så refererar jag till ett namngivet kartobjekt i stället.
with_variable('map_center',
map_get(item_variables('mgrs_map'), 'map_extent_center'),
with_variable('map_crs',
map_get(item_variables('mgrs_map'), 'map_crs'),
gzd(x(@map_center), y(@map_center), @map_crs)
))
Uttrycket ovan placerar in en punkt från kartans centrum i en variabel vid namn @map_center. Denna använder jag sedan för att separera x och y koordinaterna till mgrs-funktionen gzd(). Dessutom så hämtar jag kartobjektets referenssystem och skickar med det också. Svaret tillbaka blir som sagt MGRS GZD för kartans centrum.
Jag vill även kunna ha referenser i kartans koordinatnät. För detta så skapar jag ett rutnät (ja två egentligen men de är väldigt lika), med 1’000 meters intervall och 500 meters offset i både x- och y-led. Detta gör jag för att skapa positioner mellan de koordinatsiffror som jag redan skapat vid jämna kilometer.
Jag använder heller inga linjer utan här väljer jag att bara visa ram och etiketter.
Etiketterna är anpassade med ett uttryck.
if(right(@grid_number,5)=99500 or right(@grid_number,5)=00500,
if(@grid_axis='x',
bigram(@grid_number, y_min(@map_extent), @map_crs)
,
bigram(x_min(@map_extent),@grid_number, @map_crs)
)
,'')
Först så filtrerar jag ut endast linjer 500 meter ifrån jämna 100’000 meter. Det är nämligen där gränsen mellan olika MGRS bigram går, och bara där jag tycker jag behöver skriva ut MGRS bigrammen.
Det går att testa om koordinaten är på x- eller y-axeln men inte om det är uppe eller nere, vänster eller höger. Därför behövs det två rutnät. Ett för vänster och nere, och ett för höger och uppe. I koden ovan visas vänster och nere. För höger och uppe så använder man x_max() och y_max() i stället.
Svaret från funktionen bigram() är två bokstäver. Dessa skrivs ut som etikett mellan koordinatsiffrorna vid gränsen mellan MGRS rutorna.
Jag lägger även till ytterligare ett rutnät med 100’000 meters intervall, fast utan etiketter och med lite tjockare linje, för att ytterligare trycka på att här är en gräns.
I rutnätet med MGRS så behöver jag inte referera till kartobjektet, då jag redan är i detta, så här blir uttrycken faktiskt ganska enkla (även om jag måste ha två rutnät…).
Med denna typ av uttryck och dessa skräddarsydda funktioner så kan jag nu lägga till texter i kartans layout som anpassas dynamiskt till kartans utsträckning. Detta fungerar extremt bra… tills det kommer en UTM zons gräns och ställer till det. Men brutna UTM nät har jag beskrivit tidigare så om så blir fallet så är det bara att kavla upp ärmarna och börja anpassa koordinaterna och rutnätet.
Avslutning
Det är ju nu framför allt militär och liknande som använder MGRS, även om jag kan tycka att det är ett smidigt system om man kan det och har möjlighet att använda det. Dessutom så behöver man göra en hel del för att få till kartor på ett smidigt sätt. När man väl skapat funktionerna och har mgrs.py under kontroll, då är det inte speciellt krångligt. Layoutmallar kan förberedas för detta precis som alla andra typer av mallar.
Dom som står bakom Lat Lon Tools har också lovat att lägga till anpassade funktioner som är direkt tillgängliga i uttrycksbyggaren när du installerat tillägget, så förhoppningsvis så kommer du inte att behöva göra egna pythonfunktioner när denna uppdatering är klar, men det kunde ta ett par veckor på grund av andra pågående projekt.
Koden till Lat Lon Tools finns på GitHub https://github.com/NationalSecurityAgency/qgis-latlontools-plugin/. Japp, det stämmer, det är NSA’s officiella GitHub konto…