前言:接到一个新的需求
window单窗口程序,双view,显示并联动操作,做了两种方式进行实现,代码思路和源码如下:
(一)代码思路
一、判定谁动了?
方法1:通过当前事件的窗口位置与窗口大小中心轴进行比对
方法2:通过移动后的相机位置与两个view中相机的位置进行比对
二、如何捕获事件?
方法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()方法
(二)源码
源码1:
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkCallbackCommand.h>
#include <vtkTransform.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkCamera.h>
#include <QDateTime>
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<vtkCamera*>(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 ( (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<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
cube->SetCenter(1, 1, 1);
cube->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(cube->GetOutputPort());
vtkSmartPointer<vtkActor> actor1 = vtkSmartPointer<vtkActor>::New();
actor1->SetMapper(mapper);
actor1->GetProperty()->SetColor(.2, .3, .4);
vtkSmartPointer<vtkActor> actor2 = vtkSmartPointer<vtkActor>::New();
actor2->SetMapper(mapper);
actor2->GetProperty()->SetColor(.4, .5, .6);
double leftViewStation[4] = {0.0, 0.0, 0.5, 1.0};
double rightViewStation[4] = {0.5, 0.0, 1.0, 1.0};
vtkSmartPointer<vtkRenderer>leftRender = vtkSmartPointer<vtkRenderer>::New();
leftRender->AddActor(actor1);
leftRender->SetBackground(.6, .5, .4);
leftRender->SetViewport(leftViewStation);
vtkSmartPointer<vtkRenderer>rightRender = vtkSmartPointer<vtkRenderer>::New();
rightRender->AddActor(actor2);
rightRender->SetBackground(.2, .4, .6);
rightRender->SetViewport(rightViewStation);
vtkSmartPointer<vtkRenderWindow>renwindow = vtkSmartPointer<vtkRenderWindow>::New();
renwindow->AddRenderer(leftRender);
renwindow->AddRenderer(rightRender);
renwindow->SetSize(600, 300);
renwindow->Render();
vtkSmartPointer<vtkRenderWindowInteractor>interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<myCallbackFunc>callback = vtkSmartPointer<myCallbackFunc>::New();
callback->SetLeftRender(leftRender);
callback->SetRightRender(rightRender);
leftRender->GetActiveCamera()->AddObserver(vtkCommand::ModifiedEvent,callback);
rightRender->GetActiveCamera()->AddObserver(vtkCommand::ModifiedEvent,callback);
//用户通过控制相机对物体旋转、放大、缩小等操作。
vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
interactor->SetInteractorStyle(style);
renwindow->SetInteractor(interactor);
interactor->Initialize();
interactor->Start();
return EXIT_SUCCESS;
}
源码2:
#include <vtkSmartPointer.h>
#include <vtkCubeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkCallbackCommand.h>
#include <vtkTransform.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkCamera.h>
#include <QDateTime>
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 OnMouseMove()
{
vtkInteractorStyleTrackballCamera::OnMouseMove();
this->CameraSynchronous();
}
void OnLeftButtonDown()
{
vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
this->CameraSynchronous();
}
void OnLeftButtonUp()
{
vtkInteractorStyleTrackballCamera::OnLeftButtonUp();
this->CameraSynchronous();
}
void OnMiddleButtonDown()
{
vtkInteractorStyleTrackballCamera::OnMiddleButtonDown();
this->CameraSynchronous();
}
void OnMiddleButtonUp()
{
vtkInteractorStyleTrackballCamera::OnMiddleButtonUp();
this->CameraSynchronous();
}
void OnRightButtonDown()
{
vtkInteractorStyleTrackballCamera::OnRightButtonDown();
this->CameraSynchronous();
}
void OnRightButtonUp()
{
vtkInteractorStyleTrackballCamera::OnRightButtonUp();
this->CameraSynchronous();
}
void OnMouseWheelForward()
{
vtkInteractorStyleTrackballCamera::OnMouseWheelForward();
this->CameraSynchronous();
}
void OnMouseWheelBackward()
{
vtkInteractorStyleTrackballCamera::OnMouseWheelBackward();
this->CameraSynchronous();
}
void Rotate()
{
vtkInteractorStyleTrackballCamera::Rotate();
this->CameraSynchronous();
}
void Spin()
{
vtkInteractorStyleTrackballCamera::Spin();
this->CameraSynchronous();
}
void Pan()
{
vtkInteractorStyleTrackballCamera::Pan();
this->CameraSynchronous();
}
void Dolly()
{
vtkInteractorStyleTrackballCamera::Dolly();
this->CameraSynchronous();
}
private:
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();
}
private:
vtkRenderer *m_leftRender;
vtkRenderer *m_rightRender;
};
int main(int, char *[])
{
vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
cube->SetCenter(0, 0, 0);
cube->SetXLength(1);
cube->SetYLength(1);
cube->SetZLength(1);
cube->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(cube->GetOutputPort());
vtkSmartPointer<vtkActor> actor1 = vtkSmartPointer<vtkActor>::New();
actor1->SetMapper(mapper);
actor1->GetProperty()->SetColor(.2, .3, .4);
vtkSmartPointer<vtkActor> actor2 = vtkSmartPointer<vtkActor>::New();
actor2->SetMapper(mapper);
actor2->GetProperty()->SetColor(.4, .5, .6);
double leftViewStation[4] = {0.0, 0.0, 0.5, 1.0};
double rightViewStation[4] = {0.5, 0.0, 1.0, 1.0};
vtkSmartPointer<vtkRenderer>leftRender = vtkSmartPointer<vtkRenderer>::New();
leftRender->AddActor(actor1);
leftRender->SetBackground(.6, .5, .4);
leftRender->SetViewport(leftViewStation);
vtkSmartPointer<vtkRenderer>rightRender = vtkSmartPointer<vtkRenderer>::New();
rightRender->AddActor(actor2);
rightRender->SetBackground(.2, .4, .6);
rightRender->SetViewport(rightViewStation);
vtkSmartPointer<vtkRenderWindow>renwindow = vtkSmartPointer<vtkRenderWindow>::New();
renwindow->AddRenderer(leftRender);
renwindow->AddRenderer(rightRender);
renwindow->SetSize(600, 300);
renwindow->Render();
vtkSmartPointer<vtkRenderWindowInteractor>interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<myInteractorStyle> style = vtkSmartPointer<myInteractorStyle>::New();
style->SetLeftRender(leftRender);
style->SetRightRender(rightRender);
interactor->SetInteractorStyle(style);
renwindow->SetInteractor(interactor);
interactor->Initialize();
interactor->Start();
return EXIT_SUCCESS;
}
(其他实现方法与思路欢迎补充)