原創(chuàng)|其它|編輯:郝浩|2012-09-11 16:03:28.000|閱讀 1325 次
概述:上篇文章介紹了 HOOPS 的主要模塊,這篇文章將要向大家介紹HOOPS的數(shù)據(jù)結(jié)構(gòu)以及穿插其中的一些基本概念。這些內(nèi)容主要包含在3dGS模塊內(nèi)。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門(mén)軟控件火熱銷(xiāo)售中 >>
上篇文章介紹了 HOOPS 的主要模塊,這篇文章將要向大家介紹HOOPS的數(shù)據(jù)結(jié)構(gòu)以及穿插其中的一些基本概念。這些內(nèi)容主要包含在3dGS模塊內(nèi)。
《HOOPS 3D可視化入門(mén)教程一:簡(jiǎn)介及安裝部署》
《HOOPS 3D可視化入門(mén)教程二:模塊介紹》
HOOPS采用保留繪圖模式(retained mode)。所謂保留模式是相對(duì)于傳統(tǒng)的非保留模式而言的。做過(guò)OpenGL編程的人都知道,OpenGL的繪制都是通過(guò)調(diào)用一系列繪圖命令來(lái)實(shí)現(xiàn)的,通常是在一個(gè)叫updateGL的函數(shù)里。除非你自己把相關(guān)繪圖信息保存起來(lái),否則出了這個(gè)函數(shù)OpenGL就不認(rèn)帳了,也就是說(shuō)你無(wú)法從OpenGL里面再獲取你曾經(jīng)繪制的一些圖元信息。而保留模式則不這樣,它把繪制過(guò)的命令和圖形會(huì)保存起來(lái),放在特定的數(shù)據(jù)結(jié)構(gòu)中,從而使得我們可以事后隨時(shí)讀取這些數(shù)據(jù)。相比于非保留模式,保留模式能夠提供更高的效率(因?yàn)閿?shù)據(jù)都在內(nèi)部,下次繪制時(shí)不需要再讀取),更快的交互(通過(guò)特定的基于數(shù)據(jù)結(jié)構(gòu)的算法,可以加速選取、高亮等等交互操作),還有更方便的編程接口。當(dāng)然凡事都有兩面性,保留模式也有它的缺點(diǎn),其中之一就是它增加了程序的內(nèi)存消耗(用于存儲(chǔ)那個(gè)數(shù)據(jù)結(jié)構(gòu))。但我們認(rèn)為這樣的代價(jià)是完全值得的。
HOOPS的數(shù)據(jù)結(jié)構(gòu)簡(jiǎn)單講是基于段(segment)的樹(shù)狀結(jié)構(gòu)。最上層是根段,為“/”。該數(shù)據(jù)結(jié)構(gòu)和Linux文件系統(tǒng)有著一曲同工之妙,有Linux使用經(jīng)驗(yàn)的同學(xué)將會(huì)很容易理解。Linux的根目錄的符號(hào)也是“/”,所有文件系統(tǒng)中的文件或者文件夾的路徑都以該符號(hào)開(kāi)頭。文件夾有名字,段也有名字。如同文件夾內(nèi)可以有文件和子文件夾,segment下可以有sub segment。這樣的層次結(jié)構(gòu)可以很好地構(gòu)建我們想要的圖形。
打開(kāi)一個(gè)段的HOOPS函數(shù)是HC_Open_Segment,它有一個(gè)參數(shù),就是這個(gè)段的名字。我們可以傳一個(gè)空字符串給它,從而創(chuàng)建一個(gè)匿名段。如果已經(jīng)存在這個(gè)名字的段,則該函數(shù)會(huì)打開(kāi)這個(gè)段,否則就自動(dòng)創(chuàng)建一個(gè)新段。打開(kāi)后,我們就可以在該段內(nèi)做任何我們想要做的操作。操作結(jié)束,記得用HC_Close_Segment來(lái)關(guān)閉這個(gè)段。
HOOPS采用和OpenGL一樣的上下文機(jī)制,那就是“狀態(tài)機(jī)(State Machine)”。所謂狀態(tài)機(jī),形象地講就是一旦改變了狀態(tài),則接下去不論程序運(yùn)行到哪里,該狀態(tài)將一直保存,直到下次改變狀態(tài)。在HOOPS中,打開(kāi)一個(gè)段實(shí)際上就意味著進(jìn)入了一個(gè)狀態(tài)機(jī),直到你關(guān)閉這個(gè)段,你所有的操作都將在這樣一個(gè)上下文中進(jìn)行。具體來(lái)講就是,打開(kāi)一個(gè)段,然后你可以跳轉(zhuǎn)到任意的程序位置完成具體的繪制任務(wù),然后關(guān)閉段,這一系列操作沒(méi)有必要在一個(gè)函數(shù)中完成。這無(wú)疑大大增加了我們編程的靈活性。
舉個(gè)例子,我們想要繪制一所房子,房子有房頂、窗戶(hù)還有門(mén),我們可以用如下代碼:
HC_Open_Segment (“/”);
HC_Open_Segment (“house”);
HC_Open_Segment (“roof”);
HC_Close_Segment ();
HC_Open_Segment (“door”);
HC_Open_Segment (“windows”);
HC_Open_Segment (“window1”);
HC_Close_Segment ();
HC_Open_Segment (“window2”);
HC_Close_Segment ();
HC_Open_Segment (“window3”);
HC_Close_Segment ();
HC_Close_Segment ();
HC_Close_Segment ();
HC_Close_Segment ();
實(shí)際上我們創(chuàng)建了如下的樹(shù)狀結(jié)構(gòu):
創(chuàng)建了段之后,我們需要有相應(yīng)的方法能夠找到這個(gè)段,這時(shí)就會(huì)用到段的路徑。和Linux上的文件路徑類(lèi)似,段的路徑也分為兩種:相對(duì)路徑和絕對(duì)路徑。我們打開(kāi)一個(gè)段,進(jìn)入該段的狀態(tài)機(jī),如果要打開(kāi)它下面的子段,就可以用相對(duì)路徑。HOOPS會(huì)自動(dòng)地在該段下面找給出的段名,如果找不到,則會(huì)報(bào)錯(cuò)。絕對(duì)路徑則是從根段名“/”開(kāi)始,逐步地把段名添加上去,直到我們想要找的段為止,完整的路徑就是絕對(duì)路徑。例如我們要找第三扇窗戶(hù),相對(duì)于house的相對(duì)路徑是:”windows/window3”,而絕對(duì)路徑是:”/house/windows/window3。
我們可以用“.”和“..”來(lái)分別指代當(dāng)前目錄和父目錄,這又跟Linux上的路徑使用習(xí)慣是一致的。這種簡(jiǎn)稱(chēng)只能用于相對(duì)路徑中。
為了能夠更方便地提供段的路徑,HOOPS中還有一套特有的符號(hào),叫做“wildcards”,可以同時(shí)指代多個(gè)不同的路徑,有以下幾種:
1. 逗號(hào)wildcard。這個(gè)是最簡(jiǎn)單的一種。有時(shí)候我們需要同時(shí)對(duì)多個(gè)可枚舉的段進(jìn)行統(tǒng)一處理,例如我們想用同一種顏色來(lái)裝飾roof和door(雖然這種做法很少見(jiàn)……),我們就可以用這樣的一個(gè)路徑來(lái)同時(shí)指代這兩個(gè)段:/house/(door,roof)。
2. 通配符。可以用“*”來(lái)匹配0個(gè)或多個(gè)字符,“%”來(lái)匹配單個(gè)字符,這個(gè)跟我們用Windows系統(tǒng)搜索功能是一樣的,也和正則表達(dá)式相一致。
3. 遞歸wildcards。其實(shí)上面兩個(gè)并不是HOOPS所獨(dú)有的,在其他也有見(jiàn)到。但是HOOPS還有一個(gè)它特有的符號(hào),那就是“…”,該符號(hào)可以指代一個(gè)段名或者一串路徑上的段名。例如我們可以用/house/…/window1來(lái)指代第一扇窗戶(hù),而不用去管當(dāng)中到底隔了多少個(gè)段。該種方法非常長(zhǎng)適合于我們不清楚house到window1之間到底存在著怎樣的父子結(jié)構(gòu)。雖然方面,但是如果我們確切地知道window1的完整路徑,那就不要這么寫(xiě)了,因?yàn)镠OOPS是通過(guò)自頂向下的方式搜索得到window1,所以需要消耗一定的計(jì)算量。另外,該符號(hào)還可以遞歸地表示一個(gè)段的所有子段以及子段的子段。如果我們要對(duì)一個(gè)段內(nèi)的所有子段進(jìn)行某項(xiàng)修改,那么這個(gè)wildcards真是再合適不過(guò)了。
segment像文件夾一樣,它本身并沒(méi)有實(shí)質(zhì)的東西,而只是一個(gè)容器。真正繪制出車(chē)的形狀,還需要具體的幾何信息。因此,段內(nèi)部除了可以存儲(chǔ)子段外,還可以存儲(chǔ)Geometry。HOOPS中的Geometry豐富多樣,囊括了點(diǎn)、邊、面、殼(shell)、網(wǎng)絡(luò)(mesh)等等基本上大家能夠想到的圖元。這些基本幾何通過(guò)相互組合,可以組成更加復(fù)雜的圖像信息,這是一個(gè)自底向上的組建過(guò)程。例如我們可以通過(guò)下面的方式插入一個(gè)點(diǎn)和一條直線(xiàn):
HC_Open_Segment (“myseg”);
HC_Insert_Marker (0, 1, 1);
HC_Insert_Line (-1, -1, -1, 2, 2, 2);
HC_Close_Segment ();
HC_Insert_Marker需要傳入三個(gè)浮點(diǎn)參數(shù),也就是一個(gè)點(diǎn)的三維坐標(biāo)。HC_Insert_Line需要傳入六個(gè)參數(shù),為一個(gè)線(xiàn)段的起始點(diǎn)和終止點(diǎn)的三維坐標(biāo)。
我們可以用下面的代碼插入一個(gè)多邊形的面:
HC_POINT pts[4] =
{HC_POINT(0, 0, 0), HC_POINT(1, 0, 0), HC_POINT(1, 1, 0), HC_POINT(0, 1, 0)};
HC_Open_Segment (“mypolygon”);
HC_Insert_Polygon (4, pts);
HC_Close_Segment ();
HC_Insert_Polygon需要傳入兩個(gè)參數(shù),分別是多邊形頂點(diǎn)個(gè)數(shù)以及存放頂點(diǎn)三維坐標(biāo)的數(shù)組。該函數(shù)代表了HOOPS中一類(lèi)參數(shù),就是對(duì)一群點(diǎn)進(jìn)行操作。需要注意的是,這類(lèi)函數(shù)在內(nèi)部會(huì)對(duì)傳入的三維坐標(biāo)數(shù)組進(jìn)行拷貝,所以如果你傳入的坐標(biāo)數(shù)組是動(dòng)態(tài)申請(qǐng)出來(lái)的,在調(diào)用完該類(lèi)函數(shù)之后,必須手動(dòng)地將其釋放掉。
除了基本的點(diǎn)、線(xiàn)、多邊形等,HOOPS還提供了兩個(gè)相對(duì)高級(jí)的圖元,分別是Shell和Mesh。在進(jìn)行大型場(chǎng)景構(gòu)建時(shí),這兩個(gè)圖元是非常常用的,例如我們用三角網(wǎng)格構(gòu)建一個(gè)人的模型,那么這個(gè)三角模型就是一個(gè)shell。shell有三個(gè)層次的圖元組成,分別是node(點(diǎn))、edge(邊)和face(面),這三部分相互連接形成一個(gè)整體。mesh和shell非常類(lèi)似,同樣由點(diǎn)邊面三部分組成,唯一的區(qū)別是mesh它不能形成一個(gè)封閉的類(lèi)似于人這樣的模型,它只能是一張面,而且只能是一張四邊形面,例如一張四邊形紙。這樣的區(qū)別使得在處理特定的模型時(shí),如果mesh能夠滿(mǎn)足應(yīng)用需要,那么mesh將會(huì)比shell表現(xiàn)得高效得多。
下面舉例創(chuàng)建一個(gè)立方體,并在它的一個(gè)面上接一個(gè)金字塔體:
HC_POINT pts[] = {
HC_POINT (0, 0, 1), HC_POINT (1, 0, 1),
HC_POINT (1, 1, 1), HC_POINT (0, 1, 1),
HC_POINT (0, 0, 2), HC_POINT (1, 0, 2),
HC_POINT (1, 1, 2), HC_POINT (0, 1, 2),
HC_POINT (0.5, 0.5, 2.5)
};
int flist[] = {
4, 0, 3, 2, 1,
4, 0, 1, 5, 4,
4, 1, 2, 6, 5,
4, 2, 3, 7, 6,
4, 3, 0, 4, 7,
3, 4, 5, 8,
3, 5, 6, 8,
3, 6, 7, 8,
3, 7, 4, 8
};
HC_Open_Segment ("mymodel");
HC_Insert_Shell (9, pts, 41, flist);
HC_Close_Segment ();
HC_Insert_Shell需要四個(gè)參數(shù),分別是shell的頂點(diǎn)個(gè)數(shù),頂點(diǎn)數(shù)組,面列表數(shù)組的長(zhǎng)度,面列表數(shù)組指針。頂點(diǎn)個(gè)數(shù)和數(shù)組很好理解,就是具體的各個(gè)頂點(diǎn)的三維坐標(biāo)。面列表是這樣的格式:面頂點(diǎn)個(gè)數(shù)n, 第一個(gè)頂點(diǎn)序號(hào),第二個(gè)頂點(diǎn)序號(hào),…,第n個(gè)頂點(diǎn)序號(hào)。例如flist第一行,4表示該面由四個(gè)頂點(diǎn)構(gòu)成,也就是一個(gè)四邊形。然后,0,3,2,1表示由pts這個(gè)數(shù)組中的第0、3、2、1號(hào)點(diǎn)構(gòu)成這個(gè)面。需要注意的是HC_Insert_Shell的第三個(gè)參數(shù)實(shí)質(zhì)flist這個(gè)數(shù)組本身的長(zhǎng)度,而不是將要構(gòu)建的shell上面的個(gè)數(shù)。例如這個(gè)例子中面的個(gè)數(shù)為9,但flist的長(zhǎng)度為41。
效果如下圖所示:
上文中,我們?cè)贖OOPS中創(chuàng)建了一個(gè)房子,假設(shè)我們現(xiàn)在已經(jīng)用幾何圖元將房子給繪制出來(lái)了,但是光有結(jié)構(gòu)還不行,至少我們還需要給它上色,或許我們還會(huì)通過(guò)貼上不同的紋理來(lái)表示不同的材料。HOOPS的段結(jié)構(gòu)中除了可以存放Geometry,還可以存放屬性Attribute。我們常用的屬性包括:可見(jiàn)性(Visibility),顏色(Color),可選擇性(Selectability),點(diǎn)、邊、字體的大小,光照(light),渲染屬性(rendition)等等。甚至可以添加我們自定義的屬性(User defined attribution)??梢哉f(shuō),HOOPS的屬性功能是非常全面而強(qiáng)大的。
和插入幾何一樣,要修改一個(gè)segment的屬性,我們需要進(jìn)入該segment的狀態(tài)機(jī),亦即要首先打開(kāi)這個(gè)段。下面以house模型為例:
HC_Open_Segment (“house”);
HC_Open_Segment (“roof”);
//add roof geometry here...
HC_Set_Color (“geometry=red”);
HC_Close_Segment ();
HC_Open_Segment (“door”);
//add door geometry here...
HC_Set_Color (“geometry=grey”);
HC_Close_Segment ();
HC_Close_Segment ();
這樣,我們將屋頂和門(mén)分別設(shè)置成了紅色和灰色。
又比如剛才我們自創(chuàng)的那個(gè)集合模型,這回,我們要讓它不再空白一片了,我們給它點(diǎn)顏色看看(J):
HC_Open_Segment ("mymodel");
HC_Set_Color ("faces=grey,edges=green");
HC_Set_Visibility ("edges=on");
HC_Insert_Shell (9, pts, 41, flist);
HC_Close_Segment ();
我們?cè)O(shè)置了mymodel這個(gè)段的兩個(gè)屬性,顏色和可見(jiàn)性。在設(shè)置顏色中,我們?cè)O(shè)置面為灰色,而設(shè)置邊為綠色;在設(shè)置可見(jiàn)性上,我們?cè)O(shè)置邊為可見(jiàn)。為什么不設(shè)置面為可見(jiàn)呢?因?yàn)樵贖OOPS中,有些是默認(rèn)可見(jiàn)的,而有些是默認(rèn)不可兼得;而shell的面是默認(rèn)可見(jiàn)的,edges則恰好是默認(rèn)不可見(jiàn)的。下面是新的效果圖,怎么樣,和之前不一樣了吧?
記住這個(gè)模型,往后的教程中我們還會(huì)多次用到,比如給它貼上漂亮的紋理、光照等等,還有動(dòng)畫(huà)。
上面在設(shè)置顏色時(shí),我們用一個(gè)字符串命令同時(shí)設(shè)置了面和邊的顏色。這種格式化的字符串在HOOPS中被大量應(yīng)用,幾乎接受字符串作為參數(shù)的HOOPS函數(shù)中都有這樣的格式化命令。faces和edges對(duì)于HC_Set_Color函數(shù)來(lái)說(shuō),是可以設(shè)置顏色的對(duì)象,而等號(hào)后面是具體的值,中間用逗號(hào)分隔。如果沒(méi)有顯式地說(shuō)明設(shè)置對(duì)象,那么就是everything,也就是所有對(duì)象。該格式化字符串有很多相關(guān)使用技巧,具體可以參看HOOPS的幫助文檔,下面僅舉幾個(gè)例子來(lái)說(shuō)明格式化字符串的基本用法:
1. “red,faces=green”,設(shè)置所有幾何圖元為紅色,只有面為綠色;
2. “markers=edges=black”,點(diǎn)和邊為黑色;
3. “!edges=(r=0.5 g=0.5 b=0.5)”,非邊的圖元顏色都設(shè)置為灰色。
至于設(shè)置對(duì)象是復(fù)數(shù)還是單數(shù)是無(wú)所謂的,即edges和edge的作用效果完全一樣。
屬性(Attribute)是可以被繼承的,就像面向?qū)ο蟮木幊陶Z(yǔ)言里面類(lèi)的繼承一樣。對(duì)于絕大多數(shù)屬性來(lái)說(shuō),繼承的方向是子段從父段中繼承屬性。這種特性有時(shí)候?qū)ξ覀儊?lái)說(shuō)可以提供極大的方便?;叵胛覀冎皠?chuàng)建的house,它有三扇窗戶(hù),一般來(lái)說(shuō),一座房子的窗戶(hù)顏色都是一樣的,如果沒(méi)有屬性的繼承,那么我們大概就需要針對(duì)每一個(gè)窗戶(hù)段設(shè)置它的顏色屬性。對(duì)于我們這座小房子來(lái)說(shuō),這還可以接受,可是某天你發(fā)達(dá)了,讓你構(gòu)建一樁擁有成千上萬(wàn)扇窗戶(hù)的摩天大樓,那恐怕就是場(chǎng)災(zāi)難了。有了屬性的繼承,世界還是美好的。我們可以在windows這個(gè)段設(shè)置顏色,那么所有該段下面的子段都自動(dòng)繼承了該顏色屬性,再不用我們單獨(dú)去設(shè)置了。
然而,問(wèn)題也隨之出現(xiàn)。整幢大樓里畢竟有些窗戶(hù)所在的房間住著不尋常的人,而這些窗戶(hù)我們希望顯示出不一樣的顏色,以彰顯這些人的顯赫身份。那如何避免這些窗戶(hù)繼承父段的顏色呢?我們可以單獨(dú)設(shè)置這些窗戶(hù)的顏色,HOOPS在繪制這些窗時(shí),會(huì)優(yōu)先使用單獨(dú)設(shè)置在這些段上的顏色;如果沒(méi)有單獨(dú)設(shè)置(如同絕大多數(shù)窗戶(hù)),那么HOOPS才會(huì)自動(dòng)地去讀取父段的該屬性,直到最上層的根節(jié)點(diǎn)“/”。如果根節(jié)點(diǎn)也沒(méi)有設(shè)置該屬性,HOOPS就會(huì)報(bào)錯(cuò)。對(duì)于絕大多數(shù)的屬性來(lái)說(shuō),HOOPS正是遵循這種“追根溯源”的方式來(lái)確定一個(gè)屬性的值的。
雖然這種直接覆蓋的屬性占大多數(shù),但是有些屬性不是直接覆蓋得到的,例如旋轉(zhuǎn)矩陣。要計(jì)算一個(gè)圖元最終在世界坐標(biāo)上的位置,我們需要從根節(jié)點(diǎn)開(kāi)始,逐步地累加旋轉(zhuǎn)矩陣,一直到該段,這樣計(jì)算所得的旋轉(zhuǎn)矩陣才是最后真正的旋轉(zhuǎn)矩陣。
雖然我們能夠控制一個(gè)特定的段的屬性,但是有時(shí)候我們還是想要強(qiáng)制整個(gè)段表現(xiàn)為同一種屬性,而不管底下各個(gè)子段是否單獨(dú)設(shè)置了該屬性。有些屬性就提供了這樣的功能,其中之一就是顏色屬性。當(dāng)我們用鼠標(biāo)選中了某一個(gè)segment之后,我們希望整個(gè)段都顯示一種高亮色,而不管該段內(nèi)部子段的單獨(dú)顏色。這時(shí),我們需要用到顏色的屬性鎖。可以通過(guò)調(diào)用下面的代碼來(lái)對(duì)顏色加鎖:
HC_Open_Segment(“myseg”);
HC_Set_Color("red");
HC_Set_Rendering_Options("attribute lock = color");
HC_Close_Segment();
這樣,myseg這個(gè)段的顏色就被鎖定為紅色。如果后續(xù)操作中我們不再需要對(duì)顏色進(jìn)行鎖定,則可以使用HC_UnSet_Rendering_Option (“attribute lock”)。
上面介紹的段都是HOOPS中的普通類(lèi)型的段。此外,HOOPS還有包含段(included segment)和樣式段(style segment)。這些段的功能實(shí)際上都可以用普通段來(lái)實(shí)現(xiàn),但是正因?yàn)橐肓诉@些特殊類(lèi)型的段,我們可以將HOOPS的數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)得更為精巧和高效,我們的程序結(jié)構(gòu)性也更好。
再回顧我們之前給的house模型。我們?cè)诜孔由咸砑恿巳却皯?hù)。一般來(lái)說(shuō),一幢房子上的窗戶(hù)長(zhǎng)得都是差不多的,因此我們想到是否可以只設(shè)計(jì)窗戶(hù)一次,而三次重復(fù)使用呢?可以的,HOOPS里面使用的就是包含段(included segment)。包含段實(shí)際上就是一次定義,多次重復(fù)使用,它提高了代碼的使用率,也提高了內(nèi)存使用率。實(shí)際上包含段和C/C++語(yǔ)言中的頭文件是很像的,我們編寫(xiě)一次頭文件,然后在需要用到的地方通過(guò)#include就可以將其包含進(jìn)來(lái),而不需要另外再寫(xiě)。包含機(jī)制除了提高效率之外,還能夠方便后續(xù)的維護(hù),例如當(dāng)我們想要更新窗戶(hù)的樣式時(shí),只需要在定義處修改一次,由于三處窗戶(hù)都是包含該窗戶(hù)的,所以這三處就自動(dòng)加載了新的樣式。我們不再需要一個(gè)個(gè)地分別去修改,既提高了效率,又減少了出錯(cuò)的可能。
包含段通常是針對(duì)含有幾何信息的段(當(dāng)然,由于包含段本質(zhì)上還是普通的段,因此它可以包含屬性),而樣式段則僅包含屬性。有些時(shí)候,我們需要重用的可能僅僅是一套樣式,例如顏色、大小、光照等,對(duì)于具體的幾何圖元我們卻興趣不大,這個(gè)時(shí)候就可以用到HOOPS的樣式段。下面的代碼演示了如何使用Style segment:
HC_Open_Segment (“mystyle”);
HC_Set_Color (“edges=red,faces=(diffuse=(r=0.5 g=0.2 b=0.3))”);
HC_Close_Segment ();
HC_Open_Segment (“myseg1”);
HC_Style_Segment (“mystyle”);
//Insert my geometry...
HC_Close_Segment ();
HC_Open_Segment (“myseg2”);
HC_Style_Segment (“mystyle”);
//Insert my another geometry...
HC_Close_Segment ();
這段創(chuàng)建了一個(gè)樣式段,兩個(gè)普通段,這兩個(gè)普通段插入了不同的幾何圖元,但是使用了同樣的樣式段,所以它們顯示出來(lái)后都是紅色的邊,紫色的面。
鍵值(通常是HC_KEY類(lèi)型)是HOOPS中一個(gè)非常重要的概念。HC_KEY本質(zhì)上是一個(gè)32位帶符號(hào)的整型。前文中我們說(shuō),可以通過(guò)段的名字以及路徑(相對(duì)路徑或者絕對(duì)路徑)來(lái)索引一個(gè)段,于此同時(shí)我們也可以用鍵值來(lái)索引段。HC_Open_Segment會(huì)返回一個(gè)long型的整數(shù),就是打開(kāi)的這個(gè)段的鍵值。注意,新版本的HOOPS取消了在API謂詞前的K變形,而所以之前這些K變形函數(shù)都返回鍵值了。19版本之前的HOOPS,HC_Open_Segment返回是void類(lèi)型的,而要返回段的鍵值,則必須顯示地調(diào)用HC_KOpen_Segment。在新版本中這樣的函數(shù)已經(jīng)去掉了,HC_Open_Segment直接返回鍵值。
除了段可以有鍵值,幾何圖元也可以有鍵值。HC_Insert_Line、HC_Insert_Polygon等插入圖元的函數(shù)都會(huì)返回一個(gè)鍵值,該鍵值唯一的指代新插入的幾何圖元。
HOOPS中大部分的API函數(shù)都有By_Key結(jié)尾的變形,這一類(lèi)的變形函數(shù)實(shí)現(xiàn)和它們?cè)秃瘮?shù)一樣的功能,唯一的區(qū)別是它們的入口參數(shù)是要操作的段的鍵值,而不是字符形式的名字了。
既然現(xiàn)在我們有兩種方式來(lái)找到一個(gè)段,那么我們就需要詳細(xì)地比較一下這兩種方式各自的優(yōu)劣。
1. 存儲(chǔ)鍵值只需要一個(gè)32位整數(shù),存儲(chǔ)段名則需要一個(gè)字符數(shù)組,而且長(zhǎng)度不定;
2. 用鍵值來(lái)找到一個(gè)段速度要比用字符路徑快;
3. 段名比較直觀,便于調(diào)試的時(shí)候肉眼判斷正誤,鍵值則比較抽象,一眼看上去不太容易辨別對(duì)錯(cuò);
4. 段名還有路徑支持之前提到的wildcards,因此可以同時(shí)指代多個(gè)不同的段,但是鍵值是唯一的,它只能指代一個(gè)段或者幾何圖元;
5. 對(duì)于幾何圖元來(lái)說(shuō),我們只能夠用鍵值去找到它們,因?yàn)樗鼈兪菦](méi)有字符形式的名字的;
6. 對(duì)于匿名段來(lái)說(shuō),由于我們沒(méi)有賦給它任何段名(應(yīng)該說(shuō)是空的段名),因此也就無(wú)法用段名來(lái)索引它,而只能用鍵值。
以上只是我目前發(fā)現(xiàn)并整理的不同之處,如后續(xù)有新發(fā)現(xiàn),則會(huì)繼續(xù)補(bǔ)充。
一般來(lái)說(shuō),系統(tǒng)返回的鍵值是負(fù)數(shù)。我們可以通過(guò)HC_Renumber_Key來(lái)修改系統(tǒng)給我們的鍵值。如果我們調(diào)試的時(shí)候發(fā)現(xiàn)一個(gè)鍵值為0或者正數(shù),那么要么是我們修改了,要么是程序在哪個(gè)地方出錯(cuò)了。這個(gè)概念雖小,可是在實(shí)際操作中卻是非常有用的。另外,為了確保某些HOOPS API操作成功,我們可以在操作結(jié)束后將得到的鍵值跟INVALID_KEY進(jìn)行比較。INVALID_KEY是HOOPS預(yù)定義的一個(gè)值,它表示如果API執(zhí)行失敗返回的錯(cuò)誤鍵值。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:慧都控件網(wǎng)