VTK(2)—— 双view,显示并联动操作

前言:接到一个新的需求

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 的互动模式即可实现


(二)Demo源码

 

第1种实现方式:

方法说明:

  • 实现方式:继承自vtkCommand重写回调
  • 相机设置:两个 renderer 公用一个相机(注:当不使用一个 camera 设置两个 renderer 的时候,如果viewsation不是对称的 会出现互动最开始两个相机相对物体的位置进行同步)
  • 联动函数:通过判断当前相机 与左右两个相机比对判定哪边动了,包含两种判断方法
#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;
}

(栈溢出问题已解决)

 

第2种实现方式:

方法说明:

  • 实现方式:继承自:vtkInteractorStyleTrackballCamera,重载 Rotate()
  • 相机设置:两个 renderer 公用一个相机(注:当不使用一个 camera 设置两个 renderer 的时候,如果viewsation不是对称的 会出现互动最开始两个相机相对物体的位置进行同步)
  • 联动函数:包含两种方法 ①通过事件所在窗口位置判断哪个 render 动 ②获取当前相机,将两个相机重置为这个相机的状态
#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;
}

(其他实现方法与思路欢迎补充)

你可能感兴趣的:(VTK)