1.與測量類相關的主要Widget
與測量類相關的主要Widget如下:
- vtkDistanceWidget:用於在二維平面上測量兩點之間的距離。
- vtkAngleWidget:用於在平面的角度測量。
- vtkBiDimensionalWidget:用於測量二維平面上任意兩個正交方向的軸長。
2.創建用於測量距離的Widget應用實例
先複習一下創建Widget的一般步驟:
1.實例化Widget;
2.指定渲染窗口交互器。Widget可以通過它來監聽用戶事件。
3.必要時使用觀察者/命令模式創建回調函數。與widget交互時,它會調用一些通用的VTK事件(94個事件列表),如StartInteractionEvent、InteractionEvent、EndInteractionEvent。用戶通過監聽這些事件並作出響應,從而可以更新數據、可視化參數或者應用程序的用戶圖形界面。
4.創建合適幾何表達實體。用SetRepresentation()函數把他與Widget關聯起來,或者使用Widget默認的幾何表達實體。
5.最後,必須激活Widget,使其在渲染場景中顯示。默認情況下,按鍵<I>用於激活Widget,使其在場景中可見。
實例代碼如下:
#include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL) VTK_MODULE_INIT(vtkInteractionStyle) VTK_MODULE_INIT(vtkRenderingFreeType) #include <vtkCommand.h> #include <vtkSmartPointer.h> #include <vtkJPEGReader.h> #include <vtkImageActor.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkInteractorStyleImage.h> #include <vtkDistanceWidget.h> #include <vtkDistanceRepresentation.h> #include <vtkAngleWidget.h> #include <vtkProperty2D.h> #include <vtkLeaderActor2D.h> #include <vtkAngleRepresentation2D.h> #include <vtkBiDimensionalWidget.h> #include <vtkBiDimensionalRepresentation2D.h> class vtkBiDimensionalCallback: public vtkCommand { public: static vtkBiDimensionalCallback* New() { return new vtkBiDimensionalCallback; } virtual void Execute(vtkObject* caller, unsigned long, void*) { vtkBiDimensionalWidget* biDimensionalWidget = reinterpret_cast<vtkBiDimensionalWidget*> (caller); vtkBiDimensionalRepresentation2D* representation = static_cast<vtkBiDimensionalRepresentation2D*> (biDimensionalWidget->GetRepresentation()); double p1[3]; representation->GetPoint1DisplayPosition(p1); double p2[3]; representation->GetPoint1DisplayPosition(p2); double p3[3]; representation->GetPoint1DisplayPosition(p3); double p4[3]; representation->GetPoint1DisplayPosition(p4); //顯示其中一個點的屏幕座標(px) std::cout << "P1: " << p1[0] << " " << p1[1] << " " << p1[2] << std::endl; } vtkBiDimensionalCallback() { } }; int main() { int WidgetType; std::cout << "Please select the Measurement Distance WidgetType: " << std::endl; std::cin >> WidgetType; vtkSmartPointer<vtkJPEGReader> reader = vtkSmartPointer<vtkJPEGReader>::New(); reader->SetFileName("vtk.jpg"); reader->Update(); vtkSmartPointer<vtkImageActor> imgActor = vtkSmartPointer<vtkImageActor>::New(); imgActor->SetInputData(reader->GetOutput()); vtkSmartPointer<vtkRenderer> render = vtkSmartPointer<vtkRenderer>::New(); render->AddActor(imgActor); render->SetBackground(0, 0, 0); render->ResetCamera(); vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New(); rw->AddRenderer(render); rw->SetWindowName("MeasurementDistanceApp"); rw->SetSize(320, 320); rw->Render(); vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New(); rwi->SetRenderWindow(rw); vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New(); rwi->SetInteractorStyle(style); /****************************************************************/ //vtkDistanceWidget if (WidgetType == 0) { //實例化Widget vtkSmartPointer<vtkDistanceWidget> distanceWidget = vtkSmartPointer<vtkDistanceWidget>::New(); //指定渲染窗口交互器,來監聽用戶事件 distanceWidget->SetInteractor(rwi); //必要時使用觀察者/命令模式創建回調函數(此處沒用) //創建幾何表達實體。用SetRepresentation()把事件與Widget關聯起來 //或者使用Widget默認的幾何表達實體 distanceWidget->CreateDefaultRepresentation(); static_cast<vtkDistanceRepresentation*> (distanceWidget->GetRepresentation()) ->SetLabelFormat("%-#6.3g px"); //激活Widget distanceWidget->On(); rw->Render(); rwi->Initialize(); rwi->Start(); } //vtkAngleWidget if (WidgetType == 1) { vtkSmartPointer<vtkAngleWidget> angleWiget = vtkSmartPointer<vtkAngleWidget>::New(); angleWiget->SetInteractor(rwi); //創建個性化的實體圖標 vtkSmartPointer<vtkAngleRepresentation2D> angleRep = vtkSmartPointer<vtkAngleRepresentation2D>::New(); angleRep->GetRay1()->GetProperty()->SetColor(0, 1, 0); angleRep->GetRay1()->GetProperty()->SetLineWidth(3); angleRep->GetRay2()->GetProperty()->SetColor(0, 1, 0); angleRep->GetRay1()->GetProperty()->SetLineWidth(3); angleRep->GetArc()->GetProperty()->SetColor(0, 1, 0); angleRep->GetArc()->GetProperty()->SetLineWidth(3); angleWiget->SetRepresentation(angleRep); angleWiget->On(); rw->Render(); rwi->Initialize(); rwi->Start(); } //vtkBiDimensionalWidget if (WidgetType == 2) { vtkSmartPointer<vtkBiDimensionalWidget> bidimensionalWidget = vtkSmartPointer<vtkBiDimensionalWidget>::New(); bidimensionalWidget->SetInteractor(rwi); //採用默認的圖標 bidimensionalWidget->CreateDefaultRepresentation(); //添加“觀察者-命令模式(命令子類方案)” vtkSmartPointer<vtkBiDimensionalCallback> bidiCallback = vtkSmartPointer<vtkBiDimensionalCallback>::New(); bidimensionalWidget->AddObserver(vtkCommand::InteractionEvent, bidiCallback); bidimensionalWidget->On(); rw->Render(); rwi->Initialize(); rwi->Start(); } return 0; }
輸出結果如下所示:
上面的例子中,使用了vtkDistanceWidget類來做二維空間的距離測量。先是實例化一個vtkDistanceWidget對象實例,然後調用該類的SetInteractor()函數來設置渲染窗口交互器;接着調用CreatDefaultRepresentation()函數來創建默認的幾何表達實體,急用十字形表示兩個端點來,端點之間使用帶有刻度的直線連接。需要注意的是,在程序調用SetLabelFormat()函數來設置兩點之間所測距離的文本表示格式;最後調用On()函數來激活vtkDistanceWidget實例。
角度測量的vtkAngleWidget以及二維正交方向長度測量的vtkBiDimensionalWidget的使用方法與vtkDistanceWidget類似,他們的二維幾何表達形式所所對應的類爲vtkAngleRepresentation2D和vtkBiDimensionalRepresentation2D.
3.額外補充的C++基礎
3.1 reinterpret_cast
reinterpret_cast是強制類型轉換符!他是用來處理無關類型轉換的,通常爲操作數的位模式提供較低層次的重新解釋!但是他僅僅是重新解釋了給出的對象的比特模型,並沒有進行二進制的轉換!
他是用在任意的指針之間的轉換,引用之間的轉換,指針和足夠大的int型之間的轉換,整數到指針的轉換。
int *pi;
char *pc = reinterpret_cast<char*>(pi);
3.2 static_cast
《C++primer 第四版》中說編譯器隱式執行的任何類型轉換都可以由static_cast顯式完成!
要注意的是,此轉換沒有運行時檢測安全!他不能轉換掉expression的const、volatile、或者__unaligned屬性。他也不是用來去掉static屬性的! 大家應該清楚static限定符吧,他會造成範圍性的影響,而const則不同,他只是限定變量或對象自身!
當使用static限定符限定一個變量的時候,就拿類中吧,他會隨類的第一個實例對象的出現而出現,並且可以被這個類的所有對象所使用!!
C++中的static_cast執行非多態的轉換,用於代替C中通常的轉換操作。
對於我們的static_cast轉換符,他不僅可以應用到指針和引用上,而且還可以應用到基礎數據結構和對象上!
double da = 1.1; void *pa = &da; double *dp = static_cast<double*>(pa); int ia = static_cast<int>(da); cout << *dp << endl; cout << ia << endl;
OK,代碼編譯通過!
《C++primer》告訴我們,對於一個由較大的算術類型到一個較小的類型的賦值,編譯器通常會報錯,然後當我們顯示地提供強制類型轉換的時候,警告信息就關閉了!
要知道我們的static_cast的真正用處不是在指針的引用上,而是在基礎類型的轉換和對象的轉換上!
static_cast也支持指向基類的指針和指向子類的指針之間的轉換!
但是在這裏要注意的是,我們從基類轉換到子類是一個不安全的行爲!