I planed to show the 3D model’s bounds in the display coordinate and update it if the user rotates and zooms in/out in real-time. I’m curious about if the display bounds touch with the 3D model.

The display bounds are shown as a red rectangle in the render window, our 3D model is a simple cone.

We can find that the display bounds may be far away from the model as the view direction changed.

main.cpp

#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindowInteractor.h>

#include "CustomIteractorStyle.h"

#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();

using namespace std;

int main()
{
    vtkSPtrNew( cone, vtkConeSource );
    vtkSPtrNew( mapper, vtkPolyDataMapper );
    mapper->SetInputConnection( cone->GetOutputPort() );

    vtkSPtrNew( actor, vtkActor );
    actor->SetMapper( mapper );

    vtkSPtrNew( renderer, vtkRenderer );
    renderer->AddActor(actor);
    renderer->SetBackground( 0, 0, 0 );

    vtkSPtrNew( renderWindow, vtkRenderWindow );
    renderWindow->AddRenderer( renderer );

    vtkSPtrNew( renderWindowInteractor, vtkRenderWindowInteractor );
    renderWindowInteractor->SetRenderWindow( renderWindow );

    renderer->ResetCamera();
    renderWindow->Render();

    vtkSPtrNew( iteractorStyle, CustomIteractorStyle );
    iteractorStyle->Setm_ConeActor( actor );
    iteractorStyle->Setm_Renderer( renderer );
    renderWindowInteractor->SetInteractorStyle( iteractorStyle );

    renderWindowInteractor->Start();
    return 0;
}

CustomIteractorStyle.h

#pragma once

#include <iostream>
#include <vtkSmartPointer.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkActor.h>
#include <vtkActor2D.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkTransform.h>

#define CPP_SET_MACRO(name,type) \
  void Set##name(type _arg) \
  { \
    if (this->name != _arg) \
    { \
    this->name = _arg; \
    } \
  }

#define vtkSPtr vtkSmartPointer
#define vtkSPtrNew(Var, Type) vtkSPtr<Type> Var = vtkSPtr<Type>::New();

class CustomIteractorStyle: public vtkInteractorStyleTrackballCamera
{
public:
    static CustomIteractorStyle *New(){ return new CustomIteractorStyle(); }
    void OnMouseWheelForward() override;
    void OnMouseWheelBackward() override;
    void OnMouseMove() override;

    CPP_SET_MACRO( m_ConeActor, vtkActor *)
    CPP_SET_MACRO( m_Renderer, vtkRenderer* )
protected:
    void ComputeDisplayBds( double *resultBounds, vtkSmartPointer<vtkActor> actor );
    void UpdateDisplayBds();

    CustomIteractorStyle();
    ~CustomIteractorStyle() override;
    vtkSmartPointer<vtkActor2D> m_Actor2DDebug;
    vtkActor *m_ConeActor;
    vtkRenderer *m_Renderer;
};

CustomIteractorStyle.cpp

#include "CustomIteractorStyle.h"
#include <vtkCoordinate.h>
#include <vtkPolyDataMapper2D.h>
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty2D.h>

void CustomIteractorStyle::OnMouseWheelForward()
{
    vtkInteractorStyleTrackballCamera::OnMouseWheelForward();

    UpdateDisplayBds();
}

void CustomIteractorStyle::OnMouseWheelBackward()
{
    vtkInteractorStyleTrackballCamera::OnMouseWheelBackward();

    UpdateDisplayBds();
}

void CustomIteractorStyle::OnMouseMove()
{
    vtkInteractorStyleTrackballCamera::OnMouseMove();

    UpdateDisplayBds();
}

