From 7d4acaef6df23828413eac17644e8530a6ce5f9c Mon Sep 17 00:00:00 2001 From: AndreaRigoni Date: Wed, 25 Mar 2026 16:18:07 +0000 Subject: [PATCH] refactor using pimpl and fix test --- CMakeLists.txt | 1 + src/Core/DataAllocator.h | 33 +++- src/Core/Object.cpp | 25 ++- src/Core/Object.h | 7 +- src/Core/testing/MutexTest.cpp | 1 + src/Math/ContainerBox.h | 3 +- src/Math/VoxImage.h | 16 +- src/Math/testing/CylinderTest.cpp | 6 +- src/Vtk/Math/vtkContainerBox.cpp | 41 ++-- src/Vtk/Math/vtkContainerBox.h | 15 +- src/Vtk/uLibVtkViewer.cpp | 56 +++--- src/Vtk/uLibVtkViewer.h | 51 +---- src/Vtk/vtkHandlerWidget.cpp | 305 ++++++++++++++++-------------- src/Vtk/vtkHandlerWidget.h | 26 +-- src/Vtk/vtkQViewport.cpp | 4 +- src/Vtk/vtkViewport.cpp | 252 +++++++++++++----------- src/Vtk/vtkViewport.h | 49 ++--- 17 files changed, 479 insertions(+), 412 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ae740a..c6e0d82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,6 +103,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_WARNING_OPTION}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -UULIB_SERIALIZATION_ON -Wno-cpp") # CTEST framework +set(CTEST_PROJECT_NAME "uLib") include(CTest) enable_testing() diff --git a/src/Core/DataAllocator.h b/src/Core/DataAllocator.h index 7e5a7a3..258e092 100644 --- a/src/Core/DataAllocator.h +++ b/src/Core/DataAllocator.h @@ -52,6 +52,7 @@ public: else m_RamData = static_cast(::operator new(m_Size * sizeof(T))); } + std::cout << "DataAllocator Constructor: ptr=" << m_RamData << " size=" << m_Size << " own=" << m_OwnsObjects << std::endl; } DataAllocator(const DataAllocator &other) @@ -63,7 +64,12 @@ public: m_RamData = new T[m_Size]; else m_RamData = static_cast(::operator new(m_Size * sizeof(T))); - std::memcpy(m_RamData, other.m_RamData, m_Size * sizeof(T)); + + if (m_OwnsObjects) { + std::copy(other.m_RamData, other.m_RamData + m_Size, m_RamData); + } else { + std::memcpy(m_RamData, other.m_RamData, m_Size * sizeof(T)); + } } #ifdef USE_CUDA if (other.m_VramData) { @@ -73,14 +79,17 @@ public: } #endif } + std::cout << "DataAllocator CopyConstructor: from=" << other.m_RamData << " to=" << m_RamData << " size=" << m_Size << " own=" << m_OwnsObjects << std::endl; } ~DataAllocator() { + std::cout << "DataAllocator Destructor: ptr=" << m_RamData << " size=" << m_Size << " own=" << m_OwnsObjects << std::endl; if (m_RamData) { if (m_OwnsObjects) delete[] m_RamData; else ::operator delete(m_RamData); + m_RamData = nullptr; } #ifdef USE_CUDA if (m_VramData) { @@ -91,6 +100,13 @@ public: DataAllocator &operator=(const DataAllocator &other) { if (this != &other) { + if (m_Size == other.m_Size && m_OwnsObjects != other.m_OwnsObjects) { + // Ownership changed but size is same: we must force reallocation + // to avoid using the wrong delete operator later. + size_t oldSize = m_Size; + m_Size = 0; + resize(oldSize); // This will free the old buffer with the OLD ownership + } m_OwnsObjects = other.m_OwnsObjects; resize(other.m_Size); m_Device = other.m_Device; @@ -101,7 +117,11 @@ public: else m_RamData = static_cast(::operator new(m_Size * sizeof(T))); } - std::memcpy(m_RamData, other.m_RamData, m_Size * sizeof(T)); + if (m_OwnsObjects) { + std::copy(other.m_RamData, other.m_RamData + m_Size, m_RamData); + } else { + std::memcpy(m_RamData, other.m_RamData, m_Size * sizeof(T)); + } } #ifdef USE_CUDA if (other.m_VramData) { @@ -112,6 +132,7 @@ public: } #endif } + std::cout << "DataAllocator AssigmentOp: otherPtr=" << other.m_RamData << " thisPtr=" << m_RamData << " size=" << m_Size << " own=" << m_OwnsObjects << std::endl; return *this; } @@ -152,6 +173,8 @@ public: if (m_Size == size) return; + std::cout << "DataAllocator Resize: from=" << m_Size << " to=" << size << " ptr=" << m_RamData << " own=" << m_OwnsObjects << std::endl; + T *newRam = nullptr; T *newVram = nullptr; @@ -162,7 +185,11 @@ public: newRam = static_cast(::operator new(size * sizeof(T))); if (m_RamData) { - std::memcpy(newRam, m_RamData, std::min(m_Size, size) * sizeof(T)); + if (m_OwnsObjects) { + std::copy(m_RamData, m_RamData + std::min(m_Size, size), newRam); + } else { + std::memcpy(newRam, m_RamData, std::min(m_Size, size) * sizeof(T)); + } } #ifdef USE_CUDA diff --git a/src/Core/Object.cpp b/src/Core/Object.cpp index e3e1ef1..4be2f46 100644 --- a/src/Core/Object.cpp +++ b/src/Core/Object.cpp @@ -61,8 +61,8 @@ public: }; std::string m_InstanceName; - Vector sigv; - Vector slov; + std::vector sigv; + std::vector slov; std::vector m_Properties; std::vector m_DynamicProperties; bool m_SignalsBlocked; @@ -117,15 +117,30 @@ template void Object::serialize(Archive::log_archive &, const unsigned int); Object::Object() : d(new ObjectPrivate) { d->m_SignalsBlocked = false; + std::cout << "Object Constructor: created d=" << d << std::endl; } Object::Object(const Object ©) : d(new ObjectPrivate) { if (copy.d) { d->m_InstanceName = copy.d->m_InstanceName; d->m_SignalsBlocked = copy.d->m_SignalsBlocked; } + std::cout << "Object CopyConstructor: created d=" << d << " from copy.d=" << copy.d << std::endl; +} + +Object& Object::operator=(const Object &other) { + // Intentionally does NOT share 'd'. Each Object owns its own ObjectPrivate. + // Without this, the compiler-generated operator= would copy the 'd' pointer, + // causing two objects to share the same ObjectPrivate. When both are + // destroyed, 'd' would be deleted twice, corrupting the heap. + if (this != &other && other.d) { + d->m_InstanceName = other.d->m_InstanceName; + d->m_SignalsBlocked = other.d->m_SignalsBlocked; + } + return *this; } Object::~Object() { + std::cout << "Object Destructor: deleting d=" << d << " name=" << d->m_InstanceName << std::endl; for (auto* p : d->m_DynamicProperties) { delete p; } @@ -135,6 +150,7 @@ Object::~Object() { void Object::DeepCopy(const Object ©) { if (this == ©) return; if (copy.d) d->m_InstanceName = copy.d->m_InstanceName; + std::cout << "Object DeepCopy: from d=" << copy.d << " to d=" << d << std::endl; // Note: signals, slots and properties are intentionally not copied // to maintain instance uniquely and avoid duplicate registrations. this->Updated(); @@ -161,9 +177,8 @@ void Object::LoadConfig(std::istream &is, int version) { void Object::PrintSelf(std::ostream &o) const { o << "OBJECT signals: ------------------\n"; - Vector::Iterator itr; - for (itr = d->sigv.begin(); itr < d->sigv.end(); itr++) { - o << " signal:[ " << itr->sigstr << " ]\n"; + for (const auto& sig : d->sigv) { + o << " signal:[ " << sig.sigstr << " ]\n"; } o << "--------------------------------------\n\n"; } diff --git a/src/Core/Object.h b/src/Core/Object.h index 46a62cf..260a9df 100644 --- a/src/Core/Object.h +++ b/src/Core/Object.h @@ -75,7 +75,7 @@ public: Object(); Object(const Object ©); - ~Object(); + virtual ~Object(); virtual const char * GetClassName() const { return "Object"; } @@ -227,10 +227,7 @@ public: void PrintSelf(std::ostream &o) const; - inline const Object &operator=(const Object ©) { - this->DeepCopy(copy); - return *this; - } + Object &operator=(const Object &other); private: bool addSignalImpl(SignalBase *sig, GenericMFPtr fptr, const char *name); diff --git a/src/Core/testing/MutexTest.cpp b/src/Core/testing/MutexTest.cpp index 9a2d648..8c2f1fd 100644 --- a/src/Core/testing/MutexTest.cpp +++ b/src/Core/testing/MutexTest.cpp @@ -1,5 +1,6 @@ #include "Core/Monitor.h" #include +#include #include #include #include diff --git a/src/Math/ContainerBox.h b/src/Math/ContainerBox.h index 90146a7..dc8fba4 100644 --- a/src/Math/ContainerBox.h +++ b/src/Math/ContainerBox.h @@ -85,10 +85,11 @@ public: * @param copy The ContainerBox instance to copy from. */ ContainerBox(const ContainerBox ©) - : m_LocalT(this), // BaseClass is Parent of m_LocalTransform + : m_LocalT(copy.m_LocalT), // Copy local transform state AffineTransform(copy), p_Size(this, "Size", copy.p_Size), p_Origin(this, "Origin", copy.p_Origin) { + m_LocalT.SetParent(this); // Reset parent to the new object Object::connect(&p_Size, &Property::PropertyChanged, this, &ContainerBox::SyncSize); Object::connect(&p_Origin, &Property::PropertyChanged, this, &ContainerBox::SyncOrigin); } diff --git a/src/Math/VoxImage.h b/src/Math/VoxImage.h index 2b9f227..4dfb8c4 100644 --- a/src/Math/VoxImage.h +++ b/src/Math/VoxImage.h @@ -109,8 +109,20 @@ public: VoxImage(const Vector3i &size); - VoxImage(const VoxImage ©) : BaseClass(copy) { - this->m_Data = copy.m_Data; + // Use compiler-generated copy constructor and assignment operator + + VoxImage& operator=(const VoxImage& other) { + if (this != &other) { + // Copy the base class non-virtual parts (dims, spacing, position, etc.) + // WITHOUT going through the virtual SetDims chain (which would call + // m_Data.resize() THEN DataAllocator::operator= will resize again → double-free). + // Instead, directly copy DataAllocator and update the StructuredGrid state. + this->m_Data = other.m_Data; + StructuredGrid::SetDims(other.GetDims()); + this->SetSpacing(other.GetSpacing()); + this->SetPosition(other.GetPosition()); + } + return *this; } inline DataAllocator &Data() { return this->m_Data; } diff --git a/src/Math/testing/CylinderTest.cpp b/src/Math/testing/CylinderTest.cpp index 9f8575f..6c78773 100644 --- a/src/Math/testing/CylinderTest.cpp +++ b/src/Math/testing/CylinderTest.cpp @@ -52,7 +52,7 @@ int main() // Test 1: Basic identity transformation and cylinder parameters { - Cylinder cyl(2.0, 10.0); + Cylinder cyl(2.0, 10.0, 2); std::cout << "Cyl R=" << cyl.GetRadius() << " H=" << cyl.GetHeight() << std::endl; std::cout << "Cyl World Matrix:\n" << cyl.GetWorldMatrix() << std::endl; @@ -82,7 +82,7 @@ int main() // Test 2: Translation { - Cylinder cyl(1.0, 2.0); + Cylinder cyl(1.0, 2.0, 2); cyl.SetPosition(Vector3f(10, 20, 30)); // Local base origin (0, 0, 0) -> World (10, 20, 30) @@ -96,7 +96,7 @@ int main() // Test 3: Rotation and complex mapping { - Cylinder cyl(5.0, 20.0); + Cylinder cyl(5.0, 20.0, 2); cyl.SetPosition(Vector3f(1.0, 2.0, 3.0)); // Rotate 90 degrees around X: Local Y becomes World Z, Local Z becomes World -Y cyl.Rotate(M_PI/2.0, Vector3f(1, 0, 0)); diff --git a/src/Vtk/Math/vtkContainerBox.cpp b/src/Vtk/Math/vtkContainerBox.cpp index ecb893e..ee5bfeb 100644 --- a/src/Vtk/Math/vtkContainerBox.cpp +++ b/src/Vtk/Math/vtkContainerBox.cpp @@ -47,18 +47,25 @@ namespace uLib { namespace Vtk { +struct ContainerBoxData { + vtkActor *m_Cube; + vtkActor *m_Axes; + + ContainerBoxData() : m_Cube(vtkActor::New()), m_Axes(vtkActor::New()) {} + ~ContainerBoxData() { + m_Cube->Delete(); + m_Axes->Delete(); + } +}; + vtkContainerBox::vtkContainerBox(vtkContainerBox::Content *content) - : m_Cube(vtkActor::New()), m_Axes(vtkActor::New()), - // m_Pivot(vtkActor::New()), - m_Content(content) { + : d(new ContainerBoxData()), m_Content(content) { this->InstallPipe(); Object::connect(m_Content, &Content::Updated, this, &vtkContainerBox::contentUpdate); } vtkContainerBox::~vtkContainerBox() { - m_Cube->Delete(); - m_Axes->Delete(); -// m_Pivot->Delete(); + delete d; } vtkPolyData *vtkContainerBox::GetPolyData() const { @@ -83,8 +90,8 @@ void vtkContainerBox::contentUpdate() { vmat = mat; } - m_Cube->SetUserMatrix(nullptr); - m_Axes->SetUserMatrix(nullptr); + d->m_Cube->SetUserMatrix(nullptr); + d->m_Axes->SetUserMatrix(nullptr); Matrix4f transform = m_Content->GetMatrix(); Matrix4fToVtk(transform, vmat); @@ -143,9 +150,9 @@ void vtkContainerBox::InstallPipe() { cube->SetBounds(0, 1, 0, 1, 0, 1); mapper->SetInputConnection(cube->GetOutputPort()); mapper->Update(); - m_Cube->SetMapper(mapper); - m_Cube->GetProperty()->SetRepresentationToWireframe(); - m_Cube->GetProperty()->SetAmbient(0.7); + d->m_Cube->SetMapper(mapper); + d->m_Cube->GetProperty()->SetRepresentationToWireframe(); + d->m_Cube->GetProperty()->SetAmbient(0.7); // AXES // vtkSmartPointer axes = vtkSmartPointer::New(); @@ -153,10 +160,10 @@ void vtkContainerBox::InstallPipe() { mapper = vtkSmartPointer::New(); mapper->SetInputConnection(axes->GetOutputPort()); mapper->Update(); - m_Axes->SetMapper(mapper); - m_Axes->GetProperty()->SetLineWidth(3); - m_Axes->GetProperty()->SetAmbient(0.4); - m_Axes->GetProperty()->SetSpecular(0); + d->m_Axes->SetMapper(mapper); + d->m_Axes->GetProperty()->SetLineWidth(3); + d->m_Axes->GetProperty()->SetAmbient(0.4); + d->m_Axes->GetProperty()->SetSpecular(0); // PIVOT // axes = vtkSmartPointer::New(); @@ -165,8 +172,8 @@ void vtkContainerBox::InstallPipe() { mapper->SetInputConnection(axes->GetOutputPort()); mapper->Update(); - this->SetProp(m_Cube); - this->SetProp(m_Axes); + this->SetProp(d->m_Cube); + this->SetProp(d->m_Axes); vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp()); if (root) { diff --git a/src/Vtk/Math/vtkContainerBox.h b/src/Vtk/Math/vtkContainerBox.h index 95e10ac..6656306 100644 --- a/src/Vtk/Math/vtkContainerBox.h +++ b/src/Vtk/Math/vtkContainerBox.h @@ -29,12 +29,15 @@ #include "Math/ContainerBox.h" #include "uLibVtkInterface.h" #include "vtkPolydata.h" -#include #include +class vtkActor; + namespace uLib { namespace Vtk { +struct ContainerBoxData; + class vtkContainerBox : public Puppet, public Polydata { typedef ContainerBox Content; @@ -51,13 +54,9 @@ public: protected: virtual void InstallPipe(); - vtkActor *m_Cube; - vtkActor *m_Axes; - // vtkActor *m_Pivot; - - Content *m_Content; - bool m_BlockUpdate = false; - // boost::signals2::connection m_Connection; + struct ContainerBoxData *d; + Content *m_Content; + bool m_BlockUpdate = false; }; } // namespace Vtk diff --git a/src/Vtk/uLibVtkViewer.cpp b/src/Vtk/uLibVtkViewer.cpp index 5b2889f..a1cdd43 100644 --- a/src/Vtk/uLibVtkViewer.cpp +++ b/src/Vtk/uLibVtkViewer.cpp @@ -67,25 +67,33 @@ vtkStandardNewMacro(vtkInteractorStyleNoSpin); namespace uLib { namespace Vtk { +struct ViewerData { + vtkRenderWindow *m_RenderWindow; + vtkSmartPointer m_GridButton; + + ViewerData() : m_RenderWindow(vtkRenderWindow::New()) {} + ~ViewerData() { m_RenderWindow->Delete(); } +}; + //////////////////////////////////////////////////////////////////////////////// ///// VTK VIEWER ////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// Viewer::Viewer() - : Viewport(), m_RenderWindow(vtkRenderWindow::New()) { + : Viewport(), d(new ViewerData()) { InstallPipe(); } Viewer::~Viewer() { UninstallPipe(); - m_RenderWindow->Delete(); + delete d; } void Viewer::InstallPipe() { - m_RenderWindow->AddRenderer(m_Renderer); - m_RenderWindow->SetSize(600,600); + d->m_RenderWindow->AddRenderer(this->GetRenderer()); + d->m_RenderWindow->SetSize(600,600); vtkSmartPointer renderWindowInteractor = vtkSmartPointer::New(); - renderWindowInteractor->SetRenderWindow(m_RenderWindow); + renderWindowInteractor->SetRenderWindow(d->m_RenderWindow); // Common setup Viewport::SetupPipeline(renderWindowInteractor); @@ -99,21 +107,21 @@ void Viewer::InstallPipe() { renderWindowInteractor->SetInteractorStyle(style); // Must be rendered here in Vtk-6.0 or seg-fault // - m_RenderWindow->Render(); + d->m_RenderWindow->Render(); } void Viewer::UninstallPipe() { - if (m_Renderer) { - m_Renderer->RemoveAllViewProps(); + if (GetRenderer()) { + GetRenderer()->RemoveAllViewProps(); } } void Viewer::Render() { - if (m_RenderWindow) - m_RenderWindow->Render(); + if (d->m_RenderWindow) + d->m_RenderWindow->Render(); } -vtkSmartPointer +vtkCameraOrientationWidget * Viewer::MakeCameraOrientationWidget(vtkRenderWindowInteractor *interactor, vtkRenderer *renderer) { vtkSmartPointer widget = @@ -125,7 +133,7 @@ Viewer::MakeCameraOrientationWidget(vtkRenderWindowInteractor *interactor, } void Viewer::SetupGridButton() { - if (!m_RenderWindow || !m_RenderWindow->GetInteractor()) return; + if (!d->m_RenderWindow || !d->m_RenderWindow->GetInteractor()) return; // Create procedural textures for the button using canvas vtkNew canvas; @@ -158,9 +166,9 @@ void Viewer::SetupGridButton() { rep->SetButtonTexture(0, imgOff); rep->SetButtonTexture(1, imgOn); - m_GridButton = vtkSmartPointer::New(); - m_GridButton->SetInteractor(m_RenderWindow->GetInteractor()); - m_GridButton->SetRepresentation(rep); + d->m_GridButton = vtkSmartPointer::New(); + d->m_GridButton->SetInteractor(d->m_RenderWindow->GetInteractor()); + d->m_GridButton->SetRepresentation(rep); // Position it initially UpdateGridButtonPosition(); @@ -172,7 +180,7 @@ void Viewer::SetupGridButton() { auto* v = static_cast(clientdata); v->UpdateGridButtonPosition(); }); - m_RenderWindow->AddObserver(vtkCommand::ModifiedEvent, resizeCallback); + d->m_RenderWindow->AddObserver(vtkCommand::ModifiedEvent, resizeCallback); // Callback for state change vtkNew stateCallback; @@ -184,19 +192,19 @@ void Viewer::SetupGridButton() { v->SetGridVisible(r->GetState() == 1); }); - m_GridButton->AddObserver(vtkCommand::StateChangedEvent, stateCallback); - m_GridButton->On(); + d->m_GridButton->AddObserver(vtkCommand::StateChangedEvent, stateCallback); + d->m_GridButton->On(); // Set initial state rep->SetState(GetGridVisible() ? 1 : 0); } void Viewer::UpdateGridButtonPosition() { - if (!m_GridButton || !m_RenderWindow) return; - auto* rep = vtkTexturedButtonRepresentation2D::SafeDownCast(m_GridButton->GetRepresentation()); + if (!d->m_GridButton || !d->m_RenderWindow) return; + auto* rep = vtkTexturedButtonRepresentation2D::SafeDownCast(d->m_GridButton->GetRepresentation()); if (!rep) return; - int *sz = m_RenderWindow->GetSize(); + int *sz = d->m_RenderWindow->GetSize(); if (sz[0] == 0 || sz[1] == 0) return; // Window not yet sized or hidden int margin_rigth = 23; @@ -207,12 +215,12 @@ void Viewer::UpdateGridButtonPosition() { rep->PlaceWidget(bds); } -void Viewer::Start() { m_RenderWindow->GetInteractor()->Start(); } +void Viewer::Start() { d->m_RenderWindow->GetInteractor()->Start(); } -vtkRenderWindow *Viewer::GetRenderWindow() { return m_RenderWindow; } +vtkRenderWindow *Viewer::GetRenderWindow() { return d->m_RenderWindow; } vtkRenderWindowInteractor *Viewer::GetInteractor() { - return m_RenderWindow->GetInteractor(); + return d->m_RenderWindow->GetInteractor(); } } // namespace Vtk diff --git a/src/Vtk/uLibVtkViewer.h b/src/Vtk/uLibVtkViewer.h index e5e2b46..574f525 100644 --- a/src/Vtk/uLibVtkViewer.h +++ b/src/Vtk/uLibVtkViewer.h @@ -1,44 +1,17 @@ -/*////////////////////////////////////////////////////////////////////////////// -// CMT Cosmic Muon Tomography project ////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - - Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova - All rights reserved - - Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it > - - ------------------------------------------------------------------ - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. - -//////////////////////////////////////////////////////////////////////////////*/ - #ifndef ULIBVTKVIEWER_H #define ULIBVTKVIEWER_H -#include - #include "vtkViewport.h" +class vtkRenderWindow; +class vtkRenderWindowInteractor; +class vtkRenderer; +class vtkCameraOrientationWidget; + namespace uLib { namespace Vtk { -// template class Tie { -// public: -// void DoAction() { -// std::cout << "Tie::DoAction -> generic Tie does nothing\n"; -// } -// }; +struct ViewerData; class Viewer : public Viewport { @@ -49,9 +22,9 @@ public: // Render scene virtual void Render() override; - static vtkSmartPointer + static vtkCameraOrientationWidget * MakeCameraOrientationWidget(vtkRenderWindowInteractor *interactor, - vtkRenderer *renderer); + vtkRenderer *renderer); void Start(); @@ -65,15 +38,9 @@ private: void SetupGridButton(); void UpdateGridButtonPosition(); - vtkRenderWindow *m_RenderWindow; - vtkSmartPointer m_GridButton; + struct ViewerData *d; }; -// template <> class Tie { -// public: -// void DoAction() { std::cout << " VIEWER TIE !!! \n"; } -// }; - } // namespace Vtk } // namespace uLib diff --git a/src/Vtk/vtkHandlerWidget.cpp b/src/Vtk/vtkHandlerWidget.cpp index 8bbf030..6919ef2 100644 --- a/src/Vtk/vtkHandlerWidget.cpp +++ b/src/Vtk/vtkHandlerWidget.cpp @@ -25,6 +25,7 @@ #include "vtkHandlerWidget.h" #include +#include #include #include #include @@ -51,32 +52,60 @@ namespace uLib { namespace Vtk { +struct HandlerWidgetData { + vtkSmartPointer<::vtkRenderer> m_OverlayRenderer; + ::vtkProp *m_HighlightedProp; + + // Visual components // + vtkSmartPointer<::vtkActor> m_AxesX, m_AxesY, m_AxesZ; // Arrows + vtkSmartPointer<::vtkActor> m_RotX, m_RotY, m_RotZ; // Rings + vtkSmartPointer<::vtkActor> m_RotCam; // Camera ring + vtkSmartPointer<::vtkActor> m_ScaleX, m_ScaleY, m_ScaleZ; // Cubes + + vtkSmartPointer<::vtkPlane> m_ClipPlane; + + vtkSmartPointer<::vtkCellPicker> m_Picker; + vtkSmartPointer<::vtkTransform> m_InitialTransform; + + std::vector> m_TransformChain; + vtkSmartPointer<::vtkMatrix4x4> m_BaseMatrix; + + HandlerWidgetData() { + m_Picker = vtkSmartPointer<::vtkCellPicker>::New(); + m_InitialTransform = vtkSmartPointer<::vtkTransform>::New(); + m_ClipPlane = vtkSmartPointer<::vtkPlane>::New(); + m_OverlayRenderer = vtkSmartPointer<::vtkRenderer>::New(); + m_BaseMatrix = vtkSmartPointer<::vtkMatrix4x4>::New(); + m_HighlightedProp = nullptr; + } +}; + vtkStandardNewMacro(vtkHandlerWidget); -vtkHandlerWidget::vtkHandlerWidget() { +vtkHandlerWidget::vtkHandlerWidget() : d(new HandlerWidgetData()) { this->Interaction = IDLE; - this->m_Picker = vtkSmartPointer<::vtkCellPicker>::New(); - this->m_Picker->SetTolerance(0.01); // Increased tolerance for thin gizmos - this->m_InitialTransform = vtkSmartPointer<::vtkTransform>::New(); + d->m_Picker->SetTolerance(0.01); // Increased tolerance for thin gizmos this->EventCallbackCommand->SetCallback(vtkHandlerWidget::ProcessEvents); this->EventCallbackCommand->SetClientData(this); this->m_Frame = LOCAL; - this->m_HighlightedProp = nullptr; - this->m_ClipPlane = vtkSmartPointer<::vtkPlane>::New(); - this->m_OverlayRenderer = vtkSmartPointer<::vtkRenderer>::New(); - this->m_OverlayRenderer->SetLayer(1); - this->m_OverlayRenderer->EraseOff(); - this->m_OverlayRenderer->InteractiveOff(); + d->m_OverlayRenderer->SetLayer(1); + d->m_OverlayRenderer->EraseOff(); + d->m_OverlayRenderer->InteractiveOff(); this->Priority = 50.0; // Higher priority to beat camera style this->m_TranslationEnabled = true; this->m_RotationEnabled = true; this->m_ScalingEnabled = true; - this->m_BaseMatrix = vtkSmartPointer<::vtkMatrix4x4>::New(); - this->m_BaseMatrix->Identity(); + d->m_BaseMatrix->Identity(); this->CreateGizmos(); } -vtkHandlerWidget::~vtkHandlerWidget() {} +vtkHandlerWidget::~vtkHandlerWidget() { + delete d; +} + +::vtkRenderer *vtkHandlerWidget::GetOverlayRenderer() { + return d->m_OverlayRenderer; +} void vtkHandlerWidget::SetProp3D(::vtkProp3D *prop) { if (this->Prop3D == prop) { @@ -84,13 +113,13 @@ void vtkHandlerWidget::SetProp3D(::vtkProp3D *prop) { } this->Prop3D = prop; if (this->Prop3D) { - // Initialize m_BaseMatrix from the object's current matrix + // Initialize d->m_BaseMatrix from the object's current matrix if (this->Prop3D->GetUserMatrix()) { - this->m_BaseMatrix->DeepCopy(this->Prop3D->GetUserMatrix()); + this->d->m_BaseMatrix->DeepCopy(this->Prop3D->GetUserMatrix()); } else { - this->m_BaseMatrix->Identity(); + this->d->m_BaseMatrix->Identity(); } - this->m_TransformChain.clear(); // Clear any previous transform chain + this->d->m_TransformChain.clear(); // Clear any previous transform chain this->UpdateGizmoPosition(); } this->Modified(); @@ -141,20 +170,20 @@ void vtkHandlerWidget::SetEnabled(int enabling) { } // Sync Viewport and Camera - this->m_OverlayRenderer->SetViewport(this->CurrentRenderer->GetViewport()); - this->m_OverlayRenderer->SetActiveCamera(this->CurrentRenderer->GetActiveCamera()); - win->AddRenderer(this->m_OverlayRenderer); + this->d->m_OverlayRenderer->SetViewport(this->CurrentRenderer->GetViewport()); + this->d->m_OverlayRenderer->SetActiveCamera(this->CurrentRenderer->GetActiveCamera()); + win->AddRenderer(this->d->m_OverlayRenderer); - this->m_OverlayRenderer->AddActor(m_AxesX); - this->m_OverlayRenderer->AddActor(m_AxesY); - this->m_OverlayRenderer->AddActor(m_AxesZ); - this->m_OverlayRenderer->AddActor(m_RotX); - this->m_OverlayRenderer->AddActor(m_RotY); - this->m_OverlayRenderer->AddActor(m_RotZ); - this->m_OverlayRenderer->AddActor(m_RotCam); - this->m_OverlayRenderer->AddActor(m_ScaleX); - this->m_OverlayRenderer->AddActor(m_ScaleY); - this->m_OverlayRenderer->AddActor(m_ScaleZ); + this->d->m_OverlayRenderer->AddActor(d->m_AxesX); + this->d->m_OverlayRenderer->AddActor(d->m_AxesY); + this->d->m_OverlayRenderer->AddActor(d->m_AxesZ); + this->d->m_OverlayRenderer->AddActor(d->m_RotX); + this->d->m_OverlayRenderer->AddActor(d->m_RotY); + this->d->m_OverlayRenderer->AddActor(d->m_RotZ); + this->d->m_OverlayRenderer->AddActor(d->m_RotCam); + this->d->m_OverlayRenderer->AddActor(d->m_ScaleX); + this->d->m_OverlayRenderer->AddActor(d->m_ScaleY); + this->d->m_OverlayRenderer->AddActor(d->m_ScaleZ); this->UpdateVisibility(); @@ -167,9 +196,9 @@ void vtkHandlerWidget::SetEnabled(int enabling) { this->Highlight(nullptr); this->Interactor->RemoveObserver(this->EventCallbackCommand); if (this->Interactor->GetRenderWindow()) { - this->Interactor->GetRenderWindow()->RemoveRenderer(this->m_OverlayRenderer); + this->Interactor->GetRenderWindow()->RemoveRenderer(this->d->m_OverlayRenderer); } - this->m_OverlayRenderer->RemoveAllViewProps(); + this->d->m_OverlayRenderer->RemoveAllViewProps(); this->InvokeEvent(::vtkCommand::DisableEvent, nullptr); } @@ -214,15 +243,15 @@ void vtkHandlerWidget::OnKeyPress() { bool ctrl = (this->Interactor->GetControlKey() != 0); if (ctrl && key == "z") { - if (!this->m_TransformChain.empty()) { + if (!this->d->m_TransformChain.empty()) { std::cout << "Undoing last transform action..." << std::endl; - this->m_TransformChain.pop_back(); + this->d->m_TransformChain.pop_back(); // Update object from chain vtkNew total; total->PostMultiply(); - total->SetMatrix(this->m_BaseMatrix.GetPointer()); - for (auto& t : m_TransformChain) { + total->SetMatrix(this->d->m_BaseMatrix.GetPointer()); + for (auto& t : d->m_TransformChain) { total->Concatenate(t); } @@ -245,33 +274,33 @@ void vtkHandlerWidget::OnLeftButtonDown() { this->CurrentRenderer = this->Interactor->FindPokedRenderer(X, Y); } - this->m_Picker->Pick(X, Y, 0.0, this->m_OverlayRenderer); - ::vtkProp *prop = this->m_Picker->GetViewProp(); - this->m_Picker->GetPickPosition(this->m_StartPickPosition); + this->d->m_Picker->Pick(X, Y, 0.0, this->d->m_OverlayRenderer); + ::vtkProp *prop = this->d->m_Picker->GetViewProp(); + this->d->m_Picker->GetPickPosition(this->m_StartPickPosition); if (!prop) return; this->Interaction = IDLE; - if (prop == m_AxesX) + if (prop == d->m_AxesX) this->Interaction = TRANS_X; - else if (prop == m_AxesY) + else if (prop == d->m_AxesY) this->Interaction = TRANS_Y; - else if (prop == m_AxesZ) + else if (prop == d->m_AxesZ) this->Interaction = TRANS_Z; - else if (prop == m_RotX) + else if (prop == d->m_RotX) this->Interaction = ROT_X; - else if (prop == m_RotY) + else if (prop == d->m_RotY) this->Interaction = ROT_Y; - else if (prop == m_RotZ) + else if (prop == d->m_RotZ) this->Interaction = ROT_Z; - else if (prop == m_ScaleX) + else if (prop == d->m_ScaleX) this->Interaction = SCALE_X; - else if (prop == m_ScaleY) + else if (prop == d->m_ScaleY) this->Interaction = SCALE_Y; - else if (prop == m_ScaleZ) + else if (prop == d->m_ScaleZ) this->Interaction = SCALE_Z; - else if (prop == m_RotCam) + else if (prop == d->m_RotCam) this->Interaction = ROT_CAM; if (this->Interaction != IDLE) { @@ -285,14 +314,14 @@ void vtkHandlerWidget::OnLeftButtonDown() { // If the chain is empty, initialize base from current state? // Actually, if we just started selecting this object, we should have initialized BaseMatrix. - // For now, let's keep m_InitialTransform as the state BEFORE this drag + // For now, let's keep d->m_InitialTransform as the state BEFORE this drag vtkNew current; current->PostMultiply(); - current->SetMatrix(this->m_BaseMatrix.GetPointer()); - for (auto& t : m_TransformChain) { + current->SetMatrix(this->d->m_BaseMatrix.GetPointer()); + for (auto& t : d->m_TransformChain) { current->Concatenate(t); } - this->m_InitialTransform->SetMatrix(current->GetMatrix()); + this->d->m_InitialTransform->SetMatrix(current->GetMatrix()); } this->EventCallbackCommand->SetAbortFlag(1); this->InvokeEvent(::vtkCommand::StartInteractionEvent, nullptr); @@ -310,10 +339,10 @@ void vtkHandlerWidget::OnLeftButtonUp() { // We need to re-calculate the final 'op' to store it // Actually, we could have stored it in OnMouseMove, but let's re-calculate or - // just capture the delta between m_InitialTransform and current UserMatrix. + // just capture the delta between d->m_InitialTransform and current UserMatrix. if (this->Prop3D && this->Prop3D->GetUserMatrix()) { vtkNew inv; - vtkMatrix4x4::Invert(this->m_InitialTransform->GetMatrix(), inv); + vtkMatrix4x4::Invert(this->d->m_InitialTransform->GetMatrix(), inv); vtkNew final_op_mat; vtkMatrix4x4::Multiply4x4(this->Prop3D->GetUserMatrix(), inv, final_op_mat); @@ -321,8 +350,8 @@ void vtkHandlerWidget::OnLeftButtonUp() { vtkNew final_op; final_op->SetMatrix(final_op_mat); - this->m_TransformChain.push_back(final_op); - std::cout << "Action finalized. Chain size: " << this->m_TransformChain.size() << std::endl; + this->d->m_TransformChain.push_back(final_op); + std::cout << "Action finalized. Chain size: " << this->d->m_TransformChain.size() << std::endl; } this->Interaction = IDLE; @@ -339,8 +368,8 @@ void vtkHandlerWidget::OnMouseMove() { int Y = this->Interactor->GetEventPosition()[1]; if (this->Interaction == IDLE) { - this->m_Picker->Pick(X, Y, 0.0, this->m_OverlayRenderer); - ::vtkProp *prop = this->m_Picker->GetViewProp(); + this->d->m_Picker->Pick(X, Y, 0.0, this->d->m_OverlayRenderer); + ::vtkProp *prop = this->d->m_Picker->GetViewProp(); this->Highlight(prop); this->UpdateGizmoPosition(); // Ensure camera adjustments happen return; @@ -353,7 +382,7 @@ void vtkHandlerWidget::OnMouseMove() { // std::cout << "Interaction " << this->Interaction << " dx=" << dx << " dy=" << dy << std::endl; // Get current gizmo properties from its actors - vtkMatrix4x4 *gizmo_mat = m_AxesX->GetUserMatrix(); + vtkMatrix4x4 *gizmo_mat = d->m_AxesX->GetUserMatrix(); if (!gizmo_mat) return; @@ -542,7 +571,7 @@ void vtkHandlerWidget::OnMouseMove() { // Total transform = Base * Chain * Interaction vtkNew total; total->PostMultiply(); - total->SetMatrix(this->m_InitialTransform->GetMatrix()); // m_InitialTransform is already Base*Chain + total->SetMatrix(this->d->m_InitialTransform->GetMatrix()); // d->m_InitialTransform is already Base*Chain total->Concatenate(op); vtkMatrix4x4* targetMat = this->Prop3D->GetUserMatrix(); @@ -588,41 +617,41 @@ void vtkHandlerWidget::SetScalingEnabled(bool enabled) { } void vtkHandlerWidget::UpdateVisibility() { - if (!m_AxesX) return; + if (!d->m_AxesX) return; - m_AxesX->SetVisibility(m_TranslationEnabled); - m_AxesY->SetVisibility(m_TranslationEnabled); - m_AxesZ->SetVisibility(m_TranslationEnabled); + d->m_AxesX->SetVisibility(m_TranslationEnabled); + d->m_AxesY->SetVisibility(m_TranslationEnabled); + d->m_AxesZ->SetVisibility(m_TranslationEnabled); - m_RotX->SetVisibility(m_RotationEnabled); - m_RotY->SetVisibility(m_RotationEnabled); - m_RotZ->SetVisibility(m_RotationEnabled); - m_RotCam->SetVisibility(m_RotationEnabled); + d->m_RotX->SetVisibility(m_RotationEnabled); + d->m_RotY->SetVisibility(m_RotationEnabled); + d->m_RotZ->SetVisibility(m_RotationEnabled); + d->m_RotCam->SetVisibility(m_RotationEnabled); - m_ScaleX->SetVisibility(m_ScalingEnabled); - m_ScaleY->SetVisibility(m_ScalingEnabled); - m_ScaleZ->SetVisibility(m_ScalingEnabled); + d->m_ScaleX->SetVisibility(m_ScalingEnabled); + d->m_ScaleY->SetVisibility(m_ScalingEnabled); + d->m_ScaleZ->SetVisibility(m_ScalingEnabled); // Update picker list - if (m_Picker) { - m_Picker->InitializePickList(); + if (d->m_Picker) { + d->m_Picker->InitializePickList(); if (m_TranslationEnabled) { - m_Picker->AddPickList(m_AxesX); - m_Picker->AddPickList(m_AxesY); - m_Picker->AddPickList(m_AxesZ); + d->m_Picker->AddPickList(d->m_AxesX); + d->m_Picker->AddPickList(d->m_AxesY); + d->m_Picker->AddPickList(d->m_AxesZ); } if (m_RotationEnabled) { - m_Picker->AddPickList(m_RotX); - m_Picker->AddPickList(m_RotY); - m_Picker->AddPickList(m_RotZ); - m_Picker->AddPickList(m_RotCam); + d->m_Picker->AddPickList(d->m_RotX); + d->m_Picker->AddPickList(d->m_RotY); + d->m_Picker->AddPickList(d->m_RotZ); + d->m_Picker->AddPickList(d->m_RotCam); } if (m_ScalingEnabled) { - m_Picker->AddPickList(m_ScaleX); - m_Picker->AddPickList(m_ScaleY); - m_Picker->AddPickList(m_ScaleZ); + d->m_Picker->AddPickList(d->m_ScaleX); + d->m_Picker->AddPickList(d->m_ScaleY); + d->m_Picker->AddPickList(d->m_ScaleZ); } - m_Picker->PickFromListOn(); + d->m_Picker->PickFromListOn(); } } @@ -676,7 +705,7 @@ void vtkHandlerWidget::CreateGizmos() { auto mapper = vtkSmartPointer<::vtkPolyDataMapper>::New(); mapper->SetInputConnection(circle->GetOutputPort()); - mapper->AddClippingPlane(this->m_ClipPlane); + mapper->AddClippingPlane(this->d->m_ClipPlane); auto actor = vtkSmartPointer<::vtkActor>::New(); actor->SetMapper(mapper); @@ -690,15 +719,15 @@ void vtkHandlerWidget::CreateGizmos() { blue[] = {0.0, 0.0, 1.0}, white[] = {1.0, 1.0, 1.0}; double x[] = {1, 0, 0}, y[] = {0, 1, 0}, z[] = {0, 0, 1}; - m_AxesX = create_arrow(x, red); - m_AxesY = create_arrow(y, green); - m_AxesZ = create_arrow(z, blue); + d->m_AxesX = create_arrow(x, red); + d->m_AxesY = create_arrow(y, green); + d->m_AxesZ = create_arrow(z, blue); - m_RotX = create_ring(0, red); - m_RotY = create_ring(1, green); - m_RotZ = create_ring(2, blue); + d->m_RotX = create_ring(0, red); + d->m_RotY = create_ring(1, green); + d->m_RotZ = create_ring(2, blue); - m_RotCam = vtkSmartPointer<::vtkActor>::New(); + d->m_RotCam = vtkSmartPointer<::vtkActor>::New(); { auto circle = vtkSmartPointer<::vtkRegularPolygonSource>::New(); circle->SetNumberOfSides(64); @@ -708,10 +737,10 @@ void vtkHandlerWidget::CreateGizmos() { circle->GeneratePolylineOn(); auto mapper = vtkSmartPointer<::vtkPolyDataMapper>::New(); mapper->SetInputConnection(circle->GetOutputPort()); - m_RotCam->SetMapper(mapper); - m_RotCam->GetProperty()->SetColor(white); - m_RotCam->GetProperty()->SetLineWidth(2); - m_RotCam->GetProperty()->SetLighting(0); + d->m_RotCam->SetMapper(mapper); + d->m_RotCam->GetProperty()->SetColor(white); + d->m_RotCam->GetProperty()->SetLineWidth(2); + d->m_RotCam->GetProperty()->SetLighting(0); } auto create_cube = [](double pos[3], double color[3]) { @@ -730,23 +759,23 @@ void vtkHandlerWidget::CreateGizmos() { }; double px[] = {1.2, 0, 0}, py[] = {0, 1.2, 0}, pz[] = {0, 0, 1.2}; - m_ScaleX = create_cube(px, red); - m_ScaleY = create_cube(py, green); - m_ScaleZ = create_cube(pz, blue); + d->m_ScaleX = create_cube(px, red); + d->m_ScaleY = create_cube(py, green); + d->m_ScaleZ = create_cube(pz, blue); // Configure picker to only see gizmo actors (Pick-Through) - m_Picker->InitializePickList(); - m_Picker->AddPickList(m_AxesX); - m_Picker->AddPickList(m_AxesY); - m_Picker->AddPickList(m_AxesZ); - m_Picker->AddPickList(m_RotX); - m_Picker->AddPickList(m_RotY); - m_Picker->AddPickList(m_RotZ); - m_Picker->AddPickList(m_RotCam); - m_Picker->AddPickList(m_ScaleX); - m_Picker->AddPickList(m_ScaleY); - m_Picker->AddPickList(m_ScaleZ); - m_Picker->PickFromListOn(); + d->m_Picker->InitializePickList(); + d->m_Picker->AddPickList(d->m_AxesX); + d->m_Picker->AddPickList(d->m_AxesY); + d->m_Picker->AddPickList(d->m_AxesZ); + d->m_Picker->AddPickList(d->m_RotX); + d->m_Picker->AddPickList(d->m_RotY); + d->m_Picker->AddPickList(d->m_RotZ); + d->m_Picker->AddPickList(d->m_RotCam); + d->m_Picker->AddPickList(d->m_ScaleX); + d->m_Picker->AddPickList(d->m_ScaleY); + d->m_Picker->AddPickList(d->m_ScaleZ); + d->m_Picker->PickFromListOn(); } void vtkHandlerWidget::UpdateGizmoPosition() { @@ -843,24 +872,24 @@ void vtkHandlerWidget::UpdateGizmoPosition() { } } - m_AxesX->SetUserMatrix(mat_gizmo); - m_AxesY->SetUserMatrix(mat_gizmo); - m_AxesZ->SetUserMatrix(mat_gizmo); - m_RotX->SetUserMatrix(mat_gizmo); - m_RotY->SetUserMatrix(mat_gizmo); - m_RotZ->SetUserMatrix(mat_gizmo); - m_ScaleX->SetUserMatrix(mat_gizmo); - m_ScaleY->SetUserMatrix(mat_gizmo); - m_ScaleZ->SetUserMatrix(mat_gizmo); + d->m_AxesX->SetUserMatrix(mat_gizmo); + d->m_AxesY->SetUserMatrix(mat_gizmo); + d->m_AxesZ->SetUserMatrix(mat_gizmo); + d->m_RotX->SetUserMatrix(mat_gizmo); + d->m_RotY->SetUserMatrix(mat_gizmo); + d->m_RotZ->SetUserMatrix(mat_gizmo); + d->m_ScaleX->SetUserMatrix(mat_gizmo); + d->m_ScaleY->SetUserMatrix(mat_gizmo); + d->m_ScaleZ->SetUserMatrix(mat_gizmo); // Sync Overlay Renderer with Main Renderer - if (this->CurrentRenderer && this->m_OverlayRenderer) { - this->m_OverlayRenderer->SetViewport(this->CurrentRenderer->GetViewport()); - this->m_OverlayRenderer->SetAspect(this->CurrentRenderer->GetAspect()); - this->m_OverlayRenderer->ComputeAspect(); + if (this->CurrentRenderer && this->d->m_OverlayRenderer) { + this->d->m_OverlayRenderer->SetViewport(this->CurrentRenderer->GetViewport()); + this->d->m_OverlayRenderer->SetAspect(this->CurrentRenderer->GetAspect()); + this->d->m_OverlayRenderer->ComputeAspect(); - if (this->m_OverlayRenderer->GetActiveCamera() != this->CurrentRenderer->GetActiveCamera()) { - this->m_OverlayRenderer->SetActiveCamera(this->CurrentRenderer->GetActiveCamera()); + if (this->d->m_OverlayRenderer->GetActiveCamera() != this->CurrentRenderer->GetActiveCamera()) { + this->d->m_OverlayRenderer->SetActiveCamera(this->CurrentRenderer->GetActiveCamera()); } } @@ -890,36 +919,36 @@ void vtkHandlerWidget::UpdateGizmoPosition() { } tcam->Translate(mat_gizmo->GetElement(0, 3), mat_gizmo->GetElement(1, 3), mat_gizmo->GetElement(2, 3)); - m_RotCam->SetUserMatrix(tcam->GetMatrix()); + d->m_RotCam->SetUserMatrix(tcam->GetMatrix()); // Update clipping plane for axes rings - this->m_ClipPlane->SetOrigin(mat_gizmo->GetElement(0, 3), + this->d->m_ClipPlane->SetOrigin(mat_gizmo->GetElement(0, 3), mat_gizmo->GetElement(1, 3), mat_gizmo->GetElement(2, 3)); - this->m_ClipPlane->SetNormal(dir); + this->d->m_ClipPlane->SetNormal(dir); } } void vtkHandlerWidget::Highlight(::vtkProp *prop) { - if (this->m_HighlightedProp == prop) + if (this->d->m_HighlightedProp == prop) return; // Restore previous - if (this->m_HighlightedProp) { - ::vtkActor *actor = ::vtkActor::SafeDownCast(this->m_HighlightedProp); + if (this->d->m_HighlightedProp) { + ::vtkActor *actor = ::vtkActor::SafeDownCast(this->d->m_HighlightedProp); if (actor) { actor->GetProperty()->SetColor(m_OriginalColor); actor->GetProperty()->SetLineWidth(3); } } - this->m_HighlightedProp = nullptr; + this->d->m_HighlightedProp = nullptr; // Highlight new if it belongs to us - if (prop == m_AxesX || prop == m_AxesY || prop == m_AxesZ || prop == m_RotX || - prop == m_RotY || prop == m_RotZ || prop == m_RotCam || prop == m_ScaleX || - prop == m_ScaleY || prop == m_ScaleZ) { - this->m_HighlightedProp = prop; + if (prop == d->m_AxesX || prop == d->m_AxesY || prop == d->m_AxesZ || prop == d->m_RotX || + prop == d->m_RotY || prop == d->m_RotZ || prop == d->m_RotCam || prop == d->m_ScaleX || + prop == d->m_ScaleY || prop == d->m_ScaleZ) { + this->d->m_HighlightedProp = prop; ::vtkActor *actor = ::vtkActor::SafeDownCast(prop); if (actor) { actor->GetProperty()->GetColor(m_OriginalColor); diff --git a/src/Vtk/vtkHandlerWidget.h b/src/Vtk/vtkHandlerWidget.h index 5129b82..e49049d 100644 --- a/src/Vtk/vtkHandlerWidget.h +++ b/src/Vtk/vtkHandlerWidget.h @@ -92,6 +92,8 @@ public: void SetReferenceFrame(ReferenceFrame frame); ReferenceFrame GetReferenceFrame() const { return this->m_Frame; } + + struct HandlerWidgetData *d; using ::vtk3DWidget::PlaceWidget; virtual void PlaceWidget(double bounds[6]) override; @@ -101,7 +103,7 @@ public: void SetTransform(::vtkTransform *t); void GetTransform(::vtkTransform *t); - ::vtkRenderer *GetOverlayRenderer() { return this->m_OverlayRenderer; } + ::vtkRenderer *GetOverlayRenderer(); void SetTranslationEnabled(bool enabled); bool GetTranslationEnabled() const { return m_TranslationEnabled; } @@ -109,39 +111,23 @@ public: bool GetRotationEnabled() const { return m_RotationEnabled; } void SetScalingEnabled(bool enabled); bool GetScalingEnabled() const { return m_ScalingEnabled; } - + protected: void CreateGizmos(); void UpdateGizmoPosition(); void Highlight(::vtkProp *prop); void UpdateVisibility(); - - vtkSmartPointer<::vtkRenderer> m_OverlayRenderer; + ReferenceFrame m_Frame; bool m_TranslationEnabled; bool m_RotationEnabled; bool m_ScalingEnabled; - + int Interaction; - ::vtkProp *m_HighlightedProp; double m_OriginalColor[3]; - // Visual components // - vtkSmartPointer<::vtkActor> m_AxesX, m_AxesY, m_AxesZ; // Arrows - vtkSmartPointer<::vtkActor> m_RotX, m_RotY, m_RotZ; // Rings - vtkSmartPointer<::vtkActor> m_RotCam; // Camera ring - vtkSmartPointer<::vtkActor> m_ScaleX, m_ScaleY, m_ScaleZ; // Cubes - - vtkSmartPointer<::vtkPlane> m_ClipPlane; - - vtkSmartPointer<::vtkCellPicker> m_Picker; - double StartEventPosition[2]; double m_StartPickPosition[3]; - vtkSmartPointer<::vtkTransform> m_InitialTransform; - - std::vector> m_TransformChain; - vtkSmartPointer<::vtkMatrix4x4> m_BaseMatrix; public: virtual void SetProp3D(::vtkProp3D *prop) override; diff --git a/src/Vtk/vtkQViewport.cpp b/src/Vtk/vtkQViewport.cpp index 6ff12b5..7cd392a 100644 --- a/src/Vtk/vtkQViewport.cpp +++ b/src/Vtk/vtkQViewport.cpp @@ -70,8 +70,8 @@ QViewport::~QViewport() void QViewport::SetupPipeline() { // Add our renderer to the QVTKOpenGLNativeWidget's render window - vtkRenderWindow* rw = m_VtkWidget->renderWindow(); - rw->AddRenderer(m_Renderer); + ::vtkRenderWindow* rw = m_VtkWidget->renderWindow(); + rw->AddRenderer(this->GetRenderer()); // Common setup Viewport::SetupPipeline(rw->GetInteractor()); diff --git a/src/Vtk/vtkViewport.cpp b/src/Vtk/vtkViewport.cpp index 2af1185..1eae672 100644 --- a/src/Vtk/vtkViewport.cpp +++ b/src/Vtk/vtkViewport.cpp @@ -8,13 +8,20 @@ #include #include #include +#include +#include #include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include - #include - #include #include #include @@ -25,23 +32,50 @@ namespace uLib { namespace Vtk { +struct ViewportData { + vtkSmartPointer m_Renderer; + vtkSmartPointer m_Annotation; + vtkSmartPointer m_Marker; + vtkSmartPointer m_CameraWidget; + + vtkSmartPointer m_GridSource; + vtkSmartPointer m_GridActor; + vtkSmartPointer m_OriginAxes; + vtkSmartPointer m_OriginAxesActor; + + vtkSmartPointer m_Colors; + + vtkSmartPointer m_HandlerWidget; + vtkSmartPointer m_Picker; + vtkSmartPointer m_KeyCallback; + + ViewportData() + : m_Renderer(vtkSmartPointer::New()) + , m_Annotation(vtkSmartPointer::New()) + , m_Marker(vtkSmartPointer::New()) + , m_CameraWidget(nullptr) + , m_Colors(vtkSmartPointer::New()) + {} +}; + Viewport::Viewport() - : m_Renderer(vtkSmartPointer::New()) - , m_Annotation(vtkSmartPointer::New()) - , m_Marker(vtkSmartPointer::New()) - , m_CameraWidget(nullptr) - , m_Colors(vtkSmartPointer::New()) + : d(new ViewportData()) , m_GridAxis(Y) { } Viewport::~Viewport() { - if (m_Renderer) { - m_Renderer->RemoveAllViewProps(); + if (d->m_Renderer) { + d->m_Renderer->RemoveAllViewProps(); } + delete d; } +vtkRenderer* Viewport::GetRenderer() { return d->m_Renderer; } +vtkCornerAnnotation* Viewport::GetAnnotation() { return d->m_Annotation; } +vtkCameraOrientationWidget* Viewport::GetCameraWidget() { return d->m_CameraWidget; } + void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren) { if (!iren) return; @@ -51,49 +85,49 @@ void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren) 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."); - m_Renderer->AddViewProp(m_Annotation); + d->m_Annotation->GetTextProperty()->SetColor(1, 1, 1); + d->m_Annotation->GetTextProperty()->SetFontFamilyToArial(); + d->m_Annotation->GetTextProperty()->SetOpacity(0.5); + d->m_Annotation->SetMaximumFontSize(10); + d->m_Annotation->SetText(0, "uLib VTK viewer."); + d->m_Renderer->AddViewProp(d->m_Annotation); // right corner annotation - m_Annotation->SetText(1, "Grid: -"); + d->m_Annotation->SetText(1, "Grid: -"); // Orientation axes marker (bottom-left corner) vtkNew 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(); + d->m_Marker->SetInteractor(iren); + d->m_Marker->SetOrientationMarker(axes); + d->m_Marker->SetViewport(0.0, 0.0, 0.2, 0.2); + d->m_Marker->SetEnabled(true); + d->m_Marker->InteractiveOff(); // Grid Plane centered at (0,0,0) - m_GridSource = vtkSmartPointer::New(); - m_GridActor = vtkSmartPointer::New(); + d->m_GridSource = vtkSmartPointer::New(); + d->m_GridActor = vtkSmartPointer::New(); vtkNew gridMapper; - gridMapper->SetInputConnection(m_GridSource->GetOutputPort()); + gridMapper->SetInputConnection(d->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); + d->m_GridActor->SetMapper(gridMapper); + d->m_GridActor->GetProperty()->SetRepresentationToWireframe(); + d->m_GridActor->GetProperty()->SetColor(0.4, 0.4, 0.4); + d->m_GridActor->GetProperty()->SetLighting(0); + d->m_GridActor->GetProperty()->SetOpacity(0.5); + d->m_GridActor->PickableOff(); + d->m_Renderer->AddActor(d->m_GridActor); // Global Origin Axes - m_OriginAxes = vtkSmartPointer::New(); - m_OriginAxes->SetScaleFactor(1.0); // will be updated + d->m_OriginAxes = vtkSmartPointer::New(); + d->m_OriginAxes->SetScaleFactor(1.0); // will be updated vtkNew axesMapper; - axesMapper->SetInputConnection(m_OriginAxes->GetOutputPort()); + axesMapper->SetInputConnection(d->m_OriginAxes->GetOutputPort()); - m_OriginAxesActor = vtkSmartPointer::New(); - m_OriginAxesActor->SetMapper(axesMapper); - m_OriginAxesActor->PickableOff(); - m_Renderer->AddActor(m_OriginAxesActor); + d->m_OriginAxesActor = vtkSmartPointer::New(); + d->m_OriginAxesActor->SetMapper(axesMapper); + d->m_OriginAxesActor->PickableOff(); + d->m_Renderer->AddActor(d->m_OriginAxesActor); UpdateGrid(); @@ -104,31 +138,31 @@ void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren) static_cast(clientdata)->UpdateGrid(); }); iren->AddObserver(vtkCommand::InteractionEvent, interactionCallback); - m_Renderer->GetActiveCamera()->AddObserver(vtkCommand::ModifiedEvent, interactionCallback); + d->m_Renderer->GetActiveCamera()->AddObserver(vtkCommand::ModifiedEvent, interactionCallback); // Camera-orientation widget (VTK >= 9) #if VTK_MAJOR_VERSION >= 9 - m_CameraWidget = vtkSmartPointer::New(); - m_CameraWidget->SetParentRenderer(m_Renderer); - m_CameraWidget->SetInteractor(iren); - m_CameraWidget->On(); + d->m_CameraWidget = vtkSmartPointer::New(); + d->m_CameraWidget->SetParentRenderer(d->m_Renderer); + d->m_CameraWidget->SetInteractor(iren); + d->m_CameraWidget->On(); #endif - m_Renderer->SetBackground(0.15, 0.15, 0.15); - m_Renderer->ResetCamera(); + d->m_Renderer->SetBackground(0.15, 0.15, 0.15); + d->m_Renderer->ResetCamera(); // Setup layering for overimposed rendering if (iren->GetRenderWindow()) { iren->GetRenderWindow()->SetNumberOfLayers(2); - m_Renderer->SetLayer(0); + d->m_Renderer->SetLayer(0); } // Setup Handler Widget - m_HandlerWidget = vtkSmartPointer::New(); - m_HandlerWidget->SetInteractor(iren); - m_HandlerWidget->SetCurrentRenderer(m_Renderer); - if (m_HandlerWidget->GetOverlayRenderer()) { - m_HandlerWidget->GetOverlayRenderer()->SetLayer(1); + d->m_HandlerWidget = vtkSmartPointer::New(); + d->m_HandlerWidget->SetInteractor(iren); + d->m_HandlerWidget->SetCurrentRenderer(d->m_Renderer); + if (d->m_HandlerWidget->GetOverlayRenderer()) { + d->m_HandlerWidget->GetOverlayRenderer()->SetLayer(1); } // Observe InteractionEvent to update the selected puppet when the widget moves it @@ -142,10 +176,10 @@ void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren) } } }); - m_HandlerWidget->AddObserver(vtkCommand::InteractionEvent, widgetInteractionCallback); + d->m_HandlerWidget->AddObserver(vtkCommand::InteractionEvent, widgetInteractionCallback); // Picking for selection - m_Picker = vtkSmartPointer::New(); + d->m_Picker = vtkSmartPointer::New(); vtkNew clickCallback; clickCallback->SetClientData(this); clickCallback->SetCallback([](vtkObject* caller, unsigned long, void* clientdata, void*){ @@ -153,8 +187,8 @@ void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren) auto* self = static_cast(clientdata); int* pos = iren->GetEventPosition(); - self->m_Picker->Pick(pos[0], pos[1], 0, self->m_Renderer); - vtkProp* picked = self->m_Picker->GetViewProp(); + self->d->m_Picker->Pick(pos[0], pos[1], 0, self->d->m_Renderer); + vtkProp* picked = self->d->m_Picker->GetViewProp(); Puppet* target = nullptr; if (picked) { @@ -190,59 +224,59 @@ void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren) iren->AddObserver(vtkCommand::LeftButtonPressEvent, clickCallback); // Keyboard events for widget coordinate frame - m_KeyCallback = vtkSmartPointer::New(); - m_KeyCallback->SetClientData(this); - m_KeyCallback->SetCallback([](vtkObject* caller, unsigned long event, void* clientdata, void*){ + d->m_KeyCallback = vtkSmartPointer::New(); + d->m_KeyCallback->SetClientData(this); + d->m_KeyCallback->SetCallback([](vtkObject* caller, unsigned long event, void* clientdata, void*){ auto* iren = static_cast(caller); auto* self = static_cast(clientdata); std::string key = iren->GetKeySym(); bool handled = false; - if (self->m_HandlerWidget && self->m_HandlerWidget->GetEnabled()) { + if (self->d->m_HandlerWidget && self->d->m_HandlerWidget->GetEnabled()) { if (key == "l") { if (event == vtkCommand::KeyPressEvent) { - self->m_HandlerWidget->SetReferenceFrame(vtkHandlerWidget::LOCAL); + self->d->m_HandlerWidget->SetReferenceFrame(vtkHandlerWidget::LOCAL); std::cout << "Widget Frame: LOCAL" << std::endl; } handled = true; } else if (key == "g") { if (event == vtkCommand::KeyPressEvent) { - self->m_HandlerWidget->SetReferenceFrame(vtkHandlerWidget::GLOBAL); + self->d->m_HandlerWidget->SetReferenceFrame(vtkHandlerWidget::GLOBAL); std::cout << "Widget Frame: GLOBAL" << std::endl; } handled = true; } else if (key == "c") { if (event == vtkCommand::KeyPressEvent) { - self->m_HandlerWidget->SetReferenceFrame(vtkHandlerWidget::CENTER); + self->d->m_HandlerWidget->SetReferenceFrame(vtkHandlerWidget::CENTER); std::cout << "Widget Frame: CENTER" << std::endl; } handled = true; } else if (key == "k") { if (event == vtkCommand::KeyPressEvent) { - self->m_HandlerWidget->SetReferenceFrame(vtkHandlerWidget::CENTER_LOCAL); + self->d->m_HandlerWidget->SetReferenceFrame(vtkHandlerWidget::CENTER_LOCAL); std::cout << "Widget Frame: CENTER_LOCAL" << std::endl; } handled = true; } else if (key == "1") { if (event == vtkCommand::KeyPressEvent) { - self->m_HandlerWidget->SetTranslationEnabled(!self->m_HandlerWidget->GetTranslationEnabled()); + self->d->m_HandlerWidget->SetTranslationEnabled(!self->d->m_HandlerWidget->GetTranslationEnabled()); } handled = true; } else if (key == "2") { if (event == vtkCommand::KeyPressEvent) { - self->m_HandlerWidget->SetRotationEnabled(!self->m_HandlerWidget->GetRotationEnabled()); + self->d->m_HandlerWidget->SetRotationEnabled(!self->d->m_HandlerWidget->GetRotationEnabled()); } handled = true; } else if (key == "3") { if (event == vtkCommand::KeyPressEvent) { - self->m_HandlerWidget->SetScalingEnabled(!self->m_HandlerWidget->GetScalingEnabled()); + self->d->m_HandlerWidget->SetScalingEnabled(!self->d->m_HandlerWidget->GetScalingEnabled()); } handled = true; } @@ -256,12 +290,12 @@ void Viewport::SetupPipeline(vtkRenderWindowInteractor* iren) } if (handled) { - self->m_KeyCallback->SetAbortFlag(1); + self->d->m_KeyCallback->SetAbortFlag(1); iren->Render(); } }); - iren->AddObserver(vtkCommand::KeyPressEvent, m_KeyCallback, 1.0); - iren->AddObserver(vtkCommand::CharEvent, m_KeyCallback, 1.0); + iren->AddObserver(vtkCommand::KeyPressEvent, d->m_KeyCallback, 1.0); + iren->AddObserver(vtkCommand::CharEvent, d->m_KeyCallback, 1.0); } void Viewport::Reset() @@ -272,15 +306,15 @@ void Viewport::Reset() void Viewport::ZoomAuto() { - if (m_Renderer) { - m_Renderer->ResetCameraClippingRange(); - m_Renderer->ResetCamera(); + if (d->m_Renderer) { + d->m_Renderer->ResetCameraClippingRange(); + d->m_Renderer->ResetCamera(); } } void Viewport::ZoomSelected() { - if (!m_Renderer) return; + if (!d->m_Renderer) return; Puppet* selected = nullptr; for (auto* p : m_Puppets) { @@ -316,15 +350,15 @@ void Viewport::ZoomSelected() newBounds[2*i+1] = center[i] + 2.5 * current_h; } - m_Renderer->ResetCamera(newBounds); - m_Renderer->ResetCameraClippingRange(); + d->m_Renderer->ResetCamera(newBounds); + d->m_Renderer->ResetCameraClippingRange(); this->Render(); } void Viewport::AddPuppet(Puppet& prop) { m_Puppets.push_back(&prop); - prop.ConnectRenderer(m_Renderer); + prop.ConnectRenderer(d->m_Renderer); Render(); } @@ -333,7 +367,7 @@ void Viewport::RemovePuppet(Puppet& prop) if (prop.IsSelected()) SelectPuppet(nullptr); auto it = std::find(m_Puppets.begin(), m_Puppets.end(), &prop); if (it != m_Puppets.end()) m_Puppets.erase(it); - prop.DisconnectRenderer(m_Renderer); + prop.DisconnectRenderer(d->m_Renderer); Render(); } @@ -343,17 +377,17 @@ void Viewport::SelectPuppet(Puppet* prop) p->SetSelected(p == prop); } - if (m_HandlerWidget) { + if (d->m_HandlerWidget) { if (prop) { vtkProp3D* prop3d = vtkProp3D::SafeDownCast(prop->GetProp()); if (prop3d) { - m_HandlerWidget->SetProp3D(prop3d); - m_HandlerWidget->SetEnabled(1); - m_HandlerWidget->PlaceWidget(prop3d->GetBounds()); + d->m_HandlerWidget->SetProp3D(prop3d); + d->m_HandlerWidget->SetEnabled(1); + d->m_HandlerWidget->PlaceWidget(prop3d->GetBounds()); } } else { - m_HandlerWidget->SetEnabled(0); - m_HandlerWidget->SetProp3D(nullptr); + d->m_HandlerWidget->SetEnabled(0); + d->m_HandlerWidget->SetProp3D(nullptr); } } @@ -362,16 +396,16 @@ void Viewport::SelectPuppet(Puppet* prop) void Viewport::SetGridVisible(bool visible) { - if (m_GridActor) { - m_GridActor->SetVisibility(visible); + if (d->m_GridActor) { + d->m_GridActor->SetVisibility(visible); Render(); } } bool Viewport::GetGridVisible() const { - if (m_GridActor) { - return m_GridActor->GetVisibility() != 0; + if (d->m_GridActor) { + return d->m_GridActor->GetVisibility() != 0; } return false; } @@ -385,26 +419,26 @@ void Viewport::SetGridAxis(Axis axis) void Viewport::addProp(vtkProp* prop) { - if (m_Renderer) { - m_Renderer->AddActor(prop); + if (d->m_Renderer) { + d->m_Renderer->AddActor(prop); Render(); } } void Viewport::RemoveProp(vtkProp* prop) { - if (m_Renderer) { - m_Renderer->RemoveViewProp(prop); + if (d->m_Renderer) { + d->m_Renderer->RemoveViewProp(prop); Render(); } } void Viewport::UpdateGrid() { - if (!m_Renderer || !m_GridSource) return; - if (m_GridActor && !m_GridActor->GetVisibility()) return; + if (!d->m_Renderer || !d->m_GridSource) return; + if (d->m_GridActor && !d->m_GridActor->GetVisibility()) return; - vtkCamera* camera = m_Renderer->GetActiveCamera(); + vtkCamera* camera = d->m_Renderer->GetActiveCamera(); if (!camera) return; // Determine the "scale" of the view (how many units are visible vertically) @@ -425,6 +459,9 @@ void Viewport::UpdateGrid() double log10Spacing = std::floor(std::log10(viewHeight / 5.0)); double spacing = std::pow(10.0, log10Spacing); + // Spacing should be at least 1mm + if (spacing < 1.0) spacing = 1.0; + // Get current focal point to center the grid near what we're looking at double focalPoint[3]; camera->GetFocalPoint(focalPoint); @@ -455,31 +492,28 @@ void Viewport::UpdateGrid() p1[idxH] = maxH; p1[idxV] = minV; p1[idxN] = centerN; p2[idxH] = minH; p2[idxV] = maxV; p2[idxN] = centerN; - m_GridSource->SetOrigin(origin); - m_GridSource->SetPoint1(p1); - m_GridSource->SetPoint2(p2); - m_GridSource->SetXResolution(numLines); - m_GridSource->SetYResolution(numLines); - m_GridSource->Update(); + d->m_GridSource->SetOrigin(origin); + d->m_GridSource->SetPoint1(p1); + d->m_GridSource->SetPoint2(p2); + d->m_GridSource->SetXResolution(numLines); + d->m_GridSource->SetYResolution(numLines); + d->m_GridSource->Update(); - if (m_OriginAxes) { - m_OriginAxes->SetScaleFactor(spacing); + if (d->m_OriginAxes) { + d->m_OriginAxes->SetScaleFactor(spacing); } // Update annotation for grid size char gridLabel[32]; if (spacing >= 1000.0) { - sprintf(gridLabel, "Grid: %.0f m", spacing / 1000.0); + sprintf(gridLabel, "Grid: %.1f m", spacing / 1000.0); } else if (spacing >= 10.0) { - sprintf(gridLabel, "Grid: %.0f cm", spacing / 10.0); + sprintf(gridLabel, "Grid: %.1f cm", spacing / 10.0); } else { sprintf(gridLabel, "Grid: %.0f mm", spacing); } - m_Annotation->SetText(1, gridLabel); + d->m_Annotation->SetText(1, gridLabel); } - - - } // namespace Vtk } // namespace uLib diff --git a/src/Vtk/vtkViewport.h b/src/Vtk/vtkViewport.h index 65d41a4..0715be5 100644 --- a/src/Vtk/vtkViewport.h +++ b/src/Vtk/vtkViewport.h @@ -2,23 +2,19 @@ #define ULIB_VTK_VIEWPORT_H #include "uLibVtkInterface.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +// VTK classes are in the global namespace +class vtkRenderer; +class vtkCornerAnnotation; +class vtkOrientationMarkerWidget; +class vtkCameraOrientationWidget; +class vtkPlaneSource; +class vtkActor; +class vtkAxes; +class vtkNamedColors; +class vtkCellPicker; +class vtkCallbackCommand; class vtkProp; class vtk3DWidget; class vtkRenderWindow; @@ -28,6 +24,7 @@ class vtkCamera; namespace uLib { namespace Vtk { +struct ViewportData; class vtkHandlerWidget; /** @@ -56,11 +53,11 @@ public: void AddWidget(vtk3DWidget *widget); // Direct access to VTK internals - vtkRenderer* GetRenderer() { return m_Renderer; } + vtkRenderer* GetRenderer(); virtual vtkRenderWindow* GetRenderWindow() = 0; virtual vtkRenderWindowInteractor* GetInteractor() = 0; - vtkCornerAnnotation* GetAnnotation() { return m_Annotation; } - vtkCameraOrientationWidget* GetCameraWidget(){ return m_CameraWidget; } + vtkCornerAnnotation* GetAnnotation(); + vtkCameraOrientationWidget* GetCameraWidget(); const std::vector& getPuppets() const { return m_Puppets; } // Grid control @@ -76,23 +73,9 @@ protected: void UpdateGrid(); - vtkSmartPointer m_Renderer; - vtkSmartPointer m_Annotation; - vtkSmartPointer m_Marker; - vtkSmartPointer m_CameraWidget; - - vtkSmartPointer m_GridSource; - vtkSmartPointer m_GridActor; - vtkSmartPointer m_OriginAxes; - vtkSmartPointer m_OriginAxesActor; - - vtkSmartPointer m_Colors; - + struct ViewportData *d; Axis m_GridAxis; - vtkSmartPointer m_HandlerWidget; std::vector m_Puppets; - vtkSmartPointer m_Picker; - vtkSmartPointer m_KeyCallback; }; } // namespace Vtk