• No results found

Provinsgenerering med postprocess

N/A
N/A
Protected

Academic year: 2021

Share "Provinsgenerering med postprocess"

Copied!
52
0
0

Loading.... (view fulltext now)

Full text

(1)

Provinsgenerering med

postprocess

HAIMEN ALDABBAGH

Degree Project in

Information and Software Systems

KTH - Royal Institutet of Technology

Stockholm, Sweden - 2014

(2)
(3)

BACHELOR THESIS

DEGREE PROJECT IN INFORMATION AND SOFTWARE SYSTEMS

Provinsgenerering med

postprocess


Haimen Aldabbagh

21 Juli 2014

Stockholm, Sverige

Handledare: Fredrik Zetterman

Examinator: Christian Schulte

TRITA-ICT-EX 2014:105

(4)
(5)

Abstract

This bachelor's thesis is a part of a larger project carried out at Paradox Interactive. The project aims to improve a map generator for the strategy game Europa Universalis IV. This work addresses the creation and implementation of a province generator that divides a pre-generated landscape in provinces. The provinces in the game are the regions on the game map that the game mechanics are based upon.

The improvements that are expected of the new province generator includes the following properties:

The provinces that are created have more logically placed boundaries that are affected by the structure of the landscape.

The program gives the user more control over how the end result should look like by letting the user set the values of input parameters.

The execution should not exceed an approximate time limit. This time limit is set by Paradox Interactive.

The work began with research on the topics map creation and map division to give enough knowledge to plan the implementation of the program. The programming language that is used is Java. The implementation of the program is based on many well-known algorithms in which the most remarkable one is Fortune's algorithm which performs the main task of the provincial division of the program, the creation of Voronoi diagrams. The Voronoi diagrams are used to divide the map into regions which by using a post-process results in the creation of the provinces.

Other well-known algorithms and methods used or addressed in this report include the Lloyd relaxation, Bresenham's line algorithm, Scan Line Flood Fill, Delaunay triangulation and Bowyer-Watson's algorithm.

The result of this work is a Java application that can load a map file containing information of a landscape structure and create a division of provinces with provincial boundaries that depend on the structure of the landscape. The results of the provincial division may be controlled by a number of user defined parameters. The program could not be fully

calibrated during the time of the project because the landscape generator was not ready in time to be able to provide a map of a generated landscape. The generated provinces can be saved as an image file on the hard disk.

Keywords: algorithm implementation, computational geometry, digital cartography, efficiency, post-processing


(6)
(7)

Sammanfattning

Kandidatexamensarbetet är en del av ett större projekt som utförs på företaget Paradox Interactive. Projektets mål är att förbättra en kartgenerator för strategispelet Europa Universalis IV. Det här arbetet avser skapandet och implementationen av en

provinsgenerator som delar in ett färdiggenererat landskap i provinser. Provinserna i spelet är de landsdelar på kartan som spelmekaniken bygger på.

Förbättringarna som förväntas av den nya provinsgeneratorn är bland annat att:

Provinserna som skapas ska ha mer logiska gränser som påverkas av landskapets utformning och inte vara alltför orealistiska.

Ge användaren mer kontroll över hur slutresultatet ska se ut genom användarinmatade parametrar.

Inte överstiga en ungefärlig tidsgräns vid programmets exekvering. Tidsgränsen sätts av Paradox Interactive.

Arbetet började med forskning kring ämnena kartgenerering och kartindelning vilket gav tillräckligt med kunskap för att planera hur programmet skulle implementeras.

Programmeringsspråket som används är Java. Implementationen av programmet bygger på många kända algoritmer där den mest anmärkningsvärda algoritmen är Fortune's algoritm som utför huvuduppgiften för provinsindelningen i programmet, skapandet av Voronoi-diagram. Voronoi-diagramen används för att dela in kartan i ytor som med hjälp av en postprocess resulterar i skapandet av provinserna.

Andra kända algoritmer och metoder som används eller tas upp i den här rapporten är bland annat Lloyd relaxation, Bresenham's linjealgoritm, Scanline floodfill, Delaunay triangulering och Bowyer–Watson's algoritm.

Resultatet av arbetet är ett Java-program som kan läsa in en kartfil med information om landskapsstruktur och skapa en indelning av provinser med provinsgränser som beror på landskapets utformning. Resultatet av provinsindelningen kan styras med hjälp av ett antal användarinmatade parametrar. Programmet hann inte kalibreras fullt ut under arbetets gång på grund av att landskapsgeneratorn inte blev färdig i tid för att kunna bidra med en

genererad landskapskarta. De genererade provinserna kan sparas som en bildfil på hårddisken.

Nyckelord: algoritmimplementation, beräkningsgeometri, digital kartografi, effektivitet, postprocess


(8)
(9)

Innehållsförteckning

Abstract . . . . iii

Sammanfattning . . . . v

1 Introduktion

1

1.1 Bakgrund . . . . 1

1.1.1 Paradox Interactive . . . .

2

1.1.2 Europa Universalis IV . . . .

2

1.2 Problem . . . . 3

1.3 Syfte . . . . 4

1.4 Mål . . . . 5

1.4.1 Uppgifter . . . .

5

1.5 Arbetssätt, etik och risker . . . . 6

1.6 Disposition . . . . 7

2 Teoretisk bakgrund och metoder

9

2.1 Terrängrepresentation . . . . 9

2.2 Voronoi-diagram . . . . 9

2.2.1 Matematisk beteckning och egenskaper . . . .

10

2.2.2 Voronoi-diagram vid kartgenerering . . . .

10

2.3 Delaunay triangulering . . . . 11

2.4 Fortune's algoritm . . . . 12

2.5 Lloyd relaxation . . . . 14

2.6 Bresenham's linjealgoritm . . . . 15

(10)

3 Utförande

17

3.1 Forskningsfasen . . . . 17

3.2 Designfasen . . . . 18

3.3 Implementationsfasen . . . . 20

3.3.1 Voronoi generator . . . .

20

3.3.2 NoisyEdges . . . .

21

3.3.3 Lloyd relaxation . . . .

22

3.3.4 Representation av diagram . . . .

23

3.3.5 Områdesindelning . . . .

24

3.3.6 Datastruktur för provinser . . . .

24

3.4 Postprocessfasen . . . . 25

4 Resultat

27

4.1 Exekveringstid . . . . 28

4.2 Bilder . . . . 30

5 Diskussion och förbättringar

33

5.1 Optimering för cache-minnet . . . . 33

5.2 En förbättrad NoisyEdges . . . . 33

5.3 Kombination av provins- och landskapsgeneratorn . . . . 34

5.4 Framtida arbete . . . . 34

5.5. Slutsatser . . . . 35

Referenser

37

(11)

1 Introduktion

Digital kartografi har under de senaste åren blivit allt vanligare. Eftersom datorer har blivit mer lättillgängliga och datorkraften inte längre är en avgränsande faktor har användandet av digitala kartor stigit. Huvudsyftet med digitala kartor har bland annat varit att hitta positioner, mäta avstånd och få en överblick över hur en region ser ut. Kombinerat med ett

navigationssystem som GPS och användbara algoritmer för att mäta avstånd har digitala kartor blivit mycket populära. Men detta har inte varit det ända användningsområdet som digitala kartor har applicerats på.

Ett annat användningsområde för digitala kartor har varit inom underhållningsbranchen där datorspel använt kartor för att bygga en värld där spelet utspelas. Dessa spelvärldar kan vara skapade för hand för att spelet ska kunna använda sig av sin egen genererade värld eller vara en karta över en region ur vår värld där till exempel Europas karta kan användas för att simulera att spelet utspelas i just Europa. Dessa metoder har däremot en nackdel när de appliceras på spel som är ämnade till att repeteras flera gånger. Det kan bli tråkigt och kännas repetitivt för användaren om spelet har ett begränsat antal kartor så att det utspelas på ett liknande sätt varje gång man startar en ny spelomgång. För att få variation på spelen kan man använda sig av processuell generering för skapandet av spelkartorna.

Processuell kartgenerering är ett sätt att använda olika metoder och algoritmer med kontrollerad slump för att låta datorn ta hand om skapandet av kartor. Detta gör det möjligt att skapa en slumpad karta under en mycket kort tid. Fördelen med att använda processuell generering till att skapa kartor är att användaren kommer att få en ny outforskad karta varje gång en ny spelomgång startar samtidigt som spelets utvecklare inte behöver lägga ner varken tid eller pengar på att skapa kartorna för hand.

1.1 Bakgrund

