6、VTK基本数据结构
我們已經(jīng)學(xué)習(xí)了VTK的一個(gè)重要概念——可視化管線,了解了VTK數(shù)據(jù)的流動(dòng)過程。好比我們做一道菜,在做每一道菜之前,首先要掌握這道菜的做法,什么時(shí)候放鹽什么時(shí)候放醬油等調(diào)料,除了需要弄清楚做每一道菜的流程,還需要了解所做的每一道菜的原料,比如有些原料是要蒸出來才比較好吃,有些則可能會(huì)用燉的方法才比較可口,只有掌握做菜的流程以及了解菜的原料的特點(diǎn),最后做出來的菜才可口美味。如果說VTK可視化管線是完成VTK應(yīng)用程序這道菜的基本步驟,那么VTK的數(shù)據(jù)結(jié)構(gòu)就好比我們做每一道菜的基本原料。針對(duì)可視化領(lǐng)域的特點(diǎn),VTK定義了種類豐富的數(shù)據(jù)結(jié)構(gòu),這一章我們重點(diǎn)學(xué)習(xí)VTK的基本數(shù)據(jù)結(jié)構(gòu),了解這些數(shù)據(jù)結(jié)構(gòu),有助于我們寫出更有針對(duì)性的、更高效的可視化應(yīng)用程序。
6.1 可視化數(shù)據(jù)的基本特點(diǎn)
我們的目的是要對(duì)數(shù)據(jù)進(jìn)行可視化,因此有必要對(duì)可視化的數(shù)據(jù)特點(diǎn)作一了解。歸納起來,可視化數(shù)據(jù)具有如下一些特點(diǎn):
l 離散性
為了讓計(jì)算機(jī)能夠獲取、處理和分析數(shù)據(jù),必須對(duì)無限、連續(xù)的空間體進(jìn)行采樣,生成有限的采樣數(shù)據(jù)點(diǎn),這些數(shù)據(jù)以離散點(diǎn)的形式存儲(chǔ),采樣的過程是一個(gè)離散化的過程。
由于可視化數(shù)據(jù)的離散性特點(diǎn),在某些離散點(diǎn)上有精確的值存在,但點(diǎn)與點(diǎn)之間的值則是不可知的,要得到采樣點(diǎn)之外的其他點(diǎn)的值,只有通過插值(Interpolation)的方法獲取。常用的插值方法是線性插值,要得到更精確的數(shù)值可以采用非線性插值,如B樣條插值方法。
l 數(shù)據(jù)具有規(guī)則或不規(guī)則的結(jié)構(gòu)(或者說結(jié)構(gòu)化與非結(jié)構(gòu)化)
可視化數(shù)據(jù)可以分為規(guī)則(Regular)和不規(guī)則(Irregular)或者說結(jié)構(gòu)化(Structured)和非結(jié)構(gòu)化(Unstructured)。規(guī)則結(jié)構(gòu)數(shù)據(jù)點(diǎn)之間有固定的關(guān)聯(lián)關(guān)系,可以通過這些關(guān)聯(lián)確定每個(gè)點(diǎn)的坐標(biāo),不規(guī)則結(jié)構(gòu)數(shù)據(jù)之間沒有固定的關(guān)聯(lián)關(guān)系。
對(duì)于規(guī)則結(jié)構(gòu)的數(shù)據(jù),存儲(chǔ)時(shí)不必存儲(chǔ)所有的數(shù)據(jù)點(diǎn),只需存儲(chǔ)起始點(diǎn)、相鄰兩點(diǎn)之間的間隔以及點(diǎn)的總數(shù)就可以保存完整的數(shù)據(jù)信息。對(duì)于不規(guī)則結(jié)構(gòu)的數(shù)據(jù),雖然不可以像規(guī)則結(jié)構(gòu)的數(shù)據(jù)那樣存儲(chǔ),但它也有自身的優(yōu)勢(shì),即在數(shù)據(jù)變化頻繁的區(qū)域可以密集表示,而數(shù)據(jù)變化不頻繁的區(qū)域則稀疏表示。規(guī)則結(jié)構(gòu)的數(shù)據(jù)可以在存儲(chǔ)及計(jì)算時(shí)占優(yōu)勢(shì),不規(guī)則結(jié)構(gòu)的數(shù)據(jù)雖然存儲(chǔ)和計(jì)算時(shí)不能像規(guī)則結(jié)構(gòu)的那樣高效,但它在數(shù)據(jù)表達(dá)方面相對(duì)而言則更加自由,更加細(xì)致、靈活的表現(xiàn)數(shù)據(jù)。
l 數(shù)據(jù)具有維度
可視化數(shù)據(jù)的第三個(gè)特點(diǎn)是拓?fù)渚S度(Topological Dimension)。可視化數(shù)據(jù)具有零維、一維、二維、三維等任意維度。如,零維的數(shù)據(jù)表現(xiàn)為點(diǎn),一維數(shù)據(jù)表現(xiàn)為曲線,二維數(shù)據(jù)表現(xiàn)為曲面,三維數(shù)據(jù)表現(xiàn)為體等。數(shù)據(jù)的維度決定了數(shù)據(jù)可視化的方法,如,對(duì)于二維的數(shù)據(jù),可以將數(shù)據(jù)存儲(chǔ)到一個(gè)矩陣,然后再采用針對(duì)二維數(shù)據(jù)的可視化方法進(jìn)行可視化(如等高圖)。
6.2vtkDataObject和vtkDataSet
6.2.1 vtkDataObject
在VTK中,數(shù)據(jù)一般以數(shù)據(jù)對(duì)象(Data Object,對(duì)應(yīng)VTK里的類vtkDataObject)的形式表現(xiàn),是VTK里可視化數(shù)據(jù)最一般的表達(dá)形式。數(shù)據(jù)對(duì)象是數(shù)據(jù)的集合,數(shù)據(jù)對(duì)象表現(xiàn)的數(shù)據(jù)是可以被可視化管線處理的數(shù)據(jù),只有數(shù)據(jù)對(duì)象被組織成一種結(jié)構(gòu)(Structure)后,才能被VTK提供的可視化算法處理。
圖6.1是vtkDataObject類的繼承圖,VTK里所有的數(shù)據(jù)結(jié)構(gòu)形式都是從這個(gè)類派生出來的,實(shí)際的VTK應(yīng)用程序中,沒有直接使用vtkDataObject來實(shí)例化數(shù)據(jù)對(duì)象,而是根據(jù)具體的可視化數(shù)據(jù)選用其具體的子類實(shí)現(xiàn)可視化的。
圖6.1vtkDataObject類的繼承圖
6.2.2 vtkDataSet
數(shù)據(jù)對(duì)象被組織成一種結(jié)構(gòu)并且被賦予相應(yīng)的屬性值時(shí)就形成數(shù)據(jù)集(Dataset)。VTK里與數(shù)據(jù)集對(duì)應(yīng)的類是vtkDataSet,該類從vtkDataObject直接派生。vtkDataSet由兩個(gè)部分組成,即組織結(jié)構(gòu)(Organizing Structure)以及與組織結(jié)構(gòu)相關(guān)聯(lián)的屬性數(shù)據(jù)(Attribute Data),圖6.2描述了vtkDataSet各結(jié)構(gòu)的詳細(xì)構(gòu)成。vtkDataSet是一個(gè)抽象基類,結(jié)構(gòu)的實(shí)現(xiàn)及表達(dá)由其具體的子類來完成。
vtkDataSet的組織結(jié)構(gòu)由拓?fù)浣Y(jié)構(gòu)(Topology)和幾何結(jié)構(gòu)(Geometry)兩部分組成。拓?fù)浣Y(jié)構(gòu)描述了物體的構(gòu)成形式,幾何結(jié)構(gòu)描述了物體的空間位置關(guān)系。換言之,點(diǎn)數(shù)據(jù)(Point Data)所定義的一系列坐標(biāo)點(diǎn)構(gòu)成了vtkDataSet(數(shù)據(jù)集)的幾何結(jié)構(gòu);點(diǎn)數(shù)據(jù)的連接(點(diǎn)的連接先形成單元數(shù)據(jù)(Cell Data),由單元數(shù)據(jù)再形成拓?fù)?就形成了數(shù)據(jù)集的拓?fù)浣Y(jié)構(gòu)。比如,我們想要在屏幕上顯示一個(gè)三角形,首先我們必須定義三角形三個(gè)點(diǎn)的坐標(biāo)(即Point Data,記三個(gè)點(diǎn)為P1, P2和P3),然后將這三個(gè)點(diǎn)按照一定的順序連接起來(P1-P2-P3,或者是P3-P2-P1的順序),這三個(gè)點(diǎn)定義了數(shù)據(jù)集的幾何結(jié)構(gòu),它們的連接就構(gòu)成了數(shù)據(jù)集的拓?fù)浣Y(jié)構(gòu)。亦即,點(diǎn)數(shù)據(jù)(Point Data)定義數(shù)據(jù)集的幾何結(jié)構(gòu),單元數(shù)據(jù)(Cell Data)定義數(shù)據(jù)集的拓?fù)浣Y(jié)構(gòu),要形成完整的數(shù)據(jù)集,必須有幾何和拓?fù)鋬煞N結(jié)構(gòu)。
關(guān)于拓?fù)洹缀谓Y(jié)構(gòu)以及屬性數(shù)據(jù)的更多解釋:拓?fù)浣Y(jié)構(gòu)具有幾何變換不變性。例如,說一個(gè)多邊形是三角形,即指其拓?fù)浣Y(jié)構(gòu),而給定的每個(gè)點(diǎn)的坐標(biāo),則為其幾何結(jié)構(gòu)。幾何結(jié)構(gòu)是一種空間描述,與空間變換有緊密聯(lián)系,常見的變換有旋轉(zhuǎn)、平移和縮放。屬性數(shù)據(jù)是對(duì)拓?fù)浣Y(jié)構(gòu)和幾何結(jié)構(gòu)信息的補(bǔ)充,屬性數(shù)據(jù)可以是某個(gè)空間點(diǎn)的溫度值,也可以是某個(gè)單元的質(zhì)量之類的。
圖6.2vtkDataSet的結(jié)構(gòu)組成
接下來我們通過例子說明怎么把幾何結(jié)構(gòu)和拓?fù)浣Y(jié)構(gòu)加入到數(shù)據(jù)集(vtkDataSet)中去。先看一下只有幾何結(jié)構(gòu),沒有拓?fù)浣Y(jié)構(gòu)的vtkDataSet。
示例TrianglePoints1: #include <vtkSmartPointer.h>2: #include <vtkPoints.h>3: #include <vtkPolyData.h>4: #include <vtkPolyDataWriter.h>5: 6: int main(int argc, char *argv[])7: {8: //創(chuàng)建點(diǎn)數(shù)據(jù)9: vtkSmartPointer<vtkPoints> points =vtkSmartPointer<vtkPoints>::New();10: points->InsertNextPoint ( 1.0, 0.0, 0.0 );11: points->InsertNextPoint ( 0.0, 0.0, 0.0 );12: points->InsertNextPoint ( 0.0, 1.0, 0.0 );13: 14: //創(chuàng)建vtkPolyData類型的數(shù)據(jù),vtkPolyData派生自vtkPointSet,15: //vtkPointSet是vtkDataSet的子類。16: vtkSmartPointer<vtkPolyData> polydata =vtkSmartPointer<vtkPolyData>::New();17: 18: //將創(chuàng)建的點(diǎn)數(shù)據(jù)加入到vtkPolyData數(shù)據(jù)里19: polydata->SetPoints ( points );20: 21: //將vtkPolyData類型的數(shù)據(jù)寫入到一個(gè)vtk文件,保存位置是工程當(dāng)前目錄22: vtkSmartPointer< vtkPolyDataWriter > writer = vtkSmartPointer<vtkPolyDataWriter >::New();23: writer->SetFileName("triangle.vtk");24: writer->SetInput(polydata);25: writer->Write();26: 27: return 0;28: }TrianglePoints示例中,首先創(chuàng)建了一個(gè)點(diǎn)數(shù)據(jù)(vtkPoints),里面含有三個(gè)點(diǎn);緊接著創(chuàng)建了一個(gè)類型為vtkPolyData的數(shù)據(jù),vtkPolyData派生自類vtkPointSet,而vtkPointSet又派生自vtkDataSet,所以說vtkPolyData是一種具體的數(shù)據(jù)集;然后將創(chuàng)建的點(diǎn)數(shù)據(jù)加入到數(shù)據(jù)集,于是點(diǎn)數(shù)據(jù)就定義了該數(shù)據(jù)集的幾何;最后把vtkPolyData的數(shù)據(jù)用類vtkPolyDataWriter寫入到triangle.vtk文件。
可以利用ParaView軟件(http://www.paraview.org,ParaView是使用VTK和Qt編寫的開源的軟件)打開示例中保存的triangle.vtk文件。
圖6.3TrianglePoints生成的數(shù)據(jù)在ParaView軟件經(jīng)Glyph(符號(hào)化)處理后的結(jié)果圖
使用ParaView軟件打開該文件以后,在渲染窗口中我們看不到任何東西。這是因?yàn)槲覀冎皇窃跀?shù)據(jù)集vtkPolyData的實(shí)例里,只定義了數(shù)據(jù)的幾何結(jié)構(gòu),沒有定義拓?fù)浣Y(jié)構(gòu)。如果你想看一下我們生成的triangle.vtk數(shù)據(jù)是怎樣一種形式,可以調(diào)用ParaView的菜單Filters->Common->Glyph(在點(diǎn)數(shù)據(jù)的空間位置生成符號(hào)),可以看到在三角形的三個(gè)頂點(diǎn)位置生成了三個(gè)同向的箭頭(圖6.3所示),也就說明了示例中生成的文件triangle.vtk里面確實(shí)存在數(shù)據(jù),只不過它少了某種結(jié)構(gòu),導(dǎo)致它無法正常顯示而已。
接下來我們?cè)倏匆粋€(gè)例子,在TrianglePoints示例的基礎(chǔ)上給數(shù)據(jù)集定義拓?fù)浣Y(jié)構(gòu)。
示例TriangleVertices1: #include<vtkCellArray.h>2: #include<vtkSmartPointer.h>3: #include <vtkPoints.h>4: #include<vtkPolyDataWriter.h>5: #include <vtkPolyData.h>6: 7: int main(int argc, char*argv[])8: {9: //創(chuàng)建點(diǎn)的坐標(biāo)10: double X[3] = {1.0, 0.0,0.0};11: double Y[3] = {0.0, 0.0,1.0};12: double Z[3] = {0.0, 0.0,0.0};13: 14: //創(chuàng)建點(diǎn)數(shù)據(jù)以及在每個(gè)點(diǎn)坐標(biāo)上加入頂點(diǎn)(Vertex)類型的單元l15: vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();16: vtkSmartPointer<vtkCellArray> vertices =vtkSmartPointer<vtkCellArray>::New();17: 18: for ( unsigned int i = 0;i < 3; ++i )19: {20: //定義用于存儲(chǔ)點(diǎn)索引的中間變量,vtkIdType就相當(dāng)于int、long等類型21: vtkIdType pid[1];22: 23: //把每個(gè)點(diǎn)坐標(biāo)加入到vtkPoints中,InsertNextPoint()返回加入的點(diǎn)的索引號(hào),24: //下面我們需要使用這個(gè)索引號(hào)來創(chuàng)建頂類型的單元25: pid[0] =points->InsertNextPoint ( X[i], Y[i], Z[i] );26: 27: //在每個(gè)坐標(biāo)點(diǎn)上分別創(chuàng)建一個(gè)頂點(diǎn),頂點(diǎn)是單元(Cell)里的一種類型28: vertices->InsertNextCell ( 1,pid );29: }30: 31: //創(chuàng)建vtkPolyData對(duì)象32: vtkSmartPointer<vtkPolyData> polydata =vtkSmartPointer<vtkPolyData>::New();33: 34: //指定數(shù)據(jù)集的幾何結(jié)構(gòu)(由points指定),以及數(shù)據(jù)集的拓?fù)浣Y(jié)構(gòu)(由vertices指定)35: polydata->SetPoints (points );36: polydata->SetVerts (vertices );37: 38: //將生成的數(shù)據(jù)集寫到TriangleVerts.vtk文件里,保存在工程當(dāng)前目錄下39: vtkSmartPointer<vtkPolyDataWriter> writer =vtkSmartPointer<vtkPolyDataWriter>::New();40: writer->SetFileName ("TriangleVerts.vtk" );41: writer->SetInput (polydata );42: writer->Write();43: 44: return 0;45: }TriangleVertices示例中的第16行實(shí)例化了一個(gè)vtkCellArray的對(duì)象,我們已經(jīng)知道“點(diǎn)數(shù)據(jù)(Point Data)定義數(shù)據(jù)集的幾何結(jié)構(gòu),單元數(shù)據(jù)(Cell Data)定義數(shù)據(jù)集的拓?fù)浣Y(jié)構(gòu)。”由此我們可以知道,vtkCellArray類型的對(duì)象vertices就是用來指定數(shù)據(jù)集polydata的拓?fù)浣Y(jié)構(gòu)(第36行),而polydata的幾何結(jié)構(gòu)則是由points來定義的(第35行)。
TriangleVertices示例中定義的數(shù)據(jù)集的拓?fù)浣Y(jié)構(gòu)是零維的點(diǎn),即單元類型是Vertex。保存的VTK文件TriangleVerts.vtk在ParaView里的顯示結(jié)果如圖6.4所示(為了便于觀察三角形的三個(gè)頂點(diǎn),圖6.4顯示的時(shí)候把點(diǎn)的大小設(shè)置成5個(gè)像素)。
圖6.4TriangleVertices示例生成的VTK文件在ParaView的顯示結(jié)果
接下來我們繼續(xù)在TriangleVertices示例的基礎(chǔ)上做一些更改,將零維的點(diǎn)拓?fù)浣Y(jié)構(gòu)改成一維的線拓?fù)浣Y(jié)構(gòu),示例的完整代碼如下:(TriangleGeometryLines.cpp)
示例TriangleGeometryLines1: #include <vtkPoints.h>2: #include <vtkLine.h>3: #include<vtkCellArray.h>4: #include<vtkSmartPointer.h>5: #include<vtkPolyDataWriter.h>6: #include <vtkPolyData.h>7: 8: int main(int argc, char*argv[])9: {10: //創(chuàng)建三個(gè)坐標(biāo)點(diǎn)11: vtkSmartPointer<vtkPoints> points =vtkSmartPointer<vtkPoints>::New();12: points->InsertNextPoint( 1.0, 0.0, 0.0 ); //返回第一個(gè)點(diǎn)的ID:013: points->InsertNextPoint( 0.0, 0.0, 1.0 ); //返回第二個(gè)點(diǎn)的ID:114: points->InsertNextPoint( 0.0, 0.0, 0.0 ); //返回第三個(gè)點(diǎn)的ID:215: 16: //每兩個(gè)坐標(biāo)點(diǎn)之間分別創(chuàng)建一條線17: //SetId()的第一個(gè)參數(shù)是線段的端點(diǎn)ID,第二個(gè)參數(shù)是連接的點(diǎn)的ID18: vtkSmartPointer<vtkLine> line0 =vtkSmartPointer<vtkLine>::New();19: line0->GetPointIds()->SetId ( 0,0 );20: line0->GetPointIds()->SetId ( 1,1 );21: 22: vtkSmartPointer<vtkLine>line1 = vtkSmartPointer<vtkLine>::New();23: line1->GetPointIds()->SetId ( 0,1 );24: line1->GetPointIds()->SetId ( 1,2 );25: 26: vtkSmartPointer<vtkLine> line2 =vtkSmartPointer<vtkLine>::New();27: line2->GetPointIds()->SetId( 0,2 );28: line2->GetPointIds()->SetId ( 1,0 );29: 30: //創(chuàng)建單元數(shù)組,用于存儲(chǔ)以上創(chuàng)建的線段31: vtkSmartPointer<vtkCellArray> lines =vtkSmartPointer<vtkCellArray>::New();32: lines->InsertNextCell (line0 );33: lines->InsertNextCell (line1 );34: lines->InsertNextCell (line2 );35: 36: vtkSmartPointer<vtkPolyData> polydata =vtkSmartPointer<vtkPolyData>::New();37: 38: //將點(diǎn)和線加入到數(shù)據(jù)集中,前者定義數(shù)據(jù)集的幾何結(jié)構(gòu),后者定義拓?fù)浣Y(jié)構(gòu)39: polydata->SetPoints (points );40: polydata->SetLines (lines );41: 42: vtkSmartPointer<vtkPolyDataWriter> writer =vtkSmartPointer<vtkPolyDataWriter>::New();43: writer->SetFileName ("TriangleLines.vtk" );44: writer->SetInput (polydata );45: writer->Write();46: 47: return 0;48: }示例TriangleGeometryLines生成的VTK文件在ParaView的顯示結(jié)果如圖6.5所示。
圖6.5TriangleGeometryLines示例生成的VTK文件在ParaView的顯示結(jié)果
對(duì)于VTK的數(shù)據(jù)集而言,數(shù)據(jù)集的幾何結(jié)構(gòu)和拓?fù)浣Y(jié)構(gòu)是其必不可少的兩個(gè)部分。TrianglePoints示例只定義了數(shù)據(jù)集的幾何結(jié)構(gòu),沒有定義該數(shù)據(jù)集的拓?fù)浣Y(jié)構(gòu),所以該數(shù)據(jù)集不能直接顯示;TriangleVertices和TriangleGeometryLines除了定義數(shù)據(jù)集的幾何結(jié)構(gòu)(由points定義),還定義了相應(yīng)的拓?fù)浣Y(jié)構(gòu)。其中示例TriangleVertices定義的是零維的點(diǎn)拓?fù)浣Y(jié)構(gòu);TriangleGeometryLines定義的是一維的線拓?fù)浣Y(jié)構(gòu),它們都是保存在由類vtkCellArray所實(shí)例化的對(duì)象里,除了零維的點(diǎn)、一維的線等類型的單元以外,VTK還定義了其他類型的單元。
==========歡迎轉(zhuǎn)載,轉(zhuǎn)載時(shí)請(qǐng)保留該聲明信息==========
版權(quán)歸@東靈工作室所有,更多信息請(qǐng)?jiān)L問東靈工作室
教程系列導(dǎo)航:http://blog.csdn.net/www_doling_net/article/details/8763686
總結(jié)
以上是生活随笔為你收集整理的6、VTK基本数据结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python图像处理大全
- 下一篇: 6.3 单元类型