split viewport for Qt and VtkViewer

This commit is contained in:
AndreaRigoni
2026-03-17 15:29:07 +00:00
parent 4569407d18
commit e6e0bccffb
7 changed files with 345 additions and 233 deletions

View File

@@ -3,6 +3,7 @@ set(HEADERS uLibVtkInterface.h
vtkContainerBox.h
vtkHandlerWidget.h
vtkQViewport.h
vtkViewport.h
vtkPolydata.h
)
@@ -11,6 +12,7 @@ set(SOURCES uLibVtkInterface.cxx
vtkContainerBox.cpp
vtkHandlerWidget.cpp
vtkQViewport.cpp
vtkViewport.cpp
vtkPolydata.cpp
)

View File

@@ -37,6 +37,7 @@
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkObjectFactory.h>
#include <vtkTextProperty.h>
#include <vtkRenderWindow.h>
#include "uLibVtkViewer.h"
@@ -56,8 +57,6 @@ public:
};
vtkStandardNewMacro(vtkInteractorStyleNoSpin);
namespace uLib {
namespace Vtk {
@@ -65,24 +64,12 @@ namespace Vtk {
///// VTK VIEWER //////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Viewer::Viewer()
: m_RenderWindow(vtkRenderWindow::New()), m_Renderer(vtkRenderer::New()),
m_Annotation(vtkCornerAnnotation::New()),
m_Marker(vtkOrientationMarkerWidget::New()), m_CameraWidget(nullptr) {
#if VTK_MAJOR_VERSION >= 9 || \
(VTK_MAJOR_VERSION == 8 && VTK_MINOR_VERSION >= 90)
m_CameraWidget = vtkCameraOrientationWidget::New();
#endif
: Viewport(), m_RenderWindow(vtkRenderWindow::New()) {
InstallPipe();
}
Viewer::~Viewer() {
UninstallPipe();
m_Annotation->Delete();
m_Marker->Delete();
if (m_CameraWidget)
m_CameraWidget->Delete();
m_Renderer->Delete();
m_RenderWindow->Delete();
}
@@ -93,34 +80,14 @@ void Viewer::InstallPipe() {
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(m_RenderWindow);
// Use a custom style with no spin/inertia
// Common setup
Viewport::SetupPipeline(renderWindowInteractor);
// BUT we want to override the style with our custom NoSpin version
vtkSmartPointer<vtkInteractorStyleNoSpin> style =
vtkSmartPointer<vtkInteractorStyleNoSpin>::New();
renderWindowInteractor->SetInteractorStyle(style);
// annotation //
m_Annotation->GetTextProperty()->SetColor(1, 1, 1);
m_Annotation->GetTextProperty()->SetFontFamilyToArial();
m_Annotation->GetTextProperty()->SetOpacity(0.5);
m_Annotation->SetMaximumFontSize(10);
m_Annotation->SetText(0, "uLib VTK Viewer - OpenCMT all right reserved.");
m_Renderer->AddViewProp(m_Annotation);
// orientation marker //
vtkSmartPointer<vtkAxesActor> axes = vtkSmartPointer<vtkAxesActor>::New();
m_Marker->SetInteractor(renderWindowInteractor);
m_Marker->SetOrientationMarker(axes);
m_Marker->SetViewport(0.0, 0.0, 0.2, 0.2);
m_Marker->SetEnabled(true);
m_Marker->InteractiveOff();
// camera orientation widget //
if (m_CameraWidget) {
m_CameraWidget->SetParentRenderer(m_Renderer);
m_CameraWidget->SetInteractor(renderWindowInteractor);
m_CameraWidget->On();
}
// Must be rendered here in Vtk-6.0 or seg-fault //
m_RenderWindow->Render();
}
@@ -130,25 +97,9 @@ void Viewer::UninstallPipe() {
m_Renderer->Clear();
}
void Viewer::addProp(vtkProp *prop) {
m_Renderer->AddActor(prop);
m_Renderer->Render();
}
void Viewer::RemoveProp(vtkProp *prop) {
m_Renderer->RemoveViewProp(prop);
m_Renderer->Render();
}
void Viewer::AddPuppet(Puppet &prop) {
prop.ConnectRenderer(m_Renderer);
prop.ConnectInteractor(this->GetInteractor());
m_Renderer->Render();
}
void Viewer::RemovePuppet(Puppet &prop) {
prop.DisconnectRenderer(m_Renderer);
m_Renderer->Render();
void Viewer::Render() {
if (m_RenderWindow)
m_RenderWindow->Render();
}
vtkSmartPointer<vtkCameraOrientationWidget>
@@ -164,27 +115,11 @@ Viewer::MakeCameraOrientationWidget(vtkRenderWindowInteractor *interactor,
void Viewer::Start() { m_RenderWindow->GetInteractor()->Start(); }
vtkCornerAnnotation *Viewer::GetAnnotation() { return m_Annotation; }
vtkRenderer *Viewer::GetRenderer() { return m_Renderer; }
vtkRenderWindow *Viewer::GetRenderWindow() { return m_RenderWindow; }
vtkRenderWindowInteractor *Viewer::GetInteractor() {
return m_RenderWindow->GetInteractor();
}
vtkCameraOrientationWidget *Viewer::GetCameraWidget() { return m_CameraWidget; }
void Viewer::Reset() {
this->ZoomAuto();
m_Renderer->Render();
}
void Viewer::ZoomAuto() {
m_Renderer->ResetCameraClippingRange();
m_Renderer->ResetCamera();
}
} // namespace Vtk
} // namespace uLib

View File

@@ -26,80 +26,49 @@
#ifndef ULIBVTKVIEWER_H
#define ULIBVTKVIEWER_H
#include "uLibVtkInterface.h"
#include <iostream>
#include <vtkCornerAnnotation.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
class vtkProp;
class vtk3DWidget;
class vtkCornerAnnotation;
class vtkRenderWindowInteractor;
class vtkRenderer;
class vtkCameraOrientationWidget;
#include "vtkViewport.h"
namespace uLib {
namespace Vtk {
template <class T> class Tie {
public:
void DoAction() {
std::cout << "Tie::DoAction -> generic Tie does nothing\n";
}
};
// template <class T> class Tie {
// public:
// void DoAction() {
// std::cout << "Tie::DoAction -> generic Tie does nothing\n";
// }
// };
class Viewer {
class Viewer : public Viewport {
public:
Viewer();
~Viewer();
virtual ~Viewer();
void AddPuppet(Puppet &prop);
void RemovePuppet(Puppet &prop);
void AddWidget(vtk3DWidget *widget);
// Render scene
virtual void Render() override;
static vtkSmartPointer<vtkCameraOrientationWidget>
MakeCameraOrientationWidget(vtkRenderWindowInteractor *interactor,
vtkRenderer *renderer);
void Reset();
void ZoomAuto();
vtkRenderer *renderer);
void Start();
vtkCornerAnnotation *GetAnnotation();
vtkRenderer *GetRenderer();
vtkRenderWindow *GetRenderWindow();
vtkRenderWindowInteractor *GetInteractor();
vtkCameraOrientationWidget *GetCameraWidget();
void addProp(vtkProp *prop);
void RemoveProp(vtkProp *prop);
virtual vtkRenderWindow *GetRenderWindow() override;
virtual vtkRenderWindowInteractor *GetInteractor() override;
private:
void InstallPipe();
void UninstallPipe();
vtkRenderer *m_Renderer;
vtkRenderWindow *m_RenderWindow;
vtkCornerAnnotation *m_Annotation;
vtkOrientationMarkerWidget *m_Marker;
vtkCameraOrientationWidget *m_CameraWidget;
};
template <> class Tie<Viewer> {
public:
void DoAction() { std::cout << " VIEWER TIE !!! \n"; }
};
// template <> class Tie<Viewer> {
// public:
// void DoAction() { std::cout << " VIEWER TIE !!! \n"; }
// };
} // namespace Vtk
} // namespace uLib

View File

@@ -15,11 +15,8 @@ namespace Vtk {
QViewport::QViewport(QWidget* parent)
: QWidget(parent)
, Viewport()
, m_VtkWidget(nullptr)
, m_Renderer(vtkRenderer::New())
, m_Annotation(vtkCornerAnnotation::New())
, m_Marker(vtkOrientationMarkerWidget::New())
, m_CameraWidget(nullptr)
{
// Build the layout zero margins so VTK fills the entire widget
auto* layout = new QVBoxLayout(this);
@@ -36,14 +33,6 @@ QViewport::QViewport(QWidget* parent)
QViewport::~QViewport()
{
m_Renderer->RemoveAllViewProps();
m_Renderer->Clear();
m_Annotation->Delete();
m_Marker->Delete();
if (m_CameraWidget)
m_CameraWidget->Delete();
m_Renderer->Delete();
}
void QViewport::SetupPipeline()
@@ -52,88 +41,17 @@ void QViewport::SetupPipeline()
vtkRenderWindow* rw = m_VtkWidget->renderWindow();
rw->AddRenderer(m_Renderer);
// Qt will supply its own interactor grab it
vtkRenderWindowInteractor* iren = rw->GetInteractor();
// Trackball-camera interaction style
vtkNew<vtkInteractorStyleTrackballCamera> style;
iren->SetInteractorStyle(style);
// Corner annotation
m_Annotation->GetTextProperty()->SetColor(1, 1, 1);
m_Annotation->GetTextProperty()->SetFontFamilyToArial();
m_Annotation->GetTextProperty()->SetOpacity(0.5);
m_Annotation->SetMaximumFontSize(10);
m_Annotation->SetText(0, "uLib VTK Viewer - OpenCMT all right reserved.");
m_Renderer->AddViewProp(m_Annotation);
// Orientation axes marker (bottom-left corner)
vtkNew<vtkAxesActor> axes;
m_Marker->SetInteractor(iren);
m_Marker->SetOrientationMarker(axes);
m_Marker->SetViewport(0.0, 0.0, 0.2, 0.2);
m_Marker->SetEnabled(true);
m_Marker->InteractiveOff();
// Camera-orientation widget (VTK ≥ 9)
#if VTK_MAJOR_VERSION >= 9
m_CameraWidget = vtkCameraOrientationWidget::New();
m_CameraWidget->SetParentRenderer(m_Renderer);
m_CameraWidget->SetInteractor(iren);
m_CameraWidget->On();
#endif
m_Renderer->SetBackground(0.15, 0.15, 0.15);
m_Renderer->ResetCamera();
// Common setup
Viewport::SetupPipeline(rw->GetInteractor());
}
// ── Public API ────────────────────────────────────────────────────────────────
void QViewport::Render()
{
m_VtkWidget->renderWindow()->Render();
}
void QViewport::Reset()
{
ZoomAuto();
Render();
}
void QViewport::ZoomAuto()
{
m_Renderer->ResetCameraClippingRange();
m_Renderer->ResetCamera();
}
void QViewport::AddPuppet(Puppet& prop)
{
prop.ConnectRenderer(m_Renderer);
prop.ConnectInteractor(GetInteractor());
Render();
}
void QViewport::RemovePuppet(Puppet& prop)
{
prop.DisconnectRenderer(m_Renderer);
Render();
}
void QViewport::addProp(vtkProp* prop)
{
m_Renderer->AddActor(prop);
Render();
}
void QViewport::RemoveProp(vtkProp* prop)
{
m_Renderer->RemoveViewProp(prop);
Render();
}
void QViewport::AddWidget(vtk3DWidget* /*widget*/)
{
// vtk3DWidget integration can be added here if needed
UpdateGrid();
if (m_VtkWidget && m_VtkWidget->renderWindow())
m_VtkWidget->renderWindow()->Render();
}
vtkRenderWindow* QViewport::GetRenderWindow()

View File

@@ -12,6 +12,8 @@
#include "uLibVtkInterface.h"
#include "vtkViewport.h"
class vtkProp;
class vtk3DWidget;
class vtkRenderWindowInteractor;
@@ -25,42 +27,24 @@ namespace Vtk {
* directly into the Qt application (no separate VTK window).
* Puppets and actors are added to the embedded renderer.
*/
class QViewport : public QWidget {
class QViewport : public QWidget, public Viewport {
Q_OBJECT
public:
explicit QViewport(QWidget* parent = nullptr);
virtual ~QViewport();
// Render scene
void Render();
void Reset();
void ZoomAuto();
// Puppet / prop management
void AddPuppet(Puppet &prop);
void RemovePuppet(Puppet &prop);
void addProp(vtkProp *prop);
void RemoveProp(vtkProp *prop);
// Widget integration
void AddWidget(vtk3DWidget *widget);
virtual void Render() override;
// Direct access to VTK internals
vtkRenderer* GetRenderer() { return m_Renderer; }
vtkRenderWindow* GetRenderWindow();
vtkRenderWindowInteractor* GetInteractor();
vtkCornerAnnotation* GetAnnotation() { return m_Annotation; }
vtkCameraOrientationWidget* GetCameraWidget(){ return m_CameraWidget; }
virtual vtkRenderWindow* GetRenderWindow() override;
virtual vtkRenderWindowInteractor* GetInteractor() override;
QVTKOpenGLNativeWidget* GetWidget() { return m_VtkWidget; }
private:
void SetupPipeline();
QVTKOpenGLNativeWidget* m_VtkWidget;
vtkRenderer* m_Renderer;
vtkCornerAnnotation* m_Annotation;
vtkOrientationMarkerWidget* m_Marker;
vtkCameraOrientationWidget* m_CameraWidget;
};
} // namespace Vtk

228
src/Vtk/vtkViewport.cpp Normal file
View File

@@ -0,0 +1,228 @@
#include "vtkViewport.h"
#include <vtkAxes.h>
#include <vtkAxesActor.h>
#include <vtkCamera.h>
#include <vtkCameraOrientationWidget.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkObjectFactory.h>
#include <vtkPlaneSource.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkNew.h>
#include <vtkTextProperty.h>
#include <vtkPolyDataMapper.h>
#include <vtkNamedColors.h>
#include <vtkProperty.h>
#include <vtkCallbackCommand.h>
#include <vtkMath.h>
#include <vtkActor.h>
#include <cmath>
namespace uLib {
namespace Vtk {
Viewport::Viewport()
: m_Renderer(vtkRenderer::New())
, m_Annotation(vtkCornerAnnotation::New())
, m_Marker(vtkOrientationMarkerWidget::New())
, m_CameraWidget(nullptr)
, m_Colors(vtkNamedColors::New())
{
}
Viewport::~Viewport()
{
if (m_Renderer) {
m_Renderer->RemoveAllViewProps();
m_Renderer->Clear();
}
if (m_Annotation) m_Annotation->Delete();
if (m_Marker) m_Marker->Delete();
if (m_CameraWidget) m_CameraWidget->Delete();
if (m_Renderer) m_Renderer->Delete();
if (m_Colors) m_Colors->Delete();
}
void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren)
{
if (!iren) return;
// Trackball-camera interaction style
vtkNew<vtkInteractorStyleTrackballCamera> style;
iren->SetInteractorStyle(style);
// Corner annotation
m_Annotation->GetTextProperty()->SetColor(1, 1, 1);
m_Annotation->GetTextProperty()->SetFontFamilyToArial();
m_Annotation->GetTextProperty()->SetOpacity(0.5);
m_Annotation->SetMaximumFontSize(10);
m_Annotation->SetText(0, "uLib VTK Viewer - OpenCMT all right reserved.");
m_Renderer->AddViewProp(m_Annotation);
// Orientation axes marker (bottom-left corner)
vtkNew<vtkAxesActor> axes;
m_Marker->SetInteractor(iren);
m_Marker->SetOrientationMarker(axes);
m_Marker->SetViewport(0.0, 0.0, 0.2, 0.2);
m_Marker->SetEnabled(true);
m_Marker->InteractiveOff();
// Grid Plane centered at (0,0,0)
m_GridSource = vtkSmartPointer<vtkPlaneSource>::New();
m_GridActor = vtkSmartPointer<vtkActor>::New();
vtkNew<vtkPolyDataMapper> gridMapper;
gridMapper->SetInputConnection(m_GridSource->GetOutputPort());
m_GridActor->SetMapper(gridMapper);
m_GridActor->GetProperty()->SetRepresentationToWireframe();
m_GridActor->GetProperty()->SetColor(0.4, 0.4, 0.4);
m_GridActor->GetProperty()->SetLighting(0);
m_GridActor->GetProperty()->SetOpacity(0.5);
m_GridActor->PickableOff();
m_Renderer->AddActor(m_GridActor);
// Global Origin Axes
m_OriginAxes = vtkSmartPointer<vtkAxes>::New();
m_OriginAxes->SetScaleFactor(1.0); // will be updated
vtkNew<vtkPolyDataMapper> axesMapper;
axesMapper->SetInputConnection(m_OriginAxes->GetOutputPort());
m_OriginAxesActor = vtkSmartPointer<vtkActor>::New();
m_OriginAxesActor->SetMapper(axesMapper);
m_OriginAxesActor->PickableOff();
m_Renderer->AddActor(m_OriginAxesActor);
UpdateGrid();
// Observe interactor to update grid during interaction
vtkNew<vtkCallbackCommand> interactionCallback;
interactionCallback->SetClientData(this);
interactionCallback->SetCallback([](vtkObject*, unsigned long, void* clientdata, void*){
static_cast<Viewport*>(clientdata)->UpdateGrid();
});
iren->AddObserver(vtkCommand::InteractionEvent, interactionCallback);
m_Renderer->GetActiveCamera()->AddObserver(vtkCommand::ModifiedEvent, interactionCallback);
// Camera-orientation widget (VTK >= 9)
#if VTK_MAJOR_VERSION >= 9
m_CameraWidget = vtkCameraOrientationWidget::New();
m_CameraWidget->SetParentRenderer(m_Renderer);
m_CameraWidget->SetInteractor(iren);
m_CameraWidget->On();
#endif
m_Renderer->SetBackground(0.15, 0.15, 0.15);
m_Renderer->ResetCamera();
}
void Viewport::Reset()
{
ZoomAuto();
Render();
}
void Viewport::ZoomAuto()
{
if (m_Renderer) {
m_Renderer->ResetCameraClippingRange();
m_Renderer->ResetCamera();
}
}
void Viewport::AddPuppet(Puppet& prop)
{
prop.ConnectRenderer(m_Renderer);
prop.ConnectInteractor(GetInteractor());
Render();
}
void Viewport::RemovePuppet(Puppet& prop)
{
prop.DisconnectRenderer(m_Renderer);
Render();
}
void Viewport::addProp(vtkProp* prop)
{
if (m_Renderer) {
m_Renderer->AddActor(prop);
Render();
}
}
void Viewport::RemoveProp(vtkProp* prop)
{
if (m_Renderer) {
m_Renderer->RemoveViewProp(prop);
Render();
}
}
void Viewport::UpdateGrid()
{
if (!m_Renderer || !m_GridSource) return;
vtkCamera* camera = m_Renderer->GetActiveCamera();
if (!camera) return;
// Determine the "scale" of the view (how many units are visible vertically)
double viewHeight;
if (camera->GetParallelProjection()) {
viewHeight = 2.0 * camera->GetParallelScale();
} else {
double distance = camera->GetDistance();
// ViewAngle is height angle in degrees
double angleRad = camera->GetViewAngle() * vtkMath::Pi() / 180.0;
viewHeight = 2.0 * distance * std::tan(angleRad / 2.0);
}
if (viewHeight <= 0) viewHeight = 1.0;
// We want roughly 5-15 grid divisions visible.
// Spacing should be a power of 10 (1mm, 1cm, 10cm, 1m, 10m...)
double log10Spacing = std::floor(std::log10(viewHeight / 5.0));
double spacing = std::pow(10.0, log10Spacing);
// Get current focal point to center the grid near what we're looking at
double focalPoint[3];
camera->GetFocalPoint(focalPoint);
// Align center to spacing
double centerX = std::round(focalPoint[0] / spacing) * spacing;
double centerY = std::round(focalPoint[1] / spacing) * spacing;
// Number of lines: enough to cover the screen even if aspect ratio is wide
// or if we rotate. 20x20 is usually plenty.
int numLines = 20;
double halfSize = (numLines / 2.0) * spacing;
double xmin = centerX - halfSize;
double xmax = centerX + halfSize;
double ymin = centerY - halfSize;
double ymax = centerY + halfSize;
// Update Plane Source
m_GridSource->SetOrigin(xmin, ymin, 0.0);
m_GridSource->SetPoint1(xmax, ymin, 0.0);
m_GridSource->SetPoint2(xmin, ymax, 0.0);
m_GridSource->SetXResolution(numLines);
m_GridSource->SetYResolution(numLines);
m_GridSource->Update();
if (m_OriginAxes) {
m_OriginAxes->SetScaleFactor(spacing);
}
}
} // namespace Vtk
} // namespace uLib

76
src/Vtk/vtkViewport.h Normal file
View File

@@ -0,0 +1,76 @@
#ifndef ULIB_VTK_VIEWPORT_H
#define ULIB_VTK_VIEWPORT_H
#include "uLibVtkInterface.h"
#include <vtkCornerAnnotation.h>
#include <vtkOrientationMarkerWidget.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkVersion.h>
class vtkAxes;
class vtkProp;
class vtk3DWidget;
class vtkRenderWindow;
class vtkRenderWindowInteractor;
class vtkCameraOrientationWidget;
class vtkPlaneSource;
class vtkActor;
class vtkNamedColors;
class vtkCamera;
namespace uLib {
namespace Vtk {
/**
* @class Viewport
* @brief Base class for VTK viewports, providing core rendering and prop management.
*/
class Viewport {
public:
Viewport();
virtual ~Viewport();
// Render scene
virtual void Render() = 0;
void Reset();
void ZoomAuto();
// Puppet / prop management
void AddPuppet(Puppet &prop);
void RemovePuppet(Puppet &prop);
void addProp(vtkProp *prop);
void RemoveProp(vtkProp *prop);
// Widget integration
void AddWidget(vtk3DWidget *widget);
// Direct access to VTK internals
vtkRenderer* GetRenderer() { return m_Renderer; }
virtual vtkRenderWindow* GetRenderWindow() = 0;
virtual vtkRenderWindowInteractor* GetInteractor() = 0;
vtkCornerAnnotation* GetAnnotation() { return m_Annotation; }
vtkCameraOrientationWidget* GetCameraWidget(){ return m_CameraWidget; }
protected:
void SetupPipeline(vtkRenderWindowInteractor* iren);
void UpdateGrid();
vtkRenderer* m_Renderer;
vtkCornerAnnotation* m_Annotation;
vtkOrientationMarkerWidget* m_Marker;
vtkCameraOrientationWidget* m_CameraWidget;
vtkSmartPointer<vtkPlaneSource> m_GridSource;
vtkSmartPointer<vtkActor> m_GridActor;
vtkSmartPointer<vtkAxes> m_OriginAxes;
vtkSmartPointer<vtkActor> m_OriginAxesActor;
vtkNamedColors* m_Colors;
};
} // namespace Vtk
} // namespace uLib
#endif // ULIB_VTK_VIEWPORT_H