6.1.3 vtkPolyData 屬性資料
1、圖形著色
前一個實驗顯示結果中的影象是白色的,而圖形顏色與vtkPolyData屬性資料息息相關。由於並未指定任何顏色和屬性資料,因此在顯示時預設以白色顯示。
屬性資料包括點屬性和單元屬性。可以為vtkPolyData的點資料和單元資料分別指定屬性資料。
屬性資料可以是標量,如點的曲率;可以是向量,如點或者單元的法向量;也可以是張量,主要在流場中較為常見。
顏色可以直接作為一種標量屬性資料,設定到相應的點或者單元資料中,這也是最直接的一種圖形著色方式。
下面的例項程式碼僅是對上例圖形進行著色:
#include <vtkSmartPointer.h> #include <vtkPoints.h> #include <vtkPolygon.h> #include <vtkTriangle.h> #include <vtkCellArray.h> #include <vtkPolyData.h> #include <vtkUnsignedCharArray.h> //Attribution #include <vtkPointData.h> //點資料 #include <vtkCellData.h> //單元資料 /////// #include <vtkPolyDataMapper.h> #include <vtkActor.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> int main() { //幾何結構資料:點集 vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New(); pts->InsertNextPoint(0.0, 0.0, 0.0); pts->InsertNextPoint(1.0, 0.0, 0.0); pts->InsertNextPoint(1.0, 1.0, 0.0); pts->InsertNextPoint(0.0, 1.0, 0.0); pts->InsertNextPoint(2.0, 0.0, 0.0); //拓撲結構資料:正四邊形 //利用定義的5個座標點定義一個多邊形單元,vtkPolygon繼承自vtkCell類,表示一個多邊形單元 vtkSmartPointer<vtkPolygon> polygon = vtkSmartPointer<vtkPolygon>::New(); polygon->GetPointIds()->SetNumberOfIds(4);//設定點數 polygon->GetPointIds()->SetId(0, 0);//為對應索引的點設定座標,座標為vtkpionts中定義的5個座標點 polygon->GetPointIds()->SetId(1, 1); polygon->GetPointIds()->SetId(2, 2);//setId為指定的點設定索引 polygon->GetPointIds()->SetId(3, 3); //拓撲結構資料:三角形 vtkSmartPointer<vtkTriangle> triangle = vtkSmartPointer<vtkTriangle>::New(); triangle->GetPointIds()->SetId(0, 1); triangle->GetPointIds()->SetId(1, 2); triangle->GetPointIds()->SetId(2, 4); //構成拓撲結構集合 vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New(); cells->InsertNextCell(polygon); cells->InsertNextCell(triangle); //合成幾何拓撲結構用於顯示(包括點資料和單元資料集) vtkSmartPointer<vtkPolyData> polygonPolyData = vtkSmartPointer<vtkPolyData>::New(); polygonPolyData->SetPoints(pts); polygonPolyData->SetPolys(cells); //新增屬性結構 unsigned char red[3] = { 255, 0, 0 }; unsigned char green[3] = { 0, 255, 0 }; unsigned char blue[3] = { 0, 0, 255 }; vtkSmartPointer<vtkUnsignedCharArray> ptColor = vtkSmartPointer<vtkUnsignedCharArray>::New();//有5個點資料 ptColor->SetNumberOfComponents(3);//指定每個元組的大小,RGB三色分量組成 ptColor->InsertNextTupleValue(red); ptColor->InsertNextTupleValue(green); ptColor->InsertNextTupleValue(blue); ptColor->InsertNextTupleValue(red); ptColor->InsertNextTupleValue(green); polygonPolyData->GetPointData()->SetScalars(ptColor); vtkSmartPointer<vtkUnsignedCharArray> cellColor = vtkSmartPointer<vtkUnsignedCharArray>::New();//2個單元資料 cellColor->SetNumberOfComponents(3); cellColor->InsertNextTupleValue(blue); cellColor->InsertNextTupleValue(red); polygonPolyData->GetCellData()->SetScalars(cellColor); //////////////////////////////////////////////////////// vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();//將幾何拓撲結構資料(視覺化模型)進行對映到圖形模型 mapper->SetInputData(polygonPolyData); vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); vtkSmartPointer<vtkRenderer> render = vtkSmartPointer<vtkRenderer>::New(); render->AddActor(actor); render->SetBackground(0.0, 0.0, 0.0); vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New(); rw->AddRenderer(render); rw->SetSize(320, 240); rw->SetWindowName("Creating PolyData Structure"); vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New(); rwi->SetRenderWindow(rw); rwi->Render(); rwi->Start(); return 0; }
執行結果如下:
該示例程式碼繼承了上一節中的vtkPolyData資料。定義了兩個vtkUnsignedCharArray物件ptColor和cellColor,分別為點和單元設定顏色資料。vtkUnsignedCharArray物件實際上為一個Unsigned char型別的陣列。SetNumberOfComponents()函式指定了該陣列中每個元組的大小。由於每個顏色是由RGB三個顏色分量組成。因此設定元組大小為3。InsertNextTupleValue()函式可以順序插入元組資料。
由於要為點集設定顏色,因此顏色數目要與點數保持一致。對於單元的顏色資料設定同樣需要注意,有多少個單元,就要設定多少個顏色。設定點的顏色時,需要通過GetPointData()函式獲取vtkPointData型別的點資料指標,然後通過SetScalar()函式設定顏色資料
根據之前的內容,我們知道:點資料和單元的屬性資料是分別儲存在VTKPointData和VTKCellData中的。
在這裡,我們還是要著重區分一下標量屬性資料和向量屬性資料的區別:向量資料具有方向和模;而標量資料不具有。如果一個數據(可以是單組分、也可以是多組分)經過一個幾何變換後保持不變,那麼該資料是一個標量,例如我們說的顏色屬性。然而,對於法向量,該資料同樣有三個組分,卻是一個向量屬性,因為法向量經過幾何變換後(如影象旋轉)會發生改變。因此不能簡單滴通過組分的個數來區分標量資料或者向量資料
2、單元的標量屬性和向量屬性資料設定
/******************單元標量屬性和向量屬性資料設定*******************************/
//很多情況下,模型顏色是通過屬性資料獲取的,比如根據標量資料在顏色查詢表中獲取相應的顏色
#include <vtkSmartPointer.h>
#include <vtkPlaneSource.h>//定義網格資料
#include <vtkPolyData.h>//拓撲結構資料
#include <vtkFloatArray.h>//屬性資料
#include <vtkCellData.h>//定義單元資料
#include <vtkLookupTable.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
int main()
{
vtkSmartPointer<vtkPlaneSource> gridSource =
vtkSmartPointer<vtkPlaneSource>::New();//定義3*3的網格資料
gridSource->SetXResolution(3);
gridSource->SetYResolution(3);
gridSource->Update();
//構成幾何拓撲結構資料
vtkSmartPointer<vtkPolyData> grid = gridSource->GetOutput();
//標量屬性資料,預設情況下,其元組大小為1
vtkSmartPointer<vtkFloatArray> cellScalars =
vtkSmartPointer<vtkFloatArray>::New();
//向量屬性資料
vtkSmartPointer<vtkFloatArray> cellVector =
vtkSmartPointer<vtkFloatArray>::New();
cellVector->SetNumberOfComponents(3);
//設定屬性
for (int i = 0; i < 9; i++)
{
cellScalars->InsertNextValue(i + 1); //九個索引
cellVector->InsertNextTuple3(0.0, 0.0, 1.0);//InsertNextTuple3可以方便地插入向量資料
}
grid->GetCellData()->SetScalars(cellScalars);
grid->GetCellData()->SetVectors(cellVector);
vtkSmartPointer<vtkLookupTable> lut =
vtkSmartPointer<vtkLookupTable>::New();
lut->SetNumberOfTableValues(10);//setLookupTable()函式設定定義的顏色對映表,如果不指定,會使用內部定義的預設顏色表
lut->Build();
//lut->SetTableValue(0, 0, 0, 0, 1); //
//lut->SetTableValue(1, 0.8900, 0.8100, 0.3400, 1);
//lut->SetTableValue(2, 1.0000, 0.3882, 0.2784, 1);
//lut->SetTableValue(3, 0.9608, 0.8706, 0.7020, 1);
//lut->SetTableValue(4, 0.9020, 0.9020, 0.9804, 1);
//lut->SetTableValue(5, 1.0000, 0.4900, 0.2500, 1);
//lut->SetTableValue(6, 0.5300, 0.1500, 0.3400, 1);
//lut->SetTableValue(7, 0.9804, 0.5020, 0.4471, 1);
//lut->SetTableValue(8, 0.7400, 0.9900, 0.7900, 1);
//lut->SetTableValue(9, 0.2000, 0.6300, 0.7900, 1);
//////////////////////////////////////////////////////
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(grid);
mapper->SetScalarRange(0, 9);//指定顏色對映範圍的最小值和最大值
mapper->SetLookupTable(lut);
//////////////////////////////////////////////////////
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkRenderer> render =
vtkSmartPointer<vtkRenderer>::New();
render->AddActor(actor);
render->SetBackground(0.0, 0.0, 0.0);
vtkSmartPointer<vtkRenderWindow> rw =
vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(render);
rw->SetSize(320, 320);
rw->SetWindowName("Setting Attribution of Vectors and Scalars");
vtkSmartPointer<vtkRenderWindowInteractor> rwi =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(rw);
rwi->Start();
return 0;
}
執行結果:(右圖是SetLookupTable()函式不指定時,使用內部定義的預設顏色表)
這個例項主要演示了怎樣新增單元的標量屬性資料和向量屬性資料。
VTKPlaneSource定義了一個3*3的網格資料。cellScalars定義了vtkFloatArray型別的標量屬性資料,預設情況下其元組大小為1,因此不需要顯示指定其大小;cellVectors則定義了vtkFloatArray型別的向量屬性陣列,通過SetNumberOfComponents()指定向量維數為3,並通過InsertNextTuple3()可以方便地插入向量資料。
定義完畢後,vtkPolyData的單元資料(VTKCellData)通過呼叫函式SetScalars()和SetVectors()設定相應的屬性資料和標量資料。
為了進一步演示利用標量資料進行顏色對映,定義了一個具有10個顏色的顏色對映表。利用vtkPolyDataMapper類的SetLookupTable()函式設定定義的顏色對映表(如果不指定,會使用內部定義的預設顏色表)。另外,需要注意的是,SetScalarRange()指定了顏色對映範圍的最小值和最大值,當標量值大於最大值時,按定義最大值獲取顏色;當小於最小值時,按照指定的最小值獲取顏色。這樣做的一個好處是,可以在一個小的標量範圍內顯示更多的顏色!!!
參考資料:
1.《The Visualization Toolkit – AnObject-Oriented Approach To 3D Graphics (4th Edition)》
2. 張曉東, 羅火靈. VTK圖形影象開發進階[M]. 機械工業出版社, 2015.
所用軟體:vtk7.0+visual studio 2013
注:此文知識學習筆記,僅記錄完整程式和實現結果,具體原理參見:
https://blog.csdn.net/www_doling_net/article/details/8541534
https://blog.csdn.net/shenziheng1/article/category/6114053/4