void CustomIteractorStyle::ComputeDisplayBds(double *resultBounds, vtkSmartPointer<vtkActor> actor)
{
    double *bounds = actor->GetBounds();

    double coordinate[8][3] =
    {
        bounds[0], bounds[2], bounds[4],
        bounds[0], bounds[3], bounds[4],
        bounds[0], bounds[2], bounds[5],
        bounds[0], bounds[3], bounds[5],

        bounds[1], bounds[2], bounds[4],
        bounds[1], bounds[3], bounds[4],
        bounds[1], bounds[2], bounds[5],
        bounds[1], bounds[3], bounds[5],
    };
    double displayBounds[6] = { VTK_DOUBLE_MAX, VTK_DOUBLE_MIN, VTK_DOUBLE_MAX,
                                VTK_DOUBLE_MIN, VTK_DOUBLE_MAX, VTK_DOUBLE_MIN };
    for (int i = 0; i < 8; i++)
    {
       double tmp[4] = { coordinate[i][0], coordinate[i][1], coordinate[i][2], 0 };
       m_Renderer->SetWorldPoint( tmp );
       m_Renderer->WorldToDisplay();
       double displayPoint[3];
       m_Renderer->GetDisplayPoint( displayPoint );

       if (displayPoint[0] < displayBounds[0])
            displayBounds[0] = displayPoint[0];
       if (displayPoint[0] > displayBounds[1])
            displayBounds[1] = displayPoint[0];


       if (displayPoint[1] < displayBounds[2])
            displayBounds[2] = displayPoint[1];
       if (displayPoint[1] > displayBounds[3])
            displayBounds[3] = displayPoint[1];

       if (displayPoint[2] < displayBounds[4])
            displayBounds[4] = displayPoint[2];
       if (displayPoint[2] > displayBounds[5])
            displayBounds[5] = displayPoint[2];
    }
    for( int i = 0; i < 6; ++i )
    {
        resultBounds[i] = displayBounds[i];
    }

    // -------------- debug ----------------
    // ==== start to draw line ====
    vtkSmartPointer<vtkPoints> points =
        vtkSmartPointer<vtkPoints>::New();
    points->InsertNextPoint( displayBounds[0], displayBounds[2], 0 );
    points->InsertNextPoint( displayBounds[1], displayBounds[2], 0 );
    points->InsertNextPoint( displayBounds[1], displayBounds[3], 0 );
    points->InsertNextPoint( displayBounds[0], displayBounds[3], 0 );

    vtkSmartPointer<vtkCellArray> cells =
        vtkSmartPointer<vtkCellArray>::New();
    vtkIdType line0[2] = {0, 1};
    cells->InsertNextCell(2, line0);
    vtkIdType line1[2] = {1, 2};
    cells->InsertNextCell(2, line1);
    vtkIdType line2[2] = {2, 3};
    cells->InsertNextCell(2, line2);
    vtkIdType line3[2] = {3, 0};
    cells->InsertNextCell(2, line3);

    vtkSmartPointer<vtkPolyData> polydata =
        vtkSmartPointer<vtkPolyData>::New();
    polydata->SetPoints(points);
    polydata->SetLines(cells);
    polydata->Modified();

    vtkSmartPointer<vtkPolyDataMapper> mapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputData(polydata);
    mapper->Update();

    vtkSmartPointer<vtkCoordinate> coordinateIns =
        vtkSmartPointer<vtkCoordinate>::New();
    coordinateIns->SetCoordinateSystemToDisplay();

    vtkSmartPointer<vtkPolyDataMapper2D> mapper2D =
        vtkSmartPointer<vtkPolyDataMapper2D>::New();
    mapper2D->SetInputData(polydata);
    mapper2D->SetTransformCoordinate(coordinateIns);
    mapper2D->Update();

    m_Actor2DDebug->SetMapper( mapper2D );
    m_Actor2DDebug->GetProperty()->SetColor( 1, 0, 0 );
    // -------------- finish: debug ----------------
}

void CustomIteractorStyle::UpdateDisplayBds()
{
    double displayBds[6];
    ComputeDisplayBds( displayBds, m_ConeActor );
    m_Renderer->AddActor2D( m_Actor2DDebug );
}

CustomIteractorStyle::CustomIteractorStyle()
{
    m_ConeActor = nullptr;
    m_Renderer = nullptr;
    m_Actor2DDebug = vtkSmartPointer<vtkActor2D>::New();
}

CustomIteractorStyle::~CustomIteractorStyle()
{
    m_ConeActor = nullptr;
}

displayBounds
Categories: VTK

5 1 vote
Article Rating
Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
trackback

[…] I had tried to show display coordinate bounds of the 3D model in the article VTK: Show Display Bounds. […]

3D Model Viewer: add grid plane and convex hull.
Add google translate tool at right-bottom position.

X
A prohibited operation
1
0
Would love your thoughts, please comment.x
()
x