• No results found

En topologisk representation av en polygon; det rakkantiga skelettet

N/A
N/A
Protected

Academic year: 2021

Share "En topologisk representation av en polygon; det rakkantiga skelettet"

Copied!
47
0
0

Loading.... (view fulltext now)

Full text

(1)

En topologisk representation av en polygon;

det rakkantiga skelettet

Hanna Wallin

Stockholm 2011

(2)

Abstract

The aim of this thesis project is to produce an algorithm for finding a topolo-gical representation of a polygon, called a straight skeleton, using floating point arithmetic. Various straight skeleton algorithms are examined and discussed with a focus on time complexity and one is chosen for implementation. This imple-mentation is then compared with the open source library CGAL with regards to running time. The result is an algorithm which is based on an algorithm by Felkel and Obdrzalek and which, for polygons with more than five thousand vertices and three significant digits representing points, runs around 25% faster than CGALs implementation. Complications regarding the use of floating-point arithmetic are also discussed.

Sammanfattning

(3)

Förord

Detta examensarbete har utförts i samarbete med Tomologic, ett företag som byg-ger mjukvara för att optimera utläggning och utskärning av former på plåtskivor till stålindustrin. Detta för att minska spill vilket sparar pengar åt företagen och även sparar resurser vilket är effektivt ur miljösynpunkt. För att skriva en sådan mjukvara krävs mängder av algoritmer för en stor samling geometriska problem. Rakkantiga skelett, vilka är topologiska representationer av skelett, är en av dessa geometriska problem och är det problem som undersöks i denna rapport.

(4)

Innehåll

1 Inledning 5 1.1 Syfte . . . 7 1.2 Upplägg . . . 7 2 Definitioner 9 3 Rakkantiga skelett 10 3.1 Hörnhändelser . . . 10 4 Algoritmer 14 4.1 Den naiva algoritmen . . . 14

4.2 Felkel och Obdrzaleks algoritm . . . 15

4.3 Eppstein och Ericksons algoritm . . . 16

5 Algoritmval 17 6 Algoritm 17 6.1 Polygontraversering . . . 17

6.2 Polygon med hål . . . 17

6.3 Ingående kanter, ugående kanter och bisektriser . . . 18

6.4 Algoritmbeskrivning . . . 18

6.4.1 Kanthändelse . . . 20

6.4.2 Klyvningshändelse . . . 22

6.4.3 Att finna klyvningspunkten . . . 24

6.4.4 Hörnhändelse . . . 25

6.4.5 Samtida händelse . . . 25

6.4.6 Samtida händelser i samma punkt . . . 28

6.4.7 En kant klyvd av flera hörn . . . 31

6.4.8 Förändrade kanter och dess effekter . . . 32

6.4.9 Händelser hos polygoner med hål . . . 32

7 Implementeringen 34 7.1 Skillnader från denna implementation och den ursprungliga algorit-men . . . 34

7.2 Optimeringar som gjorts . . . 35

8 Resultat 36

(5)

9.1.1 Samtida händelse i samma punkt . . . 41

9.1.2 Ej upptäckta skärningspunkter . . . 41

9.2 Talrepresentation . . . 42

9.3 Tolkning av tider . . . 43

9.4 Förslag till förbättringar . . . 44

(6)

1

Inledning

I stålindustrin sker i dagsläget enorma ekonomiska och miljömässiga förluster på grund av den spill som produceras vid utskärning av former i stål. Som tekniken ser ut måste ett säkerhetsavstånd mellan varje form vara stort då lasern orsakar stor skada på området kring formen som skall skäras ut. Formerna packas därför inte optimalt på stålskivan utan placeras med stora säkerhetsmarginaler från varandra.

Den tekniska utvecklingen leder dock mot att laser snart kan skära finare linjer vil-ket leder till att säkerhetsavståndet mellan dessa former kan bli mindre och mindre. När avståndet mellan formerna numera inte längre behöver vara centimeterstort utan millimeterstort kan stora vinster göras om formerna packas så tätt som möj-ligt. Om vi antar att formerna kan representeras av polygoner är detta problem ett klassiskt polygonpackningsproblem (eng. polygon packing problem). Packnings-problem innebär att packa en given mängd polygoner så tätt som möjligt på en yta. Detta är ett välkänt och välutforskat ämne med en mängd tillämpningar. När formerna placerats så smart som möjligt på ytan som representerar stålskivan skall även en skärbana mellan formerna kalkyleras. Detta problem blir en typ av stig-finnarproblem (eng. pathfinding) där smartaste vägen för skärhuvudet att skära ut formerna från stålskivan, med en mängd restriktioner för hur skärhuvudet får röra sig, skall bestämmas.

Packningsproblem och stigfinnarproblem är NP-svåra vilket innebär att man i all-mänhet får nöja sig med heuristiker som approximerar en lösning. Det finns en mängd heuristiker som löser båda dessa problem och som erhåller rimliga tids-komplexiteter men inte alltid med optimalt resultat. Dessa använder en mängd olika typer av geometriska algoritmer och bland dessa återfinns olika typer av ske-lett till polygoner och däribland det rakkantiga skeske-lettet. Det rakkantiga skeske-lettet kan nämligen användas för att approximera stigen skärhuvudet skall ta mellan po-lygonerna. Låt oss först presentera begreppet rakkantigt skelett lite närmare och sedan presentera hur det kan användas för att finna stigen.

(7)

(a)Polygon med offsetvåg. (b) Det rakkantiga skelettet består av hörnens spår vid krympningsprocessen.

Figur 1

Det rakkantiga skelettet tillhör familjen av topologiska skelett till polygoner som även innefattar en än mer känd skelettstruktur vid namn mediala axeln. Den me-diala axeln av en polygon definieras som alla punkter i polygonen vars närmaste punkt på polygonkonturen inte är unik. Hos konvexa polygoner kommer den me-diala axeln att bestå av en mängd linjesegment och är identisk med det rakkantiga skelettet. Att finna den mediala axeln i området kring en reflexiv vinkel (en vinkel över 180o) liknar problemet att finna ekvidistanta punkter till en enskild punkt (det reflexiva hörnet) och lösningen till detta är en parabol. Därför kommer den mediala axeln innehålla kurvor för konkava polygoner till skillnad från det rakkan-tiga skelettet.

Om vi nu återgår till stigfinnarproblemet; som tidigare nämnt packas polygonerna med ett säkerhetsavstånd som trots att det blir mindre och mindre fortfarande måste finnas där. När skärhuvudets bana mellan formerna skall bestämmas vill man självfallet att stigen det skall ta är mitt emellan de två formernas konturer så att skadan lasern gör på stålen begränsas till säkerhetsavståndsytan. Vid rektang-lar som ligger på ett jämt avstånd från varandra är denna skärbana inte särskilt svårberäknad men i mer komplicerade fall med oregelbundna polygoner är det inte lika enkelt. Lösningen är att beräkna ett skelett för den del av ytan som inte täcks av formerna, alltså spillytan. Skelettet kommer att utgöra skärbanan (med små modifikationer).

För att få en skärbana som ligger precis mellan alla former är mediala axeln att föredra. I många fall kan det dock vara en fördel att skelettet endast innehåller raka linjesegment. Raka linjesegment är mycket enklare att beskriva och räkna med. Ett linjesegment representeras med två punkter medan en cirkel är mer svårbeskriven. Därför kan det rakkantiga skelettet vara att föredra framför den mediala axeln.

(8)

tredimensio-nell yta genom att till varje punkt i polygonen tilldelas en z-koordinat som sätts till tidpunkten då krympningsprocessen nått själva punkten. Denna yta består av en mängd ytor som alla har konstant sluttning och som möts i de punkter som utgör det rakkantiga skelettet av polygonen. Om vi tänker oss att den ursprungliga polygonen var en mängd väggar till en byggnad sedd uppifrån motsvarar denna yta ett tak till byggnaden där varje delyta får konstant sluttning. Det rakkantiga skelettet kan alltså användas för att beskriva taket till en ritning av en byggnad.

