关于vtk中的交互方式(VTk交互)以及widget交互模式(widget交互)在前面的博客里有介绍。这里主要简单介绍几个具体的和测量相关的widget: vtkAngleWidget(角度测量) 、vtkDistanceWidget(距离测量) 、vtkSplineWidget(样条部件)。 最后一个vtkSplineWidget是拟合样条的显示部件,本人把其当作曲线长度测量工具。由于其本身不能显示长度信息,所以对其进行了扩展,使其能够实时显示长度信息。这个文章后面会具体提及。三个部件的样式如下:
vtk部件实例化的一般步骤:
1.实例化Widget;
2.指定渲染窗口交互器。Widget可以通过它来监听用户事件。
3.必要时使用观察者/命令模式创建回调函数。与widget交互时,它会调用一些通用的VTK事件(94个事件列表),如StartInteractionEvent、InteractionEvent、EndInteractionEvent。用户通过监听这些事件并作出响应,从而可以更新数据、可视化参数或者应用程序的用户图形界面。
4.创建合适几何表达实体。用SetRepresentation()函数把他与Widget关联起来,或者使用Widget默认的几何表达实体。
5.最后,必须激活Widget,使其在渲染场景中显示。默认情况下,按键<I>用于激活Widget,使其在场景中可见。
以vtkdAngleWidget为例子具体说明vtk实现方法。
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkAngleWidget.h>
#include <vtkAngleRepresentation2D.h>
#include <vtkTextWidget>
//角度显示回调类
class vtkAngleCallBack : public vtkCommand
{
public:
static vtkAngleCallBack *New()
{
return new vtkAngleCallBack;
}
virtual void Execute(vtkObject *caller, unsigned long eventId, void *callData)
{
if(!m_text)
return;
if(eventId == vtkCommand::StartInteractionEvent)
m_text->On();
if(eventId == vtkCommand::InteractionEvent){
char text[200];
sprintf(text,"Angle: %f",m_angle->GetAngle());
m_text->GetTextActor()->SetInput(text);
}
}
vtkAngleWidget *m_angle = nullptr;
vtkTextWidget *m_text = nullptr;
};
int main(int argc, char *argv[])
{
// A renderer and render window
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
// An interactor
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
//实例化几何表达
vtkSmartPointer<vtkAngleRepresentation2D> rep =
vtkSmartPointer<vtkAngleRepresentation2D>::New();
rep->ArcVisibilityOff();
//实例化vtkAngleWidget
vtkSmartPointer<vtkAngleWidget> angleWidget =
vtkSmartPointer<vtkAngleWidget>::New();
angleWidget->SetRepresentation(rep); //添加集合表达
angleWidget->SetInteractor(renderWindowInteractor); //添加交互器
//角度显示面板
vtkSmartPointer<vtkTextWidget> textWidget =
vtkSmartPointer<vtkTextWidget>::New();
textWidget->CreateDefaultRepresentation();
//实例化回调类
vtkSmartPointer<vtkAngleCallBack> callBack =
vtkSmartPointer<vtkAngleCallBack>::New();
callBack->m_angle = angleWidget;
callBack->m_text = textWIdget;
angleWidget->AddObserver(vtkCommand::InteractionEvent,callBack);//添加回调类
renderWindow->Render();
renderWindowInteractor->Initialize();
renderWindow->Render();
angleWidget->On();//调用On函数激活angleWidget
textWIdget->On(); //调用On函数激活textWidget
// Begin mouse interaction
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
vtk部件将事件交互相应与实体表达分离开。widget部件本身主要响应各种事件,而部件实体表达交由vtkRepresentation来完成。可以通过调用widget->CreateDefaultRepresentation();函数创建默认表达。也可以像上面那样自己实例化一个表达实体添加进去。实际使用时候有几个可能会用到的成员函数 这里提一下:
SetWidgetStateToStart();
调用该函数 此时会重置部件为开始状态,此时表达实体恢复不显示状态 通过鼠标交互来设置三个点。
SetWidgetStateToManipulate();
调用此函数 状态设置为“Manipulate”,则假定该窗口小部件及其表示将以编程方式初始化,而不是以交互方式放置。
vtkSplineWidget本身并不显示长度信息,本人扩展该类 为其添加了一个textWidget显示面板 作为长度信息显示 代码如下:
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderWindow.h>
#include <vtkSmartPointer.h>
#include <vtkSplineWidget.h>
#include <vtkCommand.h>
#include <vtkTextWidget.h>
#include <vtkTextActor.h>
#include <vtkTextProperty.h>
#include <vtkTextRepresentation.h>
#include <vtkCoordinate.h>
#include <vtkProperty.h>
#include <QDebug>
/*!
* \brief The vtkLengthCallBack class
* SplineWidget的回调类
* 主要用来实时显示长度信息
*/
class vtkLengthCallBack : public vtkCommand
{
public:
static vtkLengthCallBack *New()
{
return new vtkLengthCallBack;
}
virtual void Execute(vtkObject *caller, unsigned long eventId, void *callData)
{
if(!m_text)
return;
if(eventId == vtkCommand::StartInteractionEvent)
m_text->On();
if(eventId == vtkCommand::InteractionEvent){
char text[200];
sprintf(text,"SummedLength: %f",m_spline->GetSummedLength());
m_text->GetTextActor()->SetInput(text);
}
}
vtkSplineWidget *m_spline = nullptr;
vtkTextWidget *m_text = nullptr;
};
/*!
* \brief The SplineWidget class
* 曲线长度测量工具。该工具继承自vtkSplineWidget
* 并在其内部集成了vtkTextWidget作为长度显示面板。
* \see vtkSplineWidget
*/
class SplineWidget : public vtkSplineWidget
{
public:
static SplineWidget *New()
{
return new SplineWidget;
}
//定义VTK类的基本函数
vtkTypeMacro(SplineWidget,vtkSplineWidget)
void SetInteractor(vtkRenderWindowInteractor *iren){
vtkSplineWidget::SetInteractor(iren);
}
void SetText(vtkTextWidget *text)
{
this->m_text = text;
m_lengthCallBack->m_text = text;
}
void On(){
vtkSplineWidget::On();
if(m_text)
m_text->On();
if(this->Interactor){
this->Interactor->GetRenderWindow()->Render();
}
}
void Off(){
vtkSplineWidget::Off();
if(m_text)
m_text->Off();
if(this->Interactor){
this->Interactor->GetRenderWindow()->Render();
}
}
protected:
SplineWidget():
m_lengthCallBack(vtkLengthCallBack::New())
{
//[1] --创建回调函数
m_lengthCallBack->m_spline = this;
//[1]
this->AddObserver(vtkCommand::InteractionEvent,m_lengthCallBack);
this->AddObserver(vtkCommand::StartInteractionEvent,m_lengthCallBack);
}
~SplineWidget(){
m_lengthCallBack->Delete()