Vissa datorspel som baseras på kartor använder sig utav ett "rutnät" för att dela in landsdelar eller regioner. På detta sätt kan man skilja mellan olika delar på kartan och använda dessa delar för spelets syfte. Till

exempel använder det kända strategispelet Sid Meier's Civilization (1991) ett kvadratiskt rutnät för att dela in landmassor och hav. Dessa rutor används sedan för att hålla koll på detaljerad information om rutan, bland annat om ytan består utav land eller hav, vilken typ av terräng det är och den ekonomiska användbarheten för området. Användaren kan sedan flytta enheter från ruta till ruta för att bygga städer och utföra uppgifter i spelet.1

Rutnätet i Civilization klarar de krav som

(12)

fungera men eftersom datorkraften har ökat och spelen blivit allt mer komplicerade så har användarnas krav på funktionaliteten hos nylanserade spel ökat. Ett exempel är uppföljaren

till spelet Civilization, Sid Meier's Civilization V (2010) som är det femte spelet i serien. Civilization V har

övergått från ett kvadratiskt rutnät till ett hexagonalt rutnät.2 Ett hexagonalt

rutnät har den geometriska egenskapen att avstånden mellan alla hexagoner är lika stora. Detta är en förbättring jämfört med det kvadratiska rutnätet där

avståndet till en kringliggande ruta inte är detsamma som avståndet till en diagonal kringliggande ruta.

Medan spel som Civilization klarar av att ha ett rutnät med anledningen att spelmekaniken bygger på just den indelningen av kartan så finns det andra typer av spel som behöver bryta sig loss från en sådan indelning. Vissa spel bygger på idéen att spelkartan ska vara

realistisk. Det ska inte finnas ett rutmönster eller tydliga linjer mellan två regioner på kartan. Spel som bygger på dessa typer av kartindelningar måste hantera regioner som

komplicerade polygoner där varje polygon har en unik struktur. Om kartan är skapad för hand kan dessa regioner också ritas ut för hand. Det är däremot mycket mer komplicerat att bestämma regionsindelningar om kartan är processuellt genererad.

1.1.1 Paradox Interactive

Det här kandidatexamensarbetet är en del av ett större projekt som ska utföras på företaget Paradox Interactive. Paradox Interactive är ett svenskt dataspelsföretag grundat år 1995. Företaget baseras i Stockholm och är främst kända för att utveckla och publicera historiska strategispel. Många av spelen som Paradox utvecklar spelas på en riktig världskarta, bygger på historiska sammanhang och håller sig till historiska händelser. Generellt sett får spelaren kontrollera en nation och hantera nationens politik, handel, ekonomi, militära styrkor och den tekniska utvecklingen. Exempel på dessa spel är Crusader Kings, Europa Universalis, Hearts of Iron och Victoria. Paradox publicerar också spel som är utvecklade av andra företag.3

1.1.2 Europa Universalis IV

Spelet Europa Universalis IV (förkortat EU4) är det fjärde spelet i Europa Universalis serien som Paradox har utvecklat. Spelet är utvecklat på spelmotorn Clausewitz 2.5 Engine och släpptes augusti 2013. EU4 bygger på de historiska händelser som skett under tidsspannet för den europeiska utforskningen och koloniseringen av den nya världen. Tidsspannet sträcker sig över 4 århundraden med början år 1444 och slutet år 1821. Genom att styra en valbar nation kan spelarens beslut förändra historiens gång. Spelaren får ta beslut bland annat inom landets militär, handel, politik och ekonomi. Dessa beslut påverkar landets utveckling antingen positivt eller negativt.4

Figur 2: Kartan i Civilization V är uppbyggt av ett hexagonalt rutnät. (Digital Trends, 2010)

(13)

EU4 använder en riktig världskarta för att simulera världen i spelet. Spelmekaniken bygger på att kartan är indelad i provinser. Provinser kan tillhöra nationer och under krig eller förhandlingar kan olika nationer ta över eller släppa ifrån sig olika provinser.

I januari 2014 släppte Paradox en expansion till EU4, Conquest of Paradise. Expansionen fokuserar på kolonisationen av den nya världen. Syftet med expansionen är att Nord- och Sydamerika inte var utforskade under spelets början och spelaren kunde upptäcka och kolonisera en ny värld utan att ha någon aning om hur världen såg ut. Expansionen går ut på att datorn processuellt genererar en eller flera kontinenter där Nord- och Sydamerika ligger varje gång man startar en ny spelomgång.5

1.2 Problem

Kartgeneratorn i Conquest of Paradise expansionen kan generera landskap med

provinsindelningar men implementationen har många aspekter som skulle kunna förbättras. Generatorn som Paradox har utvecklat genererar landskapen på ett sätt som kan anses vara orealistiskt. Provinsindelningen som är en del av kartgeneratorn har vissa problem som tar formen av att provinserna ibland placeras ut på ett overkligt sätt. Detta kan sänka kartans trovärdighet. Eftersom EU4 är ett spel som för det mesta utspelar sig efter verkliga historiska händelser och använder sig utav en riktig världskarta kan det vara viktigt för spelupplevelsen att spelet håller en konstant nivå av realism. Den nuvarande provinsindelningen följer varken naturliga barriärer eller terrängtyper. Detta betyder att medan den verkliga kartan i EU4 kan ha provinser som följer landskapskonturer som bergskedjor eller ha en variabel storlek och form på provinserna beroende på placering och vad det är för typ av mark så kommer den

Figur 3: En skärmdump av spelet Europa Universalis IV. Nord- och Sydamerika är ersatta med processuellt genererade kontinenter. Detta är en funktion i expansionen Conquest of Paradise. (Källa: Europa Universalis IV)

(14)

genererade kartan att ha slumpmässigt genererade landytor som provinser. Eftersom den genererade kartan kombineras med orginalkartan vid varje spelomgång kommer

användaren att kunna skilja på vilken del av kartan som är original och vilken del som är genererad.

Ett annat problem som kan uppstå med den nuvarande provinsindelningen är att två landmassor skilda av en sjö eller ett hav har en chans att bli indelade i samma provins. Detta är inte önskvärt eftersom det både stör realismen på provinsindelningen och spelmekaniken på grund av att man kan flytta trupper i spelet på ett orealistiskt sätt.

Dessutom har den nuvarande kartgeneratorn lite kontroll över resultatet som den genererar och eftersom kartan genereras varje gång användaren startar ett nytt spel eller laddar in en tidigare spelomgång skulle det vara en förbättring om generatorn snabbades upp.

1.3 Syfte

Syftet med det här kandidatexamensarbetet är att få en kartgenerator som till sin helhet eller till bara en viss del kan förbättra eller ha vissa fördelar över Paradox's nuvarande

implementation. Kandidatexamensarbetet är en del av ett större projekt där den andra projektgruppen har till uppgift att arbeta på landskapsgenereringen för kartgeneratorn. Huvuduppgiften med det här arbetet är att konstruera provinsindelningen över

landskapskartan som den andra gruppen genererar.

Anledningen till varför en bättre kartgenerator kan behövas är att, som tidigare nämnt få en mer realistisk karta som stämmer överens med den riktiga världskartan. Fördelen med en realistisk genererad karta är att spelen som använder kartan får en förhöjd nivå av realism vilket kan höja användarupplevelsen för spelaren.

Det är inte ämnat att provinsgeneratorn ska i sin helhet vara bättre än den nuvarande implementationen. Förutom att den nya terränggeneratorn kommer att behöva en

provinsgenerator som kompletterar den så är syftet med att bygga en ny provinsgenerator från grunden att kunna få nya idéer på hur delar av generatorn kan göras bättre. Dessa förbättringar kan sedan användas i framtida implementationer av kartgeneratorn. Ett sätt att förbättra provinsindelningen är att generera provinserna beroende på

landskapskonturer och terrängtyper. Provinsgeneratorn får då ta hänsyn till det genererade

Figur 4: Skärmdumpar som visar en genererad karta med provinsindelningar i expansionen Conquest of

(15)

landskapets utseende och anpassa provinserna efter marken. Exempel på hur detta kan fungera är att en provins inte kan gå över en bergskedja eftersom höjdskillnaderna är för stora eller att en provins som består av ökenlandskap tilldelas en större landyta än en provins som gränsar till en sjö.

Har man tillgång till en tillräckligt stor mäng data om landskapets utseende kan man anpassa provinsindelningen beroende på de tillgängliga variablerna. Man kan då göra genereringen av spelkartan mer interaktiv. Eftersom kartgenereringsprogrammet kommer att ta hänsyn till många faktorer från landskapskartan kan man förse programmet med