De befintliga algoritmer som finns för att räkna ut det rakkantiga skelettet har alla relativt hög tidskomplexitet. Den kända algoritm som har lägst tidskomplexitet, en algoritm av Eppstein och Erickson som beskrivs i kapitel 4.3, har komplexiteten O(n17/11+) (där  är en konstant större än 0 och n är antalet hörn) vilket kan jämföras med den mediala axeln som kan beräknas i linjär tid (se [2]). Detta leder till att alla implementationer av befintliga algoritmer för att finna det rakkantiga skelettet har hög körtid. Det är därför intressant att försöka ta till alla medel för att få ner körningstiden. Ett sätt att få ner körningstiden är att räkna med flyttalsaritmetik istället för att räkna med bignum-aritmetik (väldigt stora tal för precisa beräkningar) som är väldigt krävande. Det finns konsekvenser av att jobba med flyttalsaritmetik och dessa diskuteras i kapitel 9.

1.1

Syfte

Syftet med detta examensarbeta är att undersöka olika algoritmer för att finna ett rakkantigt skelett till en polygon. En algoritm skall väljas ut och implementeras och sedan jämföras med CGAL i avseendet körtid. För att läsa mer om CGAL se kompendiet [9].

1.2

Upplägg

(9)
(10)

2

Definitioner

Polygon En mängd icke skärande linjesegment, kanter, som bildar en sluten väg.

Polygon med hål En polygon som innesluter en eller fler mindre polygoner. För vidareutvecklad definition av polygon och polygon med hörn se kompendiet [9].

Kant Ett linjesegment hos polygonen. Hörn Kanter i en polygon möts i hörn.

Bärande linje Den linje som definieras av de två ändpunkterna i ett linje-segment.

Reflexiv vinkel Vinkel mellan 180o och 360o.

Ben Linjesegment tillhörande skelettet.

Led Punkt där två ben möts i skelettet till polygonen.

Ansikte Ytan som en kant passerar under krympningsprocessen. Granne Två kanter är grannar om de delar ett hörn. Två hörn är

grannar om de delar en kant. Två bisektriser är grannar om de utgår från två hörn som är grannar.

Offset Polygonen under krympning.

Offsetvåg En kant hos polygonen under krympningen.

Aktivt hörn Ett hörn som tillhör offseten.

Händelse Under krympningsprocessen kan kanter krympa till storlek 0 och även klyvas i vad som kallas för en händelse.

Händelsepunkt Punkten där en händelse inträffar.

Genererande hörn Det eller de hörn vars bisektriser är inblandade i en händel-se.

(11)

3

Rakkantiga skelett

Som tidigare nämnt beräknas en polygon P s rakkantiga skelett genom att låta P krympa på ett sådant sätt att P s kanter rör sig i en konstant hastighet längst en normal till sig själva. Om vi låter P krympa på detta sätt kommer till slut P s area krympa till 0, men under processens gång sker olika typer av händelser som förändrar polygonens utseende;

Kanthändelse Storleken av en kant krymper till 0. De två intilliggande kanterna kommer nu istället att bli grannar och den ur-sprungliga kanten förintas. Hörnet där de nya grannarna nu möts blir en led i skelettet (se figur 2). [1]

Klyvningshändelse Ett hörn med en reflexiv vinkel möter en kant. Offseten kommer att delas i två delar och kanterna kommer att få nya grannar. Punkten där hörnet mötte kanten kommer att bli en led i skelettet (se figur 3). [1]

Hörnhändelse Två hörn med reflexiva vinklar möts. Likt klyvningshändel-sen kommer offseten att delas i två delar och kanter får nya grannar (se figur 4). [6]

När arean av P slutligen är 0 är processen över och spåren som hörnen i P bildat under processens gång bildar skelettet.

I alla algoritmer som rör framtagandet av ett rakkantigt skelett simuleras denna vågrörelse då offseten krymper till den slutligen har arean 0. Under tiden sker dessa olika typer av händelser och de behandlas på lämpligt vis.

Egenskaper Ett rakkantigt skelett S(P ) av en polygon P med n hörn är ett träd som består av n sammankopplade ansikten, n − 2 leder och 2n − 3 ben. Det partitionerar polygonen i n monotona delpolygoner i icke-degenererade fall (för definition av monoton polygon se kompendiet [9]).[6]

3.1

Hörnhändelser

(12)

slutpunkt. Det kan tolkas som att hörnet klöv kanten i två delar, kanten själv och en extra punkt vid den ändpunkt kanten klöv. Vi har dock valt att definiera hörnhändelsen som en egen typ av händelse då vi anser att denna definition är mer intuitiv eftersom att kanten, vid en hörnhändelse, faktiskt inte klyvs till två seperata kanter.

h1

h2

h3

h0

(a) Skelettet till polygonen h0 → h1 →

h2→ h3skall tas fram och h0h1och h2h3

är båda grannar med h1h2.

p

h3

h0

(b) Kanthändelsen p inträffar vilket in-nebär att h1h2 har krympt till 0.

Offse-ten blir polygonen h0→ p → h3och h0p

är granne med ph3.

(c) Arean av offseten har krympt till 0 och det rakkantiga skelettet är framta-get.

(13)

h3 h4

h0

h1

h2

(a) Skelett skall tas fram till polygonen h0 → h1 → h2 → h3 → h4 och här är h0h1granne med h1h2. h2 h3 h4 h0 p1 p2

(b) h3h4klyvs av h1som ersätts med p1

och p2 och polygonen klyvs till

polygo-nerna h0→ p1→ h4och p2→ h2→ h3.

Detta resulterar i att h0p1 och p2h2 ej

längre är grannar med varandra utan med p1h4respektive h3p2.

(c) Arean av offseten har krympt till 0 och det rakkantiga skelettet är framta-get

(14)

h1 h2 h3 h4 h0 h6 h7 h5

(a) Skelettet till polygonen h0→ h1→

h2 → h3→ h4 → h5 → h6→ h7 skall

beräknas och här är h2h3 granne med

h3h4och h5h6granne med h6h7

h1 h0 p1 p2 h5 h4 h2 h7

(b) Hörnen h3 och h6möts och ersätts

med p1 och p2 och splittrar polygonen

till polygonerna h0→ h1→ h2→ p1→

h7och p2→ h4→ h5. Detta resulterar i

atth2p1blir granne med p1h7och p2h4

blir granne med h5p2.

(c) Arean av offseten har krympt till 0 och det rakkantiga skelettet är fram-taget.

(15)

4

Algoritmer

Som tidigare nämnt har det rakkantiga skelettet endast en procedurell definition. Alla undersökta algoritmer för att finna det rakkantiga skelettet simulerar krymp-ningsprocessen på något sätt. Detta begränsar möjligheterna att finna en algoritm som radikalt sänker tidskompexiteten genom att räkna ut skelettet på ett nytt sätt. Vi börjar här med att beskriva den naiva algoritmen för att finna det rakkantiga skelettet, men de två därefter följande algoritmerna bygger på samma ideer som den naiva.

4.1

Den naiva algoritmen

Den naiva algoritmen bygger på att alla händelser med tillhörande koordinater och tidpunkt för träff av offsetvågen räknas ut i första steget. Den första händelsen plockas ut, behandlas, och sedan räknas alla händelser ut igen. Detta upprepas tills inga händelser längre kan räknas ut.

För varje hörn hi i polygonen räknas skärningen mellan bisektrisen som utgår från

hi och bisektriserna som utgår från hi−1och hi+1 ut och dessa är potentiella

kant-händelser. Om vinkeln mellan de kanter som möts i hi är större än 180o måste även

en möjlig klyvnings- eller hörnhändelse beräknas. För alla kanter ki i polygonen

beräknas en klyvnings- eller hörnhändelse för hi. Denna punkt karakteriseras av

