Mendelova zemědělská a lesnická univerzita v Brně Provozně ekonomická fakulta
Modelování a vizualizace modelů pokrytí s využitím OpenGL Diplomová práce
Vedoucí práce: Ing. David Procházka
Bc. Michal Husták
Brno 2008
2
Prohlašuji, že jsem tuto diplomovou práci vypracoval samostatně na základě uvedené literatury.
V Brně dne 24. května 2008
....................................................
4
Děkuji panu Ing. Davidu Procházkovi, vedoucí mé diplomové práce, za odbornou pomoc, rady a připomínky k této práci. Dále musím poděkovat svým rodičům za podporu při studiu.
6
Abstract Husták, M. Modelling and visualization of model of covarage using OpenGL. Graduation thesis, Brno 2008 This thesis is focused on development of object oriented library for processing surfaces using T-splines. It describes development system Open Inventor, mathematical background of T-splines and implementation of the T-splines library.
Abstrakt Husták, M. Modelování a vizualizace modelů pokrytí s využitím OpenGL. Diplomová práce, Brno 2008 Práce se zabývá navrhem objektové knihovny pro zpracovávání povrchu pomocí T-spline. Popisuje vývojové prostředí Open Inventoru, matematické vyjádření Tspline a návrh knihovny.
7
8
Obsah 1 Úvod
11
2 Cíl práce
12
3 Open Inventor 3.1 Úvod do Open Inventoru . . . . . . . . . . . . . . 3.1.1 Open Inventor a OpenGL . . . . . . . . . 3.2 Struktura Open Inventoru . . . . . . . . . . . . . 3.2.1 Scene Graph . . . . . . . . . . . . . . . . 3.2.2 Path . . . . . . . . . . . . . . . . . . . . . 3.2.3 Ilustrační příklad . . . . . . . . . . . . . . 3.2.4 Pojmenování tříd, metod a proměnných . . 3.3 Proměnné . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Single Value fields a Multiple Values fields 3.3.2 Nastavení hodnot . . . . . . . . . . . . . . 3.4 Nodes . . . . . . . . . . . . . . . . . . . . . . . . 3.4.1 Vytváření uzlů . . . . . . . . . . . . . . . 3.4.2 Typy uzlů . . . . . . . . . . . . . . . . . . 3.4.3 SoGroup . . . . . . . . . . . . . . . . . . 3.4.4 SoCamera . . . . . . . . . . . . . . . . . . 3.4.5 SoLight . . . . . . . . . . . . . . . . . . . 3.4.6 SoShape . . . . . . . . . . . . . . . . . . . 3.4.7 Property nodes . . . . . . . . . . . . . . . 3.5 Textury . . . . . . . . . . . . . . . . . . . . . . . 3.5.1 SoTexture2 . . . . . . . . . . . . . . . . . 3.5.2 Mapování textur na objekt . . . . . . . . . 3.6 Handling Events . . . . . . . . . . . . . . . . . . 3.7 Draggers . . . . . . . . . . . . . . . . . . . . . . 3.7.1 Callback funkce v Draggers . . . . . . . . 3.8 Engines . . . . . . . . . . . . . . . . . . . . . . . 3.8.1 Propojení engines . . . . . . . . . . . . . 3.8.2 Global Filed . . . . . . . . . . . . . . . . 3.8.3 Animation Engines . . . . . . . . . . . . . 3.8.4 Vestavěné Engines . . . . . . . . . . . . . 3.8.5 Calculator Engines . . . . . . . . . . . . . 3.8.6 Boolean Engines . . . . . . . . . . . . . . 3.9 Sensors . . . . . . . . . . . . . . . . . . . . . . . . 3.9.1 Data sensors . . . . . . . . . . . . . . . . 3.9.2 Time sensors . . . . . . . . . . . . . . . . 3.10 Pomocné knihovny . . . . . . . . . . . . . . . . .
13 13 13 14 14 15 15 17 17 17 18 19 19 19 19 20 21 21 23 24 24 25 26 27 28 28 29 30 31 32 33 34 35 35 36 36
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
4 T-spline 4.1 Úvod k T-spline . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Polární forma – blossoms . . . . . . . . . . . . . . . . . . 4.1.2 Uzlové intervaly . . . . . . . . . . . . . . . . . . . . . . . 4.1.3 Polar labels . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Matematické vyjádření . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 Definice T-spline . . . . . . . . . . . . . . . . . . . . . . 4.2.2 Definice T-mesh . . . . . . . . . . . . . . . . . . . . . . 4.2.3 Výpočet bodu T-spline plochy . . . . . . . . . . . . . . 4.3 T-spline Local Refinement . . . . . . . . . . . . . . . . . . . . . 4.3.1 Algoritmus T-spline local refinement . . . . . . . . . . . 4.3.2 Vkládání nového uzlu do uzlového vektoru bázové funkce 4.4 T-spline Simplification . . . . . . . . . . . . . . . . . . . . . . . 5 Návrh knihovny pro výpočet T-spline 5.1 Metodika . . . . . . . . . . . . . . . . . . . 5.2 Reprezentace třídy T-spline . . . . . . . . . 5.2.1 Struktura pomocných tříd . . . . . . 5.2.2 Struktura třídy T-spline . . . . . . . 5.3 Algoritmus . . . . . . . . . . . . . . . . . . 5.3.1 Tvorba T-spline . . . . . . . . . . . . 5.3.2 Výpočet bodů plochy . . . . . . . . 5.3.3 Zobrazení plochy . . . . . . . . . . . 5.4 Diskuze . . . . . . . . . . . . . . . . . . . . 5.4.1 Využití Open Inventoru . . . . . . . 5.4.2 Další návrhy vývoje knihovny T-sline
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . .
38 38 38 39 40 40 40 41 42 43 43 44 45
. . . . . . . . . . .
47 47 48 48 48 49 49 51 52 52 53 54
6 Závěr
56
7 Literatura
57
8 Přílohy 1 – Modelování krajiny 59 8.1 Příklad 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 9 Přílohy 2 – zdojový kód 9.1 TSpline . . . . . . . . 9.2 computeUVector . . . 9.3 computeVVector . . . 9.4 yCube . . . . . . . . . 9.5 countB . . . . . . . . . 9.6 make1point . . . . . . 9.7 makepoints . . . . . .
10
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
62 62 62 63 63 64 65 66
1
Úvod
Při modelování v OpenGL (Open Graphics Library) lze teoreticky využívat pouze takzvaná grafická primitiva. Jedná se o bod, úsečku a polygon, přičemž polygony lze převést do trojúhelníkové reprezentace. Nejčastěji se právě setkáme s rozdělením povrchu na trojúhelníkové plošky, kdy jednotlivé sousední trojúhelníky sdílí společné hrany a vrcholy. Podle způsobu rozdělení povrchu tělesa je možné vytvářet pravidelné sítě trojúhelníků či naopak nepravidelné trojúhelníkové sítě ( Triangular Irregular Network – TIN).Takové zobrazení přináší řadu výhod, jako je jednoduchý výpočet normálových vektorů. Nicméně se jedná o hrubou aproximaci daného tělesa. Pro přený popis tělesa (rozumíme popis povrchu tzv. hraniční reprezentace) je nutné použít jeho matematický popis pomocí křivek. Dnes jsou nejrozšířenější křivky NURBS – Non-Uniform Rational B-Splines. Křivka (stejně i plocha) je reprezentována množinou bodů a vahami pro jednotlivé body. NURBS umožňují přesně definovat kuželosečky, což použitím Bezierových křivek nebo B-spline nebylo možné. NURBS jsou proto dnes takřka standardem pro modelování v grafice, podporován jak softwarem pro návrh, tak hardwarem pro konečné vykreslení na počítači. Při modelování NURBS povrchů je základem pravidelná mřížka bodů, přičemž hustota bodů závisí na množství detailů v nejexponovanějším místě. To vede k nadbytečnosti velkého objemu dat a tím i složitější editaci. Tento problém lze řešit pomocí rozdělení objektu na několik NURBS ploch a ty následně spojit. Při tomto řešení vzniká komplikace napojení jednotlivých ploch. Východiskem a dalším pokračováním NURBS jsou T-spline. Na rozdíl od NURBS je možné zhušťovat a rozmělňovat řídící body dle potřeby (napojením ve tvaru T). Editace je tudíž jednodušší a i renderování menšího počtu ploch rychlejší. Navíc odpadá problém s napojováním ploch. Při tom je možné převádět NURBS na T-spline. T-spline ale je poměrně nové téma a nejsou zatím příliš rozšířené. Nástrojem pro modelování T-spline je použito Open Inventor API, respektive knihovna Coin. Open Inventor je objektovou nadstavbou nad OpenGL, která odděluje programátora od primitivního OpenGL na vyšší úroveň a nabízí mu rozsáhlou množinu C++ tříd. To podstatně urychluje a zjednodušuje práci pro programátora a často poskytuje i vyšší výkon aplikace než přímá implementace v OpenGL. Vyšší výkon je možný díky optimalizacím, které Open Inventor může provádět nad daty scény.
11
2
Cíl práce
Úkolem této práce je implementace modelu T-Spline a následně její grafické znázornění. Tak, aby bylo možné na základě zadaných parametrů plochu vytvořit a popřípadě i editovat. Výsledkem by měla být objektová třída, použitelná při dalším programování nebo grafickém návrhu. V první části bude popsáno prostředí Open Inventoru. Na rozdíl od známějšího a rozšířenějšího OpenGL je Open Inventor plně objektový nástroj pro programování 3D grafiky. První kapitola by měla sloužit k pochopení struktury a myšlenky Open Inventoru. Dále bude obsahovat návod pro tvorbu modelů, včetně světelných efektů, pohybu, textur a obsluhy vstupů. Z uvedeného vyplývá, že Open Inventor je více než jen nástroj pro rendering modelů. Další kapitola bude pojednávat o matematickém vyjádření T-spline. Bude zaměřena na definice T-spline, výklad pojmů T-mesh a T-grid, algoritmy pro výpočet bodů plochy, zjednodušení plochy a přidání kontrolních bodů na plochu. Tato část je založena na práci J. Procházkové: Modelování matematických ploch v CAD systémech. Kapitola nepojednává o NURBS objektech. O této problematice existuje dostatek informací v dostupné literatuře. Poslední část se bude zabývat návrhem objektové knihovny pro výpočet Tspline. Současným cílem je zaměřit se na modelování povrchu využitelné v geografických informačních systémech. Nicméně projekt by měl schopen fungovat i pro obecnou T-spline, popřípadě by měl sloužit jako podklad pro odvozování dědičných tříd objektů. Samotné grafické znázornění je provedeno pomocí knihovny Coin využívající Open Inventor API.
12
3
Open Inventor
3.1
Úvod do Open Inventoru
Open Inventor byl uveden firmou SGI roku 1991. Během intenzivního vývoje, se stal standardem v oblasti profesionální 3D grafiky. V roce 1998 byl vývoj ukončen a SGI o dva roky později zveřejnila svou poslední verzi Open Inventoru 2.1 jako open-source. V současné době jsou k dispozici tři významnější balíky kompatibilní s Open Inventor API. První, komerční, je Open Inventor firmy TGS, která od SGI odkoupila práva na další vývoj jejich kódu. Druhá verze je přímo od SGI. Nicméně kvůli absenci dalšího vývoje již tento balík poměrně zastaral. Poslední balík pochází od norské firmy Systems In Motion, ta vyvinula vlastní knihovnu Coin, která je kompatibilní s Open Inventor API a je k dispozici pod GPL licencí. V této práci je použita právě posledně jmenovaná knihovna – Coin. Design Open Inventoru vychází z konceptu grafu scény. Scéna je složena z uzlů. Uzly jsou různých typů. Některé nesou informace o geometrii těles (krychle, kužel, model tělesa), další různé atributy (barva, textury, souřadnice objektu) a také existují speciální uzly, které propojují uzly mezi sebou, pohybují s nimi a vytváří interakci s uživatelem. Další text přepokládá znalost C++, znalost OpenGL není nutná, ale je velkou výhodou. Z důvodu rozsáhlosti celé problematiky Open Inventoru (knihovna Coin obsahuje přes pět set padesát tříd) není možné podrobně popsat celou oblast. Pro rozšíření následujícího textu jsou vhodné: The Inventor Mentor: Programming Object Oriented 3D Graphics with Open Inventor, Open Inventor C++ Reference Manual a domovské stránky Coin1 . 3.1.1
Open Inventor a OpenGL
OpenGL je knihovna pro grafické zobrazení a představuje standard pro tvorbu 2D a zejména 3D grafických aplikací. OpenGL byla navržena s důrazem na to, aby byla použitelná na různých typech grafických akcelerátorů a aby nezávisela na operačním systému. Z toho důvodu ale nenalezneme u OpenGL procedury k otevření okna nebo vstupu. Vznikla proto rozšíření, jako třeba knihovna Glut, usnadňující programátorovi tyto negrafické operace2 . Glut ale stále využívá nízkoúrovňové OpenGL. Open Inventor jde dále. Pro ilustraci lze uvést příklad: rotující krychle. glRotatef(rotx,1.0f,0.0f,0.0f); glBegin(GL_QUADS); // celni plocha 1
http://www.coin3d.org OpenGL umožňuje vykreslovat pouze grafická primitiva, Glut obsahuje funkce pro vykreslování kolule, válce atd. 2
13
glVertex3f(-150.0f, -150.0f, glVertex3f( 150.0f, -150.0f, glVertex3f( 150.0f, 150.0f, glVertex3f(-150.0f, 150.0f, // leva plocha ... glEnd();
150.0f); 150.0f); 150.0f); 150.0f);
Z programu opakovaně voláme kreslící funkci, ve které je na začátku posunuta projekční matice o úhel rotx a následně vytvoříme šest stěn krychle, každou o čtyřech vrcholech. Dále by bylo vhodné určit normály, popřípadě barvu. SoSeparator *root = new SoSeparátor; SoCube *krychle = new SoCube; krychle->width = 0.8; krychle->height = 0.8; krychle->depth = 2; SoRotor *rotace=new SoRotor; rotace->speed = 0.5; rotace->rotation.setValue(1,0,0,0); root->addChild(rotace); root->addChild(krychle); V druhém případě vytváříme objekt root, jehož vlastnosti jsou tvar krychle (specifikována délkou, šířkou a výškou) a rotace (specifikována rychlostí rotace a osou). Takto existuje objekt nezávisle na tom, jestli je vykreslován. Zatímco v OpenGL modely jsou jen zobrazovány, v Open Inventoru je vytvářen model požadovaných vlastností, jenž může být (pomocí OpenGL) vyrenderován. Pro vykreslování obrazu využívá kvalit OpenGL, které je ale zcela zapouzdřené a oddělené od programátora
3.2 3.2.1
Struktura Open Inventoru Scene Graph
Jak již bylo zmíněno výše, Open Inventor vytváří objekty. Všechny objekty tvoří acyklický scene Graph, který je uložen v scene Database. Objektem je jak tvar (SoCone), tak i vlastnosti (SoMaterial) nebo pohled (SoCamera). Některé uzly (odvozené od třídy SoGroup) mohou obsahovat další uzly a vytvářet stromovou strukturu. Graf reprezentuje následující ilustrační příklad. Model představuje červený, osvětlený kužel. Byl vytvořen kořenový uzel „rootÿ s potomky „cameraÿ, „lightÿ, 14
„materialÿ a kuželem. Záleží na pořadí vložení uzlů do grafu. Dříve vložené (vlevo) ovlivňují objekty vložené později. (V našem případě, pokud bychom prohodili pořadí SoMaterial a SoCone, kužel by se zobrazil implicitní šedou a ne červenou.
Obr. 1: kořen scény
3.2.2
Path
Jelikož je možné přiradit jeden objekt k více uzlům je pro jeho specifikování ve grafu scény používáno cest. Je toho využíváno při SoSelection (viz dále), kdy cesta k vybranému tělesu je popsána posloupností uzlu, začínající kořenem. 3.2.3
Ilustrační příklad
Nejprve byl vytvořen kořen scény. Dále byla do scény vložena kamera a osvětlení. Barva budoucího objektu byla nastavena na červenou a přidán ke kořenu. Nato byl připojen i tvar objektu kužel. Pak pomocí knihovny SoWin bylo vytvořeno okno a pohled nastaven, tak oby zobrazoval kořen. Nakonec se rozjede nekonečná smyčka, která se mimo jiné stará i o zobrazování scény. Při vytváření kužele nebyl specifikován ani poloměr, ani výška. Coin u většiny tříd dokáže nastavit zkladní hodnoty. Kromě kužele bylo tohoto postupu použito i u vytvoření pohledu a osvětlení. #include #include #include #include #include #include
15
#include Za pozornost stojí, že každá třída je do programu přidána samostatně pomocí include. int main(int , char **argv){ // Inicializuj Inventor HWND window = SoWin::init(argv[0]); if (window == NULL) exit(1); // Vytvor koren sceny SoSeparator *root = new SoSeparator; root->ref(); // Vloz kameru do sceny SoPerspectiveCamera *camera = new SoPerspectiveCamera; root->addChild(camera); // Svetlo root->addChild(new SoDirectionalLight); // Material, cervena barva SoMaterial *material = new SoMaterial; material->diffuseColor.setValue(1.0, 0.0, 0.0); root->addChild(material); // Kuzel root->addChild(new SoCone); // Vytvor renderovací okno SoWinRenderArea *renderArea = new SoWinRenderArea(window); // Nastav parametry kamery camera->viewAll(root, renderArea->getViewportRegion()); // Nastav renderovací okno renderArea->setSceneGraph(root); renderArea->setTitle("Hello Cone"); renderArea->show(); Zde končí část vlastního Open Inventoru a program pokračuje pomocí nádstavbových knihoven, závyslých na operačním systému. Tato část se nikdy nemění3 . 3
16
Měmí se samozřejmě použité knihovny.
// Zobraz okna a rozjed renderovací smycku SoWin::show(window); SoWin::mainLoop(); // Uvolni paměť delete renderArea; root->unref(); return 0; }
3.2.4
Pojmenování tříd, metod a proměnných
Názvy mají v Coin pevnou strukturu, která pomáhá se lépe orientovat v zdrojovém kódu. Používá systém předpon a zvýraznění pomocí velkých písmen. - Základní třídy v Open Inventoru začínají písmena Sb (Scene basic tipes). Příklad: SbColor, SbViewVolume. - Ostatní odvozené třídy mají předponu So (Scene object). Příklad : SoCone, SoMaterial, SoTransform. - Metody a proměnné začínají vždy malým písmenem a každé „novéÿ slovo uvnitř názvu třídy, metody nebo proměnné začíná velkým písmenem. Příklad: getNormal(), setSceneGraph(), diffuseColor. - Pokud obsahuje název proměnné číslici, následovaný dalším písmenem (SoMFVec3f), specifikuje číslo počet proměnných a následující písmeno typ (příklad je vektor tří float). Obvykle existují další variace takových proměnných. - Výčtové typy jsou zapisovány velkými písmeny. Příklad: FILLED, PER PART.
3.3
Proměnné
V rámci Open Iventoru se používají namísto běžných datových typů takzvané fields. V podstatě obecné datové typy nahrazují (SoSFFloat namísto float). Rozdílem jsou pak metody, které fields obsluhují uvnitř Open Inventor API. Příkladem může byt datová konverze nebo normalizace vektoru. 3.3.1
Single Value fields a Multiple Values fields
Single value field obsahuje jednu proměnnou daného tipu. Označena je písmeny SF v názvu. Příklad: SoSFFloat, SoSFRotation, SoSfBool. Multiple value fields obsahuje pole hodnot. Označena je písmeny MF v názvu. Příklad: SoMFFloat, SoMFVec3f, SoMFColor.) Většina fields má obě varianty SF a MF.
17
3.3.2
Nastavení hodnot
Pro nastavení hodnoty SF fields se používá metoda setValue(), nebo lze také použít operátor„=ÿ. Pro nastavení MF je metoda setValues(). Pro získání hodnoty fields existuje metody getValue(). Příklad: krychle->width = 0.8; nebo krychle->width.setValue( 0.8); Příklad: sirka=krychle->width.getValue() Při nastavování vektorů je více eventualit. Kromě možností setValue a „=ÿ, existují náledující případy: SbVec3f vector; vector.setValue(2.5, 3.5, 0.0); xform->translation.setValue(vector); nebo xform->translation.setValue(SbVec3f(2.5, 3.5, 0.0)); nebo float x = 2.5, y = 3.5, z~= 0.0; xform->translation.setValue(x, y, z); nebo float floatArray[3]; floatArray[0] = 2.5; floatArray[1] = 3.5; floatArray[2] = 0.0; xform->translation.setValue(floatArray); Při nastavování MF fields se používá metoda setValues(), do které je vloženo pole hodnot, počáteční index prvku a počet použitých prvků. Příklad: static float vertices[28][3]; SoCoordinate3 *myCoords = new SoCoordinate3; myCoords->point.setValues(0, 28, vertices);
18
3.4 3.4.1
Nodes Vytváření uzlů
Uzel je chápán v Open Inventoru jako množina datových elementů (fields), které popisují uzel. Například uzel třídy SoPointLight obsahuje čtyři fields: intensity, color, location a on. K vytvoření uzlů se používá operátor new. Jedná se buď to kořen scény nebo lze jej přiřadit do grafu scény jako potomka pomocí metody addChild(). Je možno přiřadit jeden uzel více předchůdcům. Při každém připojení do scény se zvýší reference na uzel. Z tohoto důvodu není možno zrušit uzel pomocí delete. Místo toho se používá metoda unref(), která sníží počet referencí. Objekt je skutečně smazán, pokud je počet referencí roven nule. Stejně tak není vhodné vytvářet statické pole. 3.4.2
Typy uzlů
1. Shape nodes – reprezentují 3D geometrické objekty, které jsou dále ovlivněny property nodes, Příklad: SoCone, SoCylinder, SoNurbsSurface, SoText2. 2. Property nodes – charakterizují Shape nodes. Lze je rozdělit do tří subkategorii:
- Transform – obsahuje třídy jako SoRotation, SoTranslation, SoScale - Appearance – ovlivňuje vzezření objektu. Příklad: SoMaterial, SoComplexity, SoLightModel, SoFont. - Metrics – je používán uzly, které obsahují souřadnice, normály a jiné geometrické informace. Příklad: SoNormal, SoCoordinate3f. 3.4.3
SoGroup
Třída SoGroup může, jako jediná, obsahovat další uzly. Třídy, odvozené od SoGroup, vytváří logickou strukturu grafu scény. V programu nevytváříme kužel o určité barvě a poloze, ale univerzální objekt o vlastnostech kužel, barva a poloha. Vloženy mohou být také další objekty třídy SoGroup. Jak již bylo zmíněno, záleží na pořadí vložení potomků. Některé podtřídy SoGroup: - SoSeparator – Vlastnosti dané větve stromu jsou oddělené od zbytku. Po vykreslení tohoto objektu dojde k obnovení předchozího nastavení. Příklad: Renderujeme složitý objekt, zelené barvy, jehož jedna část má být červená. Při nepoužití SoSeparotor by všechny části vykreslované až po červené části by byly také červené. - SoSwitch – Z potomků prochází pouze jednoho, specifikovaného pomocí indexu swichChild. Jednotlivé větve jsou indexované v pořadí připojení ke kořenu. - SoBlinker – odvozeno od SoSwitch. Jednotlivé větve jsou přepínané v pořadí v jakém byly zadány a rychlostí speed. 19
- SoSelection – umožňuje vybírat jednotlivé objekty stromu kliknutím myši a provést s nimi operaci určenou funkcí.
Obr. 2: Použití separátorů v grafu scény
3.4.4
SoCamera
Pro zobrazení scény je vytvořen objekt odvozený od třídy SoCamera. Každá scéna musí mít právě jednu aktivní kameru (například pomocí SoSwitch lze mezi kamerami přepínat). Kamera zobrazuje scénu, která ji následuje v grafu. Proto bývá přímým potomkem kořene grafu. Pozice a směr pohledu je určena pomocí fields: - position (SoSFVect3f) - orientation (SoSFRotation) [0.0, 0.0, 1.0] směr dopředu. Užitečnými metodami jsou také pointAt(SbVect3f) a viewAll * (SoPath, SbViewportRegion). PoitAt změní orientaci kamery směrem k zadanému bodu. ViewAt metoda nastaví kameru tak, aby byla vidět celá scéna. Třída SoCamera je třída abstraktní, a proto je nutno v programu používat třídy odvozené. Jsou to SoPerspektiveCamera a SoOrthographicCamera.
20
3.4.5
SoLight
Pro osvětlení scény je nutno přidat do grafu scény nejméně jedno světlo. Na rozdíl od kamer, může graf scény obsahovat více světel (maximální počet světel závisí na implementaci OpenGL). Efekt světla lze izolovat pro jednotlivé části scény pomocí uzlu SoSeparator. SoLight nemá ambientní složku světla. Ta lze přiřadit pomocí SoMaterial nebo SoEnvironment. Jinak kopíruje světelný model použitý v OpenGL. Solight je opět virtuální třída a obsahuje tyto fields: - on(SoSfBool) – vypnutí/zapnutí světla - intensity(SoSFFloat) [0.0-1.0] – jas světla - color (SoSFColor) – barva světla Odvozené třídy jsou: - SoPointLight – bodové světlo, určené pozicí – location (SoSFVect3f) - SoDirectionalLight – směrové světlo, určené vektorem – direction (SoSFVect3f), nejrychlejší z hlediska výpočetní rychlosti - SoSpotLight – reflektorové světlo, location (SoSFVect3f), direction (SoSFVect3f), dropOffRate (SoSFFloat) – snižování intenzity od středu kužele, cutOffAngle (SoSFFloat) – úhel, který světlo ozařuje
3.4.6
SoShape
SoShapes je abstraktní třída pro modelování tvarů. Její jednoduché deriváty jsou: -
SoSphere – koule – radius (SoSFFLoat) SoCube – kvádr – width (SoSFFloat), height (SoSFFloat), depth (SoSFFloat) SoCone – kužel – bottomRadius (SoSFFloat), height (SoSFFloat) SoCylinder – válec – radius (SoSFFloat), height (SoSFFloat)
Dalšími třídami odvozené od SoShape jsou komplexní tvary (trs trojúhelníků, sada ploch). Souřadnice definující tvar se připojí k objektu ve vlastním uzlu. Je třeba zdůraznit, že koordináty nejsou připojeny například k instanci třídy SoFaceSet, ale k SoSeparator, jehož jeden z potomků bude také i SoFaceSet. Komplexní tvary jsou: -
SoFaceSet – sada ploch – numVertices (SoMFInt32) SoLineSet – sada úseček – numVertices (SoMFInt32) SoPointSet – sada bodů – numPoints (SoSFInt32) SoQuatMesh – čtyřúhelníková síť – verticesPerColumn (SoSFInt32), verticesPerRow (SoSFInt32) - SoTriangleStripSet – trs trojúhelníku – numVertices (SoMFInt32) 21
- SoNurbsCurve – NURBS křivka – numControlPoints (SoSFInt32), knotVector (SoMFFloat) - SoNurbsSurface – NURBS plocha – numUControlPoints (SoSFInt32), numVControlPoints (SoSFInt32), numSControlPoint (SoSFInt32), snumTControlPoints (SoSFInt32), uKnotVector (SoMFFloat), vKnotVector (SoMFFloat), sKnotVector (SoMFFloat), tKnotVector (SoMFFloat) Příklad: Vytvářeným objektem je obelisk, tvořen čtyřmi trojúhelníkovými plochami (špička) a čtyřmi čtyřúhelníkovými.
Obr. 3: scéne graf pro face set
// souradnice bodu plochy static float vertices[28][3] = { {-1, 1, 10}, { 1, 1, 10}, { 0, 0, { 1, 1, 10}, { 1,-1, 10}, { 0, 0, { 1,-1, 10}, {-1,-1, 10}, { 0, 0, {-1,-1, 10}, {-1, 1, 10}, { 0, 0, {-1, 1, 10}, { 1, 1, 10}, { 1, 1, { 1, 1, 10}, { 1,-1, 10}, { 1,-1, { 1,-1, 10}, {-1,-1, 10}, {-1,-1, {-1,-1, 10}, {-1, 1, 10}, {-1, 1, };
15}, //celni trojuhelnik 15}, //leviy 15}, //zadni 15}, //pravy 0}, {-1, 1, 0}, //celni obdelnik 0}, { 1, 1, 0}, //levy 0}, { 1,-1, 0}, //zadni 0}, {-1,-1, 0} //pravy
// pocet vrcholu kazdeho poligonu static long numvertices[8] = {3, 3, 3, 3, 4, 4, 4, 4}; SoSeparator *obelisk = new SoSeparator(); 22
Obelisk->ref(); // definuj souradnice SoCoordinate3 *myCoords = new SoCoordinate3; myCoords->point.setValues(0, 28, vertices); obelisk->addChild(myCoords); // vytvor FaceSet SoFaceSet *myFaceSet = new SoFaceSet; myFaceSet->numVertices.setValues(0, 8, numvertices); obelisk->addChild(myFaceSet);
3.4.7
Property nodes
SoMaterial nastavuje základní vlastnosti objektu. Obsahuje tyto fields: -
ambientColor (SoMFColor) [0.2, 0.2, 0.2], spectacularColor (SoMFColor) [0.0, 0.0, 0.0], emissiveColor (SoMFColor) [0.0, 0.0, 0.0], shiness (SoMFFloat) [0-1, 0.2], transparency (SoMFFloat) [0-1, 0.0]
SoTransform4 nastavuje polohu a orientaci objektu v postoru. Obsahuje tyto fields: -
translation (SoSFVec3f) [0.0, 0.0, 0.0], rotation (SoSFRotation) [0.0, 0.0, 1.0, 0.0], scaleFactor (SoSFVec3f) [1.0,1.0,1.0], center (SoSFVec2f) [0.0, 0.0]
SoDrawStyle ovlivňuje způsob vykreslování objektů. Obsahuje tyto fields: - style (SoSFEnum) [FILLED, LINES, POINTS, INVISIBLE] , - lineWidth (SoSFFloat) [0-256,0.0], - linePattern (SoSFUShort) [0-0xffff, 0xffff] SoLightModel nastavuje použitý světelný model. Obsahuje field : - model (SoSFEnum) [PHONG, BASE COLOR
5
]
SoEnvironment obsahuje vlastnosti prostředí „mezi objektyÿ. Obsahuje tyto fields: 4
pokud se změna týká pouze jednoho field, je vhodné použít „specializovanéÿ třídy: SoTranslation, SoRotation, SoScale. 5 BASE COLOR ignoruje světelný model a používá pouze difuzní světlo a průhlednost
23
-
ambientIntesity (SoSFFloat), ambientColor (SoSFColor), fogType (SoSFEnum) [NONE, HAZE, FOG, SMOKE], fogColor (SoSFColor),
SoComplexity nastavuje kvalitu objektů, jako hladkost křivek. Obsahuje tyto fields:
- value (SoSFFloat) [0-1, 0.5], - textureQuality (SoSFFloat) [0-1, 0.5]
3.5
Textury
Kromě nastavení barvy a světených vlastností daného modelu, je možno pokrýt těleso texturou. Nastavená barva dále ovlivňuje vzhled textury.6 3.5.1
SoTexture2
Základní třídou pro použití textur je SoTexture27 . Obsahuje tyto fields: -
filename (SoSFName), image (SoSFImage), wrapS/wrapT (SoSFEnum) [REPEAT,CLAM], model (SoSFEnum) [MODULATE, DECAL, BLEND], blendColor (SoSFColor)
Nastavením field WrapS a WrapT popisuje namapování textury na větší povrchy. REPEAT opakuje celou texturu, CLAM opakuje poslední pixel. field model určuje způsob ovlivnění textury podkladovou barvou. Styl MODULATE vynásobí (smíchá) podkladovou barvu s barvou textury. Pokud měla textura složku alfa, ovlivní průhlednost celého objektu. Model DECAL překryje původní barvu a pokud měla textura složku alfa, týká se i nadále textury a umožňuje prosvítání základní barvy. Poslení možnost BLEND používá intensitu textury k míchání podkladové barvy a barvy specifikované v blendColor. Příklad:
// zvol texturu SoTexture2 *brick = new SoTexture2; brick->filename.setValue("brick.jpg"); brick->addChild(root); 6 7
24
Inventor používá pro horizontální souřadnice textury s a pro vertikální t. kvalitu textur ovlivňuje také SoComlexity->textureQuality
// vytvor krychly root->addChild(new SoCube);
3.5.2
Mapování textur na objekt
Prvním způsobem mapování textur na objekt je standardní nastavení pro jednoduché objekty jako kvádr, koule, válec. Inventor dopočítá koordináty textury. Nejprve vytvoří bounding box objektu, posléze určí nejdelší hranu jako horizontální (s) osu textury a druhou nejdelší jako sou vertikální (t). Textura se při nanesení na objet zdeformuje v poměru s/t. Nejjednodušším způsobem změny mapování textury je použití třídy SoTexture2Transform. Tato třída je obdobná jako SoTransform. Totéž co provádí SoTransform se souřadnicemi objektů, koná SoTexture2Transform s koordináty textury. Nicméně neexistují podtřídy jako SoRotation. Pro tvary odvozené od třídy SoVertexShape je možno zadat koordináty textury implicitně. Slouží k tomu třída SoTextuteCoordinate2. Na rozdíl od ostatních způsobů mapování textur je tento způsob nejsložitější (souřadnice jsou zadávány ručně a ne dodány Investorem), ale poskytuje programátorovy nejvíce možností. Příklad: // zvol texturu SoTexture2 *brick = new SoTexture2; root->addChild(brick); brick->filename.setValue("brick.jpg "); // Definuj souradnice objektu SoCoordinate3 *coord = new SoCoordinate3; root->addChild(coord); coord->point.set1Value(0, SbVec3f(-3,-3, 0)); coord->point.set1Value(1, SbVec3f( 3,-3, 0)); coord->point.set1Value(2, SbVec3f( 3, 3, 0)); coord->point.set1Value(3, SbVec3f(-3, 3, 0)); // Definuj souradnice textury SoTextureCoordinate2 *texCoord = new SoTextureCoordinate2; root->addChild(texCoord); texCoord->point.set1Value(0, SbVec2f(0, 0)); texCoord->point.set1Value(1, SbVec2f(1, 0)); texCoord->point.set1Value(2, SbVec2f(1, 1)); texCoord->point.set1Value(3, SbVec2f(0, 1)); // vytvor FaceSet SoFaceSet *myFaceSet = new SoFaceSet; 25
root->addChild(myFaceSet); myFaceSet->numVertices.set1Value(0, 4);
3.6
Handling Events
Pro reakce na události při běhu programu lze použít předdefinované manipulátory. Větší flexibilitu zajišťuje naprogramování vlastních Callback funkcí. Dovolují programátorovy vytvořit vlastní funkci reagující na podnět. Třída zajišťující registraci Callback funkcí je SoEventCallback. addEventCallback (
SoType eventtype, SoEventCallbackCB * funce, void * userdata = NULL
) Po provedení registrace pomocí metody addEventCallback je funkce zavolána, kdykoliv nastane událost specifikovaná v eventtype. Eventtype získáme pomocí SoEvent− >getClassTypeId(). Třída SoEvent je virtuální s těmito potomky: - SoKeyboardEvent – obsahuje informaci která klávesa byla stlačena (neindikuje uppercase nebo lowercase) - SoMouseButtonEvent – obsahuje informaci které tlačítko myši bylo stisknuto (tlačítka 1, 2,3). - SoLocation2Event – obsahuje informaci o pohybu kurzoru (souřadnice polohy v okně, 0, 0 je dolní levý roh) - SoMotion3Event – obsahuje informaci o změně polohy 3D zařízení. Obsahuje rotaci a posun od předchozí pozice. Příklad: Vstup z klávesnice // deklarace a registrace funkce SoEventCallback *cb = new SoEventCallback; cb->addEventCallback(SoKeyboardEvent::getClassTypeId(), event_cb, NULL); root->insertChild(cb, 0); //telo funkce event_cb(void *userdata, SoEventCallback *node){ const SoEvent *event = node->getEvent(); //move left if (SO_KEY_PRESS_EVENT(event, LEFT_ARROW)) { posun->translation.setValue(-10,0,0);
26
} //move right else if (SO_KEY_PRESS_EVENT(event, RIGHT_ARROW)) { posun->translation.setValue(10,0,0); } else if (SO_KEY_PRESS_EVENT(event, X)) { exit(1); } }
3.7
Draggers
Dragers jsou uzly, se specializovanou reakcí na chování uživatele. Konkrétně se jedná o vložené objekty do scény, umožňující interakci s myší. Typickým využitím dragges je posunováním model v osách nebo otáčení. Všechny draggers jsou odvozeny od třídy SoDraggers. Je dvojí způsob použití darggers: Zaprvé je to propojení gragger a field. Další možností vytvoření callback funkce, která je volána při kliknutí, pohybu myši a jiných příležitostech. Propojení s field Příklad: Je vytvořen kužel, se kterým je možno pohybovat v ose x.
Obr. 4: ukazka SoTranslate1Dragger
27
// vytvoreni darggeru SoTranslate1Dragger *myDragger = new SoTranslate1Dragger; Root->addChild(myDragger); myDragger->translation.setValue(1,0,0); // vytvoreni kuzela a jeho translace SoTranslation *myTranslation = new SoTranslation; SoCone *myCone = new SoCone; Root->addChild(myTransform); Root->addChild(myCone); // propojeni translace a graggeru myTranslation->translation.connectFrom(&myDragger->translation); Propojení dragger a translace dochází pomocí metody connectFrom(). Z použití dereference je zřejmé, že obě fields musí být stejného typu (v tomto případě SoSFVec3f). Existují různé draggers s různými fields. Například: -
SoDragPointDragger – translation, tři osy SoHandleBoxDragger – translation, scale SoTransformBoxDragger – rotation, translaton, scale SoTranslete1Dragger – translation, jedna osa SoTranslation2Dragger – translation, dvě osy
3.7.1
Callback funkce v Draggers
K zvýšení využití dragges je možno použít tyto callback funkce: -
Start callbacks – jsou volány při začátku manipulace Motion callbacks – jsou volány s každým pohybem myši během manipulace Value changed callbacks – jsou volány, když se u draggeru změní jakýkoliv field Finish callbacks – jsou volány, když manipulace skončí
Pro přidání start callback funkce se používá následující metody: addStartCallback (název funkce, data). Obdobný postup platí i pro ostatní typy. Pro zrušení callback funkce slouží metoda removeStartCallback (název funkce, data).
3.8
Engines
V předchozích kapitolách byl vytvářen statický model, popřípadě reagující na uživatelův vstup. Uzly typu Engines přinášejí do scény pohyb nebo animaci. Engines mohou být také spojeny s jinými engines a vytvářet tak reakci mezi objekty. 28
Každý engine má jednu vstupní hodnotu a jednu nebo více výstupních hodnot. Vstupní i výstupní hodnoty mohou být připojeny k jiným fields nebo engines v grafu scény. Pokaždé, když se změní vstupní hodnoty, změní se i hodnota v napojeném fields nebo engines. 3.8.1
Propojení engines
Ke spojení engines slouží metoda connetcFrom (Sofield), nebo connetcFrom (SoEngineOutput). V obou případech jsou příslušné fields převedeny, pokud je to možné, na správný typ. Možné přetypování fields: -
Jakýkoliv fields na řetězec Řetězec na jakýkoliv fields Jakákoliv konverze ve dvojici Bool, Float, Short, ULong, UShort Mezi Color a Vec3f Mezi Float a Time Mezi Matrix a Rotation Mezi Rotation a Vec4f Jakékoliv mezi verzemi MF a SF
Vícestupňová konverze není podporována. Ačkoliv lze převést z Vect4f na Rotation a Rotation na Matrix, přímá změna z Vect4f na Matrix způsobí chybu. Příklad: rotace a translace // vytvoreni rotace a translace SoRotationXYZ *rotY = new SoRotationXYZ; rotY->axis = SoRotationXYZ::X; SoTranslation *trans = new SoTranslation; // vytvoreni engine SoElapsedTime *counter = new SoElapsedTime; counter->speed.setValue(0.5); // Připojení engine na vstup rotace rotY->angle.connectFrom(&counter->timeOut); // vytvoreni pomocneho engine a propojeni SoComposeVec3f *slideDistance = new SoComposeVec3f; slideDistance->x.connectFrom(&counter->timeOut); trans->translation.connectFrom(&slideDistance->vector); root->addChild(trans); root->addChild(rotY);
29
V případě, že je jsou vytvořeny dva engines tak, že pokud je zjištěna změna na engine A dojde k změně i na engine B, a v opačném případě, pokud se změní B, dojde k změně A, by mělo dojít k zacyklení. Tento problém byl vyřešen a pokud je změněn vsup B výstupem z A, nedojde již „druhém cykluÿ k zpětné změně na A.
Obr. 5: Vzájemné propojení engine. (Open Inventor 2007)
3.8.2
Global Filed
Global fields jsou fields, které nejsou obsažené v žádném konkrétním uzlu nebo engine. Přístupné ze scene database jsou pouze přes svůj název. Jedním z Open Investorem poskytovaných global fields je realTime, typu SoSFTime. Tento field obsahuje aktuální čas, potřebný pro vstupy engines pro animace. Metoda getGlobalFileld("jméno") vrátí požadovaný field. Přkílad: textový výstup s aktuálním časem. // vytvoreni objektu text SoText3 *myText = new SoText3; Root->addChild(myText); // propojeni s~global field myText->string.connectFrom(SoDB::getGlobalfield("realTime")); Je možné vytvořit vlastní global field pomocí funkce Sofield *SoDB:: createGlobalfield (const SbName name, SoType type); V databázi scény může být 30
pouze jeden global filed téhož jména. Pokud už existuje field stejného jména i typu, je vrácen původní field. Pokud se shodují pouze ve jméně, ale ne v typu, je vráceno NULL. 3.8.3
Animation Engines
Následující engines mohou být použity k animaci objektů ve grafu scény. Každý je napojen na globální field realTime. - SoElapsedTime – výstupem je doba, které uběhla od spuštění - SoOneShot – běží určitý čas a skončí - SoTimeCounter – běží od minimálního do maximálního počtu danou frekvencí SoElapsedTime slouží jako stopky. Je používán pro „rozpohybováníÿ scény. Obsahuje tyto fields: - speed – (SoSFFloat) [0] – rychlost běhu času vzhledem k k reálnému běhu - on – (SoSFBool) – zastaví počítání času, opětovné spuštění začíná na pozici zastavení, - pause – (SoSFBool) – zastaví počítání času, opětovné spuštění nastaví čas jako by nedošlo k zastavení, čas běží na pozadí - reset – (SoSFTrigger) – nastaví čas na 0 - timeOut – (SoSFTime) – výstup, automaticky přepíráno na sekundy, počítáno od 0 Rozdíl mezi SoElapsedTime a SoOneShot je, že SoOneShot skončí po určeném čase. Obsahuje tyto fields: - duration – (SoSFTime) – specifikuje dobu trvání v sekundách, - trigger – (SoSFTrigger) – spuštění engine, pomocí metody touch() - timeOut (SoSFTime) – výstupní čas, začíná od 0 do hodnoty nastavené v duration - isActive – (SoSFBool) - ramp – (SoSFFloat) – výstupní hodnota, hodnoty od 0 (pro čas 0) do 1 (pro čas duration) SoTimeCouter na rozdíl od předešlých engines nevrací čas, ale hodnotu mezi minimální a maximální hodnotou, danou velikostí kroku a frekvencí. Pomocí proměnné syncOut je možno synchronizovat různé engines. Obsahuje tyto filed : -
min – (SoSFShort) –minimální hodnota [0] max – (SoSFShort) – maximální hodnota [1] step – (SoSFShort) – velikost kroku [1] on – (SoSFBool) – nastavení na FALSE zastaví počítadlo frequency – (SoSFFloat) – počet cyklů za sekundu [0] 31
- reset – (SoSFShort) – nastavení počítadla na libovolnou hodnotu, pokud je mimo určený rozsah, nastaví se na bližší hraniční hodnotu - syncIn – (SoSFTrigger) – restartuje počítadlo na minimální hodnotě - output – (SoSFShort) –výstupní hodnota, vrací aktuální stav počítadla - syncOut – (SoSFTrigger) – výstupní hodnota, vrátí hodnotu kdykoliv znovu začne cyklus
3.8.4
Vestavěné Engines
Některé typy animací se poměrně často opakují a jejich řešení pomocí propojení rotace nebo translace přes jeden respektive dva engines je zdlouhavé. Open Inventor nabízí nodes, které zahrnují už vestavěný engine a zároveň některé časté transformace. Jsou to například: - SoRotor – rotace kolem osy - SoPendlum – střídání mezi dvěmi rotacemi - SoShuttle – střídání mezi dvěmi translacemi SoRotor umožňuje rotaci kolem zvolené osy. Obsahuje tyto fields: - rotation – (SoSFRotation) –určuje osu a úhel o který se otáčí - speed – (SoSFFloat) – udává počet otáček za sekundu [1] - on – (SoSFBool) SoPendlum začíná rotovat do úhlu daného rotation0, když jej dosáhne rotuje dále do úhlu rotation1. Poté se cyklus opakuje. Obsahuje tyto fields: -
rotation0 – (SoSFRotation) rotation1 – (SoSFRotation) speed – (SoSFFloat) – určuje počet cyklu za sekundu on – (SoSFBool)
SoShutle je obdoba SoPendlum, ale místo úhlů pro rotaci, jsou zde určeny souřadnice pro translaci. Obsahuje tyto fileds: -
32
translation0 – SoSFVec3f translation1 – SoSFVec3f speed – SoSFFloat on – SoSFBool
3.8.5
Calculator Engines
Výše zmíněné použití engines je dostačující pro animaci rovnoměrného pohybu po obrazovce. V případě, že je pohyb dán funkcí, má programátor možnost použít aritmetické engines. Tento nástroj vypočítá na základě vstupů zadanou funkci. Třída SoCalculator má tyto fields: -
a, b, c, d, e, f, g, h – (SoMFFloat) – číselné vstupy A, B, C, D, E, F, G, H – (SoMFVect3f) – vektorové vstupy expression – (SoMFString) – výraz oa, ob, oc, od – (SoMFFloat) – číselný výstup oA, oB, oC, oD – (SoMFVect3f) – vektorový výstup
Podoba proměnné expression se skládá na levé straně z jednoho z výstupů nebo dočasné proměnné, operátoru „=ÿ uprostřed a na pravé straně z výrazu. SoCalculator obsahuje osm dočasných proměnných „taÿ až „thÿ pro skaláry a osm dočasných proměnných „tAÿ až „tHÿ pro vektory. Výrazy na pravé straně mohou mít podobu: -
binární operátory – +, −, ∗, /, <, >, <=, >=, ! =, == unární operátory – ! ternární operátory – cond ? trueexpr : falseexpr závorky – ( expr ) indexace vektorů – vec [int] funkce – ( expr, . . . ) termy – celočíselné konstanty, reálné konstanty, pojmenované konstanty jako MAXFLOAT, MINFLOAT, M LOG2E, M PI, proměnné patřící k calculator engine.
Příklad: pohyb po dráze // vytvojeni engines SoCalculator *calcXZ = new SoCalculator; SoTimeCounter *Counter = new SoTimeCounter; SoTranslation *danceTranslation = new SoTranslation; Counter->max = 360; Counter->step = 4; Counter->frequency = 0.075; // vypocty calculator engine calcXZ->a.connectFrom(&Counter->output); calcXZ->expression.set1Value(0, "ta=a*M_PI/180"); // theta calcXZ->expression.set1Value(1, "tb=5*cos(5*ta)"); // r calcXZ->expression.set1Value(2, "td=tb*cos(ta)"); // x calcXZ->expression.set1Value(3, "te=tb*sin(ta)"); // z~calcXZ->expression.set1Value(4, "oA=vec3f(td,0,te)"); 33
// propojeni translace danceTranslation->translation.connectFrom(&calcXZ->oA);
3.8.6
Boolean Engines
Variantou calculator engine je boolean engine, který řeší logické výrazy. Obsahuje tyto proměnné: -
a, b – (SoMFBool)– vstupy output – (SoMFBool) – výstup inverse – (SoMFBool) – inverzní výstup operation – (SoSFEnum) – vykonaná operace
Na rozdíl od calculator engine je množství operací silně omezené, neobsahuje nástroj na vytvoření jakéhokoliv výrazu. Nicméně množina výrazu je pro standardní použití dostatečná a lze ji rozšířit pomocí více engines. Výraz je TRUE pokud operation je: -
CLEAR – nikdy TRUE SET – vždy TRUE A – A je TRUE NOT A – A je FALSE B – B je TRUE NOT B – B je FALSE A OR B – A je TRUE nebo B je TRUE NOT A OR B – A je FALSE nebo B je TRUE A OR NOT B – A je TRUE nebo B je FALSE NOT A OR NOT B – A je FALSE nebo B je FALSE A AND B – A a zároveň B jsou TRUE NOT A AND B – A je FALSE a zároveň B je TRUE A AND NOT B – A je TRUE a zároveň B je FALSE NOT A AND NOT B – A a zároveň B jsou FALSE A EQUALS B – A je rovno B A NOT EQUALS B – A není rovno B
Příklad: Rotace1 rotuje objektem kolem osy Y a rotace2 kolem osy Z. Vždy probíhá pouze jedna rotace. Pokud je rotace1 zastavena, spustí se rotace2 a naopak. // vytvoreni rotaci SoRotation rotace1 = new SoRotation; SoRotation rotace2 = new SoRotation; rotace1->axis = SoRotationXYZ::Y; rotace2->axis = SoRotationXYZ::Z; 34
// propojeni s~engine SoElapsedTime *counter1 = new SoElapsedTime; counter->speed.setValue(0.5); SoElapsedTime *counter2 = new SoElapsedTime; counter->speed.setValue(0.4); rotace1->angle.connectFrom(&counter1->timeOut); rotace2->angle.connectFrom(&counter2->timeOut); // vytvoreni bolean engine a propojeni jednotlivych engines SoBoolOperation *myBoolean = new SoBoolOperation; myBoolean->a.connectFrom(&counter1->on); myBoolean->operation = SoBoolOperation::NOT_A; couter2->on.connectFrom(&myBoolean->output);
3.9
Sensors
Senzory jsou speciálními objekty, které jsou vázány na databázi. Reagují na změny v databází scény spuštěním callback funkce. Existují time sensors a data sensors. Data sensors se spouštějí při změně dat v databázi a time sensors po uplynutí času. 3.9.1
Data sensors
Open Inventor obsahuje tři typy data sensors: - Sofieldsensor – spouštěn, pokud se změní data v určitém field8 . - SoNodeSensor – spouštěn, pokud se změní data v určitém uzlu, potomkovy tohoto uzlu, nebo pokud se změní topologie grafu pod tímto uzlem - SoPathSensor – spouštěn, pokud se změní data v jakémkoliv uzlu daném cestou, nebo když je uzel přidán nebo smazán z cesty. Příklad: vypisování pohybu pohledu
// callback funkce cameraChangedCB(void *data, SoSensor *) { SoCamera *viewerCamera = (SoCamera *)data; SbVec3f cameraPosition = viewerCamera->position.getValue(); printf("Camera position: (%g,%g,%g)\n", cameraPosition[0], cameraPosition[1], cameraPosition[2]); 8
za změnu se také počítá volání metody touch()
35
} // vytvoreni kamery a senzoru // registrace callback funkce a pripojeni k~pohledu SoCamera *camera = new Socamera; Sofieldsensor *mySensor = new Sofieldsensor(cameraChangedCB, camera); mySensor->attach(&camera->position);
3.9.2
Time sensors
Open Inventor obsahuje dva typy time sensors: - SoAlarmSensor – spustí se v určitý čas určený metodou setTime(SbTime) nebo za čas určeny metodou setTimeFromNow(SbTime) - SoTimerSensor – spouští se opakovaně za v intervalu daném metodou setInterval( interval), lze také nastavit dobu, kdy začne senzor fungovat – funkce setBaseTime(SbTime)
3.10
Pomocné knihovny
Open Inventor je platformě nezávislá knihovna, a proto funkce spojené s vytvořením a obsluhou okna jsou obsaženy v oddělených knihovnách. Pro systémy Unix a Mac je to knihovna SoQt a pro systémy Windows je to knihovna SoWin. Pro programátora je jediným rozdílem v použití nahrazení přípony Qt za Win. // pripojeni knihoven pro vytvoreni okna #include #include Pro použití pod windows Visual C++ je nutno ještě použít: #pragma warning(disable:4275) #pragma warning(disable:4251) #pragma comment(linker, "/entry:\"mainCRTStartup\"") SoWinRenderArea je nejjednodušší třída pro vytvoření okna. // vytvor okno SoWinRenderArea *viewer = new SoWinRenderArea (window); viewer->setSceneGraph(root); viewer->setTitle("Examiner Viewer"); viewer->show(); 36
// zobraz okna a rozjed renderovaci smyčku SoWin::show(window); SoWin::mainLoop(); // Uvolni paměť delete viewer;
Ostatní třídy, odvozené od SoWinRenderArea, kromě vytvoření okna, přidají také do scény, pokud při prohledávání grafu není nalezeno, implicitní světlo a kameru. Osvětlení nasvítí vénu z pohledu pozorovatele. Použití těchto objektů je úplně stejné. Dalšími třídami jsou: -
SoWinFullViewer SoWinConstrainedViewer SoWinFlyViewer SoWinExaminerViewer SoWinPlaneViewer
Za zmínku stojí zejména SoWinExaminerViewer. Slouží pro vytváření a prohlížení modelů. Návrh lze pomocí myši otáčet, přibližovat. Pomocí pravého tlačítka myši se zpustí popap menu, ve kterém se nastavují veškeré možnosti pohledu, například změna perspektivy za orto pohled, nastavit rendering drátového modelu, antialiasing a podobně.
37
4
T-spline
4.1
Úvod k T-spline
V současnosti jsou nejrozšířenějším nástrojem pro popis nepravidelných povrchů Bspline, respektive NURBS. Pro jejich popis slouží množina řídících bodů a uzlové vektory. Pomocí nich lze modelovat jakékoliv kuželosečky. NURBS se znázorňují pomocí obdélníkové sítě řídících bodů. Tento způsob má své mantinely. I když síť nemusí být pravidelná, je nutné kvůli tvaru sítě vložit velké množství zbytečných řídících bodů. Je proto nutné volit mezi detailním popisem složité části modelu a počtem nadbytečných bodů hladkých částí. Řešením uvedeného problému je zavedení křížení ve tvaru T (T-junktions) v řídící síti NURBS. Vzniká tak síť T-mesh, znázornění T-spline. T-spline představil v roce 2003 Prof. Sederberg jako zobecněním NURBS povrchů a předpokládá se, že postupně nahradí dosavadní postupy pro modelování těles. T-spline umožňují zhušťování dosavadní sítě pomocí vkládání nových řídicích bodů bez nutnosti přidání řádku a sloupce řídicích bodů jako u NURBS. Opačně, algoritmus T-spline simplification slouží pro převedení obecné NURBS plochy danou řídící sítí do T-mesh. Omezení počtu řídících bodu dosahuje až pětasedmdesáti procent.
Obr. 6: použití T-spline a NURBS (T-splines Inc.)
4.1.1
Polární forma – blossoms
Pro práci s T-splines je nutné zavést novou strukturu pro B-spline. Jedná se o větší využití uzlového vektoru, který viditelně působí na křivku. Základy této teorie jsou obsaženy v knize Ramshaw (1989), jejíž obsah je shrnut v Sederberg et al. (2004). Struktura byla nazvána polar form - polární forma nebo také blossoms. (Procházková 2007) Název polární forma zavedl Ramshaw z DEC Systems Research Center. Jedná se nový o pohled na B-spline pomocí polární formy. Všechny důležité algoritmy pro Bézierovy a B-spline křivky mohou být odvozeny z následujících čtyř pravidel pro řídicí body – Ramshawem nazvané polar values. - Pro Bézierovy křivky stupně n na intervalu ha, bi jsou řídicí body přeznačeny:
38
Pi = P (u1 , u2 , ..., un ), kde uj = a pro j ≤ n - i a uj = b pro ostatní případy. - Pro B-spline křivku stupně n s uzlovým vektorem (t1, t2, t3, ...) přísluší řídicím bodům skupina n po sobě jdoucích uzlů, které splňují: P (ti, ..., ti + n − 1) pro i-tý bod – i-tou polar value. - Polární forma je symetrická ve svých členech. To znamená, že můžeme měnit pořadí argumentůbez změny polar value. - Máme-li dáno P (u1, u2, ..., un − 1, a) a P (u1, u2, ..., un − 1, b) můžeme spočítat hodnotu P (u1, u2, ..., un − 1, c) pro libovolné c jako: P (u1, u2, ..., un − 1, c) = (b - c)P(u1, u2, . . . , un-1, a) + (c - a)P(u1, u2, . . . , un-1, b) b−a řekneme, že bod P (u1, u2, ..., un − 1, c) je afinní kombinací bodů P (u1, u2, ..., un − 1, a) a P (u1, u2, ..., un − 1, b). Zápis polární formy je založen na symetrických polynomech. Hlavní myšlenkou je reprezentovat polynom p(t) stupně m jedné proměnné jako polynom více proměnných p[t1, ..., tn], kde každá proměnná je stupně jedna, n ≥ m a platí: p[t, . . . , t] = p(t). 4.1.2
Uzlové intervaly
Uzlový vektor je neklesající posloupnost reálných čísel, s jehož pomocí se zadávají obecné NURBS objekty. Uzlové intervaly tvoří posloupnost, jejíž hodnoty jsou rozdíly po sobě jdoucích uzlů v uzlovém vektoru. Příklad: Uzlový vektor: u = (0, 1, 3, 6, 7) Uzlové intervaly: (1, 2, 3, 1) Uzlové intervaly jsou pouze jinou alternativou zápisu pro uzlový vektor, ale mají lepší vlastnosti. Například jsou více svázány s kontrolním polygonem. čím větší je uzlový interval pro danou hranu, tím větší délku má výsledná křivka.
39
Obr. 7: ovození polar labels (Procházková 2007)
4.1.3
Polar labels
Polar labels jsou hodnoty, které jsou přiřazeny každému řídicímu bodu a které využívají uzlové intervaly. Je-li křivka stupně n, pak má polar label všech řídicích bodů právě 2n − 1 členů. Prostřední z nich je hodnota uzlového intervalu hrany předcházející. Odvození je názorně vidět na obr: Pomocí uzlových intervalů lze odvodit i metodu vložení uzlu – knot insertion nebo odebrání uzlu – knot removal. (Procházková 2007)
4.2 4.2.1
Matematické vyjádření Definice T-spline
Obecná T-spline plocha je dána vztahem: P (s, t) = (x(s, t), y(s, t), z(s, t), w(s, t)) Kartézské souřadnice bodu na ploše jsou dány vztahem: Pn
Pi wi Bi (s,t) P (s, t) = Pi=0 n wi Bi (s,t) i=0
kde Pi jsou řídící body s vahami wi a bázové funkce jsou dány jako: Bi (s, t) = N [si0 , si1 , si2 , si3 , si4 ](s)N [ti0 , ti1 , ti2 , ti3 , ti4 ](t) Bázová funkce N [si0 , si1 , si2 , si3 , si4 ](s) je asociována s uzlovým vektorem si = [si0 , si1 , si2 , si3 , si4 ]
40
a funkci N [ti0 , ti1 , ti2 , ti3 , ti4 ](t) je přiřazen uzlový vektor ti = [ti0 , ti1 , ti2 , ti3 , ti4 ].
4.2.2
Definice T-mesh
Řídící body T-spline jsou uspořádány v síti T-mesh. T-mesh je obdélníková síť, kde uzly odpovídají řídícím bodům a hrany (nazýváme je t-hrana, s-hrana) jsou označeny pomocí uzlových intervalů. Každý uzel je definován pomocí uzlových vektorů „sÿ a „tÿ, přičemž prostřední člen vektorů odpovídá souřadnicím uzlu. Odvození zbývajících hodnot se provádí z T-grid (mřížka znázorňující T-mesh) následujícím způsobem. Vedou se čtyři paprsky (nahoru, dolů, doprava, doleva) z pozice odpovídající danému řídicímu bodu a první s- nebo t-hrany, které protnou jsou dalšími uzly. Délka uzlových vektorů je dána stupněm plochy: 2 ∗ n − 1. (Procházková 2007) T-mesh mohou obsahovat křížení tvaru T – T-junctions. T-junction je vrchol, kde se sbíhají dvě s-hrany a jedna t-hrana nebo dvě t-hrany a jedna s-hrana. V případě, že je T-mesh pravidelná, tj. neobsahuje T-junction, jedná se o klasickou NURBS.
Obr. 8: T-mesh (Procházková 2007)
Základní pravidla pro T-mesh jsou: - Součet uzlových intervalů na protějších hranách každé stěny se musí rovnat.Podle obr. musí například platit: d7 = d2 + d6 a e6 + e7 = e8 + e9 - Pokud T-junction na jedné hraně stěny má být spojena pomocí T-junction na protější hraně bez porušení prvního pravidla, je nutné zahrnout tuto hranu do T-mesh (rozdělení stěny na dvě části). (Procházková 2007)
41
Příklad : uzlové vektory pro některé body P1 : pozice (s3 , t2 ) si = [s1 , s2 , s3 , s4 , s5 − d8 ] ti = [t1 − e0 , t1 , t2 , t3 , t4 + e9 ] P2 : pozice (s5 − d8 , t3 ) si = [s3 , s3 + d6 , s5 − d8 , s5 , s5 + d5 ] ti = [t1 , t2 , t3 , t4 , t5 ] P3 : pozice (s1 , t5 ) – hraniční bod, nezávisí na s3 , 0 a t3 , 4 si = [s1 − d0 , s1 − d0 , s1 , s2 , s2 + d7 ] ti = [t1 , t4 − e9 + e7 , t5 , t5 + e5 , t5 + e5 ]
4.2.3
Výpočet bodu T-spline plochy
Výpočet polohy bodu naležící T-spline ploše je dán vstupními body „sÿ a „tÿ a T-mesh. - Pro parametry „sÿ a „tÿ nalezneme body vlivu, tj. ty body, jejichž uzlové intervaly obsahují hodnoty „sÿ, „tÿ. - Pro vybrané body se vypočítají bázové funkce N0i3 (s), N0i3 (t). P - Vyhodnotí se výraz i Pi N0i3 (s)N0i3 (t) který určuje souřadnice výsledného bodu. Bázové funkce N0i3 (s), N0i3 (t) nepočítáme deBoorovým algoritmem jako u NURBS. Použijeme přímý výpočet pouze s dosazením parametru a uzlového vektoru, neboť pro třetí stupeň je tvar polynomů N0i3 vždy stejný. Pro třetí stupeň ploch je dán rovnicemi:
N[ti ](t) =
42
(t-t0 )3 (t1 −t0 )∗(t3 −t0 )∗(t2 −t0 ) pro t ∈ ht0 , t1 )
pro t ∈ ht2 , t3 )
2
−t)∗(t−t1 ) ) 3 −t)∗(t−t0 )∗(t−t1 ) (t-t0 )2 ∗ (t2 − t) (t2 −t1 )∗(t3 −t1 )∗(t2 −t0 ) + (t(t + (t2 −t(t14)∗(t 2 −t1 )∗(t3 −t1 )∗(t3 −t0 ) 4 −t1 )∗(t3 −t1 )
pro t ∈ ht1 , t2 ) 2
4 −t)∗(t3 −t)∗(t−t1 ) 4 −t )∗(t−t2 ) + (t3 −t(t2 )∗(t (t-t0 ) ∗ (t3 − t)2 (t3 −t2 )∗(t3 −t1 )∗(t3 −t0 ) + (t(t 3 −t2 )∗(t4 −t1 )∗(t3 −t1 ) 4 −t2 )∗(t4 −t1 )
(t4 − t)3 (t4 −t3 )∗(t4 −t2 )∗(t4 −t1 ) pro t ∈ ht3 , t4 ) jinak0
4.3
T-spline Local Refinement
T-spline Local Refinement je algoritmus, který slouží k vložení nových řídicích bodů do Tmesh beze změny tvaru výsledného povrchu. Samotný proces má dvě fáze – topologickou a geometrickou. V topologické části se určí, zda je nutné přidávat další řídicí body do T-mesh a určí se. V geometrické části je potom proveden samotný výpočet. Definujme T-spline prostor, což je množina T-spline ploch, které mají stejnou T-mesh topologii a uzlový souřadný systém. T-spline prostor může být reprezentován pomocí diagramu znázorňující T-mesh. Na T-spline prostorech lze také definovat relaci uspořádání. Řekneme, že T-spline prostor S1 je podprostorem S2 , pokud existuje lokální zjemnění, které převede T-spline v S1 do T-spline v S2 .(P rochzkov2007) Obecně mějme dvě T-spline plochy P (s, t) ∈ S1 a P¯ (s, t) ∈ S2 . Označíme P sloupcový vektor řídicích bodů pro P (s, t) danou rovnicí a P¯ sloupcový vektor řídicích bodů pro P¯ (s, t). Vezmeme lineární ansformaci, která zobrazí P na P¯ . M12 P = P¯ Ze vztahu podprostoru můžeme vyjádřit bázovou funkci Bi (s, t) jako lineární ¯i (s, t) : kombinaci B
Bi (s, t) =
j ¯ j=1 ci B(s, t)
Pn¯
Chceme, aby P (s, t) = P¯ (s, t) To je splněno, pokud P P¯i = ni=1 cji Pi
4.3.1
Algoritmus T-spline local refinement
Připomeňme, že pro každý bod T-spline plochy je pevně svázán se dvěma uzlovými vektory, které jsou odvozené z T-mesh a které určují příslušnou bázovou funkci. Během algoritmu vkládání bodu se mohou vyskytnout tři druhy porušení tohoto pravidla. - Chyba 1 – Bázová funkce nemá uzel, který by měla mít odvozením z T-mesh výše popsaným způsobem. - Chyba 2 – Bázová funkce má uzel, který by neměla mít odvozením z T-mesh výše popsaným způsobem. - Chyba 3 – Existuje řídicí bod, který není spjat s žádnou bázovou funkcí.
43
Pokud se po vložení bodu neobjeví žádná chyba, je T-spline v pořádku a může se vykreslit. Pokud se vyskytnou nějaké chyby, musí se podniknout vhodné kroky na jejich odstranění. Algoritmus úpravy lze popsat následujícími čtyřmi kroky: - Vložíme všechny požadované body do T-mesh. - Pokud nějaká bázová funkce nemá uzel, který by měla mít odvozením – Chyba 1, provede se vložení uzlu do této funkce podle vzorců uvedených níže. - Pokud nějaká bázová funkce má uzel, který by neměla mít odvozením – Chyba 2, provede se vložení vhodného řídicího bodu do T-mesh. - Opakujeme kroky 2 a 3 dokud nejsou všechny chyby ošetřeny.
4.3.2
Vkládání nového uzlu do uzlového vektoru bázové funkce
Máme dán uzlový vektor s = (s0 , s1 , s2 , s3 , s4 ) a jemu odpovídající bázovou funkci N (s) = (N (s0 , s1 , s2 , s3 , s4 ). Vložíme uzel s0 < k < s4 a podle pořadí se provede odpovídající přepočet. Pro s¯ = (s0 , k, s1 , s2 , s3 , s4 ) N (s) = c0 N (s0 , k, s1 , s2 , s3 )(s) + d0 (k, s1 , s2 , s3 , s4 )(s) kde c0 =
k−s0 a s3 −s0
d0 = 1 Pro s¯ = (s0 , s1 , k, s2 , s3 , s4 )
N (s) = c1 N (s0 , s1 , k, s2 , s3 )(s) + d1 (s1 , k, s2 , s3 , s4 )(s) kde c1 =
k−s0 a s3 −s0
d1 =
s4 −k s4 −s1
Pro s¯ = (s0 , s1 , s2 , k, s3 , s4 )
N (s) = c2 N (s0 , s1 , s2 , k, s3 )(s) + d2 (s1 , s2 , k, s3 , s4 )(s) kde c2 =
k−s0 a s3 −s0
d2 =
s4 −k s4 −s1
Pro s¯ = (s0 , s1 , s2 , s3 , k, s4 )
N (s) = c3 N (s0 , s1 , s2 , s3 , k)(s) + d2 (s1 , s2 , s3 , k, s4 )(s) kde c3 = 1a d3 =
s4 −k s4 −s1
Vložení uzlu můžeme provést pro parametr s i pro
parametr t pouze opakováním předchozí konstrukce.
44
4.4
T-spline Simplification
Při návrhu obecných tvarův NURBS modelovaných prostředích dochází ke vzniku tzv. superflous – nadbytečných bodů. T-spline simplification slouží k odstranění většiny z nich z původní NURBS, resp. T-spline plochy. Jako vstup máme T-spline nebo NURBS plochu, kterou chceme zjednodušit. Nejdříve pomocí postupu uvedeného v Lyche (1993) nalezne aproximace nejmenšími čtverci výchozí plochy Tn , která se skládá ze čtverců 4 ∗ 4. Tuto plochu označíme T0 a patří do prostoru S0 . Označíme P 0 vektor bodů plochy T0 a P n vektor bodů původní plochy Tn . Vypočítáme matici M0,n přechodu mezi jednotlivými prostory a rozdíl: D0n = M0n P 0 − P n
Obr. 9: metoda nejmenších čtverců (Procházková 2007)
Pokud velikost (odmocnina z druhých mocnin jednotlivých složek) chybového vektoru D0n přesahuje určitou prahovou hodnotu, dojde k dělení čtverců, ve kterých chybové body leží. Dělení se provádí v polovině strany, která obsahuje více uzlových čar. Tím přejdeme k podprostoru S1 a můžeme znovu zkontrolovat chybovou matici D1n . Obecně pro i-tý krok bereme: Din = Min P i − P n Pokud je chyba pro všechny body z vektoru Din pod prahovou úrovní, je plocha Ti prostoru Si hledanou zjednodušenou plochou bez většiny nadbytečných bodů. Na schématu je znázorněn postup T-spline simplification a na obrázku je ukázka ze softwaru Maya. K vykreslení stejného modelu je potřeba méně než polovina původních bodů při zachování modelu bez viditelné změny. Při vkládání nových hran se používá algoritmus local refinement uvedený výše, kde se krajní body vložené hrany vkládají jako nové body sítě. Někdy je nutné vložit i další pomocné body. 45
Obr. 10: příklad T-spline simplification (Procházková 2007)
46
5 5.1
Návrh knihovny pro výpočet T-spline Metodika
Cílem této kapitoly je navrhnout a popsat knihovnu pro konstrukci T-spline na základě vstupního mraku bodů. O vizualizaci dat se následně postará knihovna Coin. Obě části jsou od sebe oddělené. Konkrétní aplikace je zaměřena na zpracování geografických dat. V geografických informačních systémech (GIS) se snažíme o co možná nejvěrnější znázornění povrchu terénu se na základě naměřených hodnot. Zatímco některé ploché části terénu nejsou z hlediska měření tak zajímavé a lze je popsat několika málo body, složité nerovné potřebují k popisu hustou síť bodů. Použitím B-spline pravidelné mřížky bodů dochází ke kompromisům mezi lokální a celkovou přesností (hustotou měřených bodů) měření. TIN modely umožňují lokální zjemnění, ale ne vždy jsou vhodné pro prezentaci dat. T-spline slučují výhody obou metod. Knihovna je napsána v jazyce C/C++. Tento jazyk je velmi rozšířen a měl by jít kdekoliv přeložit. Z důvodu přenositelnosti kódu také nejsou použity žádné platformě závislé knihovny. Je také využívána knihovna STL pro obsluhu standardních rutin jako ošetření dynamických seznamů nebo seřazení hodnot. C++ je jazyk objektový, a proto by mělo být využito výhod objektového přístupu. Procedury a proměnné by měly zůstat pokud možno skryté před uživatelem knihovny a komunikace probíhat pouze určenými funkcemi. Při dalším vývoji knihovny se dá předpokládat použití zde vyvíjených tříd a urychlení práce využitím dědičnosti. Vstupními daty pro vytvoření objektu T-spline je množina bodů. Vzhledem k tomu, že není dopředu znám formát dat, nebude vytvořen pro vstup žádný datový typ „bodÿ, ale data jsou reprezentována jako jednorozměrné pole, kde každé tři hodnoty znamenají postupně souřadnici x, y a z. Dalšími vstupy jsou stupeň plochy a rozlišení. V práci je výhradně počítáno s křivkami třetího stupně, nicméně návrh musí počítat s možností rozšíření. Čím vyšší je stupeň, tím je výsledná plocha hladší. Rozlišení vyjadřuje přesnost měření, neboli hustotu bodů. Výstupem by měl být opět mrak bodů reprezentující T-spline plochu. Opět není dopředu znám formát dat, proto budou mít výstupní data stejný formát jako vstupní. Trojice reálných čísel v pořadí x, y, z. Výsledné body poté budou zobrazeny buď pouze jako body v 3D prostoru, nebo budou reprezentovat vrcholy trojúhelníků či čtyřúhelníků. Hustota výstupních bodů závisí na požadavcích aplikace. Platí, že více bodů zajistí hladší plochu, ovšem jejich výpočet bude časově náročnější. Před započetím programování je nutno se nejprve důkladně seznámit s matematickým aparátem T-spline. Špatné pochopení matematických algoritmů může mít za následek zbytečné chyby v dalších fázích. Pochopitelně největší pozornost je věnována praktickým úkolům jako vytvoření T-mesh a výpočet bodů plochy.
47
Velmi časté v počítačové grafice při práci s křivkami je zanedbání vah (nastavení vah na jedna) a změny tvaru provádět pomocí změny polohy řídících bodů. Bude tomu tak i v této práci. Navíc tomu i odpovídá povaha vstupních dat, protože všechny vstupní body ovlivňují výslednou plochu stejně.
5.2 5.2.1
Reprezentace třídy T-spline Struktura pomocných tříd
Byla vytvořena pomocná třída Point, obsahující strukturu bodu. Tato třída je použita jen uvnitř objektu T-sline. Není použita pro vstupy ani výstupy. Veřejné proměnné třídy Point: - double x; - double y; - double z; Veřejné funkce třídy Point: - Point (); – konstruktor, nastaví hodnoty bodu na nula Dále byla vytvořena dočasná pomocná třída InputArray, které uchává vstupní body, transformuje je do podoby Point. Veřejné proměnné třídy InputArray: - std::vector inputData; – pole bodů Veřejné funkce třídy InputArray: - InputArray(double *Data,int num); – konstruktor, volají se zde fukce inportData a sortByY. Soukromé funkce třídy InputArray: - int importData(double *Data,int num);– data jsou převedena do struktury Point - int sortByY(); – data jsou setříděna podle velikosti 5.2.2
Struktura třídy T-spline
Veřejné funkce třídy T-spline: - TSpline (double *inputData, int num); – konstruktor, vstupem je ukazatel na pole reálných čísel reprezentující souřadnice řídících bodů a počet řídících bodů. Obsluhuje vytvoření T-spline, jsou zde volány metody yCube, computeUVector, computeVVector.
48
- void printSpline(); – informační výpis všech bodů, vektoru „vÿ a vektorů „uÿ - double *make1point(double t, double s, double *array); – spočítá polohu jednoho bodu na T-mesh a vrátí pole tří hodnot („xÿ, „yÿ, „zÿ souřadnice ). Je zde volána funkce countB. - double *makepoints (int x, int y, double *array); – vrátí pole hodnot v obvyklém formátu, vstupy „xÿa „yÿ určují hustotu bodů na osách. Opakovaně volá funkci make1point. - int getDegree (); – výpis hodnoty degree - void setDegree (int degree); – nastavení hodnoty degree - int getResolution ();– výpis hodnoty resolution - void setResolution (float resolution); – nastavení hodnoty resolution Soukromé proměnné třídy T-spline: - std::vector < std::vector > spline; – dvojrozměrné pole bodů, uspořádané do intervalů podle „yÿ - std::vector <double> v; – ekvidistantní vektor, podle počtu intervalů v rozmezí nula až jedna - std::vector < std::vector<double> > u; – dvojrozměrný vektor, pro každý řádek vektoru „vÿ vektor „uÿ. Pro každý kontrolní bod existuje uzlový vektor o velikosti pět. Protože jsou vektory větší o stupeň křivky „z obou stranÿ, náleží nultému bodu vektor začínající nultým členem tohoto vektoru. - int degree; – stupeň křivky, - float resolution; – rozlišení bodů, ovlivňuje velikost intervalů Soukromé funkce T-spline: - int yCube(InputArray* field); – vstupní body, setříděné podle velikosti, jsou rozděleny do intervalů daných resolution podle „yÿ - int computeUVectors(); – vypočítány U vektory. - int computeVVectors(); – vypočítán v vektor - double countB(double s, double t[5]); – vypočítání bázové funkce
5.3 5.3.1
Algoritmus Tvorba T-spline
Práce s třídou T-spline má dvě části. Je to vytvoření T-mesh a vlastní vypočítání plochy. První krok je zabezpečen v konstruktoru T-spline. Nejprve se vstupní mrak bodů transformuje pomocí objektu inputArray do struktury Point a metodou quick sort z knihovny STL setřídíme podle velikosti. Setřídění je výhodné pro použití v další funkci „y-cubeÿ. Následně jsou vypočitány vektory.
49
transformuj_do_point_a_setrid; setrid_body_do_y-cube; vypocitej_vektor_V; vypocitej_vektor_U; V metodě y-cube jsou body rozděleny do intervalů daných rozlišením. Velikost rozlišení se zvolí vzhledem k velikosti snímané oblasti a kroku snímání. Postupně se naplňuje dvojrozměrné pole spline. Nakonec jsou body v řádku setříděny podle osy x. Body tak začínají tvořit kontrolní síť pro T-spline. Algoritmus yCube: projed_pres_vsechy_body{ pokud_je_v_intervalu{ pridej_ho_do_vektoru; } jinak{ zvec_interval; zaloz_novy_vektor; } setrid_body_vektoru_podle_x; Každý bod T-spline plochy je určen dvěmi uzlovými vektory, které popisují lokální okolí bodu. Vektor „vÿ odpovídající ose „yÿ je zvolen jako ekvidistatní. Při snímání mají naměřené body v jednotlivých hranolech přibližně stejné vzdálenosti. Dalším důvodem je to, že pro další úpravy by bylo časově náročné přepočítávat všechny uzlové vektory. Vektor je převeden do rozmezí nula až jedna. Algoritmus computeVVector: nastav_prvni_4_hodnoty_na _0; nastav_posledni_4_hodnoty_na _1; nastav_ostatni_podle_eqidistatniho_deleni; Pro aproximaci vektorů u pro osu x je použita středová metoda. Středová metoda byla vybrána, proto že velmi dobře popisuje změny povrchu. (Procházková 2007) Počítáme pro n + 1 bodů. d=
Pn
q
k=1
|Qk − Qk−1 |
Potom √ u¯0 = 0¯ un = 1¯ uk = u¯k−1 +
|Qk −Qk−1 | d
k = 1, . . . , n − 1
Potom z něj metodou „averagingÿ vypočítáme klasický uzlový vektor pro křivku stupně tři.
50
u0 = . . . = up = 0 uj+p =
1 n
Pj+p−1 i=j
um−p = . . . = um = 1 u¯i
j = 1, . . . , n − p
Vektory, jak u tak v začínají v hraničních pozicích nulami a jsou ukončeny jedničkami. Každý vektor je větší o stupeň plochy plus jedna než počet bodů v hranolu „y-cubeÿ. Algoritmus computeUVector: spocti_celkovou_delku; vypocti_vektor_U_spruhem; nastav_prvni_4_hodnoty_na _0; nastav_posledni_4_hodnoty_na _1; nastav_ostatni_averaging_metodou; 5.3.2
Výpočet bodů plochy
Po vytvoření T-spline plochy postoupíme k výpočtu bodů plochy. Plocha je reprezentována množinou reálných čísel, souřadnic v kartézském systému, která je výstupem dvou metod: make1point a makepoints. V Metodě makepoints opakovaným voláním funkce make1point získáme souřadnice všech bodů plochy. Hustotu bodů lze ovlivnit hodnotami x a y. Funkce také alokuje potřebné místo pro uložení hodnot. Z technických důvodů vrací funkce makepoints x − 1 ∗ y − 1 bodů. Metoda make1point vrací souřadnice jednoho bodu, daného souřadnicemi9 v Tgrid Funkce make1point sčítá výsledek bázové funkce pro všechny body. Výsledek bázové funkce vrací metoda countB, kde vstupními hodnotami jsou s, vypočítávaná pozice na T-grid a uzlový vektor aktuálního bodu. V případě, že s není v intervalu, pak se nejedná o bod vlivu a je vrácena nula. V opačném případě je vrácen výsledek dle příslušných rovnic. pro_souradnice{ projed_pres_vsechny_body{ vypocti_bazovou_fci_pro_s; vypocti_bazovou_fci_pro_t; uprav_hodnotu_bodu; } } 9
Souřadnice v rozmezí nula až jedna
51
5.3.3
Zobrazení plochy
Pro vlastní zobrazení plochy byly použity standardní nástroje knihovny Coin. Pro ilustraci byly užity tři způsoby: - SoPointSet – mrak bodů - SoQuadMesh – čtvercová síť - SoIndexedTriangleStripSet – indexovaný trs trojúhelníků Ve všech třech případech bylo použito podobného postupu. Byla vytvořena funkce, vracející SoSeparator. Uvnitř funkce je vytvořen požadovaný objekt. Koordináty pro vytvoření plochy je nejprve nutno převést z formátu tří reálných čísel na vhodné dvojrozměrné pole. double vertices[81][3]; double *vstupni_pole; int counter =0; for(int i=0 ;i<243 ;i+=3 ){ vertices[counter][0] =vstupni_pole[i]; vertices[counter][1] =vstupni_pole[i+1]; vertices[counter][2] =vstupni_pole[i+2]; counter++; } SoCoordinate3 * coords = new SoCoordinate3; coords->point.setValues(0, 81, vertices); Nejjednodušší případ je SoPointSet. Zde stačí nastavit jako parametr počet bodů. Plocha je zobrazena jako body. Při použití SoQuadMesh se nastavují dva parametry. Počet čtyřúhelníků v sloupci a v řádku. Hodnoty slouží k určení správnému pořadí bodů vstupující do funkce. Trs trojúhelníků tvoří trojúhelníky podle pořadí bodů na vstupu. Tento postup není vhodný pro formát dat zvolený v této práci. Existuje varianta indexovaných trsu trojúhelníků, kde body, tvořící jeden trojúhelník, jsou přesně specifikované. Na základě počtů bodu na ose x a y vytvoří jednoduchá funkce makeindex požadované indexy. Použitím prostředí Open Inventoru umožní, bez zdlouhavé práce programátora, vypočítat normálové vektory pro plochy. Pomocí ExaminerViewer je možno přepínat mezi drátěným modelem a plochou nebo model otáčet a přibližovat.
5.4
Diskuze
Hodnocení použitého řešení závisí na několika faktorech. Zaprvé jde o funkčnost, jestli program dělá to co má. Zadruhé jde o to, zda danou činnost provádí optimálně. 52
Obr. 11: znázornění trsu trojúhelníků a indexovaného trsu trojúhelníků
Mnohdy by se dalo upřednostnit jiné řešení na úkor například rychlosti výpočtu. Je ovšem otázkou, zda uspořený čas je významný vzhledem k objemu dat. Významným faktorem je také možnost dalšího vývoje. 5.4.1
Využití Open Inventoru
V OpenGL lze pochopitelně vytvořit stejný výsledek. Stačí postupně zadávat výchozí body plochy, ve stejném pořadí jako u určování indexů použité v této práci. Svým způsobem je tento postup i jednodušší, ale opět zde nastává nutnost dopočítat normály a souřadnice textur atd. glBegin(GL_TRIANGLE_STRIP); for(int i=0;i<x;i++){ for(int j=0;j
Obr. 12: nejjednodušší plocha 4x4
glEnd(); Použitou knihovnu Coin není ovšem zcela triviální nainstalovat. Pod systémy Windows sice existují binární instalační balíčky, ale jen pro Microsoft Visual C++ verzi 6. I tak se při vytváření projektu pro správnou kompilaci musí nastavit správné cesty k DLL knihovnám. Pro použití na systémech Linuxu je nejvhodnější cesta vlastní kompilace. Zdrojové kódy je možno stáhnout na stránkách Coin. Ani další výhody použití Open Inventoru nedojdou plného využití. Spolehlivost kódu, nebo optimalizace vzhledem k celkové jednoduchosti nebudou podstatné. Z tohoto pohledu je nevětší přínos použití SoExaminerVieweru, který pohodlně vytvoří prostředí pro prohlížení modelu. 5.4.2
Další návrhy vývoje knihovny T-sline
Současná verze knihovny T-spline je zaměřená na modelování terénu. Tomu odpovídají i požadavky na vstupy. V běhu programu tak není zapotřebí vytvářet přesné kruhové plochy a podobné. Z tohoto pohledu je toto zaměření nutno brát jako zjednodušení. Obecnější knihovna ale může být založena na tomto základu. Limitující je rozdělení všech bodů podle interval;. Toto roztřídění, respektive použití ekvidistantního vektoru v, umožňuje použít T-junction pouze v horizontálním směru. To znamená samozřejmě omezení. Toto řešení bylo použito proto, že povaha vstupních dat počítá se zaplněním všech intervalů, měřením pomocí technologie LiDAR (Light Detection and Radaring). Taková data poskytují poměrně
54
Obr. 13: T-spline plocha
pravidelnou síť dat, dle rychlosti snímkování. Další důvodem zvoleného řešení je obtížnost zpracování a přepočítání všech vektorů při změně. Návrhy pro další vývoj:
- Rozšíření o práci s různými stupni křivek. Současná verze počítá pouze s užitím křivek třetího stupně. Ve většině případů, jako velikosti uzlových vektorů, je se změnou v návrhu počítáno. Podstatné změny by ale čekaly výpočet bázové funkce, protože výpočet je zde zcela odlišný. Menší změny by také nastaly při výpočtu vektorů u, kde při průměrování má stupeň křivky taktéž vliv. - Rozšíření programu o T-spline siplification a Local Refinement, tj. o zjednodušování a přidávání bodů na T-mesh. S tím souvisí také zobrazování ostrých přechodů. - Zhodnotit, zda by mělo smysl pozměnit program tak, aby umožňoval T-junction v obou směrech. Takový zásah by znamenal nejvíce úprav.
55
6
Závěr
Cílem této práce bylo proniknout do problematiky modelování povrchů pomocí nového matematického nástroje T-spline. V současné době podporují, s použitím zásuvných modulů firmy T-Splines, modelování T-spline dva grafické editory – Rhinoceros a Maya10 . Do budoucna je pro T-sline prorokována velká budoucnost. Pro vizuální prezentaci byla zvoleno Open Inventor API a to hlavně z toho důvodu, že je méně rozšířeno něž klasické OpenGL. Jeho využitím v práci vzniká návod pro případné zájemce. Použitím objektového přístupu pro vykreslování objektů programátor ušetří spoustu „manuálníÿ práce u klávesnice a může se věnovat důležitější činnosti. Navíc se pravděpodobně vyhne chybám, použitím již vyladěného kódu. Kapitola Open Inventor by měla sloužit jako návod k prvnímu seznámení, přes tvorbu jednoduchých scén až po použití pokročilejších nástrojů jako engines. Nicméně zde nejsou uvedeny teoretické podklady pro pochopení procesu renderování scény. Lze sice programovat v Open Inventoru i bez těchto znalostí, ale jistě bude snazší dosáhnout požadovaného efektu po nastudování potřebných znalostí. Zde mohu doporučit publikaci OpenGL průvodce programátora (Neider et al. 2006), která probírá toto téma do hloubky i z teoretického hlediska. V části věnované teorii T-spline je matematicky T-sline definována a jsou popsané algoritmy pro další práci s T-spline. V současnosti nejsem schopen přinést v této oblasti nic nového a jsem odkázán na pochopení principů fungování pro pozdější implementaci. Jak jsem již zmínil, tato část diplomové práce je převážně založena na práci Ph.D. Jany Procházkové, které tímto opět děkuji za odbornou pomoc. V této době fungují v knihovně T-spline tyto funkce: načtení vstupních dat, jejich transformace do T-mesh a pro každý bod jsou spočítány uzlové vektory. Po vytvoření kompletní T-spline voláním příslušných funkcí vypočítáme jednotlivé body plochy. Věřím, že jsem v této práci přispěl k rozvoji modelování T-spline a že může být použita jako dobrý základ pro další vývoj v oblasti.
10
56
http://www.coin3d.org
7
Literatura
Akeine-Moler, T. – Haines, E. Real-time Rendering. Natick, Massachusetts, USA, 2002. Baker, H. Computer Graphics with OpenGL - Third Edition. Pearson, 2004. Eckel, B. Myslíme v jazyku C++ : knihovna programátora. Praha: Grada, 2000.
Eckel, B. – Allison, C. Myslíme v jazyku C++ : knihovna zkušeného programátora. Praha: Grada, 2006. Hill, F. S. jr.Computer Graphics using Open GL Prentice Hall, 2001. Nieder, J. – Woo, M. – Shreiner, D. OpenGL - Průvodce programátora Brno: Computer Press, 2006 . Open Inventor Architecture Group The Inventor Mentor: Programming Object Oriented 3D Graphics with Open Inventor Addison-Wesley Publishing Company 2007. Pečiva, J. Seriál Open Inventor [online] www.root.cz/serialy/open-inventor . Procházka, D., Procházková , J. T-spline – nová metoda modelování povrchů. GIS Ostrava. 2007 . Procházková, J. Modelování matematických ploch v CAD systémech Dizertační práce, VUT Brno, 2007 . Ramshaw, L. Blossoms are polar form. DEC Systems, 1989. Salamon, D. Curves and Surfaces for Computer Graphics
New York, NY. 2006.
Sederberg, T. et al. T-splines and T-NURCCs. ACM Trans. Graphic. 2003. Sederberg, T., Zheng, J., Cardon, D., and Lyche, T.T-splines simplification and local refinement ACMTrans. Graphic. Silicon GraphicsOpenGL Reference Manual Silicon Graphics, Inc., 1994. Tišnovký, P. Seriál OpenGL evaluátory evaluatory .
[online] www.root.cz/serialy/opengl-
57
Tišnovký, P. Seriál OpenGL a nadstavbová knihovna GLU www.root.cz/serialy/opengl-a-nadstavbova-knihovana-glu . Turek, M. CZ NeHe OpenGL
[online]
[online] http://nehe.ceske-hry.cz.
Wernecke J. The Inventor Mentor: Programming Object Oriented 3D Graphics with Open Inventor Addison-Wesley Publishing Company . Wright R. S.OpenGL SuperBible Waite Group Press, 1999. Zheng, J. – Wang, Y. – Seah, H. S. Adaptive T-spline Surface Fitting to Z-Map Models. GRAPHITE. 2006. Coin3D 3D Graphics Development Tools [online] http://www.coin3d.org/. Open GL – The Industry’s Foundation for High Performance Graphics [online] http://www.opengl.org. T-Splines Inc. [online] http://www.tsplines.com.
58
8
Přílohy 1 – Modelování krajiny
8.1
Příklad 1
„Krajinaÿ je tvořena plochou částí, která je popisována jen několika body, a kopcovitou, kde je počet kontrolních bodu vyšší. Řídící body: 0 10 40 50
-10 -10 -10 -10
0 0 0 0
0 10 20 50
10 10 10 10
0 0 0 0
0 20 25 30 35 40 50 50
30 30 30 30 30 30 30 40
0 3 5 15 4 8 6 7
0 20 25 28 30 35 40
40 40 40 40 40 40 40
0 3 6 0 -4 9 10
0 12 14 15 50
15 15 15 15 15
0 4 3 0 0
0 10 20 50
20 20 20 20
0 0 0 0
0 50 0 20 50 3 25 50 6 30 50 8 35 50 9 40 50 10
Obr. 14: drátěný model
Plocha je tvořena pátem 4x4. Ve středu leží objekt zájmu („kopecÿ) a jsou zde body zhušteny. 59
Obr. 15: pohled z perspektivy
Řídící body: 0 20 40 60
0 0 0 0
0 10 20 25 30 35 40 60 60
30 30 30 30 30 30 30 30 40
60
0 0 0 0
0 20 40 60
0 0 10 8 15 20 8 0 0
20 20 20 20
0 0 0 0
0 20 40 60
0 40 0 10 40 -2 20 40 5 25 40 12 30 40 13 35 40 17 40 40 10 45 40 3
40 40 40 40
0 0 0 0
0 20 40 60
50 50 50 50
0 0 0 0
0 20 40 60
60 60 60 60
0 0 0 0
Obr. 16: boční pohled
Obr. 17: pohled ze zhora
61
9
Přílohy 2 – zdojový kód
9.1
TSpline
Konstruktor objektu. Zajišťuje vytvoření T-spline. TSpline::TSpline(double *inputData,int num){ degree = 3; resolution=1; InputArray* field = new InputArray(inputData,num); yCube(field); computeUVectors(); computeVVectors(); }
9.2
computeUVector
Metoda počítá použitím středové a averaging metody vektory U. int TSpline::computeUVectors(){ for(int interval = 0; interval < spline.size(); interval++){ double d = 0.0; for (int point = 1; point < spline[interval].size(); point++){ d = d + (sqrt ( pow( spline[interval][point].x-spline[interval][point-1].x, 2) + pow( spline[interval][point].y-spline[interval][point-1].y, 2 ) + pow( spline[interval][point].z-spline[interval][point-1].z, 2 ))); } double uPruh[spline[interval].size()]; uPruh[0] = 0.0; for (int point = 1; point < spline[interval].size(); point++){ uPruh[point] = uPruh[point-1] + ((sqrt ( pow( spline[interval][point].x-spline[interval][point-1].x, 2) + pow( spline[interval][point].y-spline[interval][point-1].y, 2) + pow( spline[interval][point].z-spline[interval][point-1].z, 2))/d)); }
62
vector<double> oneU; for (int i = 0; i < degree+1; i++) oneU.push_back(0.0); for (int point = 1; point < spline[interval].size()-degree; point++) oneU.push_back((uPruh[point]+uPruh[point+1]+uPruh[point+2])/3); for (int i = 0; i < degree+1; i++) oneU.push_back(1.0); u.push_back(oneU); } return 0; }
9.3
computeVVector
Výpočet vektoru V pomocí ekvidistatního dělení. int TSpline::computeVVectors(){ for (int i = 0; i < degree+1; i++) v.push_back(0.0); float b= spline.size()+degree+1-8; for (float point = 1; point <= b ; point++) v.push_back(point/(b+1)); for (int i = 0; i < degree+1; i++) v.push_back(1.0); return 0; }
9.4
yCube
V této metodě jsou body roztříděny do ktenolů podle osy „yÿ a poté seřazeny podle „xÿ.
63
int TSpline::yCube(InputArray* field){ float intervalBoundary = field->inputData[0].y+resolution /2.0; vector oneInterval; for (vector::iterator act = field->inputData.begin(); act != field->inputData.end(); act++){ if (act->y <= intervalBoundary) { oneInterval.push_back(*act); } else { spline.push_back(oneInterval); oneInterval.clear(); oneInterval.push_back(*act); float i; for( i=intervalBoundary;i < act->y;i+=resolution); intervalBoundary=i; } } spline.push_back(oneInterval); for (vector< vector >::iterator interval = spline.begin(); interval != spline.end(); interval++){ sort((*interval).begin(), (*interval).end(), comparePointsByX); } return 0; }
9.5
countB
Funkce vrací hodnotu bázové funkce pro třetí stupeň křivky.
double TSpline::countB(double s, double t[5]){ if(s=t[4])return 0; if(t[0]<=s && s
return pow((s-t[0]),3)/((t[1]-t[0])*(t[3]-t[0])*(t[2]-t[0]));} else if(t[1]<=s && s
9.6
make1point
Metody vrací tři reálná čísla reprezentující souřadnice v kartézkém systému dle zadaných souřadnic v T-mesh. double *TSpline::make1point(double t, double s,double *aray){ Point pom; double a,b; aray =new double[3]; for (int interval = 0; interval < spline.size(); interval++){ for (int point = 0;point <spline[interval].size();point++){ a=countB(t,&u[interval][point]); b=countB(s,&v[interval]); pom.x+=spline[interval][point].x*b*a; pom.y+=spline[interval][point].y*a*b; pom.z+=spline[interval][point].z*a*b; } } aray[0]=pom.x;aray[1]=pom.y;aray[2]=pom.z; return aray; } 65
9.7
makepoints
Opakovaným voláním metody make1point se zde vytváří pole bodu dle zadané hustoty. double * TSpline::makepoints(int x,int y,double *aray){ aray = new double[(x-1)*(y-1)*3]; double *pom; int counter =0; for(float i=1 ;i<x ;i++) for(float j=1 ;j
66