inparametrar som bestämmer egenskaperna för provinsindelningen.

När användaren startar en ny spelomgång i EU4 kommer kartan att genereras.

Kartgenereringen utförs samtidigt som spelet laddas. Detta betyder att det tar längre tid än vanligt varje gång man ska starta ett nytt eller ladda in ett existerande spel.

Laddningstiderna för kartgeneratorn ska då inte bli för långa och borde kunna snabbas upp. Examensarbetets utförande kommer att ge erfarenhet av postprocessingmetoder,

optimisering och skapandet av rådata för användning i ett existerande program. Dessa är fördelar som programmeraren kommer att ha nytta av i framtida projekt.

1.4 Mål

Målet med examensarbetet är att implementera en provinsgenerator som kompletterar terränggeneratorn som den andra projektgruppen ska arbeta på. Sammansättningen av terräng- och provinsgeneratorn ska resultera i en kartgenerator som skulle kunna användas som ersättare för Paradox's nuvarande kartgenerator. Det är tänkt att provinsgeneratorn ska byggas om från grunden för att kunna ge nya idéer om hur den nuvarande implementationen kan förbättras.

1.4.1 Uppgifter

Ett flertal olika uppgifter behöver genomföras för att kunna slutföra examensarbetet. En studie av hur spelmotorn hanterar kartor krävs för att kunna arbeta med provinsindelningen. Algoritmerna som ska användas måste skapas, implementeras och anpassas efter

spelmotorn. Skapandet av egen eller modifikation av filformat behövs för att hantera kartorna. Programmeringsspråket som är tänkt att användas är Java.

Provinsgeneratorn ska uppfylla följande krav:

Provinser ska vara av varierande figur och storlek inom ett visst intervall.

Ytan på hela landskapet ska vara uppdelat i provinser. Ingen del av kartan får vara utanför en provins.

Hav ska separeras från landmassor och delas in i egna “havs-provinser”.

Programmet ska ha minst en användarinmatad parameter som påverkar hur stort antal provinser programmet genererar på kartan.

(16)

Under postprocessfasen ska provinsindelningen påverkas av olika faktorer som naturliga gränser eller terrängtyper.

Algoritmen ska uppfylla kraven för kartor med följande begränsningar:

Storleken på kartan är 2100x2000 pixlar.

Data ska sparas i en fil på pixelbasis där varje pixel representeras av en eller flera byte.

Varje provins sparas med en särskild färg (id-nummer) i filen.

Algoritmerna som används måste vara effektiva och kunna exekvera på en någorlunda kort tid. Exekveringstiden ska inte överstiga en ungefärlig tidsgräns på 15 sekunder men ska helst vara betydligt snabbare.

Dessa uppgifter ska vara uppfyllda för att nå resultaten som förväntas vid projektets slut. Information om hur arbetet fortskrider ska skickas till handledaren under jämna mellanrum och arbetet ska demonstreras hos Paradox Interactive när båda grupperna har något att visa upp. De mer subjektiva kraven på realism bedöms av en expert på Paradox.

1.5 Arbetssätt, etik och risker

Det här kandidatexamensarbetet är, som tidigare nämnt en del av ett större projekt som ska utföras på Paradox Interactive. Arbetet varar under tio veckor där en stor del av arbetstiden går åt rapportskrivningen. Det är tänkt att projektet ska utföras i samarbete mellan två projektgrupper där ena gruppen tar hand om landskapsgenereringen och den andra provinsgenereringen. Arbetet kommer att organiseras efter en agil arbetsmetod där tankar och idéer kan komma att utbytas mellan grupperna. Dagliga möten äger rum för att hålla samarbetet mellan grupperna och se till att båda projektdelarna fungerar ihop för att få den slutgiltiga kartgeneratorn. Projektmedlemmarna skriver också en daglig logg för att kunna överse arbetetsflödet.

En begränsning med arbetet är att projektet inte har någon budget. Detta betyder att licensierade program och biblioteksfunktioner inte går att använda om betalningar eller licensavgifter tillkommer.

Projektmedlemmarna har skrivit på ett NDA-dokument (sekretessavtal) hos Paradox Interactive. Sekretessbelagt material hos uppdragsgivaren får inte läckas och detta gäller också Paradox's nuvarande implementation av kartgeneratorn. Därför tas inget upp om det i det här dokumentet.

Det är troligt att open-source Java-bibliotek kan komma att användas under projektets gång. Dessa bibliotek kan användas för att få tillgång till redan implementerade funktioner och algoritmer i programmet. Om biblioteken är Copyright skyddade måste man ta hänsyn till begränsningarna för användning och modifikation av koden.

(17)

Som med många andra projekt finns det en möjlighet att projektet inte går som planerat. Risken finns att arbetstiden är för kort och provinsgeneratorn inte ger de förväntade

resultaten vid projektets slut. Denna risk gäller också den andra projektgruppen, det vill säga att de andra inte får det förväntade resultatet och sammanslagningen av de två projekten inte lyckas. En annan risk är att implementationen av provinsgeneratorn inte kan nå de tidskrav som sätts upp av Paradox. Eftersom naturliga barriärer och liknande söks måste stora delar av kartan sökas igenom, vilket kostar tid. Är det inte möjligt att bygga effektiva algoritmer kan det vara svårt att få en märkbar förändring från den nuvarande

implementationen av provinsgeneratorn.

I värsta fall kan konsekvenserna bli att Paradox inte kan implementera några förbättringar i sin egen implementation utifrån det som producerats. Men det betyder inte att man inte kan dra nytta av det utförda arbetet. Man kan alltid dra nytta av kunskapen att vissa procedurer inte fungerar bra för att inte göra om samma misstag i framtiden.

1.6 Disposition

Dispositionen för dokumentet och vad som diskuteras i nästkommande avsnitt:

2 Teoretisk bakgrund och metoder

Här beskrivs den teoretiska bakgrunden som tillvägagångssätt, metoder och algoritmer. Det som tas upp i det här avsnittet är viktiga koncept för arbetets utförande. Algoritmerna förklaras i detalj för att ge läsaren en bättre överblick över projektet.

3 Utförande

Det utförda arbetet beskrivs i detalj. Beskrivningen delas in i 4 faser där forskning, design, implementation och postprocess diskuteras. Här tas också upp varför vissa metoder har valts att användas och varför andra metoder förbisågs.

4 Resultat

Beskrivning av projektets slutgiltiga resultat. Vad åstadkommer programmet och vilka förbättringar över den nuvarande implementationen bidrar det med?

5 Diskussion och förbättringar

I det här avsnittet diskuteras slutsatserna för projektet. Programmets implementation och optimering tas upp. Vad har varit positivt, vad har varit negativt och vad kan göras bättre? Hur skulle det se ut om alternativa metoder valdes att användas?


(18)
(19)

2 Teoretisk bakgrund och metoder

I det här avsnittet beskrivs ett antal tillvägagångssätt, metoder och algoritmer som är relaterade till det här arbetet.

2.1 Terrängrepresentation

Terrängkartor kan representeras på en dator med hjälp av en höjdkarta (heightmap). En höjdkarta är en gråskalig bild som består av 256 nyanser av grå färg, se figur 5. Varje nyans representerar en unik höjd på kartan där värdet 0 som är svart färg är den lägsta höjden och värdet 255 som är vit färg är den högsta höjden. Höjden för varje koordinat ökar alltså med ljusheten av den gråskaliga pixeln som den representeras av. Ett vanligt

användningsområde för höjdkartor är satellitgenererade höjdkartor som kartritare och geologer använder för att representera terräng i tredimensionella kartor.6

För att hantera en höjdkarta på datorn brukar man använda en tvådimensionell array av bytes där varje värde motsvarar en höjd på ett koordinatsystem. Varje byte består av 8 bitar och kan spara ett värde mellan 0 och 255. Man kan också spara höjdmappen till en gråskalig 8-bitars bild för lätt filhantering. Höjdkartor brukar kompletteras med ett värde på vattennivån. På så sätt kan man sätta en gräns där alla höjdvärden som är under gränsen målas som hav eller sjöar och resten målas som land.

2.2 Voronoi-diagram

Voronoi-diagram är ett sätt att dela in ett rum i regioner. Diagrammen definierades av den ryska matematikern Georgy Voronoy i sin publikation "Nouvelles applications des

paramètres continus à la théorie de formes quadratiques" år 1908.7 För att skapa ett