att den har samma avstånd från de tre bärande linjerna motsvarande kanten som klyvs och de kanter som möts i hi (se figur 5).

Den första händelsepunkten p av alla beräknade händelsepunkter behandlas. Är denna en kanthändelse innebär det att kanten mellan de två genererande hörnen krymper till storlek noll och de genererande hörnen ersätts av p. Är p en klyv-ningshändelse kommer kanten k som p klyver delas i två nya kanter och polygonen i sig delas i två delar. Det genererande hörnet ersätts av två nya punkter med samma koordinater som p. Slutligen om p är en hörnhändelse kommer polygonen delas i två delar och de genererande hörnen ersätts av två nya punkter med samma koordinater som p.

Nya händelser för alla hörn och leder som fortfarande är aktiva beräknas och händelseförloppet upprepas. Detta upprepas tills polygonen ej längre innehåller några hörn.

(16)

po-h P

Figur 5: Klyvningshändelsepunkten P med genererande hörn h karaktäriseras av att den ligger på samma avstånd från de tre bärande linjerna motsvarande kanten som klyvs och de kanter som möts i h .

lygonen (enligt kapitel 3) får vi en total tidskomplexitet på O(n(r + 1)k) som i värsta fall innebär en tidskomplexitet av O(n3). Eftersom en iteration ger O(rk)

klyvnigns- och hörnhändelser blir minneskomplexiteten O(n2).

Den naiva algoritmen är lätt att implementera och därmed lätt att underhålla och utveckla. Tidskomplexiteten är dock för hög då vi är ute efter en algoritm med bättre praktisk körtid.

4.2

Felkel och Obdrzaleks algoritm

Denna algoritm är en modifierad version av den naiva algoritmen där man undvi-ker att räkna om alla händelser i varje steg. Precis som i den naiva algoritmen gås alla hörn igenom för att finna händelser som hörnet ger upphov till. Den tidigaste händelsen för varje hörn läggs till i en kö där händelsen längst fram i kön nås av offsetvågen först. Skillnaden från den naiva algoritmen är alltså att händelserna sparas i denna kö och inte kastas efter varje iteration. Händelserna plockas från kön en och en, behandlas och nya händelser beräknas sedan utifrån dessa. Alla hän-delser beräknas alltid utifrån den urpsrungliga polygonens kanter, medan offseten sakterliga förändras genom att hörnen ersätts med leder.

För varje hörn hi i polygonen beräknas skärningspunkterna p1och p2 mellan

bisek-trisen som utgår från hi och bisektriserna som utgår från hi−1 och hi+1 och dessa

är potentiella kanthändelser. Om vinkeln mellan de kanter som möts i hi är större

än 180o måste även en möjlig klyvnings- eller hörnhändelse p

3 räknas ut. För alla

kanter ki i polygonen räknas en klyvnings- eller hörnhändelse ut för hi och den av

alla dessa punkter som är närmast hi är sökt p3. Den av p1, p2 och p3 som nås av

(17)

För varje aktiv händelsepunkt p i kön som ligger inuti offseten behandlas p enligt dess typ precis som i naiva algoritmen 4.1. Skärningspunkten blir en ny led i ske-lettet och bisektrisen ett ben. En ny bisektris beräknas utifrån denna nya led, och nya skärningspunkter beräknas och läggs in i kön enligt tidigare. Detta upprepas tills kön är tom. [6]

Precis som i naiva algoritmen så kommer för en konkav polygon med r reflexiva vinklar en klyvnings- eller hörnhändelse räknas ut för varje kant k i polygonen. Skillnaden från den naiva algoritmen är att händelserna sparas i en kö och nya händelser räknas ut endast en gång för varje hörn och för varje led vilket gör att vi blir av med termen n i tidskomplexiteten och får en tidskomplexitet på O(rk) eller O(n2). För varje hörn och led kommer en händelse lagras i kön vilket ger en minneskomplexitet på O(n).

4.3

Eppstein och Ericksons algoritm

Det som gör att den naiva algoritmen och Felkel och Obdrzaleks algoritm har O(n3) respektive O(n2) tidskomplexitet är beräknandet av klyvnings- respektive hörnhändelsepunkter. Eppstein introducerade år 1992 en datastruktur [4] för att bibehålla närmaste punktpar och som här används för att finna nästkommande klyvnings- eller hörnhändelse i subkvadratisk tid. Datastrukturen reducerar pro-blemet av att finna nästkommande händelsepunkt till två dynamiska räckvidds-problem [8];

(1) Bibehåll en dynamisk mängd av trianglar i R3och svara på frågar angående vilket triangel som först träffas av en stråle.

(2) Bibehåll en dynamisk mängd av strålar i R3 och svara på frågar angående

den lägsta (lägst z-koordinat) skärningspunkten mellan en stråle och en triangel.

Vanliga tekniker kan lösa dessa typer av problem i sublinjär tid per operation vilket ger en subkvadratisk tidskomplexitet på O(n1+e+ n8/11+e· r9/11+e ) = O(n17/11+2e)

för alla konstanter e > 0. Minneskomplexiteten blir O(n1+e + n8/11+er9/11+e) =

O(n17/11+2e). [5]

(18)

5

Algoritmval

Algoritmen som implementerats var den introducerad av Felkel och Obdrzaled [6], här kallad FO-algoritmen, och detta trots att Eppsteins och Ericksons [5] algoritm har lägre asymptotisk tidskomplexitet. Vald algoritm verkade dock relativt enkel att implementera till skillnad från Eppsteins och Ericksons där författarna själva nämner att deras algoritm inte är praktiskt gångbar. De nämner att även för polygoner som är speciellt konstruerade för att försvåra för FO-algoritmen skulle den ändå vara snabbare än deras egen algoritm för ett ”rimligt” antal hörn. [5]

Algoritmen är tänkt att användas ute i industrin och därför är det av största vikt att den är just praktiskt gångbar. En algoritm med en låg tidkomplexitet som är svårimplementerad och ändå har relativt hög körtid är ingenting som är önskvärt i industrin då implementationen blir dyr att underhålla för relativt små, om några, vinster. Därför har vi valt att utveckla FO-algoritmen.

6

Algoritm

Vi presenterar här en detaljerad beskrivning av algoritmen. Algoritmen följer FO-algoritmen, men är utökad och något modifierad för att dels klara av polygoner med hål och händelser som sker samtidigt, och dels för att optimera körtiden. Innan vi går in på detaljerna presenteras några begrepp som är viktiga att förstå innan vi går vidare med algoritmbeskrivningen.

6.1

Polygontraversering

Som bekant rör sig offsetvågen inåt polygonen och för att vi ska veta åt vilket håll en kant hos offseten skall förflytta sig under krympningsprocessen måste en riktning hos polygonen och hos krympningsprocessen definieras. När vi talar om polygontraversering talar vi om att gå igenom alla hörn hos polygonen i en given riktning och denna riktning är motsols. Då polygonen traverseras motsols kommer offsetvågen röra sig åt vänster.

6.2

Polygon med hål

(19)

funk-versering skall alla polygonens hörn besökas och detta innefattar även hörnen hos hålen. Under krympningsprocessen då offsetvågen hos den yttre polygonen fär-das inåt kommer offsetvågen från ett hål färfär-das, utifrån hålets perspektiv, utåt och hålet växer i storlek. Då offsetvågen rör sig åt vänster innebär det att hålen traverseras medsols.

6.3

Ingående kanter, ugående kanter och bisektriser

Då polygonen, enligt kapitel 6.1, har en given riktning kommer polygonens kanter består av riktade linjesegment så att varje kant har en start- och en slutpunkt. Varje hörn har en ingående kant och en utgående kant där dessa till en början är den kant vars slutpunkt motsvarar hörnet i fråga respektive den kant vars start-punkt motsvarar hörnet. Utifrån dessa kan hörnets bisektris tas fram som beräknas utifrån vinkeln den utgående kanten måste roteras motsols för att överlappa den inåtgående kanten. Varje kant har även en bärande linje som innehåller kantens start- och slutpunkt (se figur 6).

