Hur mycket lutar vägen? Denna övning är inspirerad av Anders, ingenjör på Tekniska kontoret i Lilla Edet. Vi har precis hämtat hem avfallshanteringen i kommunen i egen regi, efter att detta legat på entreprenad i flera år. Som jag förstått det är hanteringen både bättre och billigare nu, och det är ju kul, men resan har inte varit helt smärtfri. Ett av de största problemen har varit att kundregistret haft gott om felaktiga uppgifter, och att hämtningsrutterna bara funnits i chaufförernas huvud. Med hjälp av några GPS-puckar har vi nu rutterna på karta, och vi ska försöka matcha ihop rutterna med registret också. Det är dock inte detta som övningen här handlar om; över en kopp kaffe undrade Anders om man kan få fram en karta över alla branta vägar i kommunen. Det hade ju varit käckt, speciellt när man ska planera vinterrutter. Jajamensan! Sa jag. Det tog en stund att reda ut hur man gör detta, trots att frågeställningen låter hyfsat enkel. Här har vi i alla fall resultatet! Översiktlig beskrivning av övningen Målet med övningen är att få fram en karta där vi kan välja ut och visualisera vägsegment baserat på lutning. Lutning kommer att beskrivas i %. Underlagsdatat består av: Vagar_sodra.shp bil- och cykelvägar från NVDB, i ett mindre område i södra Lilla Edet. Datat kommer ursprungligen från Trafikverkets Lastkajens shape-export, och har sedan transformerats till Sweref 99 12:00. Koordinaterna har z-värden, men det är inte många koordinater som har verkliga värden (-9999 är vanligt) Hojd_sodra_lillaedet.tif Höjdgrid från Lantmäteriet, 2*2m-celler. Jag har klippt ut ett område över södra Lilla Edet och sparat ner det som geotiff, i övrigt inga modifikationer. Vi kommer använda oss av en del minnes- och processorintensiva beräkningar, därav det lilla analysområdet. Verktygen vi använder oss av är dels några algoritmer från GRASS GIS, som vi hittar i Verktygslådan, och dels lite SQL som vi kör i Spatialite, för att kunna jobba med z-värden trots QGIS begränsningar på det området. Lutningen på vägarna får vi genom att drapera vägnätet över höjdmodellen, och sedan räkna lite på koordinatvärdena. För att få användbara lutningsvärden behöver vi dock först hacka upp vägnätet lite, så att vi får korta linjeobjekt med bara 2 noder per linje. På så sätt består varje linje av 2 xyzkoordinater, och differensen mellan dessa kan användas för att beräkna vägens lutning. Har man flera noder i linjesegmentet blir det lite lurigare att få fram lutningen, vägen kan ju guppa upp och ner. Samma sak om vägsegmenten är för långa, då kan man missa att vägen faktiskt guppar upp och ner. Jag tror att jag har tänkt rätt här; när ni har tagit er igenom övningen får ni gärna kommentera tillvägagångssättet. Då börjar vi! Öppna upp QGIS, och börja med att tala om för QGIS att vi kommer att jobba i Sweref 99 12:00. I menyn Inställningar, under Alternativ, fyll i värden under Referenskoordinatsystem enligt bilden nedan:
Sedan lägger vi till underlagsdatat i kartan. Datat ligger i mappen Data, som du redan laddar ner, och det är filerna vagar_sodra.shp och hojd_sodra_lillaedet.tif vi vill ha. Resultatet bör se ut ungefär såhär:
Verktygen vi skall använda hittar vi i Verktygslådan. Om denna panel inte redan är öppen, klicka fram den enligt bilden nedan:
Vi kommer börja med att använda några algoritmer från GRASS GIS. GRASS är ett gammalt och mycket hedervärt öppen källkods-projekt som började utvecklas av amerikanska militären. Tror jag. GRASS har sedan utökats och byggts på och använts mycket inom universitetsvärlden och på andra håll, och har väldigt många roliga funktioner. En sak som kan vara lite knepigt med GRASS är dataoch konceptmodellen, som inte är helt intuitiv. Det är därför vi använder oss av QGIS och Verktygslådan: algoritmerna vi kommer åt härigenom jobbar i GRASS-världen, men vi behöver inte fundera jättemycket på GRASS-databaser, platser, kartset, regioner och annat, för allt detta sköts i bakgrunden, och vi befinner oss hela tiden i QGIS-världen. Så, sök fram algoritmen v.split.length i verktygslådan:
Detta verktyg skall vi använda för att hacka upp vägarna i 20-meterssegment. Jag sparar ner resultatet till en ny fil, som jag lägger i en ny mapp kallad Min data, och döper till vag20m. Ställ in verktyget som bilden nedan visar: Resultatet läggs automatiskt till i kartan, men det kallas för Output layer istället för vag20m, som filen i sig heter. Vi kommer att få fler Output layers, så för att inte villa bort oss döper vi om Output layer till vag20m. Innan:
Efter: Nu vill vi också säkerställa att vi bara har 2 noder per linje. Då tar vi hjälp av den andra splitfunktionen, v.split.vert. Fyll i parametrar enligt nedan, döp filen till vag20msplit.shp:
Döp om även detta Output layer, till vag20msplit. Såhär ser det ut om man visar antal objekt per lager: Vi har alltså 25-dubblat det ursprungliga antalet vägdelar med dessa operationer. Snyggt! Nästa steg är att ge geometrierna höjdvärden genom att drapera vägarna över höjdmodellen. Vi använder algoritmen v.drape, och ställer in såhär:
Vi sätter Z till 9999 på de vägsegment som ligger utanför höjdmodellen, detta för att slippa besväras av NULL-värden. När du klickar Kör kan det komma upp en liten ruta som varnar om olika koordinatsystem; bortse från detta och klicka OK! Och nu får du nog vänta ett tag på resultatet Om det finns nåt kaffe kvar kan du gärna ta lite! När processen är klar, och vi har fått ett nytt output layer, byter vi namn på det till vag3d, så slipper vi förvirras. Vag3d innehåller nu vägsegment som är max 20 m långa, och består av 2 noder. Detta är också höjdsatt. Nu kvarstår då bara att räkna ut lutningen för varje segment. Det finns faktiskt ett verktyg i GRASS som kan göra detta, v.to.db. Dessvärre är detta inte implementerat i Verktygslådan. Dessutom har jag bara lyckats få det att ge märkliga resultat när jag prövat det på andra sätt. Det kan säkert bero på att jag missuppfattat funktionen, men hursomhelst skall vi inte använda det verktyget nu. Istället laddar vi in shapefilen i en Spatialite-databas på så sätt kan vi labba med z-värdena genom
SQL. Det finns flera sätt att komma åt en Spatialite-databas genom QGIS, men det sätt jag ska visa nu är det enda där jag lyckats få med mig z-värdena in. Högerklicka på vag3d i lagerlistan, välj Spara som, och fyll i dialogen som följer såhär: På detta sätta skapar vi en ny Spatialite-databas, som bara innehåller ett lager, vag3d. Nu skall vi använda DB Manager för att plocka fram z-värden ur geometrierna och fylla attributfält med detta. Eventuellt måste du först skapa en anslutning till din nya Spatialite-databas genom att klicka på Lägg till spatialite-lager i datamenyn:
Annars är det bara att öppna DB Manager, från Databas-menyn, och ansluta till vag3d.sqlite. Där ser vi att vi minsann har xyz-koordinater i datat:
Kolumnerna startavst och slutavst kommer från NVDB, och stämmer inte längre, då vi ju har klippt upp geometrierna flera gånger. Vi lånar därför dessa kolumner för att istället stoppa in info om z- koordinaten för linjens start- och slutpunkt. Det gör vi med SQL-satserna: UPDATE vag3d SET startavst = (SELECT ST_MinZ(GEOMETRY)); UPDATE vag3d SET slutavst = (SELECT ST_MaxZ(GEOMETRY)); Och denna SQL kör du då I DB Managers SQL-fönster:
Jämför nu gärna resultatet på vägstumparna med den underliggande höjdmodellen! Använd infoverktyget för att jämför höjdvärden på vag3d med höjdvärden i höjdmodellen. Ser det ut som om det funkat så här långt? Något som är konstigt? Vilka parametrar kan man skruva på för att justera slutresultatet? Tips: Om du aktiverar redigering av vag3d kommer, om QGIS standardinställningar används, varje nod markeras med ett rött X. Detta gör det lättare att se var stumparna börjar och slutar. Om vi är nöjda med resultatet såhär långt är nästa steg att beräkna lutningen. Jag har redan förberett vägtabellen med en kolumn för detta, slope. För att räkna fram lutningen kör vi följande SQL-sats: UPDATE vag3d SET slope = (((SELECT ST_MaxZ(GEOMETRY))-(SELECT ST_MinZ(GEOMETRY)))/(SELECT ST_Length(GEOMETRY))); Lutningen kommer att anges i decimaler, där 0,1 är samma sak som 10%. Sätt en lämplig stil på resultatet, baserat på värdena för lutningen. Kanske dela in i tre klasser, under 1%, 1-10%, över 10%? Studera sedan resultatet, och jämför gärna med Lantmäteriets höjdmodell, samt deras bakgrundskarta. Såhär kan det se ut, t ex:
Avslutande funderingar Fundera på om detta var en bra analys! Vad har vi gjort för antaganden, på vilka sätt har vi bearbetat data? Exempel på frågeställningar: Vi har nu en massa korta (under metern, och tom under centimetern) vägstumpar. Tillför de något? Vad händer om man struntar i att hacka upp vägarna i bitar om 2 noder, utan nöjer sig med att kapa dom till 20-m-längder? Vad händer om man inte kapar vägarna alls? Vilka höjder har vi satt på vägarna egentligen? Kan det finnas fel i höjdmodellen, och i så fall vilken typ av fel? Är nearest neighbor en vettig algoritm att använda för att överföra data från höjdmodellen till vägnätet?