Voronoi-diagram behövs en mängd av punkter, så kallade frön. Varje frö har en motsvarande region i Voronoi-diagrammet. Dessa regioner kallas även för Voronoi-celler. En Voronoi-cell består av alla punkter närmast till fröet som tillhör cellen än till något annat frö i diagrammet. Detta betyder att det kortaste avståndet från en punkt på planet till ett av fröna är avståndet till fröet som tillhör cellen som punkten ligger i. Figur 6 visar en illustration av ett Voronoi-diagram.

Voronoi-diagram har många användningsområden. Ett exempel på ett användningsområde är att kartlägga ett Voronoi-diagram över ett ökenlandskap där det finns ett begränsat antal vattenkällor. Man kan representera vattenkällorna som Voronoi-frön i diagrammet. På så sätt kan man slå upp och få reda på var den närmaste vattenkällan ligger för olika platser på

Figur 5: En höjdkarta över världen. Höjdkartan är tagen från Europa

Universalis IV och används för att bygga upp kartan i spelet.

(20)

kartan. Voronoi-diagram har också bland annat använts för att modellera marknader inom ekonomin, studera konkurrensen mellan växter, förklara strukturen i kristaller och beskriva olika kulturers påverkan på regioner.8 Ett mer

modernt användningsområde är till exempel när man vill ta reda på vilken telefonmast som kan förse mobiltelefoner med bäst täckning på en specifik position. Tillämpningen fungerar på samma sätt som i exemplet med vattenkällor med undantaget att det är telefonmastar som används som frön i diagrammet. Varje

telefonmast har hand om en cell på kartan, därav kommer benämningarna "cell tower" och "cellphone".9 Voronoi-diagram har också

använts för att skapa "mossaikfilter" som används i bildredigeringsprogram liknande Adobe Photoshop.10

2.2.1 Matematisk beteckning och egenskaper

Låt mängden P innehålla n Voronoi-frön (punkter) på det tvådimensionella planet R2.

Voronoi-diagrammet för mängden P är en fördelning av planet i n antal celler där varje frö i P tilldelas en cell på planet. En punkt, x på planet ligger i en cell med tillhörande frö, p om och endast om dist(x,p) ≤ dist(x,z) där z är ett frö ur mängden P som är skilt från p och

funktionen dist returnerar det Euklidiska avståndet mellan två punkter.11a Detta betyder att

varje punkt på planet blir tilldelat ett frö där punkten är närmare till fröet än till alla andra frön i mängden P.

Notera att det finns punkter på planet som har lika stort avstånd till 2 eller fler frön. Det är dessa punkter som bygger upp gränserna mellan Voronoi-cellerna. Cellerna är alltså inte disjunkta.12

En annan egenskap med Voronoi-diagram är att varje cell på diagrammet är en konvex polygon.11b Detta betyder att varje inre vinkel mellan två kanter för en Voronoi-cell är mindre

än 180°.

2.2.2 Voronoi-diagram vid kartgenerering

Relationen mellan det här arbetet och användningen av diagram är Voronoi-diagrammens användbarhet för genereringen av kartor. Voronoi-celler är komplexa

polygoner som inte är regelbundna till ett rutnät. Slumpar man fram en mängd med frön och genererar ett diagram för fröna kan man snabbt få ett antal oregelbundet fördelade

polygoner med unika strukturer över planet. Dessa polygoner kan användas för att både skapa terräng och dela in en karta i delar. Mer om procedurer för kartgenerering tas upp under avsnitten 3.1, 3.2 och 5.3 i rapporten.


Figur 6: Ett Voronoi-diagram uppbyggt av 20 frön. Varje frö tilldelas en cell på diagrammet. (Raincomplex, 2013)

(21)

2.3 Delaunay triangulering

En mängd, P av punkter på ett plan kan ha många icke-isomorfa trianguleringar. Med en triangulering på en mängd av punkter menar man att planet delas in i trianglar där punkterna är trianglarnas hörn utan att någon av kanterna i trianguleringen skär en annan kant.11c En

Delaunay triangulering till mängden P, DT(P) är en unik triangulering där ingen av punkterna i P är inuti en omskriven cirkel till någon triangel på DT(P). Trianguleringen är nämnd efter matematikern Boris Delaunay för hans arbete år 1934.13

En omskriven cirkel till en triangel är en cirkel som går igenom triangelns 3 hörn. Relationen mellan Delaunay och Voronoi är att en Delaunay triangulering är den duala grafen till ett Voronoi-diagram.11d Detta betyder att varje par av frön som tillhör två grannliggande celler i

Voronoi-diagrammet skapar en kant i Delaunay trianguleringen. Se figur 7. En annan egenskap hos Delaunay trianguleringar är att man kan få ut hörnen till det motsvarande Voronoi-diagrammet genom att hitta alla mittpunkter till de omskrivna cirklarna för Delaunay trianguleringen. Se figur 8. En av de mest använda algoritmerna för att skapa Delaunay trianguleringar är Bowyer–Watson's algoritm. Algoritmen kan i sin tur användas för att skapa Voronoi-diagram genom att använda relationerna mellan Voronoi och Delaunay.14

När det gäller kartindelningsmetoder med Voronoi är Delaunay triangulering ett viktigt redskap eftersom kanterna i trianguleringen kan representera grannarna till varje Voronoi-cell. Detta kan utnyttjas för att hantera och modifiera indelningen eftersom man kan representera och hålla reda på cellerna på ett bättre sätt när man känner till deras grannar.


Figur 8: En Delaunay triangulering med de omskrivna cirklarna utritade. De röda punkterna är cirklarnas mittpunkter och representerar hörnen i det

motsvarande Voronoi-diagrammet. (Matthias Kopsch, 2012)

Figur 7: Delaunay trianguleringen (svart) för Voronoi-diagrammet (röd). Varje kant i Delaunay

trianguleringen representerar ett par av frön som tillhör två grannliggande celler i Voronoi-diagrammet. (Hferee, 2011)

(22)

2.4 Fortune's algoritm

Det finns ett antal kända algoritmer för generering av Voronoi-diagram och Fortune's

algoritm är en av de mest effektiva. Fortune's algoritm är känd för sin komplexa men intuitiva "plane sweep" 11e uppbyggnad av diagrammen. Algoritmen publicerades av Steven Fortune

på AT&T Bell Laboratories år 1986 i "A sweepline algorithm for Voronoi-diagrams".15

Tidskomplexiteten för algoritmen är O(n*log(n)).11f Förklaringen av algoritmen med

illustrationer är baserad på David Austin's "Voronoi-diagrams and a Day at the Beach".8

Fortune's algoritm använder sig av vad Fortune kallar för "sweep line", en linje som sveper över ett plan med utplacerade frön. Linjen går horisontellt igenom planet från topp till botten. Mängden av alla punkter på planet som ligger på

lika stort avståndet mellan den svepande linjen och ett av fröna formar en parabel. Denna parabel delar in planet i två delar där ena delen består av

mängden av alla punkter som är närmare till fröet än till linjen och den andra delen av alla punkter som är närmare till linjen än till fröet.

Steven Fortune insåg att om man låter linjen svepa ner över planet med frön och ritar ut parablerna mellan linjen och fröna som är ovanför linjen får man en mängd av parabler som öppnar uppåt och har ett minimivärde. Fortune kallar den lägsta gränsen som dessa parabler bildar på planet för "beach line". Vi kallar den här för "kustlinjen". Det som är speciellt med kustlinjen är att korsningarna mellan

parablerna på kustlinjen skapar ett intressant mönster.

En punkt på kustlinjen där två parabler korsar är alltid en punkt som ligger på ett lika stort avstånd mellan de två fröna som tillhör parablerna. Denna korsning markerar gränsen mellan två Voronoi-celler. En kant på Voronoi-diagrammet skapas så länge de två parablerna korsar varandra medan linjen sveper ner över planet.

En punkt på kustlinjen där tre parabler korsar är en punkt som har lika stort avstånd mellan de tre fröna för parablerna. Eftersom punkten har ett lika stort avstånd till de tre fröna kan man säga att det är mittpunkten till den omskrivna cirkeln som tillhör fröna. Fortune kallar därför denna händelse för "circle event", här kallat för "cirkelhändelse". Tre parabler korsar varandra på kustlinjen när den mellersta parabeln knuffas ut ur kustlinjen av de två yttre parablerna. Det betyder att två kanter på Voronoi-diagrammet har sin slutpunkt och en kant har sin startpunkt i skärningspunkten för en cirkelhändelse.


Figur 9: Illustrationen visar vissa element i Fortune's algoritm. Den violetta linjen är linjen som sveper över planet. De röda punkterna representerar de frön som är placerade ovanför den svepande linjen och de gråa punkterna representerar fröna som ligger under linjen. Parablerna visar vilka punkter på planet som ligger närmare till ett frö än till linjen och den gulmarkerade linjen är parablernas nedersta gräns, kustlinjen. (David Austin, 2006)