Hörn ingående utgående αB isek tris

Figur 6: Varje hörn har en ingående och utgående kant, samt en bisektris som delar dess vinkel i två.

6.4

Algoritmbeskrivning

(20)

genom att en offsetpolygon, som från början är en kopia av ursprungspolygonen, uppdateras för varje händelse.

Som nämnts är offseten, från början, en kopia av ursprungspolygonen där nya leder/hörn tillfogas och gamla leder/hörn tas bort varje gång en händelse inträf-far. Krympningsprocessen simuleras genom att händelser ordnas med avseende på deras avstånd från ursprungspolygonens kanter. Då kanterna under krympnings-processen rör sig med konstant hastighet på en normal till sig själva är ett mått på tidpunkten då en händelse sker helt enkelt avståndet från händelsepunkten till polygonkonturen (se figur 7). Avståndet för en händelsepunkt p beräknas vara avståndet från p till ps inåtgående kants bärande linje.

A B

C D

E

Figur 7: Då kanterna rör sig med samma kon-stanta hastighet rör sig varje hörn med en konstant hastighet som kan vara skilda från varandra och kanternas hastighet. Hörn A, B, E har rört sig längre än hörnen C, D vid denna offsetvåg.

När nu offseten är skapad och alla hörns bisektriser är uträknade kan vi beräkna skelettet.

För varje hörn i polygonen beräknas två stycken kanthändelser och om hörnet är reflexivt beräknas även en potentiell hörn- eller klyvningshändelse. Dessa händelser ordnas med avseende på dess avstånd till polygonkonturen enligt tidigare. En händelsepunkt i taget, de händelser med kortast avstånd först, behandlas enligt den specifika händelsetypen om det är så att händelsepunkten är aktiv och fortfarande ligger inom offseten.

(21)

i kommande kapitel. Vid en kanthändelse skapas en led och vid en klyvnings-eller hörnhändelse skapas två leder. Den/de nya ledernas inåtgående och utgående kanter definieras av den/det genererande hörn som var inblandade i händelsen. Detta innebär att de inåtgående och utgående kanterna för alla punkter såväl ursprungliga hörn som leder i skelettet alltid är kanter från ursprungspolygonen. Utifrån ledens ingående och utgående kanter beräknas en bisektris och utifrån denna räknas nya händelsepunkter ut och ordnas med de andra händelsepunkterna.

Detta upprepas tills inga händelser längre finns kvar att behandla eller offseten inte innehåller några hörn.

6.4.1 Kanthändelse

En kanthändelse p är en händelse mellan två intilliggande hörn, h1 och h2, vars

bisektriser skär varandra i punkten. Eftersom endast två intilliggande hörn kan skapa en kanthändelse tillhör hörnen alltid samma polygon vilket innebär att h1

och h2 antingen båda tillhör ursprungspolygonen eller att båda tillhör samma hål

i polygonen. När en kanthändelse sker kommer två ben skapas, ett från vardera genererande hörn till p. Hörnen h1 och h2 ersätts i polygonen med p som blir en

led i skelettet vilket leder till att offseten nu har ett färre hörn. Ingående- och utgående kanter för p sätts till h1s inåtgående kant respektive till h2s utgående

(22)

(a) Polygonen: h0→ h1→ h2→ h3. h1 h2 h 1bisektris h2bisektris in ut in ut h0 h3 (b) Polygonen: h0→ P → h3

Bisektriserna tillhörande h1 och h2

skär varandra i händelsepunkten P vil-ket resulterar i att ben1och ben2läggs

till i skelettet och P ersätter h1 och h2

i polygonen. Ingående kant till P blir h1’s ingående kant och utgående kant

till P blir h2’s utgående kant. h1 h2 P in ut ben 1 ben 2 h0 h3

(c) P s bisektris beräknas utifrån dess ingående och dess utgående kant. Uti-från denna räknas nya skärningspunk-ter med h0 och h3s bisektriser ut.

(23)

6.4.2 Klyvningshändelse

Det är beräknandet av punkter där klyvningshändelser sker och behandlandet av dessa som gör att rakkantiga skelett-algoritmer är långsamma i jämförelse med andra typer av skelettalgoritmer såsom t.ex. mediala axeln. För varje klyvnings-händelse måste nämligen alla punkter i polygonen behandlas vilket ger en kvadra-tisk komplexitet.

I en klyvningshändelse är ett reflexivt hörn h och en kant k, kanten som klyvs, inblandade. Ett ben skapas mellan h och klyvningshändelsepunkten p. Två nya punkter, p1 och p2, skapas på samma koordinater som p och p1s inåtgående kant

blir hs inåtgående kant och dess utgående kant blir k. På samma sätt blir p2s

inåtgående kant k och dess utgående kant hs utgående kant. Polygonen kommer nu delas i två delar så att alla hörn från och med h till och med ks startpunkt hamnar i en polygon där p2 ersätter h. I andra polygonen hamnar alla hörn från och med

ks slutpunkt fram till och med h där p1 ersätter h. Bisektriser för p1 och p2 räknas

ut och nya händelsepunkter utifrån dessa beräknas. För hela händelseförloppet se figur 9.

En klyvningshändelse kan klyva polygonen så att en delpolygon endast innehåller två hörn, och om så är fallet krymper denna delpolygons area till 0 direkt och ett ben skapas mellan dessa hörn.

(24)

(a) Offseten: h0 → h1 → h2 → h3 →

h4

h1 möter kanten h3 → h4 i en

klyv-ningshändelse P . h3 h4 h0 h1 h2 P in ut (b) Polygon 1: h0→ P2→ h4 Polygon 2: P1→ h2→ h3

Ett ben h1 → P skapas. I ena

delpo-lygonen finns alla hörn från och med h1till och med h3och P1ersätter h1. I

andra delpolygonen finns alla hörn från och med h4till och med h1 och P2

er-sätter h1. h3 h4 h0 h1 h2 P1 P2 in ut ut in

(c) P1s och P2s bisektriser utifrån

de-ras respektive ingående och utgående kanter beräknas. Utifrån dessa beräk-nas nya skärningspunkter med h0 och

h4s respektive h2och h3s bisektriser.

(25)

6.4.3 Att finna klyvningspunkten

För att finna punkten p där en klyvningshändelse för ett reflexivt hörn h kan ske måste den kant som kan klyvas av h letas upp. Det kan kännas intuitivt att det skulle vara den första kanten som hs bisektris skär, men detta behöver inte vara fallet (som synes i bild 10a). Den kan dock inte ligga ”bakom” hörnet h, så vi kan bortse från alla kanter vars bärande linje skär hs bisektris bärande linje i den delen av bisektrisen som vi ej är intresserade av (se bild 10b).

En kandidat p till potentiell klyvningspunkt för en kant k tas fram genom att beräkna skärningspunkten mellan hs bisektris och bisektrisen mellan hs ingående kants bärande linje och ks bärande linje. Om denna skärningspunkt ligger till höger om ks startpunkts bisektris och till vänster och ks slutpunkts bisektris är den en möjlig klyvningspunkt.

För ett reflexivt hörn h undersöks alla kanter i polygonen för att finna den kant som h kan tänkas klyva. En potentiell klyvningspunkt för varje kant beräknas och det är sedan den kandidat som ligger närmast h som blir hs potentiella klyvningspunkt. Speciell hänsyn måste tas om polygonen innehåller hål, se avsnitt 6.4.9.

(a) En potentiell klyvningshändelsepunkt för hörnet h0 och kanten h3h4 skall

beräk-nas. En bisektris räknas ut mellan h0s

inåt-gående kants bärande linje och kanten h3h4s

bärande linje. Skärningspunkten, P , mellan denna bisektris och h0s bisektris är en

