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