(23)

Följande illustrationer visar steg för steg hur Fortune's algoritm sätter upp ett Voronoi-diagram från en mängd av utplacerade frön på planet:

Steg 1: Linjen sveper ner över ett frö och en parabel som tillhör fröet skapas.

Steg 2: Linjen sveper ner över det andra fröet och en ny parabel skapas. Den nya parabeln delar den första parabeln i två delar.

Steg 3: De två parablerna korsar varandra på kustlinjen medan den svepande linjen rör sig nedåt. En kant på Voronoi-diagrammet ritas ut där parablerna korsar varandra.

Steg 4: Exekveringen fortsätter, två nya parabler skapas och korsar varandra. Nya kanter på Voronoi-diagrammet fås fram. Till höger kan man se att tre parabler på kustlinjen kommer att korsa.

Steg 5: En cirkelhändelse med mittpunkt på den blåa punkten. Detta resulterar i en förgrening mellan tre kanter på Voronoi-diagrammet och den mellersta parabeln tas ut ur kustlinjen.

Steg 6: Efter cirkelhändelen fortsätter en ny kant att skapas från förgreningen eftersom de två kvarvarande parablerna fortfarande korsar varandra.

Figur 10: Illustrationer tagna från David Austin's "Voronoi-diagrams and a Day at the Beach" som visar hur Fortune's algoritm bygger upp ett Voronoi-diagram. Resultatet av exekveringen visas i figur 11. (David Austin, 2006)

(24)

2.5 Lloyd relaxation

Lloyd relaxation, även känt som Voronoi iteration är ett sätt att jämna ut placeringen av Voronoi-frön för att få mer jämnfördelade celler på ett Voronoi-diagram. Algoritmen är namngedd efter Stuart P. Lloyd för sitt arbete inom ämnet år 1982.16 Många

användningsområden för Voronoi-diagram kräver att positionerna på alla frön slumpas ut på planet. Detta resulterar troligtvis i att cellerna får oreguljära strukturer. Ett sätt att jämna ut cellernas strukturer på är att låta diagrammet gå igenom att par iterationer av Lloyd relaxation.

Algoritmen har för uppgift att flytta på de utplacerade fröna på ett Voronoi-diagram sådant att de nya placeringarna är i de nuvarande Voronoi-cellernas centroider (medelpunkter). Lloyd relaxation kan exekveras flera iterationer efter varandra. Ju mer iterationer som körs desto jämnare Voronoi-diagrammet blir. Fortsätter exekveringen tillräckligt länge går algoritmen in i en stationär fas där cellerna får en kvasi-hexagonal struktur.17

Figur 11: Resultatet av exekveringen av Fortune's algoritm från figur 10. (David Austin, 2006)

Figur 12: Illustrationerna visar Lloyd relaxations påverkan på ett Voronoi-diagram med slumpade frön (vänster). Resultatet genererades på 4 iterationer av algoritmen (höger). (Amit Patel, 2010)

(25)

För varje iteration av Lloyd relaxation sker följande: I. Ett Voronoi-diagram skapas från de nuvarande fröna. II. Centroiderna för cellerna i Voronoi-diagrammet räknas ut. III. Varje frö i diagrammet flyttas till positionen för cellens centroid.

2.6 Bresenham's linjealgoritm

En känd algoritm inom datorgrafiken. Bresenham's linjealgoritm är skapad av Jack Elton Bresenham, 1962 och används vanligtvis för att rita ut raka linjer på en datorskärm.18

Algoritmen avgör vilka punkter mellan linjens start- och slutpunkt som ska fyllas i för att representera den raka linjen på ett kvadratiskt rutmönster som på pixlarna på en datorskärm. Anledningen till varför Bresenham's linjealgoritm är så känd inom datagrafiken är att den är mycket effektiv. Algoritmen använder bara additioner, subtraktioner och bitshiftning för att räkna ut vilka punkter som behöver fyllas i. Dessa är mycket billiga operationer för en vanlig datorarkitektur.19a

2.7 Scanline floodfill

Floodfill algoritmer är användbara algoritmer inom datorgrafiken. Algoritmerna har för uppgift att fylla en area som är länkat genom att alla pixlar inuti arean är markerade med samma färg. På så sätt kan man markera areor med vissa valda färger. Floodfill algoritmer är mest kända för sin användning i ritprogram där de används i fyllnings verktyget.

Den vanligaste typen av floodfill algoritm är 4-vägs floodfill. Denna algoritm börjar på en punkt och expanderar genom att rekursivt fylla i de 4 gränsande punkterna ända tills den gamla färgen ersätts helt av den valda färgen. Algoritmen måste utföra operationer på 4 punkter för varje punkt som ska fyllas i.19b

En mer effektiv algoritm är Scanline floodfill. Denna algoritm hanterar fyllnaden en linje i taget för att undgå att utföra onödiga operationer på alla gränsande punkter. Algoritmen kan delas in i dessa 4 steg20:

I. Fyll linjen som startpunkten ligger på från ena kanten till den andra. II. Medan fyllningen sker, testa höger och vänster linje om de behöver fyllas. III. Om en gränsande linje behöver fyllas, spara punkten på en stack / kö. IV. Repetera för alla punkter i stacken / kön ända tills den är tom.


Figur 13: Figuren visar en linje som är inritad i ett kvadratiskt rutmönster med hjälp av Bresenham's linjealgoritm. (Crotalus horridus, 2007)

(26)
(27)

3 Utförande

Arbetet startade i april 2014 och utfördes av en person. Arbetstiden varade i 10 veckor där rapportskrivningen upptog en stor del av tiden. Beskrivningen av det utförda arbetet delas in i flera faser. Dessa faser är forskningsfasen, planeringsfasen, implementationsfasen och postprocessfasen.

Forskningsfasen utfördes under arbetets början, här ingår forskningen om existerande algoritmer och relaterade arbeten. I designfasen ingår planeringen av arbetets utförande, vilket sätt problemen tacklades på och förklaring till varför vissa metoder valdes och andra förbisågs. Under implementationsfasen beskrivs hur programmet implementerades och hur testningen gick till. Postprocessfasen är programmets slutfas, här utförs beräkningsarbetet för ihopsättningen av provinserna. Nedan beskrivs alla dessa faser i mer detalj. Orsaken till att beskrivningen är uppdelad i dessa faser är för att texten ska bli lättare att följa.

3.1 Forskningsfasen

Projektet började med forskning kring olika kartindelningsmetoder. Enligt anvisningar från Paradox började forskningen med inläsning om Voronoi-diagram och Delaunay triangulering. Idéer uppkom om att använda Voronoi-diagram till att skapa provinser och Delaunay

triangulering till att hålla reda på gränserna mellan provinserna. Forskningen om Voronoi-diagram fortsatte i sökning efter algoritmer för att konstruera Voronoi-diagrammen. En av

algoritmerna som hittades var Bowyer–Watson's algoritm. Denna algoritm skapar ett

Voronoi-diagram genom en Delaunay triangulering. En annan, mer märkvärd algoritm för att konstruera diagrammen är Fortune's algoritm. Denna algoritm är mycket effektiv vilket är en passande egenskap när programmets exekveringstid har en satt tidsgräns. Fortune's algoritm exekverar på O(n*log(n)) tid där n är antalet frön i Voronoi-diagrammet.

Tidskomplexiteten för Fortune's algoritm är bättre än tidskomplexiteten för många andra kända algoritmer vilket ger algoritmen en fördel över dem andra.

Läsningen om Voronoi-diagram och Delaunay triangulering gav en snabb översikt över ämnet och sökning efter relaterade arbeten kunde påbörjas. Amit Patel's arbete, "Polygonal Map Generation for Games" som är publicerat på Red Blob Games21 innehåller många

intressanta aspekter vad gäller användningen av Voronoi-diagram och andra algoritmer för generering av terräng. Hans arbete gav inspiration om hur en provinsgenerator kunde byggas men samtidigt resulterade det i mycket fundering över hur man skulle kunna gå tillväga med implementationen. Den största frågan här var om man skulle bygga generatorn efter den genererade höjdkartan från den andra gruppen eller om man skulle göra som Patel's implementation och använda samma Voronoi-diagram till att både skapa terrängen och få ut provinserna från Voronoi-cellerna. Detta problem diskuteras vidare under

designfasen.

