En karta i militär stil skall följa vissa standarder, men även ge stöd för rapportering i speciella format. Hur man kan bygga kartor för detta i QGIS tänkte jag titta på idag. Jag kommer även att ta upp ett problem som jag inte lyckats lösa.
För det första så avgränsar jag mig till ”taktiska” kartor i skala 1:50’000 och 1:100’000. För mina exempel så använder jag Lantmäteriets WMTS tjänst, vilket fungerar bra på skärm, men för tryck så bör man använda lokala data.
Grunden i en militär karta är koordinatsystem i UTM baserat på WGS-84. UTM delar in jorden i 60 sektorer och så länge man håller sig helt innanför en sådan sektor så kommer det inte att bli några problem. Problemen uppstår när ”skarven” mellan två zoner måste hanteras i kartan. Detta slipper man om man använder exempelvis SWEREF99TM, men för ett globalt system som UTM måste det omhändertas.
Som det ser ut nu så finns det ingen metod med QGIS att skapa så kallade ”delade” koordinatnät.
För det första så används ett koordinatnät med 1 km intervall. Etiketter för dessa anges med hela kilometer med två siffror. Dessutom så bör man ha med siffror för att även beskriva de kompletta UTM koordinaterna.
För detta så använder jag egentillverkade funktioner för ”index” och ”korta” etiketter. Vill man enbart ha med kilometersiffrorna så kan man skapa det utan speciella funktioner med uttrycket:
left(right(@grid_number, 5),2)
Som komplement till koordinater i UTM så kan man även lägga till koordinater i latitud och longitud baserat på WGS-84 (EPSG:4326). Dessa är mindre viktiga och ges därför en mer diskret färg och storlek för såväl texter som linjer. I min karta är mina linjer för lat/long 0,1 mm tjocka, det räcker.
Då kommer vi till det som är lite mera avancerat, nämligen MGRS. ”Military Grid Reference System” är ett system för att rapportera positioner på ett standardiserat sätt. För detta så används en indelning av kartan i 100 km stora rutor. Dessa namnges enligt ett speciellt system, vilket kan härledas i kod med QGIS.
from qgis.core import * from qgis.gui import * from qgis.utils import iface @qgsfunction(args='auto', group='MGRS') def mgrs_bigram(easting, northing, feature, parent): canvas = iface.mapCanvas() epsg_code = canvas.mapRenderer().destinationCrs().authid() utm_z = int(epsg_code[-2:]) mgrs_col = utm_z%3 col_type_list = [['S','T','U','V','W','X','Y','Z'],['A','B','C','D','E','F','G','H'],['K','L','M','N','P','Q','R']] col_100k = int(easting/100000)-1 mgrs_row = utm_z%2 row_list = ['A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V'] if mgrs_row == 0: eq_offset = 5 else: eq_offset = 0 row_100k = (int(northing/100000) + eq_offset)%20 bigram = col_type_list[mgrs_col][col_100k] + row_list[row_100k] return bigram @qgsfunction(args='auto', group='Custom') def mgrs_gzd(easting, northing, feature, parent): canvas = iface.mapCanvas() epsg_code = canvas.mapRenderer().destinationCrs().authid() utm_z = int(epsg_code[-2:]) gzd_list = ['C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X'] gzd_nr = (int(northing/888960) + 10)%20 gzd = str(utm_z) + gzd_list[gzd_nr] return gzd
Funktionerna ovan är byggda för norra hemisfären och förutsätter att man är ute efter positioner i den UTM zon som projektet är projicerat i. De tar två variabler (easting och northing koordinat) som indata. Funktionen mgrs_bigram ger som resultat den ”kod” som betecknar den 100 km ruta som koordinaten befinner sig i. Funktionen mgrs_gzd anger den ”grid zone designator” som utgör inledningen av positionen i MGRS.
För att skapa dessa ”koder” på ömse sida om 100 kilometersgränsen i kartan, så behöver inte mindre än fyra nya koordinatnät skapas. Ett för övre, vänstra hörnet av 100 km rutorna samt ytterligare tre för de andra hörnen.
Som grund för samtliga rutnät skapas ett nät med 100’000 meters intervall. Till detta kopplas ett ”offset” på 500 meter. Beroende på om det är uppe till vänster, uppe till höger, nere till vänster eller nere till höger, så är det +500 eller -500 meter som är intressant för x, respektive y som offset. Nu går det inte att ange offset till -500 meter, så man får ange 99500 i stället, för att komma 500 meter ”kort” om nästa linje.
Koordinater som har sitt ”kryss” 500 meter från 100 km rutans övre högra hörn (UR) skall endast skriva ut etiketter till vänster och i nederkant, det vill säga diagonalt mitt emot. När detta görs för alla fyra koordinatnät så kan man separera de 100km rutor som finns med och skapa etiketter för dessa på ömse sidor om gränsen i kartans kant. Jag tror bilden ovan förklarar lite bättre än vad jag lyckas med i text.
Lite omständligt, men inte så svårt egentligen. Men det kan bli lite krångligare i nästa steg, för nu måste man använda ytterligare speciella funktioner. Man behöver nämligen veta kartans max och min för såväl x som y, det vill säga kartbladets utbredning. För detta finns det ingen inbyggd funktion, men som väl är så har funktioner för detta redan skapats av Alexandre Neto (https://gisunchained.wordpress.com/2014/09/09/coordenadas-dos-cantos-do-mapa-em-qgis-map-corner-coordinates-in-qgis/). I den länkade artikeln finns kod och nedladdningslänkar för dessa funktioner.
Funktionerna (map_x_min, map_x_max, map_y_min, map_y_max) behöver veta vilken layout och vilken kartram i layouten som värden skall beräknas för. Därför skickar man med namnet på layouten, samt kartans indexnummer (i de flesta fall 0). För min exempelkarta, som har layoutnamnet ”test” så blir funktionen för minsta x-koordinat:
map_x_min('test', 0)
Denna funktion tillsammans med min funktion för MGRS bigram används för att ta reda på vilken bokstavskod som skall användas vid varje position. Koordinaten för skärningen av en vertikal koordinatlinje och kartan i nederkant blir därför:
mgrs_bigram(@grid_number, map_y_min('test',0))
I uttrycket behöver man även separera etiketter längs x- och y-axlarna. I bilden nedan visas uttrycket för det som blir ”VD” i kartan.
Allt går ut på att ta fram koordinater för där rutnätet skär de olika axlarna och hämta MGRS bigram (kod) för dessa punkter.
Upprepa för alla fyra MGRS koordinatnäten, men anpassa uttrycket något beroende på vilket ”hörn” av 100km rutan som skall beskrivas.
I bilden ovan har jag även använt två av funktionerna för att bygga en exakt koordinat för kartans hörn.
'E '||map_x_min('test',0)||'\nN '||map_y_min('test',0)
Allt sammantaget så blir det riktigt bra!
Min andra MGRS funktion ger mig Grid Zone Designator för bladet, vilket behövs för att ange en position i MGRS. Som exempel kan jag använda den exakta koordinaten för hörnet och ange denna i MGRS:
33V VD 96621 97831
Så länge jag inte behöver bry mig om gränser mellan två UTM zoner och ”brutna” koordinatnät så fungerar detta perfekt!
Tänk om man kunde rita ut koordinatnät i QGIS med ett geografiskt filter. Då skulle UTM koordinater i EPSG:32633 kunna begränsas till mellan 12 och 18 grader öst. Sedan kunde man lägga till ett nytt koordinatnät i EPSG:32634 för longituder över 18 grader… eller motsvarande för andra UTM gränser.