I detta inlägg testar jag ett skript som skapar förutsättningar för snyggt ”skruvade” eller ”krökta” etiketter i oregelbundna polygoner.
Häng med så blir det Pythonskript och projicerade singelgeometrier med snygga etiketter. Detta låter ju fantastiskt, men som det visar sig är skriptet inte riktigt i mål för att jag skall vara helt nöjd.
Skriptet kommer ursprungligen vad jag kan hitta av Joachim Ungar (https://eox.at/2015/12/curved-labels/) vilket senare applicerats som javascript av Noah Veltman (https://bl.ocks.org/veltman/403f95aee728d4a043b142c52c113f82). Detta har sedan tillämpats som ett QGIS processkript av Frank Broniewski (https://github.com/frankbroniewski/polygoncenterline/blob/master/PolygonCenterline.py).
Om du följer den senare länken så kan du ladda hem pythonskriptet till din dator. Filen skall du lagra i din hemmakatalog på sökvägen:
.local/share/QGIS/QGIS3/profiles/default/processing/scripts
Katalogen ”.local” är en dold katalog i Linux och den heter nog något annat på Windows (kanske ”local”) och ytterligare något annat på Mac (kanske ”_local”).
När detta är gjort så kommer du åt skriptet från verktygslådan med skript.
Det är lite speciella förutsättningar som krävs för att det skall fungera, vilket kan kräva en del bearbetning först. Jag använder Natural Earth ”regions” i 10 miljoners skala, vilka är multipart och oprojicerade. Båda dessa saker måste ”fixas” först. Som det skulle visa sig lite senare så var detta inte det enda problemet, men det återkommer jag till längre fram.
Multipart till singlepart finns det ett skript för och sedan är det bara att exportera resultatet till ett nytt lager med lämplig projektion. I mitt fall är det globala data så det går ju inte direkt att välja Sweref99TM, så jag väljer Google Mercator, det är ju trots allt bara etiketter i skal 1:10 miljoner.
Nästa ”problem” blir att välja ett passande värde på punktavståndet. Det gäller ju att få en tillräckligt snygg kurva, utan att överdriva med väldigt täta punkter. Det tar bara en massa tid i onödan. Då min projektion inte har någon bra och tydlig enhet så blir det till att testa lite och för att säkerställa att de minsta polygonerna blir någorlunda snygga så landar jag till slut på 100’000. Det tar lite tid, men resultatet blir ganska bra (för körningar med en enda polygon). Det går att välja att bara köra beräkningen på en markerad polygon i ett lager med många polygoner. När jag testat detta lite så provade jag att köra med många polygoner åt gången, och då började de allvarliga begränsningarna uppdaga sig.
Processen körs i flera steg och det är bara det färdiga resultatet som till slut visas på kartan. Jag tror jag räknade till ett tiotal gånger som stapeln räknade upp till 100% i bakgrunden när skriptet kördes. Några steg gick fortare än andra… Alla delsteg hanteras som ”minneslager” så beroende på hur stora dataset man kör bearbetningen på så tar det inte bara en massa tid, utan kan i extrema fall även låsa upp ganska mycket minne (vilket skulle visa sig hade sin förklaring). Om man som jag gör här och kör på lager med många polygoner så tröttnar man på att vänta innan minnet tar slut, processen använder nämligen bara en av CPU kärnorna. Vänta bara tills man kan lasta över beräkningar på grafikkortet med OpenCL (kommer eventuellt i framtida QGIS). Då kan processer som tar lång tid på en CPU kärna gå betyyyydligt snabbare.
Alla attribut från polygonlagret följer inte med till linjelagret som blir resultatet. Vilket förvånade mig något. Genom att läsa skriptet så kan man försöka begripa vad som händer och vad som skulle kunna göra att data inte försvinner.
- Skapa punkter längs polygonens kanter.
- Skapa Voronoipolygoner
- Klipp dessa med ursprungspolygonen
- Gör om polygoner till linjer
- Dela upp linjer i segment
- Ta bort dubletter
- Lös upp geometrierna från steg 3 (dissolve)
- Gör om polygoner från 7 till linjer
- Välj linjer från steg 6 som rör vid ytterlinjen (steg 8)
- Radera alla valda segment (kvar är centrumlinjen)
- Ta fram alla brytpunkter från centerlinjen
- Ta bort alla dubblettpunkter
- Skapa ett fält med uppräknat ordningtal (nu blir det jobbigt om man har många polygoner)
- Skapa en distanstabell för alla punkter (nu blir det RIKTIGT jobbigt för lager med många polygoner. Här ligger det nog en hund begraven.)
- Leta reda på den längsta vägen mellan punkterna (bara en?)
- Någon form av beräkning jag inte riktigt förstår
- Ta fram en linje längs den kortaste vägen mellan punkterna från 15
- Förenkla geometrin och…
- Mjuka upp kurvorna.
Jag förstår inte hela skriptet till 100%, men såvitt jag kan läsa mig till så försvinner attributen redan i steg 1? Sedan verkar det som att man bara kan köra skriptet på enstaka polygoner. Det jag inledningsvis uppfattade som att man inte kunde använda ”multipart” polygoner (vilket man för övrigt inte heller kan), är helt enkelt att man inte kan använda polygonlager med mer än ETT enda objekt i sig. Snacka om begränsning…
Att köra skriptet på enstaka valda polygoner fungerar och är skapligt snabbt, men när jag testade att köra på ett större antal polygoner så uppdagades som sagt problemet och begränsningarna med all önskvärd tydlighet.
För att skriptet skall bli riktigt användbart så är det som jag ser det två saker som måste fixas:
- Attribut från polygonen måste följa med till linjen.
- Det måste gå att köra på lager med flera polygoner.
Om detta sedan skulle visa sig ta lång tid så kan det vara önskvärt att kunna använda flera CPU trådar, men det är inte unikt för det här skriptet.