Andra intressanta metoder som Patel använder är Lloyd relaxation och det som han kallar för "Noisy Edges". Båda dessa metoder används för att modifiera Voronoi-diagrammet för att kunna skapa en mer passande struktur på cellerna. Lloyd relaxation är ett sätt att jämna ut

(28)

placeringen på Voronoi-fröna för att få mer jämnfördelade celler. Detta används av Patel för att få regelbundna landsdelar i storlek och form. Lloyd relaxation behöver inte användas för landprovinserna i EU4 men resultaten som man får efter ett par iterationer av algoritmen blir mycket lik havsprovinserna i spelet. "Noisy Edges" är en metod som skapar brus på de raka linjerna i Voronoi-diagrammet. Algoritmen kan användas till att skapa oregelbundna

provinsgränser för landprovinserna.

3.2 Designfasen

Planeringen av programmets design började med grundsteget, att dela in ett plan i delar som inte höll sig till ett regelbundet rutnät. Den mest eleganta lösning som hittades var att använda Voronoi-diagram eftersom diagrammen är i allmänhet oregelbundna när frönas placeringar slumpas ut och Fortune's algoritm har en snabb exekveringstid vilket passar bra med det som krävs av programmet. Dessutom kan man använda Delaunay trianguleringen för diagrammet till att mappa alla celler till varandra. På så sätt kan man hitta alla grannceller till en cell, vilket är viktigt om man vill modifiera cellerna med en postprocess.

Problemet är att indelningen måste ta hänsyn till land och havsfördelningen av höjdkartan och dela in landprovinserna och havsprovinserna med avseende på landskapsstrukturen. Havsprovinserna i EU4 är i de flesta fall större i storlek än landprovinserna. Landprovinserna har också vågiga, oregelbundna kanter medan havsprovinserna har raka kanter med mer regelbundna figurer. Eftersom skillnaderna mellan de två provinstyperna är så stora behövdes två typer av celler. Ett sätt att få två olika typer av cellindelningar är att använda två olika Voronoi-diagram för kartindelningen, ett för landsprovinserna och ett för

havsprovinserna. Kanterna för landprovinsernas Voronoi-diagram behövde modifieras för att få de vågiga, oregelbundna gränserna. Detta kunde göras med en metod liknande Patel's "NoisyEdges". För havsprovinserna skulle man kunna använda Lloyd relaxation för att jämna ut fördelningen och få en struktur som liknar den originala kartan i EU4.

En viktig fråga var om provinsindelning skulle kunna kombineras med den andra

projektgruppens terränggenerering. Tanken är att man först skapar en indelning på ett plan och sedan genererar landskap beroende på denna indelning. Fördelarna blir att man inte skulle behöva hålla reda på var gränserna mellan land och hav ligger på kartan eftersom det är själva provinsindelningen som skapar dessa gränser. Denna idé sköts snabbt ner

eftersom en viktig del av landskapsgenereringen var att använda Perlin Noise, en algoritm som skapar slumpad brus på höjdkartan. Detta betydde att det skulle vara svårt att

bestämma dem exakta gränserna på landskapet vilket ledde till idéen att skapa

provinsindelningen med hjälp av den färdiggenererade höjdkartan. Mer om detta tas upp under avsnitt 5.3.

När grundkoncepten för att hantera Voronoi-diagram blev tydliga fortsatte planeringen till kombinationen av diagrammen med höjdkartan. Problemet var att

Voronoi-diagrammen representerades av grafer medan höjdkartan representerades av en bild med pixlar. Detta betydde att det behövdes komplicerade beräkningar bara för att ta reda på om en pixel låg inuti en polygon i grafen eller inte. Problemet kunde lösas genom att konvertera

(29)

Voronoi-diagrammen till en bild med samma dimensioner som höjdmappsbilden. Detta kan göras med hjälp av Bresenham's linjealgoritm som är en mycket snabb algoritm för att rita ut kanterna för en Voronoi-graf på pixlar. Idéen med att arbeta med kartan på pixelbasis lät som en bra idé eftersom datorer kan utföra heltalsberäkningar på pixlarna mer effektivt än andra typer av beräkningar.

Eftersom höjdkartan och Voronoi-diagrammen kan läsas igenom på samma sätt som bilder så går det att använda modifierade versioner av floodfill algoritmer för att markera ut unika provinser på kartan. En fördel med att göra så är att man kan dela in provinserna efter landskapskonturen och inte bara efter Voronoi-cells formerna. Detta förhindrar bland annat den oönskbara händelsen att två landmassor skilda av en sjö eller ett hav (men som ändå ligger på samma Voronoi-cell) blir indelade som en enda provins.

Efter indelningen är det tänkt att provinskartan ska gås igenom och information om delarna ska läsas in och sparas på minnet. Informationen kan bland annat vara vilka grannprovinser en provins har, storleken på provinsen i antal pixlar, provinsens medelhöjd, terrängtypen för provinsen, om provinsen har en kust och positionen på kartan. Dessa värden kan sedan användas vid postprocessen för att kombinera olika indelningar för att skapa provinser som beror av landskapsstrukturen vilket kan få provinsindelningen att se mer realistisk ut. Efter mycket planering om hur programmet skulle designas sattes följande plan i verk: I. Skapa två Voronoi-diagram, den ena för landprovinser och den andra för havsprovinser.

Diagrammet för landprovinserna ska vara tätare packat än diagrammet för havsprovinser.

II. Kör Lloyd relaxation på diagrammet för havsprovinserna ett antal iterationer för att få bättre distributerade celler likt den originala kartan.

III. Kör "NoisyEdges" på kanterna i diagrammet för landprovinserna för att få mer naturliga provinsgränser.

IV. Konvertera Voronoi-diagrammen till pixlar i 2-dimentionella arrayer med lika stora dimensioner som höjdkartan.

V. Skapa en 2-dimensionell array för provinskartan och iterera igenom höjdkartan och de två diagrammen för att dela in kartan i små områden. Indelningen av dessa områden ska vara beroende av terränggränserna och de två Voronoi-diagrammen. Markera varje område med ett unikt nummer.

VI. Gå igenom provinskartan och samla information om de olika områdena. Informationen som ska samlas är bland annat storlek, höjdskillnader, grannprovinser, position, storlek på kust och terrängtyp.

VII. Postprocess, gå igenom alla områden och sätt ihop de till provinser med hjälp av den information som samlades från provinskartan, se också till att små provinser på terrängtypsgränserna inte blir alltför små.

VIII.Spara provinsindelningarna till fil där varje pixel innehåller ett provinsnummer och representerar en koordinat på kartan.

(30)

För att programmet ska implementeras behöver dessa uppgifter utföras:

Filhantering, läsa från kartfiler

Implementation av Fortune’s algorithm

Implementation av Lloyd relaxation

Implementering av en variant av "NoisyEdges"

Implementering av Bresenham's linjealgoritm

Implementering av en effektiv floodfill algoritm

Uppbyggnad av ett system för att spara information om provinser

Samling av information från kartfilerna

Ihopsättning av två provinser

Implementering av ett system som hanterar och prioriterar ihopsättningen av provinser

Filhantering, skriva till fil

3.3 Implementationsfasen

Programmerinsspråket som används för att implementera provinsgeneratorn är Java och programmeringsmiljön är open-source programmet Eclipse IDE22.

3.3.1 Voronoi generator

Implementationen av programmet började med en sökning på internet efter redan implementerade algoritmer som kunde vara till hjälp för arbetet. Sökningen ledde till ett open-source Java bibliotek för att generera Voronoi-diagram med hjälp av Fortune's algoritm. Biblioteket simplevoronoi som är publicerat på "sourceforge.net"23 den 29:e Juni

2011 och är en översättning från en C++ implementation som i sin tur bygger på Steven Fortune's C implementation till Java. Koden är öppen för användning och modifiering så länge man håller sig till Copyright lagarna genom att inkludera licensen för biblioteket. Java biblioteket simplevoronoi har en enda

metod som tar emot en mängd av x och y värden och returnerar en mängd av objekt som representerar kanter i

diagrammet. För att hantera

Voronoi-genereringen skrevs en metod som slumpar fram punkter på planet och använder

biblioteksmetoden för att returnera Voronoi-diagrammet. Resultatet får man i form av en lista med kanter där varje kant har x och y koordinaterna för start och slut punkten. Dessutom har varje kant information på vilka två celler i diagrammet som kanten delar på.


Figur 14: Bild på det första Voronoi-diagrammet som genererades under examensarbetet.

(31)

Eftersom den andra projektgruppen redan hade skapat ett sätt att visa upp sina höjdmappsbilder på var det enkelt att bygga på deras lösning för att testa att Voronoi-genereringen fungerade som den skulle. Lösningen var att använda programmet