po-tentiell klyvningspunkt. Då P ligger till hö-ger om h3s bisektris och till vänster om h4s

bisektris är P godkänd. h0 h1 h2 h3 h4 h5 P

(b) En potentiell klyvningspunkt mellan h och kant behöver inte räknas ut då hs bisek-tris bärande linje skär kants bärande linje i X som ligger bakom h.

h

kant

X

(26)

6.4.4 Hörnhändelse

Hörnhändelsen är väldigt lik klyvningshändelsen och, som tidigare nämnts, väljer somliga att inte urskilja den som en egen händelse utan som ett specialfall av klyv-ningshändelsen. Här väljer vi dock att se hörnhändelsen som en egen händelsetyp. När ett reflexivt hörn möter ett annat reflexivt hörn kommer, precis som i klyv-ningshändelsen, en polygon att delas upp i två delpolygoner. Skillnaden är att två hörn är inblandade i en hörnhändelse och ingen kant.

Två ben skapas, från båda reflexiva hörnen h1 och h2 till hörnhändelsepunkten p.

Precis som i klyvningshändelsen skapas två nya punkter, p1 och p2, med samma

koordinater som p. Polygonen delas i två delar så att alla hörn från och med h1

till, men inte med, h2 hamnar i en polygon där p2 ersätter h1. I andra polygonen

hamnar alla hörn från ursprungspolygonen från och med h2 till, men inte med,

h1 där p1 ersätter h2. Ingående och utgående kanter för p1 blir h1s inåtgående

kant respektive h2s utgående kant. Ingående och utgående kanter för p2 blir h2s

inåtgående kant respektive h1s utgående kant. Bisektriser för p1 och p2 räknas ut

och nya händelsepunkter utifrån dessa läggs till i kön.

Precis som i fallet klyvningshändelse kan hörnhändelsen klyva polygonen till del-polygoner med endast två hörn, och är så fallet krymper dessa deldel-polygoners area till 0 direkt och ett ben skapas mellan dess hörn. Även här måste viss logik till om h1 och h2 inte tillhör samma polygon (se 6.4.9).

6.4.5 Samtida händelse

Det finns en problematik i fallet då en mängd händelser, H, sker samtidigt (eller nås av offsetvågen samtidigt). Vi tänker oss en rektangel som bildar ett hål inuti en större rektangel (se bild 11a) så att ett av hålets hörns bisektriser överlappar ett av den yttre polygonens hörn bisektriser. När hålet växer och den yttre polygonen krymper inser vi att kanterna h7h4och h6h7kommer smälta samman med kanterna

h1h2 respektive h2h3 vid samma tidpunkt. Problemet är att händelserna sker i

samma tidpunkt och kan därför ske i godtycklig ordning. När en av händelserna sker, i vårt exempel P2, kan denne ge upphov till nya händelser som även de sker

i samma tidpunkt, i exemplet P5. Återigen kan de händelser som sker i samma

tidpunkt ske i godtycklig ordning och om nu P5 sker först kan inte h7h4 smälta

samman med h1h2 såsom skulle skett.

(27)
(28)

(a) Rektangeln h0 → h1 → h2 →

h3 innesluter den mindre rektangeln

h4 → h5 → h6 → h7. Kanterna

h7h4 och h6h7 kommer smälta

sam-man med kanterna h1h2 respektive

h2h3 i samma tidpunkt. h0 h1 h2 h3 h4 h5 h6 h7 (b) I kön: P2 → P1 → P3. Alla

händelser i kön sker samtidigt och kommer därför i godtycklig ordning. Först ur kön plockas P2 och

behand-las enligt hörnhändelsetypen. h0 h1 h2 h3 h4 h5 h6 h7 P1 P2 P3 (c) En kanthändelse, P5, beräknas

utifrån P2 och kön kan nu se ut som;

P5 → P1 → P3. Först sker därför P5

vilket omöjliggör P1 (eftersom P1 nu

inte ligger inuti offseten) vilket inne-bär att hörnet h4 numera inte kan

delta i en händelse. h0 h1 h2 h3 h4 h5 h6 h7 P2 P5 P1 P3

(d) Istället skulle en händelsefamilj bestående av P1 och P3 skapats då

P2 plockats ur kön. Den möjliga

kanthändelsen P5 hade fortfarande

adderats till kön, men då den inte låg inom händelsefamiljen hade den inte skett före P1 och P3. Alla händelser

i händelsefamiljen sker i en följd och när P5 sedan plockas ur kön kan den

inte ske eftersom P2 ej längre är

ak-tiv. h0 h1 h2 h3 h4 h5 h6 h7 P5 P1 P2 P3

(29)

6.4.6 Samtida händelser i samma punkt

Att flertalet händelser sker samtidigt i samma punkt är ett degenererat fall som kan leda till problem om det inte behandlas på rätt sätt. Vi tänker oss en kvadrat. Intuitivt vet vi att polygonen kommer krympa till en punkt i mitten av kvadraten och leder kommer skapas från alla hörn till denna punkt (se bild 12b). Detta kommer dock inte ske eftersom den första av kanthändelserna som sker kommer blockera de andra kanthändelserna då de ligger på randen av polygonen (se bild 12a). För att klara av denna situation måste antingen händelsepunkter på randen av offseten tolereras, eller så behandlas alla händelsepunkter som sker i samma punkt samtidigt tillsammans. Vi har valt det senare sättet.

(a) Kanthändelserna h0-h1, h1-h2,

h2-h3 och h3-h0 sker alla samtidigt

i samma punkt P. Om kanthändel-sen h1-h2 sker först ligger de andra

kanthändelserna på randen av offse-ten och kan inte ske.

h0

h1

h2 h3

P

(b)Skelettet till polygonen såsom det borde se ut när händelserna som skedde samtidigt i samma tidpunkt tilläts ske.

h0

h1

h2 h3

P

Figur 12: Samtida händelser i sam-ma punkt

I kapitel 6.4.4 förklarades hur kön gås igenom för varje händelsepunkt p som skall behandlas för att finna punkter att bilda händelsefamiljer av. Nu adderar vi vill-koret att om dessa funna punkter även har samma koordinater som p skall de behandlas tillsammans med p.

Händelserna betraktas alla som hörnhändelser. Ett antal bisektriser träffar samma punkt och de behandlas två och två. Först samlas de genererande hörnen ihop och de hörn, h0 och h1, vars bisektriser har minst respektive näst minst motsols

vinkelsumma till alla andra hörns bisektriser behandlas först (se bild 13b).

Ett ben skapas från vardera hörn, h0 och h1, till p. Sedan skapas en ny punkt p0

som har samma koordinater som p och vars ingående kant blir h1s ingående kant

(30)

hörnhändelse, polygonen delas i två delpolygoner och p0 ersätter h1 i ena

delpoly-gonen. Endast en punkt skapas dock, till skillnad från den vanliga hörnhändelsen, och h1 finns kvar i polygonen.

Efter detta paras h1 ihop med nästa prioriterade hörn, h2, och processen upprepas.

När alla hörn i kön parats ihop paras till slut sista hörnet hnihop med första hörnet

h0 och processen är därmed avslutad. För hela händelseförloppet se figur 13.

