EÖTVÖS LORÁND TUDOMÁNYEGYETEM INFORMATIKAI KAR PROGRAMOZÁSELMÉLET ÉS SZOFTVERTECHNOLÓGIAI TANSZÉK
Térinformatikai alakzatok 3 dimenziós megjelenítése
Témavezetők:
Szerző:
Giachetta Roberto
Balog Szabolcs Dávid
egyetemi tanársegéd,
programtervező informatikus BSc,
ELTE IK Programozáselmélet és
nappali tagozat
Szoftvertechnológiai Tanszék Valasek Gábor egyetemi tanársegéd, ELTE IK Algoritmusok és Alkalmazásaik Tanszék
Budapest, 2012
A
projekt
az
Európai
Unió
támogatásával,
az
Európai
Szociális
Alap
társfinanszírozásával valósul meg (a támogatás száma TÁMOP 4.2.1./B-09/1/KMR2010-0003).
Köszönetnyílvánítás Ezúton szeretnék köszönetet mondani a kollégáimnak és a projektvezetőnek, Giachetta Robertonak a shape-fájl feldolgozókon végzett munkájukért. Továbbá szeretném megköszönni a konzulenseimnek Giachetta Robertonak és Valasek Gábornak a támogatást, a türelmes útmutatást, segítségükkel megtehettem első lépéseim a számítógépes grafika problémákkal övezett világában. A
projekt
az
Európai
Unió
támogatásával,
az
Európai
Szociális
Alap
társfinanszírozásával valósul meg (a támogatás száma TÁMOP 4.2.1./B-09/1/KMR2010-0003).
Tartalomjegyzék Bevezetés............................................................................................................ 1
1.
2. Technológiai- és elméleti háttér ............................................................................... 2 2.1. Microsoft XNA Framework .............................................................................. 2 2.2 XNA Game ......................................................................................................... 3 2.3 Számítógépes grafika(elméleti háttér) ................................................................ 3 2.4 Vektorok, vektoralgebra ..................................................................................... 4 2.4.1 Vektor .......................................................................................................... 4 2.4.2 Vektorműveletek ......................................................................................... 5 2.5 Fülvágó algoritmus ............................................................................................. 6 2.6 3 Dimenziós kamera ........................................................................................ 10 Felhasználói Dokumentáció ............................................................................. 14
3.
3.1 Előfeltételek ...................................................................................................... 14 3.2 Az alkalmazás részei......................................................................................... 14 3.3 Az alkalmazás használata ................................................................................. 15 3.4 Az InfoForm ablak ............................................................................................ 16 3.5 4.
A kamera mozgatása..................................................................................... 18 Fejlesztői Dokumentáció .................................................................................. 19
4.1 Használati esetek .............................................................................................. 19 4.2 A program felépítése......................................................................................... 21 4.2.1 AEGIS.Core .............................................................................................. 21 4.2.2 AEGIS.IO .................................................................................................. 26 4.2.3. AEGIS.XnaDisplay .................................................................................. 27 4.4 A program statikus terve ................................................................................... 29 4.5 Felület ............................................................................................................... 29 4.5.1. InfoForm .................................................................................................. 34 4.6 VPU (Vertex Processing Unit) ......................................................................... 34 4.7. Kamera ............................................................................................................. 36 4.8. Háromszögelő .................................................................................................. 38 4.9 Tesztelés ........................................................................................................... 41 4.9.1 Fehér doboz tesztesetek ............................................................................ 42 4.9.2 Fekete doboz tesztesetek ........................................................................... 43 5.
Összegzés ......................................................................................................... 46
Irodalomjegyzék ......................................................................................................... 47
1. Bevezetés Miután napjaink modern világában az informatikán belül a grafikus megjelenítés szerepe kulcsfontosságúvá nőtte ki magát, ezért különösen fontos a témakörben használatos hatékony, gyors algoritmusok implementálása az ezzel foglalkozók számára a lehető legnagyobb elérhetőség és kényelem érdekében. Az emberek vizuálissága, a látvány melyet például egy professzionális animációs film grafikája nyújthat, valamint, hogy a probléma, melyre a szakdolgozat megoldást kínál, még nincs megírva a .NET keretrendszerben, kellő motivációt biztosítottak a program elkészítésére. Az XNA, mely a Microsoft által nyújtott DirectX alapú technológia, gyors és egyszerű, továbbá az egyetem és általam is használt technológiákba remekül integrálható, ebből kifolyólag kitűnő lehetőség a grafikus megjelenítéshez, ezért lett a szakdolgozat fő technikai háttere. Jelen XNA-ra épülő shape-fájl megjelenítő az ELTE AEGIS térinformatikai rendszer egy modulja és később továbbfejlesztésre majd integrálásra kerül és szerves része lesz a projekt kliensének, mely a Microsoft WPF technológiára épül. Az internetes műholdfelvételek, a vektoros és raszteres ábrázolású képek robbanásszerű elterjedése kiváló alapot szolgáltattak a szakdolgozat számára (legkézenfekvőbb példa a Google Maps). Ezen fájlok megjelenítése esetén, nagy számú alakzat kirajzolására kerül sor, ami magas műveletigényű, így a feladat kielemzése után az előzetes viszgálatok alapján a legoptimálisabb megoldás került kiválasztásra. Mindehhez szükséges a vektoros és raszteres fájlokban található elemi adatok tökéletes feldolgozása, reprezentációja és ezen adatok felhasználásával az alakzatok kiháromszögelése és kirajzolása. A kirajzolt képre felhelyezésre került egy kamera is, melynek segítségével 3 dimenzióban figyelhetjük meg a kirajzolt képet. A program későbbi továbbfejlesztése és az AEGIS projektbe történő integrációja miatt fontos a pontos feldolgozás, ekkor már bonyolultabb alakzatokat (egylyukas, többlyukas, önmetsző) is háromszögesíteni kell.
1
2. Technológiai- és elméleti háttér Annak érdekében, hogy minél jobban megérthessük a korábban említett feladatot, ez a fejezet némi technológiai hátteret szolgáltat a Microsoft XNA keretrendszerről és egy kevés elméleti anyagot tartalmaz a számítógépes grafikáról, annak matematikai vonatkozásairól.
2.1. Microsoft XNA Framework Az XNA Framework-öt 2004-ben jelentette be a Microsoft, mely a videójátékok fejlesztését hivatott megkönnyíteni, legyen szó PC-ről, vagy akár a Microsoft saját játékkonzoljáról az XBOX360-ról (a legfrissebb XNA Game Studio már a Microsoft okostelefonokra készített Windows Phone 7 operációs rendszerét is támogatja, teljes 3D hardvergyorsítással). [2] A DirectX ekkor már egy kiforrott technológia, és a videójátékok fejlesztését végző cégek legkedveltebb eszköze volt, így nem túlságosan meglepő, hogy az XNA ezen alapokra épül a kezdetek óta. Használatához a már említett Microsoft XNA Game Studio nevű szoftver szükséges, melyet érdemes a Visual Studioval kiegészíteni. Az XNA biztosít a fejlesztő számára audió és videó beágyazást, néhány primitív alakzat kirajzolását, amik a számítógépes grafikában használatosak (erről kicsit később), de számtalan más lehetőség is kinálkozik. Minden XNA alatt készült program egy Game típusú objektum futtatása. Ez a Game osztály a keretrendszer sajátja, egyik nagy előnye, hogy tömérdek mennyiségű kódtól kíméli meg a programozót, hiszen más grafikus könyvtárak alatt (legyen szó OpenGL-ről, vagy épp a DirectX-ről), egy szimpla ablak létrehozása és megjelenítése is kész tortúra, az XNA kód többszörösét lenne kénytelen begépelni a programozó, viszont a Game-nek hála valóban a lényegre kell csak ügyelnie a fejlesztőnek. Az XNA sikerét, megbízhatóságát és erejét mi sem mutatja jobban, mint az a rengeteg „amatőr” kezekből származó ún. Indie játék, melyek közül a Microsoft minden évben díjaz néhányat a Dream Build Play nevű rendezvény alkalmával. [2]
2
2.2 XNA Game Mint ahogyan az korábban szerepelt, minden XNA program egy Game típusból származtatott objektum futtatása. Mikor egy ilyen program fejlesztésébe fogunk, a kapott Game osztályon a következő metódusok felüldefiniálása kötelező és meg is történik (a Visual Studio generálja), többnyire üres, vagy nagyon kevés kóddal: Game(): Létrehozza a Game objektumot, ez az osztály konstruktora. Ide írhatunk minden olyan utasítást, melynek már az objektum létrejöttekor meg kell történnie. Initialize(): A program inicializáló utasításai kerülhetnek a metódus törzsébe, mint az ablak mérete, háttérszíne, az ablak címe stb. A program indulásakor az egyik első lefutó hívás. (Un)LoadContent(): Egyszer meghívásra kerülő programrészlet, minden szükséges forrás, készlet itt betöltendő (vagy az UnloadContent esetben törölhető), játékokhoz például textúrák, vagy éppen a videókártya számára használatos ún. effektfájl. Update(): Ezen metódus belsejébe háttérlogikákat helyezhetünk, mint a világ frissítése, ütközések vizsgálata, de a programhoz szánt zene lejátszásáért felelős kódot is ide érdemes begépelni. Draw(): Természetesen mit érne egy grafikus program kirajzoló metódus nélkül, a Draw() metódussal ez is rendelkezésre áll. Törzsében több tényleges rajzoló utasítás hívható, a tárgyalt kód minden pillanatban meghívódik, mikor rajzolásra van szükség. [2][3]
2.3 Számítógépes grafika(elméleti háttér) Az XNA – mint minden grafikus könyvtár - képes bizonyos primitív alakzatok kirajzolására, továbbá, mivel a számítógépes grafikában óriási szerepe van a 2-3 dimenziós vektoroknak, valamint a mátrixoknak, így ezen matematikai fogalmakhoz is biztosít reprezentációt, a rajtuk értelmezett műveletekkel együtt, ezzel is könnyítve a fejlesztő dolgát. Vegyünk egy síkbeli alakzatot, melynek ismerjük a csúcsainak koordinátáját és az ismert adatok alapján szeretnénk megrajzolni. Ehhez az alakzatot ki kell háromszögelni 3
(1. ábra), mivel a videókártya számára a háromszög a legbonyolultabb alakzat, amit képes rajzolni. A háromszögesítő eljáráshoz pedig szögvizsgálatok szükségesek, amihez elengedhetetlen a 2 dimenziós vektor és a rajta értelmezett skaláris szorzás művelet.
1.ábra: Háromszögesítés
Az ún. forgatás mátrixok segítségével megoldható az alakzatok forgatása, természetesen ezek csupán példák és nem merítik ki a vektoroknak és a mátrixoknak a grafikában betöltött szerepét, hiszen mind 2 dimenziós, mind 3 dimenziós esetben az eltolások is vektorokkal történnek, hogy még egy esetet említsünk.[1] A 2.4-es szakaszban bemutatásra kerül a vektoralgebra a szükséges definíciókkal, az ezt követő 2.5-ös alfejezet pedig a fülvágó algoritmus részletes leírását tartalmazza.
2.4 Vektorok, vektoralgebra Az
alábbiakban áttekintjük a vektoralgebrai
(Minden
művelethez,
definícióhoz megadjuk a megfelelő XNA hívást) A továbbiakban jelölje
a vektorok
halmazát,
alapokat.
a valós számok halmazát.
2.4.1 Vektor
Definíció(Vektor):
Két esetet definiálunk, az első a geometriai, a második az
algebrai eset. Geometriai eset: irányított szakasz, melynek nagysága és iránya van. Algebrai eset: a vektortér halmazának elemei, rendezett n-es, ahol n a dimenziók száma. Jelölés(mindkét esetben): a. 4
XNA
alatt
a
Vector2,
Vector3,
Vector4
osztályok
felhasználásával
definiálhatunk vektorokat (2,3,4 dimenziós vektorok). [3] Definíció: Legyen √|
Ekkor az
vektor hossza: | |
| 2.4.2 Vektorműveletek
Összeadás:
leképezés. Két vektor csak akkor adható össze, ha közös a
kezdőpontjuk, és az ismert paralelogramma szabály szerint értelmezzük az eredményt (lásd: 2. ábra). Az eredményvektor az első operandus kezdőpontjából a második operandus végpontjába mutat. XNA: Add metódus (minden XNA-ban található vector típusra)
2.ábra: Vektorösszeadás
Kivonás: paralelogramma
leképezés. Szintén közös kezdőpont szükséges, és a szabály
szerint
értelmezzük
az
eredményt
(3.
ábra).
Az
eredményvektor a második operandus végpontjából az első operandus végpontjába mutat. XNA: Substract metódus (mindhárom vector típusra létező művelet)
5
3.ábra: Vektorok kivonása
Skaláris szorzás:
leképezés. Mint látható a művelet eredménye egy
skalár az eddigiekkel ellentétben. Jelölése: 〈
〉
. Létezik értelmezése az
euklideszi térben, valamint egy általános változata, mely tetszőleges dimenziójú vektortérre megadható. Euklideszi változat: 〈
〉
| | | |
| |
közrezárt szöge. Általános változat (n dimenziójú vektortérre összegzéssel felírva): 〈 ∑
ahol
, az
〉
vektorok i. koordinátái.
Két vektor skaláris szorzatának eredménye alapján meghatározható a két vektor közrezárt szöge. Ha ez a szám pozitív, akkor a szög hegyesszög, ha negatív, akkor tompaszög.
Ezen információk felhasználásával a 0 esete triviális (és középiskolai
tanulmányainkból ismerős is). Ezen információk a szakdolgozathoz elengedhetetlen segítségek az alakzatok csúcsainak szögvizsgálatában. XNA: Dot metódus.[3] Vektoriális szorzás:
leképezés. Ez a művelet csak háromdimenziós
vektorokra értelmezett, nem általánosítható. Az eredmény egy olyan vektor, mely mindkét operandusra merőleges. Jelölése: b”.
| | | |
, kiejtése: „a kereszt az
és
által közrezárt szög.
XNA: Cross metódus. [3]
2.5 Fülvágó algoritmus A különböző sík, vagy térbeli alakzatok kirajzolása már-már „ősi” probléma, ebből kiindulva több algoritmus is ismeretes a kiháromszögelésre, itt most a fülvágó 6
algoritmus (angol nyelvű szakirodalmakban Earclipping Algorithm) ismertetése következik, a hozzá szükséges definíciók, egy tétel és egy pszeudokód társaságában. Ez az eljárás a szakdolgozat fő algoritmusa is egyben. Definíció: Egy sokszög vagy más néven poligon a síknak véges sok szakasszal határolt, korlátos, azaz egyenest nem tartalmazó része. A sokszöget a határoló szakaszokat tartalmazó zárt töröttvonalak felsorolásával definiáljuk. Egy töröttvonalat a csúcsaival adunk meg. [4] Definíció: Egy sokszög egyszeresen összefüggő, ha egyetlen zárt töröttvonal határolja. [4] Definíció: Egy sokszög egyszerű, ha egyszeresen összefüggő, és a határoló töröttvonal nem metszi saját magát (4.ábra). [4]
4.ábra: Egyszerű sokszög
Definíció: Egy sokszög átlója egy, a sokszög két csúcsát összekötő olyan szakasz, amely teljes egészében a sokszög belsejében van (5. ábra). [4]
7
5.ábra: Sokszög átlója
Az átló tulajdonság vizsgálata a következő eljárással történik: ahhoz, hogy átló legyen a vizsgált szakasz, az alakzat egyetlen pontjának sem szabad a szakaszon, vagy az átló behúzásával kapott háromszög belsejében lennie. Ez a háromszög Baricentrikus koordinátáival ellenőrizhető. Definíció(Baricentrikus koordináták): Egy háromszög belső
pontjai (és
csak is kizárólag ezek a pontok) előállnak a ∑ [5] Definíció: A sokszög egy csúcsa fül, ha az adott csúcsot megelőző és követő csúcsokat összekötő szakasz a sokszög átlója. Nyilván csak azok a csúcsok lehetnek fülek, amelyekben a belső szög 180 foknál kisebb. Az ilyen csúcsokat konvex csúcsoknak nevezzük, a nem konvexeket pedig konkáv csúcsoknak. [4] Tétel: Egy egyszerű sokszög az átlóival mindig háromszögekre bontható. Ha a sokszög csúcsainak száma , akkor a keletkező háromszögek száma n-2.[4] A háromszögekre bontó fülvágó algoritmus füleket keres, és azokat levágja addig, amíg egyetlen háromszögre egyszerűsödik az eredeti sokszög. Az algoritmus az alakzat 2. csúcsától indul. Amikor egy csúcsot feldolgozunk, először ellenőrizzük, hogy eme csúcspont fül-e. Ha nem fül, a következő csúcspontra lépünk. Ha az aktuális csúcs fül, akkor a következő, a megelőző és az aktuális csúcsból egy háromszöget hozunk létre, és 8
az aktuális csúcsot töröljük a sokszög csúcsai közül. Ha a törlés után a csúcslista már csak 3 elemet tartalmaz, akkor azokat a csúcsokat az utolsó háromszögként tekintjük. Mint látható, az algoritmus egy háromszöget vág le a sokszögből amíg talál fület, az algoritmus terminálását pedig a csúcslista méreténe ellenőrzése mellett, az a tétel biztosítja, miszerint minden egyszerű sokszögnek van füle. [4]
6.ábra: Fülvágó algoritmus egyszerű sokszögön
A már többször használt példa alakzatra futtatott algoritmus eredménye a 6.ábrán látható. Alant az algoritmus lefutása lépésenként: A 2. csúcstól indul és ellenőrzi, konvex-e a csúcs, ezt az (1-2) és a (3-2) vektorok skaláris szorzatából megállapítja, ez az eredmény pozitív, így a csúcs konvex. Ezután megvizsgálja, hogy a csúcs fül-e, ehhez a még le nem vágott csúcsokból (jelen esetben az összes, hiszen, egyet sem vágtunk még ki), a megelőző és a következő közt húzott szakasz átló tulajdonságát ellenőrzi. Erre alkalmazza a Baricentrikus koordinátákat. Miután a 2-es csúcs fül megvan az algoritmus első háromszöge: [1,2,3] és a 2-es csúcsot kivágja a csúcslistából. Az „új” alakzat pontjai így: (1,3,4,5,6) és az algoritmus egyet előrelép, azaz a 3. csúcsot vizsgálja ugyanígy. Ez a csúcs konvex is és fül is, megkapjuk a 2. háromszöget, ami az előzőekben leírt logika szerint: [1,3,4] és a 3-ast kivágjuk a csúcslistából. 9
Új pontok: (1,4,5,6) és a 4. csúcs kerül feldolgozásra, ami konkáv, fül nem lehet, emiatt ismét egyet előrelép az algoritmus és az 5. csúcsot ellenőrzi. Az 5. konvex és még fül is, tehát újabb háromszöget kapunk: [4,5,6] (a 4. csúcs fül nem lehet, de háromszögben részt vehet) a csúcs törlődik a listából. A lista hossza elérte a 3-at, ami azt jelenti, hogy a fennmaradó pontok alkotják az
utolsó
háromszöget
a
listában:
[1,4,6],
így
az
eredmény
az
([1,2,3],[1,3,4],[4,5,6],[1,4,6]) lista. Az algoritmus pszeudokódja: void function Háromszögesítés(csúcslista) if(csúcslista.hossz > 3) feldolgozcsúcslista(); if(VanFül()) set háromszög = Háromszög(biztonságos_hátralépés(aktuális fül), aktuális fül, biztonságos_előrelépés(aktuális fül); Hozzáad(háromszög, háromszöglista); Töröl(aktuális fül, csúcslista); Háromszögesítés(csúcslista); if(csúcslista.hossz == 3) set elsőpont = biztonságos_előrelépés(0); set másodikpont = biztonságos_előrelépés(elsőpont); set harmadikpont = biztonságos_előrelépés(másodikpont); set háromszög = Háromszög(elsőpont,másodikpont,harmadikpont); Hozzáad(háromszög, háromszöglista);
2.6 3 Dimenziós kamera A tárgyalt program egyik leglátványosabb összetevője a videójátékokban régóta alkalmazott 3 dimenziós kamera, ami a billentyűzet és az egér együttes használatával működik. Amíg a billentyűzet csupán 2 dimenziós mozgatásra, addig az egér a tényleges
3 dimenzióra használatos.
A kamera
megvalósításához
szükséges
komponensek a következők: egy nézőpont (angol szakirodalmakban eye), egy nézett 10
pont (target), a két pont különbségéből létrejövő előre mutató vektor, és a 3 dimenziós térben bárhol elhelyezkedő felfelé mutató vektor. Fontos kiemelni, hogy az XNA jobbkezes koordinátarendszerrel rendelkezik, az elméleti leírás is ezt használja. A billentyűzet megfelelő gombjainak lenyomásával a 2 dimenziós mozgás tulajdonképpen a nézőpont és a nézett pont együttes mozgatása, a lenyomott gomb konfigurációban megadott irányának megfelelő vektor mentén, egy tetszőlegesen meghatározott értékkel (az oldalirányú mozgatáshoz az előre mutató vektort és a felfele mutató vektort vektoriálisan szorozzuk és az így kapott balra mutató vektort adjuk a nézőponthoz és a nézett ponthoz (jobb irányú elmozdulás esetén, bal irányba kivonjuk)). Minél magasabb lesz a tetszőleges érték, annál gyorsabb a mozgásnak a mértéke, ezzel finomhangolható a kamera. Billentyűzetes irányítás (a továbbiakban , ) A 7. ábrán a 3 dimenziós kép 2D-s projekcióját láthatjuk, az imént említett komponensekkel. A használt elnevezések a korábban leírtaknak megfelelőek.
7.ábra: A kamera felépítése
11
Előrefele mozgás: ekkor a Hátrafele mozgás: ebben az esetben Balra
történő
Jobbra
mozgás:
történő
mozgás:
Egeres komponens Az egérrel történő mozgás során a nézőpont egy tetszőleges sugarú gömb középpontja, a nézett pont pedig ennek a gömbnek a felszínén helyezkedik el, a nézőpont ebben az esetben nem mozdul, míg a nézett pont a feljebb említett gömb felszínén mozog, azaz a gömbi koordinátája megváltozik. A továbbiakban:
[
[ |
|
()
Működés: Ha csak kattintottak az egérrel, akkor a pozícióját megjegyezzük. Ha a kattintás mellé egérmozdulás párosult: [
]
, ahol
az
pontok
gömbi koordinátáját jelenti. Természetesen, annak érdekében, hogy a haladás iránya mindig relatív legyen és nem abszolút, újraszámoljuk
-t és
-t,
azaz az előremutató vektort és a balra mutató vektort, az alábbi módon:
12
A kép láthatósága érdekében átlagkoordinátákat számolunk, a nézőpont és a nézettpont kezdeti megadásához minimális illetve maximális koordinátákat és a kamera vágósíkját tágra állítjuk. A programban is használt kezdeti értékek:
[
] [
]
. A programban is használt érték:
. [1]
13
3. Felhasználói Dokumentáció Ez a fejezet a program használatához szükséges információkat tartalmazza. Fontos megemlíteni, hogy a program csupán a használt algoritmus és kirajzolás hatékonyságát, valamint a kamera működésének demonstrációs célját szolgálja. Az alkalmazás célja a következő: maximum
4
adva van egy úgynevezett
shape-fájl, amely
nagyságrendű pontmennyiséget tartalmaz (ezen a korláton belül
tetszőleges számú, lyuk nélküli alakzat csúcspontjainak koordinátái találhatóak). A feladatunk az, hogy háromszögeljük, majd kirajzoljuk a képernyőre a fájlban található alakzatokat az imént megadott adatokat felhasználva. Az alakzatban lehet konvex és konkáv csúcs egyaránt, az egyetlen megkötés, hogy az alakzat egyszerű sokszög legyen!
3.1 Előfeltételek A program futtatásához az alkalmazott számítógépnek néhány hardveres és szoftveres kritériumnak meg kell felelnie: Minimális hardver követelmények: [6] DirectX 9.0, vagy újabb technológiával kompatibilis, Shadermodel 2.0-t támogató videókártya. Minimális szoftver követelmények: [6] Microsoft Windows Vista, vagy újabb operációs rendszer. .NET 4.0 keretrendszer. DirectX 9.0 vagy frissebb.
3.2 Az alkalmazás részei Az alkalmazás telepítést nem igényel, két dinamikusan betöltődő fájlt (AEGIS.IO.dll és AEGIS.CORE.dll), amik az AEGIS térinformatikai rendszer fejlesztése során elkészített shape-fájl feldolgozók, 6 tesztelést szolgáló shape-fájlt (test_a.shp, test_b.shp, test_c, MCO_adm0.shp, HUN_adm1.shp, usa_state_shapefile), egy Content könyvtárat, amiben egy effects.xnb fájlt találunk (ennek a fájlnak a segítségével tudja a videókártya, milyen
módon
kell
rajzolnia)
valamint
egy futtatható
állományt
tartalmaz
(AEGIS_XNA_DISPLAY.exe), ami a fentebb említett feldolgozók által készített adatokat felhasználva elvégzi a háromszögesítést és megjeleníti a shape-fájl által tartalmazott 14
alakzatokat a képernyőn, valamint egy információs ablakban adatokkal látja el a felhasználót.
3.3 Az alkalmazás használata A program egyfelhasználós, nincs külön adminisztrátori komponens, így mindenki számára ugyanazokkal a funkciókkal rendelkezik, installációt nem igényel, a sikeres feldolgozáshoz
és
megjelenítéshez
azonban
szükségesek
az
ESRI
Shapefile
szabványnak megfelelő .shp kiterjesztésű fájlok, ezekből is azok, amik az óramutató járásával megegyező irányú poligonokat tartalmaznak. Fontos, hogy ezeket a fájlokat a programmal azonos könyvtárba helyezzük el, mert csak így tudjuk argumentumként megadni ezeket a programnak. Ha nem adunk meg argumentumot, a program automatikusan a test_a.shp fájlra futtatja a programot, nem tesz semmit, ha nem létező fájlnevet adunk meg. Az alkalmazás maximum
4
nagyságrendű pontokat tartalmazó
fájllal működik. Indítás (8.ábra) például a Microsoft Windows Command Prompt-ból történhet, (a Total
Commander
nevű alkalmazás
(AEGIS_XNA_DISPLAY.exe), és
is
használható),
a feldolgozni
kívánt
a futtatható állomány shape-fájl
nevét
(.shp
kiterjesztéssel együtt) beírva.
8.ábra: A program futtatása command promptból
15
A futtatás megkezdése után a beolvasó feldolgozza a programnak argumentumként shape-fájlt, átadja a koordinátákat a megjelenítőnek, ami elvégzi az alakzatok háromszögelését, és kirajzolja azokat egy ablakban. A 9. ábrán a játékablak eredményét láthatjuk, a program számára valóban mindegy, hogy konkáv, vagy konvex az alakzat, sőt az egymást fedő alakzatok sem jelentenek problémát. Az alkalmazás tartalmaz egy információs ablakot is (InfoForm), ami a játékablakkal együtt jelenik meg a futáskor és hasznos adatokkal szolgál a feldolgozott fájlról, valamint a program futásának állapotáról a felhasználó számára.
9.ábra: Játékablak
3.4 Az InfoForm ablak A program futásakor kommunikál a felhasználóval, még ha a program ezen szegmense nem is oly látványos és interaktív, mint a játékablak. Ennek a kommunikációnak az eszköze az InfoForm ablak, amiről a 10.ábrán láthatunk egy lehetséges állapotot (ez a kép a programmal érkező test_a.shp fájlal történő futtatás eredményét ábrázolja). 16
10.ábra: InfoForm ablak
Az ablak egy gombbal rendelkezik, aminek felirata: Exit: értelemszerűen a programból való kilépést hajtja végre. Az ablakban olvasható információk: VPU: Created: a shape-fájl beolvasása megtörtént, a program megkezdi az adatok tárolóinak létrehozását és inicializálását a háromszögeléshez. Number of Shapes: a fájlban lévő alakzatok száma. Number of Vertices: az összes csúcspont száma. Vertices’ Arrays’ Array: Created: a vertexpontok tárolója létrejött és megkapta kezdeti értékét. Indices’ Arrays’ Array: Created: a bejárások tárolója létezik, kezdő értékekkel feltöltve. Trilist: Created: a háromszögek adatainak listája él, feltöltése az inicializáló értékekkel megtörtént. Setting up vertices and triangulating: az alakzatok pontjainak betöltése és a kiháromszögelés állapota. Triangulation time: az összes alakzat háromszögelésének ideje. Copy data to VGA buffers: a háromszögesítésből származó adatok másolása a videókártya puffereibe. Started: kezdés, Finished: befejezés. Draw polygons: ha ezt az üzenetet adja az ablak, a program megkezdte az alakzatok kirajzolását a videókártya memóriájából. 17
Drawing time: az alakzatok kirajzolásának ideje.
3.5 A kamera mozgatása A programban lévő kamera segítségével a kirajzolt kép forgatható, közelíthető, távolítható tetszőleges mértékben, így biztosítva a felhasználó számára a térinformatikai alakzatok alapos 3 dimenziós vizsgálatát. Alapvetően a kamera két komponensre bontható: egy billentyűzet által vezérelt 2 dimenziós részből, amivel közelíteni, távolítani, jobb/bal irányba lehet menni a képhez képest, és egy 3 dimenziós egérrel vezérelt rész, ezzel a térben lévő mozgatások hajthatók végre. A kamera 2 dimenziós részének mozgatása (11. ábra) a videójátékokban is használt konfiguráció, ami a következő gombokat jelenti: W gomb: a kamera előre mozgatása. S gomb: a kamera hátra mozgatása. A gomb: a kamera balra mozgatása. D gomb: a kamera jobbra mozgatása. A kamera egeres komponensének működtetéséhez az egér bal gombjának nyomva tartására és az egér mozgatására van szükség, ekkor a kép az egér új pozíciójába ugrik (csak klikk esetén is) és az iránynak valamint a mértéknek megfelelően fordul.
11.ábra: Mozgatási lehetőségek 18
4. Fejlesztői Dokumentáció Célunk, hogy olyan alkalmazást készítsünk, ami képes az argumentumként bemenő ESRI Shapefile szabványnak megfelelő fájl megjelenítésére. Fontos, hogy jelen alkalmazás csak a lyukas/önmetsző alakzatok nélküli bemenő fájlokat tudja háromszögelni. A programba 3 dimenziós kamerát is implementálunk, amivel a megjelenített képet alaposan meg tudjuk vizsgálni. Ehhez szükségünk van a bemenő fájlban lévő adatok feldolgozására, ezen adatok pontos reprezentációjára. Ennek a feldolgozónak a megvalósítása, az AEGIS térinformatikai projekt keretein belül már korábban megtörtént és a fejlesztés során felhasználásra került. A feladat kielemzése után, a probléma speciálissága miatt, a korábban ismertetett fülvágó algoritmus került implementálásra, ami az előzetes vizsgálatok és összehasonlítások alapján kellően gyors eljárás a cél eléréséhez. Az alkalmazás C# nyelven írodott, .NET 4.0 keretrendszer alatt, a Microsoft Visual Studio 2010 Professional fejlesztőkörnyezet segítségével. A 4.2.1 és a 4.2.2 szakaszban a program két AEGIS-ből származó komponense kerül terítékre, a 4.2.3-as szakasz pedig a futtatható állományt, a szakdolgozatot mutatja be.
4.1 Használati esetek A program működése: a fájlban lévő adatokat a feldolgozó átalakítja és a szükséges információkat átadja a programnak, ezeknek az adatoknak az átvételére egy külön típus került implementálásra, majd az adatok felhasználásával képes háromszögesíteni az alakzatot, és kirajzolni a képernyőre. A fájl betöltésével együtt jár, hogy megjelenik a játékablak és az információs ablak is egyaránt. Innen van lehetősége a felhasználónak a képet a 2. fejezetben elméleti szinten és a 3. fejezetben felhasználói szemszögből ismertetett kamerával közelíteni, távolítani, forgatni, valamint kilépni az alkalmazásból. A 12. ábrán a használati esetek diagramját láthatjuk az előbbiekben.
19
uc AEGIS.XnaDisplay
Információs ablak
«include»
Kilépés
«invokes»
Fáj l betöltése
Billentyűzettel mozgatás
Felhasználó
«invokes»
Játékablak
«include»
«include»
3D Kamera
«include»
Egeres irányítás
12.ábra: Felhasználói esetek
Fájl betöltése Információs ablak megtekintése Játékablak megjelenése Információs ablak Kilépés Játékablak 3D Kamera Billentyűzettel mozgatás Egeres irányítás
20
4.2 A program felépítése Az alkalmazás szerkezetileg 3 komponensre bontható, (13. ábra) a futtatható állományra, ami maga a szakdolgozat és 2 dinamikusan töltődő állományra, amik a shape-fájl kezelésére szolgálnak, egymástól függenek, ezeket használja a szakdolgozat, információszerzés céljából: a csúcspontok koordinátáit, az alakzatok számát, hány koordináta van összesen a fájlban, mind-mind a 2 dinamikusan töltődő állományból nyeri. A komponensek név szerint az alábbiak: AEGIS.XnaDisplay: ez adja a futtatható állományt, maga a szakdolgozat. AEGIS.IO: AEGIS.IO.dll az első dinamikusan töltődő állomány, a bejövő fájl feldolgozásáért felelős. AEGIS.Core:
AEGIS.Core.dll
második
dinamikusan
töltődő
állomány,
alacsonyszintű reprezentációkat tartalmaz, mindkét előző komponens használja.
cmp AEGIS.XnaDisplay
AEGIS.XnaDisplay
AEGIS.IO
AEGIS.Core
13.ábra: Komponensdiagram
4.2.1 AEGIS.Core
Ez a komponens felel a térinformatikai adatok (alakzatok, vonalak, pontok stb.) alacsonyszintű reprezentálásáért, kezeléséért (15. ábra). A szakdolgozathoz a VertexProcessor típuson keresztül kapcsolódik. A programnak érkező shape-fájl feldolgozását és az abból szükséges információk kinyerését teszi lehetővé az AEGIS.IO komponens beolvasást végző osztályai számára, amik felhasználásra kerültek az előbb említett programegységben.
21
A továbbiakban bemutatásra kerülnek a tárgyalt komponens szakdolgozatban hasznosított típusai és azok metódusai. FeatureType
class Core «enumeratio... FeatureType Unknown Point Line MultiLine Polygon MultiPoint
14.ábra: FeatureType osztálydiagram
Ennek a felsorolótípusnak (14.ábra) a segítségével megállapítható milyen típusú adatok vannak a bejövő shape-fájlban, jelen program csak a Polygon típusú adatokkal képes dolgozni.
class Core ICloneable ICloneable
CoordinateD
Point ICloneable «interface» IFeatureCompatible
«enumeratio... FeatureType
«interface» ILayerGroupCompatible
Coordinate
Sev enthGradeGeometry ICloneable
«interface» ILayerCompatible
Rectangle
LayerGeodata
ICloneable
LayerMetadata
ICloneable
LineFeature
Layer
PolygonFeature
ICloneable MultiLineFeature
VectorLayer
RasterLayer
ICloneable
Feature
PointFeature Exception
ICloneable
XmlDeserializationException
MultiPointFeature
15.ábra: AEGIS.Core osztálydiagram 22
PolygonFeature Ez az osztály (16. ábra) valósítja meg az alakzatot, minden térinformatikai adat típus közös ősének a Feature-nek egy leszármazottja. Az alakzat csúcspontjainak számát, azok koordinátáit és egyéb adatait tárolja, melyek kritikus fontosságúak a szakdolgozat szempontjából. Lehetőséget biztosít szerkesztésre, az alakzat körvonala lecserélhető egy másik LineFeature típusú objektummal, lyukak adhatók hozzá, vagy törölhetőek ki XMLNode-ra is konvertálható, tulajdonságain keresztül elérhető az alakzat csúcsainak száma, lyukainak száma, a körvonal, a tárolt adatok típusa, egyszóval a lehetőségek tárháza kellően magas számú. class Core ICloneable PolygonFeature #
_ShellAndHoles: List
+ + + + + + + + +
AddHole(LineFeature) : void ChangeShell(LineFeature) : void Clone() : object DeleteHole(Int32) : void FromXmlNode(XmlNode) : void IsCoordinateOnShell(Coordinate) : bool PolygonFeature() PolygonFeature(List) ToXmlNode(XmlDocument) : XmlNode
«property» + CoordinateCount() : Int32 + HoleCount() : Int32 + Shell() : LineFeature + Type() : FeatureType «indexer» + this(int) : LineFeature
16.ábra: Polygonfeature
Felhasznált indexelő: LineFeature this[int index]: ezzel az operátorral konstans időben elérhető az alakzat indexedik körvonala. Fontos, hogy a 0 indexű elem az alakzat körvonala, a továbbiak a lyukaknak, esetlegesen üres szekcióknak a koordinátáit tartalmazzák. A visszaadott LineFeature típus a következő bekezdésben részletes bemutatásra kerül.
LineFeature 23
Körvonal osztálya (17.ábra), fontos, hogy az első és az utolsó koordináta, amiket tárol megegyeznek, a programnak a helyes működéshez azonban nincs szüksége az utolsó koordinátára. A vonalhoz hozzávehetők/törölhetők a megadott indexű pontok, akár a vonal közepébe is, lekérhető a pontok száma és egy indexelő operátorral bármely pont adatai megszerezhetőek.
class Core ICloneable LineFeature -
_Coordinates: List
+ + + + + + + + + +
AddCoordinate(Coordinate) : void Clone() : object DeleteAt(Int32) : void FromXmlNode(XmlNode) : void InsertAt(Int32, Coordinate) : void InsertHalfwayPoint(Int32) : void LineFeature() LineFeature(List) LineFeature(List) ToXmlNode(XmlDocument) : XmlNode
«property» + CoordinateCount() : Int32 + Type() : FeatureType «indexer» + this(int) : Coordinate
17.ábra: LineFeature osztálydiagram Felhasznált tulajdonság:
Int32 CoordinateCount(): ez a tulajdonság egy egész szám formájában visszaadja a vonalat reprezentáló pontok számát. Coordinate this[int index]: ezzel az operátorral lekérdezhető a vonal indexedik pontjának koordinátái.
Coordinate Az egyszerű 2 dimenziós koordináták típusa (lásd: 18. ábra). Két Single típusú objektumban tárolja az x és az y koordinátákat, lehetőség kínálkozik szöveggé alakításra és XMLNode-ra konvertálásra is.
24
class Core ICloneable Coordinate + + + + + + +
Clone() : object Coordinate() Coordinate(Single, Single) FromXmlNode(XmlNode) : void operator CoordinateD(Coordinate) : explicit ToString() : string ToXmlNode(XmlDocument) : XmlNode
«property» + X() : Single + Y() : Single
18.ábra: Coordinate osztálydiagramja Felhasznált tulajdonságok:
Single X: visszaadja az x koordinátát. Single Y: értelemszerűen az y koordináta lekérésére szolgál.
VectorLayer A vektoros shape-fájl osztálya (19. ábra), a PolygonFeature típushoz hasonlóan egy közös ősnek a Layer-nek leszármazotta. Az implementált funkciók közt találjuk az XML fájlokból konvertálást, a tárolt alakzatok számának lekérdezését, alakzatok hozzáadását, egy tulajdonságon keresztül azok listája is elérhető, valamint egy másik tulajdonságban a típusuk is a lehetőségek sorát gyarapítja. Felhasznált tulajdonságok: Int32 FeatureCount: ezen a tulajdonságon át lekérhető a tárolt alakzatok száma. List FeatureList: a tárolt alakzatok listája, ez is egy tulajdonság.
25
class Core
VectorLayer + + + + + + +
AddFeature(Feature) : void FromXmlMetadataNode(XmlNode) : void FromXmlNode(XmlNode) : void T oXmlMetadataNode(XmlDocument) : XmlNode T oXmlNode(XmlDocument) : XmlNode VectorLayer(LayerMetadata, LayerGeodata, FeatureT ype) VectorLayer(XmlNode)
«property» + FeatureCount() : Int32 + FeatureList() : List + T ype() : FeatureT ype
19.ábra: VectorLayer osztálydiagramja
4.2.2 AEGIS.IO
Ennek a komponensnek (lásd: 20.ábra) a segítségével történik a program argumentumaként érkező fájl beolvasása, ehhez az AEGIS.Core komponens osztályait is használja, az alkalmazáshoz pedig a VertexProcessor típuson keresztül kapcsolódik. class IO «enumeratio... CompressionType
ShapeFileData
Exception FileFormatException
«enumeratio... ShapeType
ShapeFileReader
Shape
Exception ShapePartNotExistsException
«enumeratio... ByteEncoding -_ByteOrder
«enumeration» GeoTaggedImageOpenMode
TaggedImageReader #_Reader
«enumeration» Proj ectionModelType TaggedImageData
«enumeration» RasterSpaceType GeoTaggedImageData
20.ábra: AEGIS.IO 26
ShapeFileData Shape-fájl beolvasást végrehajtó osztály (21. ábra), az alkalmazáshoz a VertexProcessor típuson keresztül kapcsolódik. Megvalósítja az IlayerCompatible interfészt, így képes a kinyert adatok Layer típusúvá alakítására ezen túl kiemelhető a minimális/maximális x,y távolságok visszaadásának lehetősége egy-egy tulajdonság segítségével.
class IO
ShapeFileData + + + +
FromLayer(Layer) : void ReadFromFile(String) : void ShapeFileData() ShapeFileData(String) ToLayer() : Layer
«property» + Height() : Single + LeftUpper() : Coordinate + Name() : String + Path() : String + RightLower() : Coordinate + Shapes() : List<Shape> + Type() : ShapeType + Width() : Single + XMaximum() : Single + XMinimum() : Single + YMaximum() : Single + YMinimum() : Single
21.ábra: Shapefiledata osztálydiagram Felhasznált metódusok:
ShapeFileData(String filename): a bejövő sztringnek megfelelő fájl megnyitására és feldolgozására szolgáló paraméteres konstruktor.
Layer ToLayer(): a megszerzett adatok Layer típusúvá konvertálása, ez az IfeatureCompatible interfész egyik megvalósítandó metódusa.
4.2.3. AEGIS.XnaDisplay
Az AEGIS_XNA_DISPLAY komponens maga a szakdolgozat. (22. ábra) Függősége a másik két komponens, amelyek felhasznált elemei a 4.2.1 és 4.2.2 alfejezetekben találhatóak.
27
class XnaDisplay «enumeration» Camera::Direction Program Triangle Camera
Microsoft.Xna.Framework.Game VertexProcessor
Display
EarClipping
Form InfoForm
22. ábra: A program osztálydiagramja
Az osztályok funckió alapján történő besorolása: Háromszögesítést segítő- és rajzoló osztályok: Display: ez az osztály felelős a kirajzolásért, ide küldi adatait a Vertexprocessor, és innen kerülnek az adatok az EarClipping osztályhoz. EarClipping: a 2. fejezetben leírt fülvágó algoritmus, a Display-től kapja az adatait és oda is küldi vissza. Triangle: ez a háromszög típus, a Display és az EarClipping egyaránt használja. Adatok beszerzését végző osztályok: VertexProcessor: megteremti a kapcsolatot a program 3 komponense között az AEGIS.IO valamint az AEGIS.Core komponensek segítségével megszerzi a shape-fájl minden szükséges adatát, amivel aztán a Display-t kiszolgálja. A kép kamerája és a mozgatás irányát meghatározó osztályok: Camera: megvalósítja a 2.6. szakaszban leírt 3D kamerát. A Display-ben kerül létrehozásra. Direction: a kamera mozgásának irányának meghatározásában segítő felsoroló. A Display mellett természetesen a Camera típussal is kapcsolatban, e két osztály közt segíti a kommunikációt, segítségével meghatározható a Displayben kapott felhasználói input alapján a Camera mozgásának iránya. 28
A felhasználóval történő kommunikációt segítő osztály InfoForm: információs központ.
4.4 A program statikus terve Tekintsük át az alkalmazás statikus tervét (22. ábra). A program szerkezetileg 4 fő részre bonthatóak, mivel a főprogram csak a játékot hozza létre a bejövő argumentummal és futtatja azt, ha nincs hiba: Felület: kirajzolásért és a további 3 egység összehangolt működésének koordinációjáért felelős, valamint ez a rész tartalmazza az információs ablakot is. Háromszögelő: a Felülettől kapott koordinátákból háromszögesíti az alakzatot, amit vissza is ad. VPU (Vertex Processing Unit): shape-fájl feldolgozó minden szükséges adatot a Felületnek továbbít. Kamera: 2.6 alfejezetben ismertetett 3D kamera része, a Felületben végzi működését.
4.5 Felület Ennek a komponensnek a játékablak része a Game osztály leszármazottja (lásd 23. ábra), amit a főprogramban futtatunk. Összegyűjt minden információt, amire a Háromszögelőnek szüksége van, majd átadja azokat. A visszakapott adatokból kirajzolja a képet, elindítja a kommunkációs ablakot, amire a korábban (3. fejezet) leírt információkat írja. Ebben a komponensben számítjuk a 3D kamera számára szükséges kezdő értékeket a 2. fejezetben leírtak szerint és ebben a komponensben jön létre maga a Kamera is, valamint egy tulajdonságon keresztül kommunikációt végez a főprogrammal. Mezők: _bigbuffer: VertexPositionColor típusú tömb, amibe a feldolgozott shapefile összes csúcspontjának koordinátája kerül. Ez az adattag a teljes tartalmával a videókártya a vertexbufferébe, azaz a kártya saját memóriájába kerül, így a 29
program leglátványosabb utasításakor, a rajzoláskor kerül felhasználásra, biztosítva, hogy ez az igencsak magas műveletigényű hívás „olcsóbb” lehessen. _bigindices: tartalma a videókártya indexbufferébe kerül, azaz a videókártya azon memória szegmensébe, ahol a csúcsok kirajzolási sorrendjét tárolja. _Camera: Camera típusú objektum, a játék 3 dimenziós kamerája. _csize: számláló, ami a _bigindices feltöltését segíti, mivel a különböző alakzatokat, a háromszögelés eredményét, egy-egy tömbök tömbjében tároljuk, és ahhoz, hogy a memóriából való rajzolást megtehessük ezekből a tömbök tömbjéből fel kell töltenünk a _bigbuffer-t és a _bigindices-t, utóbbihoz kell a _csize. _device: GraphicsDevice objektum egy összekötő kapocs a program és a számítógép videókártyája között. Ezen az objektumon keresztül elérhető és feltölthető a videókártya vertexbuffere és indexbuffere egyaránt. _earclip: az EarClipping osztály egy példánya, a program fő algoritmusának a fülvágó algoritmusnak megvalósítója. Az EarClipping osztály később kerül részletes bemutatásra. _effect: Effect típusú objektum, ennek a segítségével meghatározható, hogyan rajzoljon a videókártya. Ehhez szükség van egy .fx kiterjesztésű fájlra a fejlesztés során, amiben definiálhatóak a különböző rajzolási módok. A szakdolgozat a Joe Riemer XNA Tutorial oldalon található effects.fx fájl egy módosított változatát használja. _indexbuffer: IndexBuffer, része a videókártya memóriájának, a _bigindices-ből kerül feltöltésre, és ebből tudja meghatározni a videókártya, hogy az aktuális alakzatot milyen csúcssorrendben rajzolja ki. _indices: a bejárást tároló tömbök tömbje, az _indices[i] az i. alakzat kiháromszögelésének eredménye. Ebből tölti fel a program a _bigindices-t egy külön metóduson keresztül. _M_At: Vector3 típusú (ez az XNA Framework része), a _camera számára biztosítja a 2.fejezetben című fejezetben bemutatott nézett pontot. _M_Eye: Vector3, a _camera számára az előző privát adattagban is említett fejezetben bemutatott nézőpontot adja meg. Az előző és a jelen adattagot a FindAverageCoordinate() metódusban számoljuk ki.
30
_Trilist: Triangle tömbök tömbje, az i. pozíción az i.alakzat háromszöglistája van, ami a háromszögelés valódi eredménye, és ebből tölti fel egy külön függvényben a program, az _indices-t. _vertexbuffer: VertexBuffer típus, tartalma bekerül a videókártya memóriájába, a _device objektumon keresztül, létrehozása külön metódusban történik. _vertices:
tömbök
VertexPositionColor
tömbje,
amiben
az
alakzatok
koordinátáit tároljuk, ebből töltjük fel a _bigbuffert. projectionMatrix: Matrix (XNA Framework), a Kamera vágósíkját határozza meg, ami ettől közelebb van, vagy távolabb van, az nem látszik majd a képen. viewMatrix: szintén Matrix, ez határozza meg, mit látunk éppen a képernyőn. Timespan
triangulationtime:
ebben
a
változóban
kerül
eltárolásra
a
háromszögelő algoritmus ideje, ami majd kiírásra kerül az információs ablakra. StopWatch _watch: a rajzolás idejének lemérésére szolgáló stopper. bool counter: ez a változó segít a rajzolás idejének lemérésében. Kezdetben igaz, a rajzoláskor lemérésre kerül az idő, ez az érték hamisra állítódik és innentől kezdve a rajzoláskor nincs időmérés. Metódusok Display(String layername): konstruktor, itt jön létre a VertexProcessor, ami beolvassa a program számára argumentumként megadott fájlt, a különböző számlálók 0-ra állítódnak, és beállítjuk az adattárolókat. SetupIndices(): létrehozza és kinullázza a bejárások tömbök tömbjét. SetupBigIndices():
A
videókártya
Indexbufferének
szánt
_bigindicest
inicializálja (végig 0-val). SetupBigBuffer():
a
videókártya
VertexBuffer
típusának
adatforrását
a
_bigbuffert tölti fel, 0 vektorokkal. SetupTrilist(): a háromszöglista tömbök tömbjét (_Trilist) 0-val tölti fel. SetupVertex(): hasonlóképp 0-val inicializálja a _bigbuffer tárolót. SetupVertices(): a már korábban létrehozott _vpu segítségével végigmegy a teljes shape-fájlon, mindig betölti az i. alakzat koordinátái a _vertices i. tömbjébe, átadja ezt a tömböt az _earclip objektumnak, ami végrehajtja a háromszögelést, feltölti a _bigindices és _bigbuffer objektumokat a majd
31
megkeresi a maximális/minimális/átlag koordinátákat és ezen adatok birtokában létrehozza a _camera objektumot. FillBigIndices(int[]
buffer,
VertexPositionColor[]
bufferb):
a
bejövő
paraméterek segítségével feltölti a _bigindices változót a megfelelő helyről kezdve az első paraméter értékeivel, a _bsize, _csize számlálókat megnöveli az első és a második paraméter hosszával. FillBigBuffer(VertexPositionColor[] smallbuffer): a metódus argumentumaként kapott tömbből feltölti a _bigbuffer tárolót a megfelelő indextől kezdve és növeli a paraméter hosszával a _size számlálót. UpdateViewMatrix():
megváltoztatja
a
projectionMatrix
értékét,
ezáltal
megváltoztatva a kamera pozícióját. Draw(): kirajzoló utasítás, ami a DrawTerrain(Matrix viewMatrix) metódust hívja, majd az ős Game típus Draw utasítását. DrawTerrain(Matrix viewMatrix): ez a metódus a tényleges rajzolás, a _device objektum itt kapja meg a vertexbufferét és az indexbufferét, majd egy ciklusban mindig az i. alakzat kerül kirajzolásra a videókártya memóriájából. Processinput(float amount): ebben az utasításban figyeli az osztály a felhasználói inputokat a kamera számára és a megfelelő gombok lenyomásakor meghívja a kamera billentyűzetkezelő metódusát, valamint az egeres irányítás is itt kerül meghívásra a konfigurációnak megfelelő esemény megtörténtekor. Update(GameTime time): 1000 miliszekundomként meghívja a ProcessInput metódust. LoadContent(): ebben a metódusban jön létre a kapocs a videókártya és a játék között, itt kerül betöltésre a rajzolást segítő effects.fx fájl, itt történik meg az alakzatok háromszögesítése és a videókártya memóriájának feltöltése is. UnLoadContent(): üres törzsű hívás. WriteTriangleListIndices(Triangle[] Trilist, int index): a háromszögek tömbök tömbjéből az indexedik pozícióban elhelyezkedő lista képernyőre iratása, ez a metódus a fejlesztő számára hasznos a program nyomonkövetésében. Initialize(): ebben az utasításban kerül inicializálásra a játékablak mérete. CopyToBuffers(): ennek a metódusnak a törzsében jön létre és töltődik fel a _VertexBuffer és az _IndexBuffer.
32
Tulajdonság: bool GameError: ezzel a tulajdonsággal képes a típus a főprogram fele jelzést adni arról, hogy történt-e valami hiba a játék inicializálása közben. Ha ez az érték igaz, a főprogram nem futtatja a játékot.
class XnaDisplay Microsoft.Xna.Framework.Game Display -
_bigbuffer: VertexPositionColor ([]) _bigindices: int ([]) _bsize: int _Camera: Camera _counter: bool = true _csize: int _device: GraphicsDevice _earclip: EarClipping _effect: Effect _Form: InfoForm _indexBuffer: IndexBuffer _indices: int ([][]) _M_At: Vector3 _M_Eye: Vector3 _mouseflag: bool = false _OMouseState: MouseState _ProjectionMatrix: Matrix _size: int _triangulationtime: TimeSpan = TimeSpan.Zero _Trilist: Triangle ([][]) _vertexBuffer: VertexBuffer _vertices: VertexPositionColor ([][]) _ViewMatrix: Matrix _vpu: VertexProcessor _watch: Stopwatch graphics: GraphicsDeviceManager
+ # # # # # -
CopyToBuffers() : void Display(String) Draw(GameTime) : void DrawTerrain(Matrix) : void FillBigBuffer(VertexPositionColor[]) : void FillBigIndices(int[], VertexPositionColor[]) : void FindAverageCoordinate() : void Initialize() : void LoadContent() : void LoadingIndices(Triangle[], int) : void ProcessInput(float) : void SetUpBigBuffer() : void SetUpBigIndices() : void SetUpIndices() : void SetUpTrilist() : void SetUpVertex() : void SetUpVertices() : void UnloadContent() : void Update(GameTime) : void UpdateViewMatrix() : void WriteTriangleListIndices(Triangle[], int) : void
«property» + GameError() : bool
23.ábra: Display osztálydiagramja 33
4.5.1. InfoForm
Ez a típus (24. ábra) a System.Windows.Forms Form típusának leszármazottja, 2 Button és 1 TextBox van rajta. A gombhoz eseménykezelő tartozik: _ExitButton_Click(object sender, EventArgs e): leállítja az alkalmazást. class XnaDisplay Form InfoForm + + +
_ExitButton_Click(object, EventArgs) : void Exit() : void InfoForm() InfoForm_Load(object, EventArgs) : void SetText(String) : void
24.ábra: Inform osztálydiagramja
Metódusok SetText(string text): ennek a metódusnak a segítségével a bejövő stringet kiírhatjuk a szövegdobozra. InfoForm(): konstruktor. Exit(): kilépést megvalósító metódus. InfoForm_Load(object sender, EventArgs e): az ablak inicializáló metódusa, letiltja az ablak teljes képernyőssé tételét.
4.6 VPU (Vertex Processing Unit) A VPU (25.ábra), melyet a VertexProcessor típus valósít meg, a programban egy összekötő típus, ez az osztály teremti meg a kapcsolatot az AEGIS.Core valamint az AEGIS.IO névterek programegységei és a Felület között. Segítségével a feldolgozók eredményei, az alakzatok csúcsainak száma, és a csúcsok koordinátái
eljutnak az előző alfejezetben tárgyalt Felület részhez ami majd ezen
adatokkal ki tudja szolgálni a Háromszögelő komponenst, és a visszakapott adatokból kirajzolja az eredetileg beolvasott shape-fájlt.
34
class XnaDisplay
VertexProcessor -
_CoordinateCount: int _FeatureType: String _Layer: VectorLayer _PFeature: PolygonFeature _ShapeData: ShapeFileData _VertexContainer: VertexPositionColor ([])
+ + + + + + + +
CheckLayerFeatureType() : String FeatureCoordinateCount(int) : int FetchVertices(int) : void GetVertexList() : VertexPositionColor[] VertexProcessor(String) VPUCoordinateCount() : int VPUSize() : int WriteVertexList(int) : void
«property» + _FeatureFlag() : bool
25. ábra: VertexProcessor
Mezők: int
_CoordinateCount:
az
összes
vertexpont
száma,
kiszámítása
a
VPUCoordinateCount() függvényben történik. String
_FeatureType:
a
tárolt
alakzatok
típusa.
Értéket
a
CheckLayerFeatureType() függvénytől kap. VectorLayer _Layer: maga a vektoros kép, a beolvasott adat konvertált alakja. PolygonFeature _PFeature: a FetchVertices(int index) metódusban a a fájlból éppen beolvasott alakzat változója. ShapeFileData _ShapeData: ezzel a mezővel történik meg az argumentumként bejövő shape-fájl beolvasása. VertexPositionColor[] _VertexContainer: az aktuálisan beolvasott alakzat csúcspontjainak tárolója. Metódusok: VertexProcessor(String layername): létrehozza a _ShapeData objektumot a bejövő paraméterrel, ezzel (ha valid fájlnevet takar a paraméter) megtörténik a beolvasás és a _Layer is értéket kap. FetchVertices(int index): Ez a kód végzi az indexedik alakzat VertexContainerbe helyezését(mivel körvonalat tárol a PolygonFeature így az első és az utolsó 35
vertexe ugyanaz, emiatt nincs szükség az utolsó pontra). Annak érdekében, hogy az alakzat tökéletesen látszódjon, minden koordinátát 100-zal felszorzunk. int VPUCoordinateCount(): Kiszámolja, hogy a beolvasott shape-fájl összesen hány vertexpontot tartalmaz, ez az adat, a Felület komponens _bigbuffer változója szempontjából kritikus fontossággal bír. int FeatureCoordinateCount(int index): Az éppen feldolgozott alakzat csúcspontjainak számának kiszámolására szolgáló metódus. int VPUSize(): visszaadja a tárolt alakzatok számát, például a Felület komponens rajzoló metódusában egy ciklusfeltétel. VertexPositionColor[] GetVertexList(): ezzel a metódussal valósul meg az aktuálisan beolvasott alakzat adatainak átadása a Felület komponensnek (a visszaadott érték a _VertexContainer). String CheckLayerFeatureType(): visszadja a tárolt alakzatok típusát, ami ellenőrzésre szolgál, ha ez a függvény nem „Polygon”-t ad vissza, a program nem fut le. WriteVertexList(int index): kiírja az indexedik elem összes koordinátáját a képernyőre, ez az utasítás a program nyomonkövetésében nyújt segítséget a fejlesztő számára. Tulajdonság:
bool _FeatureFlag: ez az érték a tárolt adatok helyességét hivatott jelezni (kezdetben igaz), ha a CheckLayerFeatureType() metódus nem Polygon visszatérési értékkel rendelkezik, akkor hamissá állítódik, amit a Felület komponens Display osztálya ellenőriz.
4.7. Kamera A kamerát (lásd: 2.6 alfejezet) a Camera osztály (26.ábra) valósítja meg. Az elmélet korábbi leírása okán, csak a privát adattagok és a metódusok megfeleltetései, leírásai szerepelnek.
36
class AEGIS_XNA_DISPLAY
Camera -
_M_AT: Vector3 _M_EYE: Vector3 _M_FW: Vector3 _M_STD: Vector3 _M_UP: Vector3 = new Vector3(0.0... _OMOUSE: MouseState _RADIUS: float = 40.0f u: double v: double
+ + + + + + + +
Camera(Vector3, Vector3) G(double, double) : Vector3 Keypressed(Direction) : void M_AT() : Vector3 M_EYE() : Vector3 M_OMOUSE() : MouseState M_UP() : Vector3 MouseDragged(MouseState) : void MousePressed() : void
26.ábra: Camera
Mezők: _M_AT: nézett pont. _M_EYE: nézőpont. _M_FW: előremutató vektor. _M_STD: balra mutató vektor. _M_UP: felfele mutató vektor. _OMOUSE: egér státuszt megjegyző privát adattag. _RADIUS: R (gömb sugara). u: u. v: v. Metódusok: Camera(Vector3 eye, Vector3 target): létrehozza a kamerát a bejövő nézőponttal és nézett ponttal. double G(double u, double v): g(u,v). Keypressed() ~ billentyűzettes irányítás (2.6 szakasz). Vector3 M_AT(): visszaadja a típus által tárolt nézett pontot. Vector3 M_EYE(): az aktuális nézőpont lekérdezésére szolgáló függvény. 37
M_OMOUSE(): visszaadja a tárolt egérstátuszt. M_UP(): a felfele mutató vektor elérési lehetősége más programegységek számára. MouseDragged() ~ egérmozgatás 2.6 szakasz. MousePressed() ~ egérmozgatás 2.6 szakasz.
4.8. Háromszögelő A program statikus tervében az egyik legfontosabb tényező, melyet az EarClipping típus (27. ábra) valósít meg a programban. Ez a 2.5 alfejezetben leírt fülvágó algoritmus implementációja. Implementáció és Elmélet
Az algoritmus bemenete egy koordinátákat tartalmazó lista (a programban a _Vertex nevet viselő változó), eredménye pedig egy háromszöglista (_TriangleList). Fontos, hogy az algoritmus csak olyan alakzatokra működőképes, melyek lyuk nélküliek és csúcsai az óramutató járásával megegyező irányban vannak, ellenkező esetben leáll. A 2.5 alfejezetben leírtakhoz képest az implementációban találunk néhány eltérést: a fülvágó algoritmus implementációja öt listát használ: fülek listája: Int32[] _EarVertex. konvex csúcsok listája: Int32[] _CxVertex. konkáv csúcsok listája: Int32[] _CeVertex. élő csúcsok listája: Boolean[] _VertexGuard . háromszöglista: Triangle[]. Ezen listákból a háromszöglista kivételével mindegyik maximális méretű, azaz a hossz megegyezik a csúcsok számával és az élőcsúcsok listáját nem számítva mindegyik lista rendelkezik egy számlálóval (_EarSize, _CxSize, _CeSize, _Tsize) , hogy mindig a megfelelő helyre történjen a beszúrás. Az algoritmus működése annyiban módosul, hogy amikor talál egy fület, akkor azt az élő csúcsok listájából törli ki azzal, hogy ellentétesre állítja a lista megfelelő elemének értékét. Ebben a listában az i. elem az alakzat i. csúcsának felel meg.
38
A típus rendelkezik egy biztonságos előrelépéssel és egy biztonságos hátralépéssel. Ezek a metódusok egy indexet várnak és visszaadják hányadik indexű a még élő következő/megelőző csúcs. Erre azért van szükség, mert ha talált fület az algoritmus, akkor azt kivágja az élő csúcsok listájából, a már leírt módon, beszúrja a füllistába, és az algoritmusnak csak a még élő csúcsokra van szüksége, ezért minden főbb ciklusban a kezdeti értékadásban, a ciklusfeltételben és a léptetésben is szerepel valamelyik biztonságos lépés, így némileg eltér a csúcsok bejárási sorrendje (mindig a biztonságos_előrelépés(0)-ig (legyen ez most vég) megy a feldolgozás és a biztonságos_előrelépés(vég)-től indul) a 2.5 szakaszban leírtakhoz képest, de ez az eredményt nem befolyásolja. Annak érdekében, hogy az algoritmus teljesítménye időben mérhető legyen és ezt a felhasználó számára is láthatóvá tegye az alkalmazás, ez az osztály rendelkezik egy Stopwatch típusú _watch változóval, ami az adatok átvételének pillanatától a háromszögesítés végéig méri az időt és azt egy Timespan típusú tulajdonságban (_time) elérhetővé teszi más osztályok számára. Az algoritmus implementációja egy rekurzív megvalósítás, melynek leírása az alant lévő pszeudokódban található. Ennek a kódnak a 2.5 szakaszban leírt fülvágó algoritmus pszeudokóddal történő összehasonlításakor könnyen láthatóak azok a különbségek, melyek az elmélet és a C# -os megvalósítás között húzódnak. Pszeudokód void function Háromszögesítés(csúcslista) if(élőcsúcsoklista.hossz > 3) if(konvexpontokszáma > 0) feldolgozélőcsúcsoklistája(); //itt megtörténik a konvex/konkáv //pontok kiválogatása és a fülvizsgálat if(füllistaszámláló != 0) set háromszög= Háromszög(biztonságoshátralépés(füllistaszámláló-1), füllistaszámláló-1, biztonságoselőrelépés(füllistaszámláló1)); Hozzáad(Háromszög, háromszöglista); Megnövel(háromszöglistaszámláló); 39
Töröl(élőcsúcsok, füllista[füllistaszámláló-1]); Háromszögesítés(); if(élőcsúcsoklista.hossz == 3) set elsőpont
= biztonságoselőrelépés(0);
set másodikpont = biztonságoselőrelépés(elsőpont); set harmadikpont =biztonságoselőrelépés(másodikpont); set háromszög = Háromszög(elsőpont,másodikpont,harmadikpont); Hozzáad(Háromszög, háromszöglista);
class XnaDisplay
EarClipping -
_CeSize: Int32 _CeVertex: Int32 ([]) _Checker: int _CxSize: Int32 _CxVertex: Int32 ([]) _EarSize: Int32 _EarVertex: Int32 ([]) _TriangleList: Triangle ([]) _TSize: Int32 _Vertex: VertexPositionColor ([]) _VertexGuard: Boolean ([]) _VSize: Int32 _watch: Stopwatch
+ + + + +
BaryCentricCheck(Vector3, Vector3, Vector3, Vector3) : bool EarClipping(VertexPositionColor[]) GetChecker() : int GetTriangleList() : Triangle[] IsConvex(int) : bool IsDiagonal(int, int, int) : bool IsEar(int) : bool Posti(Int32) : Int32 Prei(Int32) : Int32 PreprocessVertices() : void Remove(Int32) : void SetVertex(VertexPositionColor[]) : void Triangulate() : void
«property» + time() : TimeSpan
27.ábra: EarClipping típus
Metódusok EarClipping(VertexPositionColor[]
vertex):
konstruktor,
ami
a
háromszögesíteni kívánt listát a bejövő paraméterre állítja és inicializálja a tárolókat, számlálókat. 40
Triangulate(): a korábban leírt rekurzív függvény. PreprocessVertices(): ez a metódus végzi az előző alfejezetben az algoritmus működéséről szóló szekcióban leírt feldolgozást. bool IsConvex(int index): eldönti a beadott pontról, hogy konvex-e. bool IsEar(int index): fülvizsgálat a beadott csúcsra. bool IsDiagonal(int p1, int p2, int p3): eldönti, hogy a p1,p2,p3 alkotta háromszögben benne van-e az alakzat bármelyik pontja, azaz elvégzi az átlóvizsgálatot a 2. fejezetben leírt Baricentrikus koordináták segítségével. bool BaryCentricCheck(Vector 3 a, Vector 3 b, Vector 3 c, Vector 3 point): eldönti egy pontról, hogy benne van-e a bejövő háromszögben. Ez a kód a [7]-en alapul. int Prei(int index): biztonságos hátralépés. int Posti(int index): biztonságos előrelépés. Remove(int data): a bemenő indexnek megfelelő elemnek az értékét hamisra állítja az élő csúcsok listában és a csúcsok számát csökkenti egyel. SetVertex(VertexPositionColor[] vertices): ez a metódus nyújt lehetőséget az algoritmus újrainicializálására egy másik koordinátatömbbel. Triangle[] GetTriangleList(): a háromszöglista lekérdezésére szolgáló függvény. int GetChecker(): a konvex pontok számlálóját adja vissza. Ez az utasítás más programegységek számára visszajelzést biztosít az alakzatok csúcsainak irányáról. Tulajdonság:
TimeSpan time: a korábban leírtaknak megfelelően az algoritmus teljesítményét reprezentáló tulajdonság.
4.9 Tesztelés A Fejlesztői Dokumentáció jelen alfejezetében bemutatásra kerül a program tesztelése. A 4.9.1-es alfejezet a fehér doboz (egységtesztek, integrációs tesztek), a 4.9.2-es szakasz a fekete doboz teszteseteket tartalmazza, a 4.9.3-as alfejezetben pedig a program teljesítménytesztjét találjuk.
41
4.9.1 Fehér doboz tesztesetek
A program (fülvágó algoritmus) tesztjei Egy bejárását tekintve jó és csak konvex csúcsokból álló alakzat háromszögelése és kirajzolása (test_c.shp). Egy bejárását tekintve jó és konkáv csúcsot is tartalmazó alakzat kiháromszögelése és kirajzolása (test_d.shp). Bejárásukat tekintve jó és konvex valamint konkáv csúcsokat is tartalmazó alakzatok kiháromszögelése és kirajzolása (test_a.shp és test_b.shp).
nagyságrendű pontokat tartalmazó shape-fájl kiháromszögelése és kirajzolása (HUN_adm1.shp).
4
nagyságrendű pontokat tartalmazó shape-fájl kiháromszögelése és
kirajzolása (usa_state_shapefile.shp). A program implementációjából fakadóan ez a nagyságrend a határ, ettől magasabb nagyságrendű shape-fájl esetén a program nem fut le. Egységtesztek A fülvágó osztály egységtesztjei Egyszerű négyzet háromszögesítése, a kódban kézzel megadott koordináták alapján. Tesztelő koordináták: (1000,1000), (1000,-1000), (-1000,-1000), (-1000,1000) Várt háromszöglista a 2.5 alfejezetben leírtak alapján: (1,2,3),(1,3,0). Az eredmény ezzel azonos. Egyszerű ötszög háromszögekre bontása, szintén a kódban kézzel megadott adatok alapján. Koordináták:
(0,1300),
(1500,1000),
(1000,-1000),
(-1000,-1000),
(-
1500,1000). Várt eredmény: (1,2,3), (1,3,4), (1,4,0). Az eredmény ezzel megegyező lista. Egyszerű hatszög kiháromszögelése, a kódban kézzel megadott koordináták alapján. Adatok: (700,1300), (1500,1000), (1000,-1000), (-1000,-1000), (-1500,1000), (-700,1300). Várt eredmény: (1,2,3), (1,3,4), (1,4,5), (1,5,0), az eredmény megfelelő.
42
Konkáv csúcsot tartalmazó hatszög háromszögesítése, kódban megadott adatokkal. Pontlista: (700,1300), (1500,1000), (1000,-1000), (0,1100), (-1000,-1000), (1500,1000). Várt eredmény: (1,2,3), (3,4,5), (3,5,0), (1,3,0), az eredmény ezzel megegyező lista. Integrációs tesztek Az EarClipping és a VertexProcessor osztályok együttes működésének tesztjei Az ellenőrizhetőség érdekében csak a kisebb méretű tesztfájlokkal történt integrációs teszt. Eredménynek a háromszögesítés listáját tekintjük. Az alkalmazással együtt érkező test_a.shp fájllal történő tesztelés eredménye: 1. alakzat: (1,2,3), (1,3,4), (1,4,5), (5,6,7), (5,7,8), (1,5,8), (1,8,9), (1,9,0). 2. alakzat: (1,2,3), (1,3,0). 3. alakzat: (1,2,3), (1,3,0). A tesztelés eredménye a várt eredménynek megfelelő. test_b.shp fájlal hasonlóképp: 1. alakzat: (1,2,3), (3,4,5), (3,5,0), (1,3,0). 2. alakzat: (1,2,3), (1,3,4), (1,4,0). 3. alakzat: (1,2,3), (1,3,4), (1,4,0). 4. alakzat: (2,3,4), (2,4,5), (2,5,6), (1,2,6), (1,6,0). A kapott eredmény a várakozásnak megfelelő. test_c.shp esetén: (1,2,3), (1,3,0) 4.9.2 Fekete doboz tesztesetek
Mi történik, ha a program nem kap argumentumot? Ekkor a program a test_a.shp fájlra (ami a programmal együtt érkező bemutató fájlok egyike) fut le. Mi történik ha tesztfájlokat törlik és úgy futtatják a programot argumentum nélkül? A program nem fut le. Mi történik, ha a Contents könyvtárat, vagy annak tartalmát törlik? A program ezen fájl hiányában nem képes működésre. 43
Mi történik, ha a kapott argumentum nem megfelelő? (nincs .shp, a fájl nem a programmal azonos könyvtárban van, a fájl nem létezik). A program nem fut le. Mi történik, ha óramutató járásával ellentétes irányban lévő alakzatot kap a program? A háromszögelő algoritmus ilyen esetekben idő előtt leáll, nem végzi el a háromszögesítést, így a kirajzoláskor ezen alakzatok nem látszódnak, ebből kifolyólag a kép nem lesz teljes illetve egyéb eltérések lehetségesek az eredeti képhez képest. Mi történik, ha nem alakzatokat tartalmazó fájlt adunk meg a programnak? A program nem fut le. Mi történik, ha a kamera konfigurációjában nem definiált gombokat nyomnak le? Nem történik semmi. Mi történik, ha bezárják csak a játékablakot? Az információs ablak is bezárul és a program leáll. Mi történik, ha bezárják az információs ablakot? Az információs ablak bezárul, a játékablak fut tovább, úgy vettük, hogy a felhasználó nem kíváncsi az információkra. Megjeleníthető-e másik kép az alkalmazás futása közben? Nem, ehhez a programot újra kell indítani. Mi történik az Alt+F4 parancs hatására? A program leáll (a játékablak és az információs ablak is eltűnik). Mi történik az Exit feliratú gomb megnyomásának hatására? A program leáll (az előzőhöz hasonló módon). 4.9.3 Teljesítménytesztek A 28. ábrán a program teljesítményét bemutató ábra látható, a háromszögesítés és a kirajzolás ideje a pontok nagyságrendjének függvényében. A diagram a tesztfájlokkal végzett mérések átlagával készült. Pontok nagyságrendje a fájlokban és a program időeredményei:
: test_a.shp (18), test_b (17). Háromszögelés: 0.03 s, rajzolás: 0.027 s.
: MCO_adm0.shp (284). Háromszögelés: 0.016 s, rajzolás: 0.030 s.
: HUN_adm1.shp (8924). Háromszögelés: 0.822 s, rajzolás: 0.042 s.
4
: usa_state_shapefile (11939). Háromszögelés: 1.003 s, rajzolás: 0.049 s. 44
1,000
0,800
0,600
Háromszögelés ideje (s) Rajzolás ideje (s)
0,400
0,200
0,000 10
100
1000
10000
28.ábra: Teljesítményteszt diagram
45
5. Összegzés A szakdolgozat célja egy térinformatikai alakzatok 3 dimenziós vizsgálatát segítő grafikus program elkészítése volt. Bár a program nagyon látványos és a funkcióját betölti, bőven van potenciál a továbbfejlesztésre, amik az AEGIS térinformatikai rendszer keretein belül, szándékaim szerint meg is fognak valósulni, továbbá a megjelenítő integrálásra kerül a kliens program WPF ablakába. Számos új technológiával és elmélettel sikerült megismerkednem a program implementálása során, kezdve az XNA-val, a 2 dimenziós alakzatok tesszellációján át, egészen a metszésvizsgálatokig (Baricentrikus koordináták). Továbbfejlesztési lehetőségek: Komplexebb alakzatok megjelenítése: egylyukas, többlyukas, és önmetsző alakzatok. Szerkesztési opció beépítése: lenne lehetőség alakzatokat létrehozni/módosítani, azaz még inkább interaktívvá tenni az alkalmazást. Integrálás: jelen program integrációra kerül egy WPF ablakba.
46
Irodalomjegyzék [1]: Számítógépes Grafika. http://people.inf.elte.hu/valasek/bevgraf_ea/ 2012.05.04. [2]: Microsoft XNA Wikipedia: http://en.wikipedia.org/wiki/Microsoft_XNA 2012.04.29. [3]: Kurt Jaegers: XNA 4.0 Game Development by Example, Packt Publishing, 2010, [411], ISBN 978-1-84969-066-9. [4]: Szirmay-Kalos László: Számítógépes Grafika. http://compalg.inf.elte.hu/~tony/Elektronikus/Informatikai/I15E.pdf4 2012.04.29. [5]: 2D Grafikai Algoritmusok: http://rs1.szif.hu/~gasparcs/2D_grafikai_algoritmusok.pdf 2012.04.29. [6]: XNA Studio 4.0 Hardware and Operating System Requirements: http://msdn.microsoft.com/en-us/library/bb203925(v=xnagamestudio.40).aspx 2012.04.29. [7]: Point in triangle test. http://www.blackpawn.com/texts/pointinpoly/default.html 2012.05.05.
47