GameMaker: Studio24 för att skapa ett GUI (graphical user interface) som kan rita ut en bild

och hantera visningen av bilden. Ett enkelt sätt att skriva ut kanter som bytes till en fil

skapades och den andra gruppen hjälpte till med att modifiera programmet så att den kunde skriva ut linjer med hjälp av de inbyggda funktionerna i GameMaker. Programmet kunde sedan läsa in kanterna från filen och visa dem grafiskt. Se figur 14. Denna lösning användes inte länge eftersom den ersattes genom att skriva ut diagrammen direkt till bilder, se avsnitt 3.3.5.

3.3.2 NoisyEdges

För att fixa så att gränsen mellan två landprovinser skulle se mer naturlig ut än en rak linje behövdes en metod liknande Amit Patel's NoisyEdges. Tanken var att Patel's lösning var för komplicerad för det som skulle uppnås i provinsgeneratorn. Därför skapades en egen algoritm som delar in de raka kanterna i mindre ojämna kanter. Mer om detta diskuteras vidare under avsnitt 5.2 i rapporten.

Lösningen för att skapa ojämna linjer är relativt enkel. Metoden som skapades tar emot tre parametrar: antal iterationer, en faktor på ojämnheten och själva diagrammet. Här nedan finns en pseudokod för algoritmen där funktionen random() returnerar ett slumpat värde mellan -0,5 och +0,5. Random-funktionen används är en biblioteksfunktion från Javas standardbibliotek.

loopa för antalet iterationer

loopa för alla kanter i diagrammet

edge := den nuvarande kanten

halfDistX := (edge.x2 - edge.x1) / 2

halfDistY := (edge.y2 - edge.y1) / 2

midX := edge.x1 + halfDistX + random() * halfDistX * faktor

midY := edge.y1 + halfDistY + random() * halfDistY * faktor

dela kanten i två nya kanter med hjälp av den uträknade mittpunkten

ersätt de gamla kanterna med de nya

Figur 15: Bilderna visar NoisyEdges påverkan på ett Voronoi-diagram en iteration åt gången. Bilden till vänster visar det originala diagrammet. De nästkommande bilderna visar samma diagram med 1, 2 respektive 3 iterationer av NoisyEdges.

(32)

Tanken med funktionen är att gå igenom alla kanter i diagrammet och ta fram mittpunkter med slumpat avstånd för att skapa ojämnheten. Vid varje iteration delas alla kanter i två delar. Med andra ord fördubblas antalet kanter för varje iteration (kanter * 2^iterationer). Därför bör antalet iterationer begränsas för stora diagram. Slumpen påverkas av två

variabler, faktorn som är en användarinmatad parameter och "halfDist" som är halva kantens längd. Detta betyder att kantens längd påverkar ojämnheten som de två nya delkanterna skapar. Mittpunktens förskjutning förhåller sig då till kantens skala. Rekommenderat antal iterationer av NoisyEdges är 3 för att få en ojämnhet liknande EU4:s orginalkarta.

3.3.3 Lloyd relaxation

På ett liknande sätt som NoisyEdges fixar gränserna för landprovinserna ska Lloyd

relaxation fördela havsprovinserna på ett bättre sätt. Varje iteration av Lloyd relaxation flyttar fröna i Voronoi-diagrammet till de tillhörande cellernas centroider. Metoden som skapades tar emot Voronoi-diagrammet och antal iterationer som inparametrar och returnerar det nya relaxerade diagrammet.

Huvuduppgifterna som metoden utför är följande:

I. Skapa en datastruktur där varje cell i Voronoi-diagrammet har en mängd av punkterna som bygger upp cellens gränser.

II. Beräkna centroidernas position genom att addera x och y värdena för en cells punkter och dela summan med antal värden som adderats.

III. Skapa ett nytt Voronoi-diagram genom att använda de beräknade centroiderna som frön och ersätt det gamla diagrammet med det nya

IV. Loopa för så många iterationer som anges i inparametern.

Tidsåtgången för algoritmen beroende på antal iterationer är linjär eftersom problemets storlek är oförändrad för alla iterationer. Rekommenderat antal iterationer av Lloyd relaxation är en enda iteration för att få en fördelning liknande EU4:s orginalkarta. Den första

iterationen är alltid den mest signifikanta förändringen av diagrammet eftersom diagrammens celler är mer jämnfördelade under de nästkommande iterationerna.


Figur 16: Bilderna visar Lloyd relaxations påverkan på ett Voronoi-diagram en iteration åt gången. Bilden till vänster visar det originala diagrammet. De nästkommande bilderna visar samma diagram med 1, 2 respektive 3 iterationer av Lloyd relaxation.

(33)

3.3.4 Representation av diagram

För att representera Voronoi-diagrammen användes tvådimensionella byte-arrayer med lika stor bredd och höjd som höjdkartan. Diagrammen behövde representeras som pixlar i arrayen för att man skulle kunna utföra operationer mellan dem och höjdkartan. Därför behövdes Bresenham's linjealgoritm för att rita ut diagrammens kanter på arrayerna.

Bresenham's linjealgoritm är en relativt enkel algoritm att implementera. Dessutom behövde algoritmen anpassas till att hantera kanterna från Voronoi-diagrammen och markera

kanterna på arrayerna. På grund av detta implementerades algoritmen från grund istället för att använda en färdig biblioteksfunktion. Följande implementation är tagen från Wikipedia-sidan för Bresenham's linjealgoritm25 och förklarar hur algoritmen fungerar.

void bresenham(x1, y1, x2, y2)

boolean steep := abs(y2 - y1) > abs(x2 - x1)

if steep then

swap(x1, y1)

swap(x2, y2)

if x1 > x2 then

swap(x1, x2)

swap(y1, y2)

int deltaX := x2 - x1

int deltaY := abs(y2 - y1)

int error := deltaX / 2

int y := y1

if y1 < y2 then int yStep := 1 else int yStep := -1

for x from x1 to x2

if steep then point(y,x) else point(x,y)

error := error - deltaY

if error < 0 then

y := y + ystep

error := error + deltaX

Där abs(a) returnerar absolutbeloppet för a, swap(a,b) byter mellan a och b och point(x,y) ritar ut en punkt i det tvådimensionella planet på (x,y) koordinaten. Den booleska variabeln steep och swap(a,b) funktionerna har för uppgift att få iterationen över linjens punkter att gå från den vänstra ändpunkten till den högra där linjens lutningen inte är brant. Detta görs för att slippa hanteringen av felmarginal på båda axlarna. Variabeln error håller reda på när punkten som ritas ut ska skifta värde på y-axeln.

Fördelen med denna implementation är att alla operationerna som utförs är

heltalsoperationer som addition och subtraktion. Den speciella divisionen med 2 hanteras som en bitshiftning till höger. I vanliga datorarkitekturer är det känt att dessa operationer är mycket effektiva. Bilderna i figur 15 och 16 är exempel på diagram som är grafiskt

(34)

3.3.5 Områdesindelning

Nästa steg var att dela in kartan i områden. Detta kan göras med hjälp av en floodfill

algoritm. Tanken är att begränsa de två Voronoi-diagrammen till höjdkartan så att områdena håller sig till terränggränserna. Med hjälp av en satt havsnivå för höjdkartan kan man skapa en ny tvådimensionell array som representerar kartindelningen med separerade land- och havsrutor. Detta görs genom att gå igenom alla element i arrayen för höjdkartan och

markera rutorna i den nya arrayen enligt höjden för varje koordinat. Vi kallar den nya arrayen för områdeskartan.

Floodfill algoritmen som implementerades är en sorts Scanline floodfill som läser in ett Voronoi-diagram för en viss terrängtyp och fyller i alla områden som tillhör samma terrängtyp på områdeskartan med ett unikt id-nummer. Dessutom fyller algoritmen i gränserna på

Voronoi-diagrammet om de inte redan är ifyllda. En postprocess behövdes här eftersom det kan hända att det förekommer sällsynta fall där Voronoi-diagrammet blockerar en pixel från att fyllas. Lösningen till problemet var att hitta dessa pixlar och lägga ihop de med närliggande områden.

Det skapades också en funktion som omvandlar id-numren i områdeskartan till unika RGB-färger (datorstandard för färger) där land- och havsområden kan skiljas åt. Med hjälp av Java-bibliotekets inbyggda funktioner kunde sedan en filhanterare konstrueras. Filhanteraren kan spara områdeskartan till en ".bmp" bild (Bitmap file format26) och dessutom