Då händelserna betraktas som hörnhändelser och en hörnhändelse genererar två nya hörn till offseten kommer varje egentlig kanthändelse medverka till att det ska-pas ett hörn för mycket (eftersom en kanthändelse endast genererar ett hörn till offseten). Då n kanthändelser sker i samma punkt skapas egentligen bara ett hörn, det mellan hn och h0, eftersom resterande hörn var intilliggande (krav för

(31)

(a) Flertalet hörnhändelser finns i kön och sker samtidigt i punkten P . De genererande hörnen, h1, h2 och

h3, samlas ihop. Det gråa området

symboliserar offseten. h1 h2 h3 P h1 h2 h3 P α β C E

(b) Hörnet h1s bisektris har minsta

sammanlagda vinkel motsols (α + β) till resterande hörns bisektriser.

h1

h2

h3

P P1

(c)Hörnen h1 och h2 behandlas först

tillsammans. En punkt P1 skapas

och polygonen klyvs mellan h1 och

h2.

(d)Detta upprepas sedan för h2 och

h3 och sedan även för h3och h1.

Var-je genererande hörn har nu ersatts av en punkt och polygonen har klyvts till tre polygoner.

P1

C E

P2

P3

(32)

6.4.7 En kant klyvd av flera hörn

När ett hörn klyver en kant som tidigare klyvts uppstår ett problem. När en klyvningshändelse p skett skapas två nya punkter p1 och p2 där p1 hamnar i en

delpolygon och p2 i den andra. Som beskrevs i kapitel 6.4.2 ingick i p2s polygon

alla hörn från det genererande hörnet hs efterföljare till och med startpunkten på kanten och i p1s polygon alla hörn från och med slutpunkten på kanten till hs

föregångare. Den kluvna kanten ingår nu i två delpolygoner och om ett annat hörn nu skall klyva kanten vet vi inte i vilken delpolygon detta är (se 14). Vi måste beräkna punkterna mellan vilka kanten klyvs.

Punkterna vi letar efter, Pstartoch Pslut, karaktäriseras av att p ligger på offsetvågen

mellan Pstart och Pslut som vågen ser ut då själva händelsen p inträffar. För varje

hörn hi som är den aktuella kantens start- eller slutpunkt eller som tidigare klyvt

kanten räknas en offsetvåg ut mellan hi och hi+1 på det avståndet där p skedde.

Om p ligger på denna våg klyvs alltså kanten mellan dessa punkter som är de sökta Pstart och Pslut.

(a) Ett hörn D har klyvt kanten HI och delade då upp polygonen i delpolygon 1: A → B → C → D1 → I och

delpolygon 2: D2 → E → F → G → H.

Nu klyver B och F samma kant och då beräknas B klyva kanten HI mellan D1 och I, eftersom B ligger på offsetvågen D1I, och F beräknas

klyva kanten HI mellan H och D2, eftersom F ligger på offsetvågen HD2.

H D2 E G D1 I A C F2 F1 B2 B1

(33)

6.4.8 Förändrade kanter och dess effekter

Vid alla typer av händelser kommer offsetens kanter att förändras. Vid t.ex. en kanthändelse kommer en kant ks slutpunkt ersättas med händelsepunkten och då skapas en ny bisektris. Detta innebär att k kommer tillåta nya klyvningshändelser som tidigare inte låg på offsetvågen men som nu skulle kunna göra det. För varje händelse som sker förändras alltså minst två kanter hos offseten och för dessa kanter måste nya klyvningshändelser räknas ut för alla reflexiva hörn i polygonen.

6.4.9 Händelser hos polygoner med hål

Det går att tillämpa FO-algoritmen på en polygon med hål, men viss logik måste till för klyvningshändelser och hörnhändelser. Som tidigare diskuterats i kapitel 6.4.2 och 6.4.4 kommer en klyvningshändelse och en hörnhändelse att dela upp polygonen i två delar. Om ett hörn klyver en kant som tillhör en annan poly-gon, vilket fallet ofta är när man arbetar med polygoner med hål, så kommer två polygoner istället att smälta samman till en polygon (se figur 15).

För att behandla en klyvningshändelse eller en hörnhändelse måste en kontroll göras för att se om de inblandade hörnen ingår i samma polygon eller ej. Om de ingår i samma polygon behandlas de enligt kapitel 6.4.2 annars skall den behandlas på ungefär samma sätt, med undantaget att den ena polygonen skall infogas i den andra. Hålet kommer infogas mellan start- och slutpunkten till den klyvda kanten i fallet klyvningshändelse (se bilderna 15b, 15c). I fallet hörnhändelse innebär det att polygonen som utgör hålet infogas mellan föregångaren och efterföljaren till det andra hörnet som var inblandat i händelsen.

(34)

(a) Polygon: D → E → F → G Hål: A → B → C E F G D C B A

(b) Hörnet A möter kanten DE. E F G D C B A (c) Polygon: A2 → B → C → A1 → E → F → G → D

A ersätts i hålet med två nya punkter, A1 och A2. Alla hörn i hålet infogas

sedan mellan D och E.

E A1 C B A2 D G F (d) Skelettet framställt.

(35)

7

Implementeringen

7.1

Skillnader från denna implementation och den

ursprung-liga algoritmen

En del punkter har i denna algoritm vidare utretts och utvecklats från FO-algoritmen. Vissa steg har även förädlats för att ge en snabbare körtid vid implementation.

Dessa punkter har utvecklats från FO-algoritmen: • Hörnhändelser är tillagda (avsnitt 6.4.4).

• I Felkel och Obdrzaleks artikel nämns att FO-algoritmen klarar av polygoner med hål, men funktionalitet måste till för att algoritmen ska klara av att han-tera dessa typer av polygoner. Som visats i avsnitt 6.4.9 smälter hål ihop med varandra och den yttre polygonen under vissa klyvnings- och hörnhändelser och detta måste tilläggas för att inte få ett felaktigt resultatet.

• Händelser som sker samtidigt behandlas separat. Att inte behandla dessa händelser separat (se figur 13d) kan ge ett felaktigt resultat.

• Även händelser som sker samtidigt i samma punkt måste behandlas separat om händelsepunkter på randen av offseten inte skall tillåtas (se avsnitt 6.4.6). • Som nämnt i avsnitt 6.4.8 kommer kanternas ändpunkter att förändras och detta kommer tillåta nya klyvningshändelser. Då varje hörn endast behandlas en gång för att finna händelser utifrån dennes bisektris kommer en klyvnings-händelse som vid detta tillfälle inte ligger på offsetvågen inte att läggas till i kön, men när kantens start- och slutpunkts bisektriser förändras kanske denna klyvningshändelse blir möjlig. Eftersom vi söker efter nya klyvnings-händelser varje gång en kant förändras fångas denna klyvningshändelse upp, men görs det inte kan den gå förlorad vilket leder till ett felaktigt resultat. • Vi lägger till alla, högst tre, möjliga nya händelser för varje behandlad

hän-delsepunkt i kön. Görs inte detta läggs bara den närmaste av händelserna, säg P1, till i kön och de andra två, P2 och P3, förkastas. Det kan dock hända

att P1 är omöjliggjord när den plockas ut ur kön för att den då inte ligger

inom offseten eller liknande, och då kanske en av de andra händelserna P2

eller P3 borde skett. Om dessa inte lades till i kön från början kommer ingen

av dem nu kunna ske vilket kan ge ett felaktigt resultat (se figur 16). • Vi väljer att undersöka om punkten ligger i polygonen innan den ska

(36)

såpass tidigt då det inte är säkert att punkten kommer att behandlas utan kanske är inaktiv då den plockas ut ur kön.

C B A P1 P3 P2

Figur 16: Då nya händelser beräknade utifrån A skall läggas till i kön hittas en klyvningshändelse P1 och kanthändelsen P2. Först sker P2 och i enlighet med FO-algoritmen läggs endast denna till i prioritetskön. När sedan nya händelser beräknas utifrån B läggs även kanthändelsen P3 till. Först i kön är P3 som

behandlas och då omöjliggör P2. Efter detta hade P1kunnat ske, men eftersom den inte var tillagd i kön så kan den inte ske vilken den borde.

7.2

Optimeringar som gjorts

Optimeringar som gjorts innefattar till största del att koden har försökts hållas så ren och enkel som möjligt. En modern kompilator klarar att utföra de flesta typer av optimeringar såsom att ersätta multiplikation med shiftoperationer och att flytta ut onödig kod inuti loopar utanför loopar. Det som tjänas in på att t.ex. rulla ut en loop förloras i läsbarhet och i valet mellan läsbarhet och snabbhet har vi här valt läsbarhet.

Datastrukturer har valts med omsorg, t.ex. används Java.util.ArrayList för att lagra listan av hörn då operationer såsom size, isempty, get, set, iterator och listIterator har konstant tidskomplexitet och add har amorterad konstant tids-komplexitet. ArrayList har linjär tidskomplexitet för för att ta bort element under en iterering till skillnad från t.ex. Java.util.LinkedList som har konstant tidskom-plexitet för en sådan operation, men get används oftare och där har LinkedList linjär tidskomplexitet. Den konstanta termen är också högre i LinkedList vilket påverkar körhastigheten [7].

(37)

så sent som möjligt. Att undersöka om en punkt ligger i en polygon är en mycket kostsam operation (linjär tidskomlexitet) så detta görs helst så sällan som möjligt. Java Virtual Machine (JVM) kan optimera körningstiden ytterligare då den bl a har så kallad Java HotSpot vilket är en runtime optimerare som ser mönster i indata under körning och optimerar för vanlig indata. Anrop kan alltså få lägre körtid efter programmet kört ett tag i jämförelse med första anropet. För poly-goner med ett par tusen hörn handlar det om en sekund för det femte skelettet i ordningen som programmet räknar ut under samma körning. Effekten av denna typ av optimering är därmed marginell och inget som vi fördjupar oss i.

8

Resultat

Under utvecklandet av implementationen har många olika testfall använts, men de som används i körtidstestningen är en yttre kvadratisk polygon med hörn i origo och (10,10) och som innehåller en mängd hål som ligger på ett jämt avstånd från varandra. Hålen är 20-hörningar och liknar kvadrater där olika punkter på kvadratens kontur förflyttats lite åt vänster eller höger så att kvadraten blir "hac-kig"(se figur 17). Den typen av polygoner är bra för att testa slumpartade ”svåra” polygoner eftersom de innehåller väldigt många reflexiva hörn. Koordinaterna för polygonens hörn, vilket är vår indata, har tre värdesiffror.

Metoderna som använts för att mäta körtid är System.currentTimeMillis() för Java och gettimeofday() för C++. Dessa mäter förfluten tid från en referenstid-punkt till anropet, System.currentTimeMillis() i millisekunder och gettimeofday() i mikrosekunder. Tiden efter skelettet är framtaget subtraheras med tiden innan skelettanropet och för gettimeofday() omvandlas mikrosekunder till millisekunder. Dessa mäter alltså förfluten tid och kan ge osäkra resultat om andra processer kör i bakgrunden, men självklart har alla applikationer och åtkomst till nätverk och liknande stängts av innan körning.

Implementationen använde double som flyttalsrepresentation (se avsnitt 9.2).

(38)
(39)

En jämförelse med CGAL Implementationen Polynomisk regression av implementationen CGAL Polynomisk regression av CGAL Antal hörn K ö rt id ( s) 0 1000 2000 3000 4000 5000 6000 120 100 80 60 40 20 0 (a)

Antal hål Antal hörn Implementationen (s) CGAL (s) 16 324 0,921 0,306 36 724 2,224 1,420 64 1284 6,295 5,134 100 2004 12,949 12,688 144 2884 25,366 28,541 196 3924 45,485 54,351 256 5124 75,112 99,299 (b)

(40)
(41)

Som synes i tabell 18b har vår implementation en initialt marginellt högre körtid än CGAL, men går om CGAL strax efter ett par tusen hörn, och har en körtid som är ca 25% snabbare än CGAL efter 5000 hörn. Vi ser direkt i grafen att körtiden inte är linjär i relation till antalet hörn hos polygonen, så vi låter Open Office utföra en polynomisk regression på våra datapunkter för vår implementation och för CGAL. Resultatet syns i diagram 18a och det visar sig att för vår implementation växer körtiden ungefärligen som n1,9 och för CGAL växer den ungefärligen som n2,1.

Vår implementation uppvisar alltså O(n2) beteende såsom förväntat och båda körtiderna ser därmed ut att uppvisa en asymptotisk kvadratisk tillväxthastighet.

9

Diskussion

Som nämnt har vi övergett bignum-aritmetik och valt att använda flyttalsaritme-tik vid implementationen av denna algoritm. Detta för att få ner körningstiden. Implementationen av denna algoritm är tänkt att användas ute i industrin och skärhuvudet som skall följa vår skärbana har inte oändlig precision. Stålskivan som formerna ska utplaceras på är ungefär tre gånger tre meter stor och det är brukligt att den representeras av en fyrkant med hörn i (0, 0) och (10, 10) som är uppdelat i ett rutnät där rutorna är så stora som precisionen hos skärhuvudet.

Vet vi precisionen hos skärhuvudet kan vi räkna ut hur många värdesiffror vår indata till implementationen kommer bestå av. Om skärhuvudet har en precision på millimetern innebär det att vårt rutnät är 10, 000 × 10, 000 rutor stort och att vår indata har 4 värdesiffror. Beroende på skärhuvudets precision kommer koordinaterna till hörnen hos polygonen (som är indata till implementationen) beskrivas av ett visst antal värdesiffror som i sin tur kommer kräva ett visst antal värdesiffror i våra beräkningar för att resultatet skall bli korrekt.

Låt oss utreda korrektheten hos denna algoritm. Vi diskuterar först två problem som kan uppstå om vi inte använder oss av tillräckligt många värdesiffror i våra beräkningar för att sedan gå in på flyttalsaritmetik och val av flyttalsrepresentation för att säkerställa ett korrekt resultat.

9.1

Numerisk stabilitet hos algoritmen

(42)

(a) Två kanthändelser, p1 och p2,

uppfattas ske i samma punkt så P skapas med ingående kant kant2och

utgående kant kant1.

kant1 kant2

h0

h1

h2

P

(b) Egentligen skedde p2i p1+ 

vil-ket inte resulterar i en samtida hän-delse i samma punkt. Först sker p1

och dess inåtgående kant blir kant2

och dess utgående kant blir h1h2.

kant1 kant2 h0 h1 h2 p1 Figur 20

9.1.1 Samtida händelse i samma punkt

Problematik uppstår när vi inte lyckas särskilja två punkter som ligger väldigt nära varandra. Händelsen förknippad med denna typ av problematik är samtida händelser i samma punkt. Vi uppfattar att två händelser, p1 och p2, sker samtidigt

i samma punkt vilket resulterar i endast en led med en resulterande bisektris. Egentligen skedde dock p2 i p1+  vilket hade resulterat i att p1 och p2 inte skedde

i samma punkt och att två separata leder hade skapats med en bisektris vardera vilket hade gett ett helt annorlunda utseende till det rakkantiga skelettet (se figur 20).

9.1.2 Ej upptäckta skärningspunkter

En annan problematik uppstår när vi inte lyckas särskilja lutningarna hos två bisektriser där bisektriserna är nästintill parallella. Vi tänker oss två intilliggande hörn h1 och h2. Vi uppfattar hörnens bisektrisers lutningar, k1 och k2, som lika

och eftersom två parallella linjer ej skär varandra så beräknas en kanthändelse mellan h1 och h2 vara omöjlig. Om k2 egentligen var k1 +  så var bisektriserna

inte parallella och en kanthändelse mellan h1 och h2 hade vart möjlig vilket hade

(43)

Flyttalsrepresentation Bitar Maximal exponent Antal värdesiffror i mantissan (2-potens) (10-potens)

Float 32 1038 23 7

Double 64 10307 52 15

Quadruple 128 104931 112 34

Figur 21: Olika typer av flyttalsrepresentationer.

cision. För att inte råka ut för situationer liknande de som beskrivits i detta kapitel måste vi kunna skilja på alla tal så att vi inte uppfattar två tal som inte är lika som lika eller tvärtom.

9.2

Talrepresentation

Ett flyttal är en approximerad representation av ett reellt tal och approximativt då det endast kan representera ett tal med ett ändligt antal värdesiffror. Ett flyttal består av en teckenbit som avgör om talet är positivt eller negativt, en mantissa som innehåller själva värdesiffrorna för talet och en exponent (som kan ha 2, 10 eller 16 som bas) som kan skala talet (för att läsa mer om flyttal se [9]). Talet innehåller även en ”gömd” bit vilket gör att antalet värdesiffror möjliga i talet är en bit större än mantissan.

Flyttalen finns representerade som primitiva datatyper i de flesta moderna språk och det finns även stöd för dessa datatyper i de flesta moderna processorer vilket gör att det är effektivt att jobba med sådana för att få ner körtiden för en algoritm. I Java ingår stöd för F loat och Double men inte Quadruple som stöds av C + +. För tal med fler värdesiffror än Double klarar av att lagra måste man i Java gå över till att använda bignum-aritmetik genom att använda sig av befintliga bibliotek såsom java.lang.BigNum.

(44)

såda-Precision hos Värdesiffror Värdesiffror Talrepresentation skärhuvudet hos indata i beräkningar

meter 1 4 Float

centimeter 3 12 Double

millimeter 4 16 BigNum

Figur 22: Talrepresentation för skärhuvudsprecision.

na tal inte skall uppfattas som lika då de inte är lika, såsom beskrevs i kapi-tel 9.1, måste vi kunna särskilja dessa två tal. Två rationella tal, p1

q1 och

p2

q2, där

p1, p2, q1, q2 ∈ [−1000, 1000] skiljer sig med minst 10−6 enligt ekvation (1).

p1 q1 − p2 q2 = p1· q2− p2· q1 q1· q2 ≥ 1 q1· q2 (1)

För att vi skall kunna särskilja på lutningarna hos orginalkanterna måste vi därför välja en flyttalsrepresentation som kan lagra minst sex värdesiffror.

Tyvärr räcker det inte att kunna särskilja lutningar på orginalkanterna utan vi måste även kunna särskilja koordinaterna hos leder och lutningar på bisektriser för att inte råka ut för problematiken som beskrivs i kapitel 9.1.2. Detta är lite mer komplicerat då dessa inte behöver vara rationella tal utan beräkningarna av dessa innefattar kvadratrötter. Som tumregel innebär detta att vi förlorar ytterligare en kvadrat då vi utför beräkningar motsvarande ekvation (1) vilket i sin tur innebär att vi behöver går från att behöva sex värdesiffror till tolv.

Beroende på vilken precision skärhuvudet har kan vi enligt ovanstående resone-mang beräkna vilken flyttalsrepresentation som bör användas. Tabell 22 mappar precision hos skärhuvudet mot flyttalsrepresentation som bör användas för att säkerställa ett korrekt resultat.

9.3

Tolkning av tider

(45)

att använda bignum-aritmetik än flyttalsberäkningar och det är svårt att veta vilken av dessa faktorer som väger tyngst.

9.4

Förslag till förbättringar

Förmodligen skulle denna implementation kunna förbättras ytterligare. Väldigt mycket tid går t.ex. åt för att hela tiden räkna ut nya klyvningshändelser då kanter förändras och det kanske går att göra detta smartare och kanske behövs det inte räknas ut nya händelser varje gång. Detta är dock det enda hittills påkomna sättet att lyckas täcka upp alla klyvningshändelser som måste ske.

Det finns algoritmer som klarar att lösa ut det rakkantiga skelettet för speciella typer av polygoner mycket effektivare, t.ex. kan skelettet till en monoton polygon räknas ut med en tidskomplexitet av O(n log n) (se [3]). Eftersom det går att utröna om en polygon är monoton i linjär tid skulle alla sådana polygoner kunna räknas ut på detta vis.

Ytterligare optimeringar skulle kunna göras i koden också, men det gäller då att veta exakt vilka optimeringar kompilatorn och Java HotSpot utför så att man inte lägger krokben för dessa. Vi har valt att hellre skriva tydlig kod som kompilatorn kan optimera än att försöka överlista kompilatorn.

Det ett öppet problem att finna bättre algoritmer för att lösa ut rakkantiga skelett än de som finns. Algoritmen av Eppstein och Ericksson (se [5]) är den kända algoritmen som har asymptotiskt lägst tidskomplexitet för tillfället, men med sin komplexitet O(n17/11+) är det inte helt otroligt att det går att finna en algoritm som har lägre komplexitet än så.

10

Slutsats

(46)

Som synes i tabell 22 skall bignum-aritmetik användas redan vid millimeterpreci-sion hos skärhuvudet. Eftersom vi arbetar med kvadratrötter då vi räknar ut det rakkantiga skelettet måste vi jobba med såpass många värdesiffror att vi tvingas överge flyttalsaritmetik relativt snabbt. Tvingas vi använda java.lang.BigNum för att representera tal förlorar vi tidsvinsterna som Double gav oss och då finns inte längre anledning att inte använda sig av CGAL. Ett anat alternativ hade varit att implementera algoritmen i C++ där Quadruple stöds som primitiv datatyp.

(47)

Referenser

[1] Oswin Aichholzer, Franz Aurenhammer, David Alberts, and Bernd Gartner. A novel type of skeleton for polygons. Journal of Universal Computer Science, pages 752–761, 1995.

[2] Francis Chin, Jack Snoeyink, and Cao An Wang. Finding the medial axis of a simple polygon in linear time. Discrete And Computational Geometry, pages 405–420, 1999.

[3] Gautam K. Das, Asish Mukhopadhyay, Sudhas C. Nandy, Sangameswar Patil, and S. V. Rao. Computing the straight skeleton of a monotone polygon in o(nlogn) time. In Proceedings of the 22nd Canadian Conference on Computa-tional Geometry, pages 207–210, 2010.

[4] David Eppstein. Dynamic Euclidean minimum spanning trees and extrema of binary functions. Technical Report 92-05, Univ. of California, Irvine, Dept. of Information and Computer Science, 1992.

[5] David Eppstein and Jeff Erickson. Raising roofs, crashing cycles, and playing pool: applications of a data structure for finding pairwise interactions. In Proceedings of the fourteenth annual symposium on computational geometry, pages 58–67, 1998.

[6] Peter Felkel and Stepan Obdrzalek. Straight skeleton implementation. In Proceedings of spring conference on computer graphics, pages 210–218, 1998. [7] Oracle. Lesson: Implementations.

http://download.oracle.com/javase/tutorial/collections/ implementations/list.html.

[8] Mirela Tanase. Shape Decomposition and Retrieval:. PhD thesis, Utrecht Uni-versity: Department of Computer Science, 2005.

References

Related documents

2 AS – Förkortning för Aspergers syndrom (Både AS och Aspergers syndrom kommer att användas för att få flyt i språket).. klass för elever med denna diagnos. Under

Särskilt vid tillfällen då läraren själv inte är närvarande, till exempel på raster, är det viktigt att de andra lärarna har en medvetenhet om elevens diagnos och

Ridning är inte bara en hobby, sport eller spel utan fungerar även som ett alternativ behandlingsmetod för både psykologiska och fysiska sjukdomar till exempel genom

Detta kan vi då i nästa led problematisera utifrån dilemmaperspektivet som vi då baserar på dessa utbildningsmässiga problem som enligt Nilholm (2020) inte går att

”Även om de flesta utbildningar för lärare erbjuder kunskap om olika barn i behov av särskilt stöd bör detta givetvis även kompletteras med en kunskap kring olika verktyg för

Hon menar att genom att det finns specialpedagoger så kan läraren/pedagogen anse att ansvaret för barn i svårigheter ligger hos specialpedagogen, det är

Leken är en möjlighet för att föra samman delar av personutvecklingen hos ett barn som skapar en helhet därför är det viktigt att leken är en central del i förskolans

Intentionen med denna studie har varit att undersöka förskollärares uppfattningar om och erfarenheter av barn i behov av särskilt stöd samt inkludering i relation till arbetet med