I have two old posts about draw display bounding box, VTK: Show Display Bounds After Project Points and VTK: Show Display Bounds. But they didn’t give me a statisfy result.
In this post, I find feature edges of the mesh firstly, convert the world points to display points by vtkViewport object. Then the program computes the bounding box from these display points. It gives me a valid rectangle.
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 <vtkFeatureEdges.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 );
cone->Update();
vtkSPtrNew( boundaryEdges, vtkFeatureEdges );
boundaryEdges->SetInputData( cone->GetOutput() );
boundaryEdges->BoundaryEdgesOff();
boundaryEdges->FeatureEdgesOn();
boundaryEdges->NonManifoldEdgesOff();
boundaryEdges->ManifoldEdgesOff();
boundaryEdges->SetFeatureAngle( 30 );
boundaryEdges->Update();
vtkSPtrNew( mapper, vtkPolyDataMapper );
mapper->SetInputConnection( boundaryEdges->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 );
iteractorStyle->Setm_Window( renderWindow );
renderWindowInteractor->SetInteractorStyle( iteractorStyle );
renderWindowInteractor->Start();
return 0;
}
CustomIteractorStyle.h
/**********************************************************************************************
*
* Filename: CustomIteractorStyle.h
*
* Author: theArcticOcean - [email protected]
*
**********************************************************************************************/
#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>
#include <vtkActor2DCollection.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* )
CPP_SET_MACRO( m_Window, vtkRenderWindow* )
protected:
void ShowDisPts();
CustomIteractorStyle();
~CustomIteractorStyle() override;
vtkSmartPointer<vtkActor2D> m_DisBds;
vtkSmartPointer<vtkActor2DCollection> m_ActorDisPts;
vtkActor *m_ConeActor;
vtkRenderer *m_Renderer;
vtkRenderWindow *m_Window;
};
CustomIteractorStyle.cpp
/**********************************************************************************************
*
* Filename: CustomIteractorStyle.cpp
*
* Author: theArcticOcean - [email protected]
*
**********************************************************************************************/
#include "CustomIteractorStyle.h"
#include <vtkCoordinate.h>
#include <vtkPolyDataMapper2D.h>
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty2D.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataSilhouette.h>
#include "point.hpp"
void CustomIteractorStyle::OnMouseWheelForward()
{
vtkInteractorStyleTrackballCamera::OnMouseWheelForward();
ShowDisPts();
}
void CustomIteractorStyle::OnMouseWheelBackward()
{
vtkInteractorStyleTrackballCamera::OnMouseWheelBackward();
ShowDisPts();
}
void CustomIteractorStyle::OnMouseMove()
{
vtkInteractorStyleTrackballCamera::OnMouseMove();
ShowDisPts();
}
void CustomIteractorStyle::ShowDisPts()
{
auto data = m_ConeActor->GetMapper()->GetInput();
m_ActorDisPts->InitTraversal();
auto actor2D = m_ActorDisPts->GetNextActor2D();
while( actor2D )
{
m_Renderer->RemoveActor2D( actor2D );
actor2D = m_ActorDisPts->GetNextActor2D();
}
m_ActorDisPts->RemoveAllItems();
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 < data->GetNumberOfPoints(); ++i )
{
auto pt = data->GetPoint( i );
double tmp[4] = { pt[0], pt[1], pt[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];
cout << "displayPoint: " << displayPoint[0] << ", " << displayPoint[1] << ", " << displayPoint[2] << endl;
vtkSmartPointer<vtkSphereSource> sphere =
vtkSmartPointer<vtkSphereSource>::New();
sphere->SetThetaResolution( 100 );
sphere->SetPhiResolution( 50 );
sphere->SetRadius( 10 );
sphere->SetCenter( displayPoint );
sphere->Update();
vtkSmartPointer<vtkPolyDataMapper2D> mapper2D =
vtkSmartPointer<vtkPolyDataMapper2D>::New();
mapper2D->SetInputData(sphere->GetOutput());
mapper2D->Update();
vtkSmartPointer<vtkActor2D> actor2D =
vtkSmartPointer<vtkActor2D>::New();
actor2D->SetMapper( mapper2D );
actor2D->GetProperty()->SetColor( 0, 1, 0 );
actor2D->GetProperty()->SetPointSize( 10 );
m_Renderer->AddActor( actor2D );
m_ActorDisPts->AddItem( actor2D );
}
// ==== start to draw line ====
vtkSmartPointer<vtkPoints> points =
vtkSmartPointer<vtkPoints>::New();
points->InsertNextPoint( displayBounds[0], displayBounds[2], displayBounds[5] );
points->InsertNextPoint( displayBounds[1], displayBounds[2], displayBounds[5] );
points->InsertNextPoint( displayBounds[1], displayBounds[3], displayBounds[5] );
points->InsertNextPoint( displayBounds[0], displayBounds[3], displayBounds[5] );
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<vtkPolyDataMapper2D> mapper2D =
vtkSmartPointer<vtkPolyDataMapper2D>::New();
mapper2D->SetInputData(polydata);
mapper2D->Update();
m_DisBds->SetMapper( mapper2D );
m_Renderer->AddActor2D( m_DisBds );
m_Window->Render();
}
CustomIteractorStyle::CustomIteractorStyle()
{
m_ConeActor = nullptr;
m_Renderer = nullptr;
m_ActorDisPts = vtkSmartPointer<vtkActor2DCollection>::New();
m_DisBds = vtkSmartPointer<vtkActor2D>::New();
}
CustomIteractorStyle::~CustomIteractorStyle()
{
m_ConeActor = nullptr;
}
Result can be saw in the following video.