läsa in bilder till arrayer. Figur 17 visar resultatet för ett testfall med en egen genererad "höjdkarta".

3.3.6 Datastruktur för provinser

Eftersom områdesindelningen bara sparar unika id-nummer på områdeskartan krävdes det ett sätt att organisera dessa områden. Därför skapades en Java-klass som kan spara all info som behövs för att hantera områdena som provinser. Ett provins-objekt kan spara

provinsens id-nummer, storlek i pixlar, landskapstyp (land/hav), terrängtyp, medelaltitud, position på kartan och kuststorlek. Dessutom innehåller objektet listor med vilka områden på områdeskartan som tillhör provinsen och vilka grannprovinser med samma typ av landskap som provinsen har. Grannarna tillhör en egen Java-klass där ett grann-objekt refererar till de två provinserna som gränsar till varandra och håller reda på gränsens storlek i antal pixlar. Tanken med det här systemet är att man ska kunna modifiera och sätta ihop flera områden

Figur 17: Ett testfall som användes för att felsöka programmet. Det här är ett områdeskarta som skapades med en egen genererad "höjdkarta". De blåa områdena representerar hav och resten representerar land. Det kan vara svårt att urskilja vissa områden eftersom de gränsar till andra områden med liknande nyans av samma färg.

(35)

till större provinser och sedan kunna mappa områdena på områdeskartan till dessa provinser för att få den slutliga kartindelningen.

Ihopsamlingen av informationen börjar med att objekt för varje område på områdeskartan skapas. Sedan loopas kartan igenom pixel för pixel för att samla ihop informationen som behövs. Provinsstorleken fås genom att inkrementera räknaren för varje objekt när man stöter på en pixel som tillhör området för objektet. Positionen för en provins fås genom att räkna ut medelpunkten från de minsta och största x och y värdena för varje provins. Höjdinformationen fås från höjdkartan och terränginformationen från terrängkartan. Information om grannar sparas genom att gå igenom alla pixlar och söka igenom pixlarna som ligger nedan eller till höger om den nuvarande pixeln. Om en gräns mellan den nuvarande provinsen och en ny olänkad provins hittas skapas ett grann-objekt och de två grannprovinserna länkas samman, annars inkrementeras storleken på grannarnas gräns. På samma sätt hittar man kuststorleken mellan provinser med olika landskapstyper.

3.4 Postprocessfasen

Under postprocessen sker hanteringen och ihopsättningen av olika områden för att skapa provinsfördelningen. Den här fasen har två syften. Det första syftet är att rätta till alla fel som kan ske vid direkt-mappning av provinser från Voronoi-diagrammen. Ett vanligt problem som sker är att en Voronoi-cell tillkommer på en yta som ligger på gränsen mellan land och hav och området som markeras är för litet för att vara användbart. Ett annat problem kan ske på grund av min implementation av NoisyEdges där det finns en chans att ojämnheten för en kant är så stor att den korsar andra kanter och skapar områden som är bara ett par pixlar i storlek, se avsnitt 5.2. Det andra syftet, som dessutom är huvudsyftet med postprocessen är att kunna sätta ihop områdena till provinser på ett sätt som följer de naturliga barriärerna för landskapet.

För att kunna hantera ihopsättningen av provinserna skapades en metod som tar emot två provinser och sätter ihop dem till en ny provins. Metoden har för uppgift att kombinera de två provinserna genom att bland annat räkna fram den nya storleken, den nya positionen, sätta ihop listorna med alla områden som tillhör de två provinserna och byta ut alla gamla grannar mot grannar till den nya provinsen som skapas. Problemet med grannarna var att det fanns tre typer av grannar, grannar som exklusivt tillhör den första provinsen, grannar som

exklusivt tillhör den andra provinsen och grannar som tillhör båda provinserna. Dessa grannar skulle länka ihop den nya provinsen med dess grannprovinser utan att förlora datan för storleken på gränserna. Detta problem ledde till skapandet av en ny datastruktur för att spara objekt av grannar.

När metoden för sammansättning av provinserna blev klar började planeringen av hur de mest lämpade kombinationerna av provinser skulle bestämmas. Det behövdes ett system som kunde sortera ihopsättningarna efter vissa regler som användaren kunde sätta upp. Idéen var att man kunde skapa ett poängsystem som alla kombinationer klassades efter. Det behövdes en sorterad datastruktur där man enkelt kunde plocka ut en kombination av

(36)

Det som skulle åstadkommas krävde många sorteringar och sökningar genom en lista av alla provinskombinationer (grannar) som fanns. Det är inte så effektivt att iterera igenom en lista med tusentals grann-objekt, därför användes ett binärt sökträd. Binära sökträd har egenskapen att tidskomplexiteten för varje sökning är O(log(n)) vilket är mycket mer effektivt än O(n) för sökning genom en vanlig lista. Dessutom är ett binärt sökträd alltid sorterat vid insättning och uttag av element. Java-biblioteket har bara en trädmängd där det inte går att spara två element av lika stort värde. Därför implementerades ett eget generiskt binärt sökträd som bygger på liknande metoder som Javas implementering. Sökträdet som skapades kan hantera element av lika stora värden genom att iterera vidare och spara elementet i ett av nodens barn (det vänstra barnet). En sökning efter ett element måste nu kontrollera att elementet med samma värde är just det sökta elementet innan någon operation kan utföras.

Poängsystemet implementeras i form av olika metoder som avgör ett slutvärde som

bestämmer vilka kombinationer som är mest gynnsamma. Först och främst tar man hänsyn till provinsernas storlek. På så sätt kommer alla små provinser att rensas bort. Tar man också hänsyn till gränsens storlek mellan två provinser kan man undvika att få alltför ojämna former. Informationen om medelhöjden för varje provins kan användas till att undvika

kombinationer med stora höjdskillnader, kustprovinser och provinser med samma terrängtyp kan också begränsas till storlek och ha en mer gynnsam kombination med andra gränsande provinser av samma typ. För havsprovinserna behöver man bara ta hänsyn till storlek och gränsstorlek för att rensa bort alla provinser som är för små.

Varje gång två provinser sätts ihop tas alla länkade grannar bort från det binära sökträdet och nya grannar med nyuträknade värden läggs till. Poängsystemet som avgör de mest gynnsamma kombinationerna kan modifieras för att ge användaren kontroll över

provinsfördelningens egenskaper.

En annan sak som kan utföras med hjälp av den samlade informationen är att kombinera små närliggande öar med varandra så att man får fina arkipelag. Arkipelag brukar

förekomma på EU4:s originala världskarta och det är något som kan fixas i

provinsgeneratorn med hjälp av den samlade informationen. Öprovinser är de provinser som inte gränsar till någon annan provins. Man kan plocka ut dessa öar och jämföra storlek och position på kartan för att sätta ihop dem med varandra.


Figure

Figur 2: Kartan i Civilization V är uppbyggt av ett  hexagonalt rutnät. (Digital Trends, 2010)
Figur 3: En skärmdump av spelet Europa Universalis IV. Nord- och Sydamerika är ersatta med processuellt  genererade kontinenter
Figur 4: Skärmdumpar som visar en genererad karta med provinsindelningar i expansionen Conquest of  Paradise
Figur 5: En höjdkarta över världen. Höjdkartan är tagen från Europa  Universalis IV och används för att bygga upp kartan i spelet
+7

References

Related documents

Idag har 3PL tullager med andra kunder. Man kan ha tullager för en viss marknad till exempel en världsdel eller land. Det kan bli ett moment 22 med tullager om tullens system

Diagrammet visar fördelningen av intagna förstahandsval till hemkommun, annan kommun inom Göteborgsregionen (GR) samt fristående skola inom GR mellan 2003-2009.. Fördelning

Diagrammet visar fördelningen av intagna förstahandsval till hemkommun, annan kommun inom Göteborgsregionen (GR) samt fristående skola inom GR mellan 2002-2008.. Fördelning

Diagrammet visar antal elever, 1009, som sökt och blivit intagna på en utbildning i annan kommun trots att utbildningen finns i hemkommunen, dvs effekter av

Diagrammet visar antal elever, 993, (12,3 %) som sökt och blivit intagna på en utbildning i annan kommun trots att utbildningen finns i hemkommunen, dvs effekter

/…/ det är ju också, har ju med yrket att göra, just det här med ångesten, det är väl det jag känner är jobbigt men det börjar man ju också lära sig mer och mer

[r]

Mina longitudinella kvantitativa studier, över flera näringsgrenar på en detaljerad näringsgrensnivå, kan bidra till detta forskningsfält (se Mirchandini, 1999; Ahl m.fl., 2014),