前言:接到一个新的需求
window单窗口程序,双view,显示并联动操作,做了两种方式进行实现,代码思路和源码如下:
一、判定谁动了?
方法1:通过当前事件的窗口位置与窗口大小中心轴进行比对
方法2:通过移动后的相机位置与两个view中相机的位置进行比对
方法3:获取当前renderer, 与两个renderer 做对比
二、如何捕获事件?
方法1:继承自vtkCommand重写回调
Step1: 定义回调函数,继承自vtkCommand
Step2: 设置回调函数
Step3: 为两个view的相机添加观察者,通过AddObserver(vtkCommand::ModifiedEvent,callback)
(其中ModifiedEvent可以接收任意发生事件,
当有事件产生时,interactor底层会调用ModifiedEvent事件,callback为step1自定义的回调函数)
方法2:vtkInteractorStyleTrackballCamera 重写响应事件
Step1: 自定义交互类型,继承自vtkInteractorStyleTrackballCamera
Step2: 重写OnMouseMove()等方法
三、如何根据一个view变化设置另一个view?
方法1:将要设置的view中的相机的状态设置为变化的相机状态
(因为在vtk中图像变化默认采用的是相机移动方式,在此先不讨论actor变化方式)
(注:vtk中的相机,主要由三个因素决定:1.焦点 2.相机位置 3.向上方向)(另外也可以通过直接获取相机来设置想让变化的相机状态)
Step1: 获取改变的相机的状态,通过GetPosition(), GetFocalPoint(), GetViewUp() 进行获得
Step2: 设置要改变的相机的状态,通过SetPosition(), SetFocalPoint(), SetViewUp() 进行设置
Step3: 使用vtkRenderer的ResetCameraClippingRange()方法重置图像的法向量
Step4: 如果信号没有进行同步,需要手动调用vtkRendererWindow的Render()方法
方法2:创建一个相机对象,给左右两个renderer添加同一个相机对象
方法3:通过获取当前相机,将两个renderer的相机设置为当前相机
四、同类型问题思考?
一个view中,两个actor,根据鼠标指向不同,可挪动不同的物体。(这个实现起来相对简单一点,vtk有现成的函数)
方法:使用 vtkInteractorStyleTrackballActor 的互动模式即可实现
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class myCallbackFunc:public vtkCommand
{
public:
static myCallbackFunc *New()
{
return new myCallbackFunc;
}
void SetLeftRender(vtkRenderer *leftRender)
{
this->m_leftRender = leftRender;
}
void SetRightRender(vtkRenderer *rightRender)
{
this->m_rightRender = rightRender;
}
virtual void Execute(vtkObject *caller, unsigned long eventId, void* callData)
{
vtkCamera *camera = reinterpret_cast(caller);
vtkCamera *leftCamera = m_leftRender->GetActiveCamera();
vtkCamera *rightCamera = m_rightRender->GetActiveCamera();
double *act_position = camera->GetPosition();
double *act_FocalPoint = camera->GetFocalPoint();
double *act_ViewUp = camera->GetViewUp();
//方法一:指针判断
if (leftCamera == camera)
{
if (rightCamera->GetPosition() != act_position)
{
rightCamera->SetPosition(act_position);
}
if (rightCamera->GetViewUp() != act_ViewUp)
{
rightCamera->SetFocalPoint(act_FocalPoint);
}
if (rightCamera->GetViewUp() != act_ViewUp)
{
rightCamera->SetViewUp(act_ViewUp);
}
}
else if (rightCamera == camera)
{
if (leftCamera->GetPosition() != act_position)
{
leftCamera->SetPosition(act_position);
}
if (leftCamera->GetViewUp() != act_ViewUp)
{
leftCamera->SetFocalPoint(act_FocalPoint);
}
if (leftCamera->GetViewUp() != act_ViewUp)
{
leftCamera->SetViewUp(act_ViewUp);
}
}
//方法二:camera具体细节判断
// if ( (isSame(act_position, leftCamera->GetPosition()))
// &&(isSame(act_FocalPoint, leftCamera->GetFocalPoint()))
// &&(isSame(act_ViewUp,leftCamera->GetViewUp())))
// {
// rightCamera->SetPosition(act_position);
// rightCamera->SetFocalPoint(act_FocalPoint);
// rightCamera->SetViewUp(act_ViewUp);
// this->m_rightRender->ResetCameraClippingRange();
// }
// else
// {
// leftCamera->SetPosition(act_position);
// leftCamera->SetFocalPoint(act_FocalPoint);
// leftCamera->SetViewUp(act_ViewUp);
// this->m_leftRender->ResetCameraClippingRange();
// }
}
//private:
// //计算获取到的相机是否为leftRender或rightRender的相机
// static bool isSame(double *value0, double *value1) {
// bool result = true;
// for (int idx = 0; idx != 3; ++idx) {
// result = result && qFuzzyCompare(value0[idx], value1[idx]);
// }
// return result;
// }
private:
//此处为双view,若为多view,可设置数组,通过提供参数进行设置
vtkRenderer *m_leftRender;
vtkRenderer *m_rightRender;
};
int main(int, char *[])
{
vtkSmartPointer cube = vtkSmartPointer::New();
vtkSmartPointer mapper = vtkSmartPointer::New();
vtkSmartPointer actor1 = vtkSmartPointer::New();
vtkSmartPointer actor2 = vtkSmartPointer::New();
vtkSmartPointer leftRender = vtkSmartPointer::New();
vtkSmartPointer rightRender = vtkSmartPointer::New();
vtkSmartPointer renwindow = vtkSmartPointer::New();
vtkSmartPointer camera = vtkSmartPointer::New();
vtkSmartPointer interactor = vtkSmartPointer::New();
vtkSmartPointer callback = vtkSmartPointer::New();
vtkSmartPointer style = vtkSmartPointer::New();
cube->SetCenter(1, 1, 1);
cube->Update();
mapper->SetInputConnection(cube->GetOutputPort());
actor1->SetMapper(mapper);
actor1->GetProperty()->SetColor(.2, .3, .4);
actor2->SetMapper(mapper);
actor2->GetProperty()->SetColor(.4, .5, .6);
double leftViewStation[4] = {0.0, 0.0, 0.4, 1.0};
double rightViewStation[4] = {0.4, 0.0, 1.0, 1.0};
leftRender->AddActor(actor1);
leftRender->SetBackground(.6, .5, .4);
leftRender->SetViewport(leftViewStation);
rightRender->AddActor(actor2);
rightRender->SetBackground(.2, .4, .6);
rightRender->SetViewport(rightViewStation);
camera->SetPosition(4, 4, 4);
rightRender->SetActiveCamera(camera);
leftRender->SetActiveCamera(camera);
renwindow->AddRenderer(leftRender);
renwindow->AddRenderer(rightRender);
renwindow->SetSize(600, 300);
renwindow->Render();
callback->SetLeftRender(leftRender);
callback->SetRightRender(rightRender);
leftRender->GetActiveCamera()->AddObserver(vtkCommand::ModifiedEvent,callback);
rightRender->GetActiveCamera()->AddObserver(vtkCommand::ModifiedEvent,callback);
interactor->SetInteractorStyle(style);//用户通过控制相机对物体旋转、放大、缩小等操作。
renwindow->SetInteractor(interactor);
interactor->Initialize();
interactor->Start();
return EXIT_SUCCESS;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class myInteractorStyle:public vtkInteractorStyleTrackballCamera
{
public:
static myInteractorStyle* New()
{
return new myInteractorStyle;
}
void SetLeftRender(vtkRenderer *render)
{
this->m_leftRender = render;
}
void SetRightRender(vtkRenderer *render)
{
this->m_rightRender = render;
}
void Rotate()
{
vtkInteractorStyleTrackballCamera::Rotate();
this->CameraSynchronous();
}
//**************** 方法一: 通过事件所在窗口位置判断哪个 render 动 ************//
void CameraSynchronous()
{
vtkCamera *leftCamera = m_leftRender->GetActiveCamera();
vtkCamera *rightCamera = m_rightRender->GetActiveCamera();
//获取窗口大小
int *winSize = this->GetInteractor()->GetRenderWindow()->GetSize();
//获取事件窗口位置
int eventStation[3];
this->GetInteractor()->GetEventPosition(eventStation);
if (eventStation[0] < winSize[0]/2)
{
rightCamera->SetPosition(leftCamera->GetPosition());
rightCamera->SetFocalPoint(leftCamera->GetFocalPoint());
rightCamera->SetViewUp(leftCamera->GetViewUp());
m_rightRender->ResetCameraClippingRange();
}
else
{
leftCamera->SetPosition(rightCamera->GetPosition());
leftCamera->SetViewUp(rightCamera->GetViewUp());
leftCamera->SetFocalPoint(rightCamera->GetFocalPoint());
m_leftRender->ResetCameraClippingRange();
}
this->GetInteractor()->GetRenderWindow()->Render();
}
//**************** 方法二: 获取当前相机,将两个相机重置为这个相机的状态 ************//
// void CameraSynchronous()
// {
// vtkCamera *camera = this->GetCurrentRenderer()->GetActiveCamera();
// this->m_leftRender->SetActiveCamera(camera);
// this->m_rightRender->SetActiveCamera(camera);
// }
private:
vtkRenderer *m_leftRender;
vtkRenderer *m_rightRender;
};
int main(int, char *[])
{
vtkSmartPointer cube = vtkSmartPointer::New();
vtkSmartPointer mapper = vtkSmartPointer::New();
vtkSmartPointer actor1 = vtkSmartPointer::New();
vtkSmartPointer actor2 = vtkSmartPointer::New();
vtkSmartPointer leftRender = vtkSmartPointer::New();
vtkSmartPointer rightRender = vtkSmartPointer::New();
vtkSmartPointer camera = vtkSmartPointer::New();
vtkSmartPointer renwindow = vtkSmartPointer::New();
vtkSmartPointer interactor = vtkSmartPointer::New();
vtkSmartPointer style = vtkSmartPointer::New();
cube->SetXLength(1);
cube->SetYLength(1);
cube->SetZLength(1);
cube->Update();
mapper->SetInputConnection(cube->GetOutputPort());
actor1->SetMapper(mapper);
actor1->GetProperty()->SetColor(.2, .3, .4);
actor2->SetMapper(mapper);
actor2->GetProperty()->SetColor(.4, .5, .6);
double leftViewStation[4] = {0.0, 0.0, 0.4, 1.0};
double rightViewStation[4] = {0.4, 0.0, 1.0, 1.0};
leftRender->AddActor(actor1);
leftRender->SetBackground(.6, .5, .4);
leftRender->SetViewport(leftViewStation);
rightRender->AddActor(actor2);
rightRender->SetBackground(.2, .4, .6);
rightRender->SetViewport(rightViewStation);
camera->SetPosition(4, 4, 4);
rightRender->SetActiveCamera(camera);
leftRender->SetActiveCamera(camera);
renwindow->AddRenderer(leftRender);
renwindow->AddRenderer(rightRender);
renwindow->SetSize(600, 300);
renwindow->Render();
style->SetLeftRender(leftRender);
style->SetRightRender(rightRender);
interactor->SetInteractorStyle(style);
renwindow->SetInteractor(interactor);
interactor->Initialize();
interactor->Start();
return EXIT_SUCCESS;
}
1. 一个窗口中有4个view,实现两两联动
2. 继承自 vtkInteractorStyleTrackballCamera , 重写了 Rotate() 方法
3. 作为接口,提供了增加联动,删除联动的功能
4. 注:下面两个不联动是通过删除方法,删掉了联动
源代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define vSP vtkSmartPointer
typedef QMap, vSP> RenderMap;
class myInteractorStyle:public vtkInteractorStyleTrackballCamera
{
public:
static myInteractorStyle* New()
{
return new myInteractorStyle;
}
void SetRenderPair(vSP render1, vSP render2)
{
do
{
if (render1 == nullptr)
{
break;
}
if (render2 == nullptr)
{
break;
}
this->m_renderMap[render1] = render2;
this->m_renderMap[render2] = render1;
}while(false);
}
void RemoveRenderPair(vSP render1, vSP render2)
{
do
{
if (!this->m_renderMap.contains(render1))
{
break;
}
if (!this->m_renderMap.contains(render2))
{
break;
}
if (render1 != this->m_renderMap.value(render2, nullptr))
{
break;
}
if (render1 == nullptr)
{
break;
}
if (render2 == nullptr)
{
break;
}
this->m_renderMap.remove(render1);
this->m_renderMap.remove(render2);
}while(false);
}
void Rotate()
{
vtkInteractorStyleTrackballCamera::Rotate();
this->CameraSynchronous();
}
public:
void CameraSynchronous()
{
vSP curRender = this->GetCurrentRenderer();
vSP curCamera = curRender->GetActiveCamera();
if (this->m_renderMap.contains(curRender))
{
vSP linkRender = this->m_renderMap.value(curRender, nullptr);
if (linkRender != nullptr)
{
linkRender->SetActiveCamera(curCamera);
}
}
}
private:
RenderMap m_renderMap;
};
class Client
{
public:
Client()
{
this->Init();
this->setCube();
this->setMapper();
this->setActor();
this->setRender();
this->setRenderWindow();
this->setStyle();
this->setInteractor();
this->start();
}
void Init()
{
this->m_cube = vtkSmartPointer::New();
this->m_mapper = vtkSmartPointer::New();
this->m_actor1 = vtkSmartPointer::New();
this->m_actor2 = vtkSmartPointer::New();
this->m_leftRender = vtkSmartPointer::New();
this->m_rightRender = vtkSmartPointer::New();
this->m_leftRender2 = vtkSmartPointer::New();
this->m_rightRender2 = vtkSmartPointer::New();
this->m_renwindow = vtkSmartPointer::New();
this->m_interactor = vtkSmartPointer::New();
this->m_style = vtkSmartPointer::New();
}
void setCube()
{
m_cube->SetXLength(1);
m_cube->SetYLength(1);
m_cube->SetZLength(1);
m_cube->Update();
}
void setMapper()
{
m_mapper->SetInputConnection(m_cube->GetOutputPort());
}
void setActor()
{
m_actor1->SetMapper(m_mapper);
m_actor1->GetProperty()->SetColor(.2, .3, .4);
m_actor2->SetMapper(m_mapper);
m_actor2->GetProperty()->SetColor(.4, .5, .6);
}
void setRender()
{
m_leftRender->AddActor(m_actor1);
m_leftRender->SetBackground(.6, .5, .4);
m_leftRender->SetViewport(0.0, 0.5, 0.5, 1.0);
m_leftRender2->AddActor(m_actor1);
m_leftRender2->SetBackground(.6, .5, .4);
m_leftRender2->SetViewport(0.0, 0.0, 0.5, 0.5);
m_rightRender->AddActor(m_actor2);
m_rightRender->SetBackground(.2, .4, .6);
m_rightRender->SetViewport(0.5, 0.5, 1.0, 1.0);
m_rightRender2->AddActor(m_actor2);
m_rightRender2->SetBackground(.2, .4, .6);
m_rightRender2->SetViewport(0.5, 0.0, 1.0, 0.5);
}
void setRenderWindow()
{
m_renwindow->AddRenderer(m_leftRender);
m_renwindow->AddRenderer(m_rightRender);
m_renwindow->AddRenderer(m_leftRender2);
m_renwindow->AddRenderer(m_rightRender2);
m_renwindow->SetSize(600, 600);
m_renwindow->Render();
}
void setStyle()
{
m_style->SetRenderPair(m_leftRender, m_rightRender);
m_style->SetRenderPair(m_leftRender2, m_rightRender2);
m_style->RemoveRenderPair(m_leftRender2, m_rightRender2);
}
void setInteractor()
{
m_interactor->SetInteractorStyle(m_style);
}
void start()
{
m_renwindow->SetInteractor(m_interactor);
m_interactor->Initialize();
m_interactor->Start();
}
private:
vtkSmartPointer m_cube;
vtkSmartPointer m_mapper;
vtkSmartPointer m_actor1;
vtkSmartPointer m_actor2;
vtkSmartPointer m_leftRender;
vtkSmartPointer m_rightRender;
vtkSmartPointer m_leftRender2;
vtkSmartPointer m_rightRender2;
vtkSmartPointer m_renwindow;
vtkSmartPointer m_interactor;
vtkSmartPointer m_style;
};
int main(int, char *[])
{
Client client;
client.start();
return EXIT_SUCCESS;
}
(其他实现方法与思路欢迎补充)