From db76513e791a530d670a2d04d8ba2241edc8b76c Mon Sep 17 00:00:00 2001 From: AndreaRigoni Date: Thu, 9 Apr 2026 10:38:45 +0000 Subject: [PATCH] refactor: migrate vtk classes to use ObjectWrapper for model management and update registration logic --- src/Core/ObjectFactory.h | 112 ++++++--- src/Core/SmartPointer.h | 12 +- src/Core/testing/CMakeLists.txt | 1 + src/Core/testing/ObjectWrapperTest.cpp | 26 +++ src/Math/MathRegistrations.cpp | 8 +- src/Vtk/HEP/Detectors/vtkDetectorChamber.cxx | 4 +- .../testing/vtkVoxRaytracerTest.cpp | 2 +- src/Vtk/Math/testing/vtkQuadMeshTest.cpp | 9 +- .../Math/testing/vtkStructuredGridTest.cpp | 3 +- src/Vtk/Math/testing/vtkTriangleMeshTest.cpp | 10 +- .../testing/vtkVoxImageInteractiveTest.cpp | 216 +++++++++--------- src/Vtk/Math/testing/vtkVoxImageTest.cpp | 3 +- src/Vtk/Math/vtkAssembly.cpp | 30 +-- src/Vtk/Math/vtkAssembly.h | 10 +- src/Vtk/Math/vtkContainerBox.cpp | 19 +- src/Vtk/Math/vtkContainerBox.h | 16 +- src/Vtk/Math/vtkCylinder.cpp | 20 +- src/Vtk/Math/vtkCylinder.h | 8 +- src/Vtk/Math/vtkQuadMesh.cpp | 44 ++-- src/Vtk/Math/vtkQuadMesh.h | 14 +- src/Vtk/Math/vtkStructuredGrid.cpp | 24 +- src/Vtk/Math/vtkStructuredGrid.h | 10 +- src/Vtk/Math/vtkTriangleMesh.cpp | 40 ++-- src/Vtk/Math/vtkTriangleMesh.h | 14 +- src/Vtk/Math/vtkVoxImage.cpp | 32 +-- src/Vtk/Math/vtkVoxImage.h | 17 +- src/Vtk/vtkObjectsContext.cpp | 124 +++++----- 27 files changed, 479 insertions(+), 349 deletions(-) create mode 100644 src/Core/testing/ObjectWrapperTest.cpp diff --git a/src/Core/ObjectFactory.h b/src/Core/ObjectFactory.h index e22ecc3..02bd111 100644 --- a/src/Core/ObjectFactory.h +++ b/src/Core/ObjectFactory.h @@ -1,53 +1,55 @@ #ifndef U_CORE_OBJECTFACTORY_H #define U_CORE_OBJECTFACTORY_H -#include -#include -#include -#include #include "Core/Object.h" +#include +#include +#include +#include +#include namespace uLib { /** - * @brief Singleton factory for dynamic Object instantiation based on class name. + * @brief Singleton factory for dynamic Object instantiation based on class + * name. */ class ObjectFactory { public: - typedef std::function FactoryFunction; + typedef std::function FactoryFunction; - /** @brief Get the singleton instance. */ - static ObjectFactory& Instance(); + /** @brief Get the singleton instance. */ + static ObjectFactory &Instance(); - /** @brief Register a factory function for a given class name. */ - void Register(const std::string& className, FactoryFunction func); + /** @brief Register a factory function for a given class name. */ + void Register(const std::string &className, FactoryFunction func); - /** @brief Create a new instance of the specified class. */ - Object* Create(const std::string& className); + /** @brief Create a new instance of the specified class. */ + Object *Create(const std::string &className); - /** @brief Get the names of all registered classes. */ - std::vector GetRegisteredClasses() const; + /** @brief Get the names of all registered classes. */ + std::vector GetRegisteredClasses() const; private: - ObjectFactory() = default; - ~ObjectFactory() = default; + ObjectFactory() = default; + ~ObjectFactory() = default; - // Prevent copy and assignment - ObjectFactory(const ObjectFactory&) = delete; - ObjectFactory& operator=(const ObjectFactory&) = delete; + // Prevent copy and assignment + ObjectFactory(const ObjectFactory &) = delete; + ObjectFactory &operator=(const ObjectFactory &) = delete; - std::map m_factoryMap; + std::map m_factoryMap; }; /** * @brief Helper class to statically register a factory function. */ -template -class ObjectRegistrar { +template class ObjectRegistrar { public: - ObjectRegistrar(const std::string& className) { - ObjectFactory::Instance().Register(className, []() -> Object* { return new T(); }); - } + ObjectRegistrar(const std::string &className) { + ObjectFactory::Instance().Register(className, + []() -> Object * { return new T(); }); + } }; #define ULIB_REG_CONCAT_IMPL(a, b) a##b @@ -57,11 +59,63 @@ public: * @brief Macro to register a class to the factory. * Put this in the .cpp file of the class. */ -#define ULIB_REGISTER_OBJECT(className) \ - static uLib::ObjectRegistrar ULIB_REG_CONCAT(g_ObjectRegistrar_, __LINE__)(#className); +#define ULIB_REGISTER_OBJECT(className) \ + static uLib::ObjectRegistrar ULIB_REG_CONCAT( \ + g_ObjectRegistrar_, __LINE__)(#className); -#define ULIB_REGISTER_OBJECT_NAME(className, registeredName) \ - static uLib::ObjectRegistrar ULIB_REG_CONCAT(g_ObjectRegistrar_, __LINE__)(registeredName); +#define ULIB_REGISTER_OBJECT_NAME(className, registeredName) \ + static uLib::ObjectRegistrar ULIB_REG_CONCAT( \ + g_ObjectRegistrar_, __LINE__)(registeredName); + +template class ObjectWrapper { +public: + ObjectWrapper(const std::string &className) { + ObjectFactory::Instance().Register(className, + []() -> Object * { return new T(); }); + } + + ObjectWrapper(T *model) : m_model(model) {} + + template >> + ObjectWrapper() : m_model(new T()) {} + + ObjectWrapper(const ObjectWrapper &other) : m_model(other.m_model) {} + + ObjectWrapper &operator=(const ObjectWrapper &other) { + m_model = other.m_model; + return *this; + } + + ObjectWrapper(ObjectWrapper &&other) noexcept + : m_model(std::move(other.m_model)) {} + + ObjectWrapper &operator=(ObjectWrapper &&other) noexcept { + m_model = std::move(other.m_model); + return *this; + } + + ~ObjectWrapper() = default; + + T *operator->() const { return m_model.get(); } + + T &operator*() const { return *m_model; } + + T *get() const { return m_model.get(); } + + bool operator==(const ObjectWrapper &other) const { + return m_model == other.m_model; + } + + bool operator!=(const ObjectWrapper &other) const { + return m_model != other.m_model; + } + + explicit operator bool() const { return m_model != nullptr; } + +protected: + SmartPointer m_model; +}; } // namespace uLib diff --git a/src/Core/SmartPointer.h b/src/Core/SmartPointer.h index bac7d1e..cd48008 100644 --- a/src/Core/SmartPointer.h +++ b/src/Core/SmartPointer.h @@ -28,6 +28,7 @@ #include #include +#include #include namespace uLib { @@ -50,7 +51,11 @@ public: * If ptr is nullptr, a new T is allocated (legacy behavior). */ explicit SmartPointer(T* ptr = nullptr) : m_counter(nullptr) { - if (!ptr) ptr = new T(); + if (!ptr) { + if constexpr (std::is_default_constructible_v) { + ptr = new T(); + } + } if (ptr) m_counter = new ReferenceCounter(ptr); } @@ -156,6 +161,11 @@ public: */ T* get() const noexcept { return m_counter ? m_counter->ptr : nullptr; } + /** + * @brief Implicit conversion to raw pointer (legacy compatibility). + */ + operator T*() const noexcept { return get(); } + /** * @brief Returns the number of SmartPointers sharing ownership. */ diff --git a/src/Core/testing/CMakeLists.txt b/src/Core/testing/CMakeLists.txt index 73766f6..fec775f 100644 --- a/src/Core/testing/CMakeLists.txt +++ b/src/Core/testing/CMakeLists.txt @@ -3,6 +3,7 @@ set( TESTS SmartVectorTest SmartPointerTest + ObjectWrapperTest VectorTest ObjectFlagsTest ObjectParametersTest diff --git a/src/Core/testing/ObjectWrapperTest.cpp b/src/Core/testing/ObjectWrapperTest.cpp new file mode 100644 index 0000000..84191dd --- /dev/null +++ b/src/Core/testing/ObjectWrapperTest.cpp @@ -0,0 +1,26 @@ +#include "Core/ObjectFactory.h" +#include + +struct NonDefault { + NonDefault(int) {} +}; + +struct Default { + Default() : value(42) {} + int value; +}; + +int main() { + std::cout << "Testing ObjectWrapper with Default Constructible type..." << std::endl; + uLib::ObjectWrapper w1; + + std::cout << "Testing ObjectWrapper with Non-Default Constructible type..." << std::endl; + NonDefault nd(10); + uLib::ObjectWrapper w2(&nd); + + // The following would NOT compile without SFINAE: + // uLib::ObjectWrapper w3; + + std::cout << "Tests passed (compilation and manual instantiation)!" << std::endl; + return 0; +} diff --git a/src/Math/MathRegistrations.cpp b/src/Math/MathRegistrations.cpp index 86056fc..367196b 100644 --- a/src/Math/MathRegistrations.cpp +++ b/src/Math/MathRegistrations.cpp @@ -1,12 +1,12 @@ #include "Core/ObjectFactory.h" +#include "Math/Assembly.h" #include "Math/ContainerBox.h" #include "Math/Cylinder.h" #include "Math/Geometry.h" -#include "Math/TriangleMesh.h" #include "Math/QuadMesh.h" -#include "Math/VoxImage.h" -#include "Math/Assembly.h" #include "Math/StructuredData.h" +#include "Math/TriangleMesh.h" +#include "Math/VoxImage.h" namespace uLib { @@ -14,8 +14,6 @@ ULIB_REGISTER_OBJECT(TRS) ULIB_REGISTER_OBJECT(ContainerBox) ULIB_REGISTER_OBJECT(Cylinder) ULIB_REGISTER_OBJECT(Assembly) -ULIB_REGISTER_OBJECT(CylindricalGeometry) -ULIB_REGISTER_OBJECT(SphericalGeometry) ULIB_REGISTER_OBJECT(TriangleMesh) ULIB_REGISTER_OBJECT(QuadMesh) ULIB_REGISTER_OBJECT_NAME(VoxImage, "VoxImage") diff --git a/src/Vtk/HEP/Detectors/vtkDetectorChamber.cxx b/src/Vtk/HEP/Detectors/vtkDetectorChamber.cxx index 0dfcabd..7e046da 100644 --- a/src/Vtk/HEP/Detectors/vtkDetectorChamber.cxx +++ b/src/Vtk/HEP/Detectors/vtkDetectorChamber.cxx @@ -73,13 +73,13 @@ DetectorChamber::~DetectorChamber() { } DetectorChamber::Content *DetectorChamber::GetContent() const { - return static_cast(m_Content); + return static_cast(this->m_model.get()); } void DetectorChamber::Update() { this->BaseClass::Update(); - if (!m_Content) return; + if (!this->m_model) return; Content *c = this->GetContent(); Vector3f size = c->GetSize(); HLine3f plane = c->GetProjectionPlane(); diff --git a/src/Vtk/HEP/MuonTomography/testing/vtkVoxRaytracerTest.cpp b/src/Vtk/HEP/MuonTomography/testing/vtkVoxRaytracerTest.cpp index 68a6a28..dcb5eb8 100644 --- a/src/Vtk/HEP/MuonTomography/testing/vtkVoxRaytracerTest.cpp +++ b/src/Vtk/HEP/MuonTomography/testing/vtkVoxRaytracerTest.cpp @@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(vtkVoxRaytracerRepresentationTest) { grid.SetSpacing(Vector3f(1, 1, 1)); grid.SetPosition(Vector3f(0, 0, 0)); - Vtk::StructuredGrid v_grid(grid); + Vtk::StructuredGrid v_grid(&grid); // voxraytracer // VoxRaytracer rt(grid); diff --git a/src/Vtk/Math/testing/vtkQuadMeshTest.cpp b/src/Vtk/Math/testing/vtkQuadMeshTest.cpp index c77c0af..a60d245 100644 --- a/src/Vtk/Math/testing/vtkQuadMeshTest.cpp +++ b/src/Vtk/Math/testing/vtkQuadMeshTest.cpp @@ -23,7 +23,6 @@ //////////////////////////////////////////////////////////////////////////////*/ -#include "Vtk/Math/vtkQuadMesh.h" #include "Vtk/Math/vtkQuadMesh.h" #include "Vtk/uLibVtkViewer.h" @@ -39,10 +38,10 @@ BOOST_AUTO_TEST_CASE(vtkQuadMeshConstruction) { mesh.AddPoint(Vector3f(1, 0, 0)); mesh.AddPoint(Vector3f(1, 1, 0)); mesh.AddPoint(Vector3f(0, 1, 0)); - + mesh.AddQuad(Vector4i(0, 1, 2, 3)); - Vtk::QuadMesh v_mesh(mesh); + Vtk::QuadMesh v_mesh(&mesh); Object::connect(&mesh, &QuadMesh::Updated, [&mesh]() { Vector3f points[4]; @@ -50,8 +49,8 @@ BOOST_AUTO_TEST_CASE(vtkQuadMeshConstruction) { points[1] = mesh.GetPoint(1); points[2] = mesh.GetPoint(2); points[3] = mesh.GetPoint(3); - std::cout << "mesh updated: " << points[0] << " " << points[1] - << " " << points[2] << " " << points[3] << std::endl; + std::cout << "mesh updated: " << points[0] << " " << points[1] << " " + << points[2] << " " << points[3] << std::endl; }); v_mesh.Update(); diff --git a/src/Vtk/Math/testing/vtkStructuredGridTest.cpp b/src/Vtk/Math/testing/vtkStructuredGridTest.cpp index 1e9853a..cadad79 100644 --- a/src/Vtk/Math/testing/vtkStructuredGridTest.cpp +++ b/src/Vtk/Math/testing/vtkStructuredGridTest.cpp @@ -23,7 +23,6 @@ //////////////////////////////////////////////////////////////////////////////*/ -#include "Vtk/Math/vtkStructuredGrid.h" #include "Vtk/Math/vtkStructuredGrid.h" #include "Vtk/uLibVtkViewer.h" @@ -36,7 +35,7 @@ BOOST_AUTO_TEST_CASE(vtkStructuredGridTest) { StructuredGrid grid(Vector3i(10, 10, 100)); grid.SetSpacing(Vector3f(3, 1, 1)); - Vtk::StructuredGrid grid_viewer(grid); + Vtk::StructuredGrid grid_viewer(&grid); if (std::getenv("CTEST_PROJECT_NAME") == nullptr) { Vtk::Viewer viewer; diff --git a/src/Vtk/Math/testing/vtkTriangleMeshTest.cpp b/src/Vtk/Math/testing/vtkTriangleMeshTest.cpp index 5053215..af51590 100644 --- a/src/Vtk/Math/testing/vtkTriangleMeshTest.cpp +++ b/src/Vtk/Math/testing/vtkTriangleMeshTest.cpp @@ -23,7 +23,6 @@ //////////////////////////////////////////////////////////////////////////////*/ -#include "Vtk/Math/vtkTriangleMesh.h" #include "Vtk/Math/vtkTriangleMesh.h" #include "Vtk/uLibVtkViewer.h" @@ -40,15 +39,16 @@ BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction) { mesh.AddPoint(Vector3f(1, 0, 0)); mesh.AddTriangle(Vector3i(0, 1, 2)); - Vtk::TriangleMesh v_mesh(mesh); + Vtk::TriangleMesh v_mesh(&mesh); Object::connect(&mesh, &TriangleMesh::Updated, [&mesh]() { Vector3f points[3]; points[0] = mesh.GetPoint(0); points[1] = mesh.GetPoint(1); points[2] = mesh.GetPoint(2); - std::cout << "mesh updated: " << points[0].transpose() << " " << points[1].transpose() - << " " << points[2].transpose() << std::endl; + std::cout << "mesh updated: " << points[0].transpose() << " " + << points[1].transpose() << " " << points[2].transpose() + << std::endl; }); v_mesh.Update(); @@ -66,7 +66,7 @@ BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction) { BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction2) { TriangleMesh mesh; - Vtk::TriangleMesh v_mesh(mesh); + Vtk::TriangleMesh v_mesh(&mesh); v_mesh.ReadFromStlFile("capelluzzo.stl"); v_mesh.Update(); diff --git a/src/Vtk/Math/testing/vtkVoxImageInteractiveTest.cpp b/src/Vtk/Math/testing/vtkVoxImageInteractiveTest.cpp index 13b424f..fe2cb50 100644 --- a/src/Vtk/Math/testing/vtkVoxImageInteractiveTest.cpp +++ b/src/Vtk/Math/testing/vtkVoxImageInteractiveTest.cpp @@ -9,134 +9,140 @@ //////////////////////////////////////////////////////////////////////////////*/ -#include "Vtk/Math/vtkVoxImage.h" #include "Vtk/Math/vtkVoxImage.h" #include "Vtk/uLibVtkViewer.h" -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include using namespace uLib; struct AppState { - std::vector images; - Vtk::Viewer* viewer; + std::vector images; + Vtk::Viewer *viewer; }; -void KeyPressCallbackFunction(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData) { - auto* interactor = static_cast(caller); - auto* state = static_cast(clientData); - - std::string key = interactor->GetKeySym(); - if (key == "w") { - std::cout << "--> Switching all images to Wireframe Box" << std::endl; - for (auto* img : state->images) img->SetRepresentation(Vtk::Prop3D::Wireframe); - state->viewer->GetRenderWindow()->Render(); - } - else if (key == "s") { - std::cout << "--> Switching all images to Surface (Volume Rendering)" << std::endl; - for (auto* img : state->images) img->SetRepresentation(Vtk::Prop3D::Surface); - state->viewer->GetRenderWindow()->Render(); - } - else if (key >= "0" && key <= "5") { - int preset = key[0] - '0'; - std::cout << "--> Switching all images to Rendering Preset " << preset << std::endl; - for (auto* img : state->images) img->setShadingPreset(preset); - state->viewer->GetRenderWindow()->Render(); - } +void KeyPressCallbackFunction(vtkObject *caller, long unsigned int eventId, + void *clientData, void *callData) { + auto *interactor = static_cast(caller); + auto *state = static_cast(clientData); + + std::string key = interactor->GetKeySym(); + if (key == "w") { + std::cout << "--> Switching all images to Wireframe Box" << std::endl; + for (auto *img : state->images) + img->SetRepresentation(Vtk::Prop3D::Wireframe); + state->viewer->GetRenderWindow()->Render(); + } else if (key == "s") { + std::cout << "--> Switching all images to Surface (Volume Rendering)" + << std::endl; + for (auto *img : state->images) + img->SetRepresentation(Vtk::Prop3D::Surface); + state->viewer->GetRenderWindow()->Render(); + } else if (key >= "0" && key <= "5") { + int preset = key[0] - '0'; + std::cout << "--> Switching all images to Rendering Preset " << preset + << std::endl; + for (auto *img : state->images) + img->setShadingPreset(preset); + state->viewer->GetRenderWindow()->Render(); + } } -int main(int argc, char** argv) { - float factor = 1.0e6f; +int main(int argc, char **argv) { + float factor = 1.0e6f; - // --- Image 1: Spherical Shell --- - Vector3i dims1(64, 64, 64); - VoxImage img1(dims1); - img1.SetSpacing(Vector3f(1.0, 1.0, 1.0)); - img1.SetPosition(Vector3f(-40, -32, -32)); + // --- Image 1: Spherical Shell --- + Vector3i dims1(64, 64, 64); + VoxImage img1(dims1); + img1.SetSpacing(Vector3f(1.0, 1.0, 1.0)); + img1.SetPosition(Vector3f(-40, -32, -32)); - for (int z = 0; z < dims1(2); ++z) { - for (int y = 0; y < dims1(1); ++y) { - for (int x = 0; x < dims1(0); ++x) { - float dx = x - 32.0f; - float dy = y - 32.0f; - float dz = z - 32.0f; - float dist = std::sqrt(dx*dx + dy*dy + dz*dz); - Voxel v; - if (dist < 25.0f && dist > 10.0f) { - v.Value = (40.0f * (25.0f - dist) / 15.0f) / factor; - } else { - v.Value = 0.0f; - } - img1[Vector3i(x, y, z)] = v; - } + for (int z = 0; z < dims1(2); ++z) { + for (int y = 0; y < dims1(1); ++y) { + for (int x = 0; x < dims1(0); ++x) { + float dx = x - 32.0f; + float dy = y - 32.0f; + float dz = z - 32.0f; + float dist = std::sqrt(dx * dx + dy * dy + dz * dz); + Voxel v; + if (dist < 25.0f && dist > 10.0f) { + v.Value = (40.0f * (25.0f - dist) / 15.0f) / factor; + } else { + v.Value = 0.0f; } + img1[Vector3i(x, y, z)] = v; + } } + } - // --- Image 2: Axes Gradient --- - Vector3i dims2(64, 64, 64); - VoxImage img2(dims2); - img2.SetSpacing(Vector3f(1.0, 1.0, 1.0)); - img2.SetPosition(Vector3f(40, -32, -32)); + // --- Image 2: Axes Gradient --- + Vector3i dims2(64, 64, 64); + VoxImage img2(dims2); + img2.SetSpacing(Vector3f(1.0, 1.0, 1.0)); + img2.SetPosition(Vector3f(40, -32, -32)); - for (int z = 0; z < dims2(2); ++z) { - for (int y = 0; y < dims2(1); ++y) { - for (int x = 0; x < dims2(0); ++x) { - Voxel v; - // Linear gradient along X, Y, Z - float val = (float(x)/dims2(0) + float(y)/dims2(1) + float(z)/dims2(2)) / 3.0f; - v.Value = (40.0f * val) / factor; - img2[Vector3i(x, y, z)] = v; - } - } + for (int z = 0; z < dims2(2); ++z) { + for (int y = 0; y < dims2(1); ++y) { + for (int x = 0; x < dims2(0); ++x) { + Voxel v; + // Linear gradient along X, Y, Z + float val = + (float(x) / dims2(0) + float(y) / dims2(1) + float(z) / dims2(2)) / + 3.0f; + v.Value = (40.0f * val) / factor; + img2[Vector3i(x, y, z)] = v; + } } + } - Vtk::VoxImage vtk_img1(img1); - vtk_img1.setShadingPreset(0); + Vtk::VoxImage vtk_img1(&img1); + vtk_img1.setShadingPreset(0); - Vtk::VoxImage vtk_img2(img2); - vtk_img2.setShadingPreset(1); // Use Composite without MIP for variety + Vtk::VoxImage vtk_img2(&img2); + vtk_img2.setShadingPreset(1); // Use Composite without MIP for variety - Vtk::Viewer viewer; - viewer.GetRenderer()->SetBackground(0.05, 0.05, 0.1); - viewer.AddProp3D(vtk_img1); - viewer.AddProp3D(vtk_img2); - - // Setup KeyPress Callback - AppState state; - state.images.push_back(&vtk_img1); - state.images.push_back(&vtk_img2); - state.viewer = &viewer; + Vtk::Viewer viewer; + viewer.GetRenderer()->SetBackground(0.05, 0.05, 0.1); + viewer.AddProp3D(vtk_img1); + viewer.AddProp3D(vtk_img2); - vtkSmartPointer keyCallback = vtkSmartPointer::New(); - keyCallback->SetCallback(KeyPressCallbackFunction); - keyCallback->SetClientData(&state); - viewer.GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, keyCallback); + // Setup KeyPress Callback + AppState state; + state.images.push_back(&vtk_img1); + state.images.push_back(&vtk_img2); + state.viewer = &viewer; - std::cout << "=========================================" << std::endl; - std::cout << " VoxImage Interactive Viewer Test" << std::endl; - std::cout << " [LEFT] Spherical Shell (MIP)" << std::endl; - std::cout << " [RIGHT] Axes Gradient (Composite)" << std::endl; - std::cout << "-----------------------------------------" << std::endl; - std::cout << " Press [w] to show Wireframe Bounding Boxes" << std::endl; - std::cout << " Press [s] to show Volume Rendering" << std::endl; - std::cout << " Press [0..5] to switch Rendering Presets:" << std::endl; - std::cout << " 0: MIP (Grayscale)" << std::endl; - std::cout << " 1: Composite (Grayscale)" << std::endl; - std::cout << " 2: Composite (Shaded)" << std::endl; - std::cout << " 3: CT Bone/Tissue (Bone colors)" << std::endl; - std::cout << " 4: MIP (Rainbow)" << std::endl; - std::cout << " 5: Additive (Total path sum)" << std::endl; - std::cout << " Press [q] to quit" << std::endl; - std::cout << "=========================================" << std::endl; + vtkSmartPointer keyCallback = + vtkSmartPointer::New(); + keyCallback->SetCallback(KeyPressCallbackFunction); + keyCallback->SetClientData(&state); + viewer.GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, keyCallback); - viewer.ZoomAuto(); - viewer.Start(); + std::cout << "=========================================" << std::endl; + std::cout << " VoxImage Interactive Viewer Test" << std::endl; + std::cout << " [LEFT] Spherical Shell (MIP)" << std::endl; + std::cout << " [RIGHT] Axes Gradient (Composite)" << std::endl; + std::cout << "-----------------------------------------" << std::endl; + std::cout << " Press [w] to show Wireframe Bounding Boxes" << std::endl; + std::cout << " Press [s] to show Volume Rendering" << std::endl; + std::cout << " Press [0..5] to switch Rendering Presets:" << std::endl; + std::cout << " 0: MIP (Grayscale)" << std::endl; + std::cout << " 1: Composite (Grayscale)" << std::endl; + std::cout << " 2: Composite (Shaded)" << std::endl; + std::cout << " 3: CT Bone/Tissue (Bone colors)" << std::endl; + std::cout << " 4: MIP (Rainbow)" << std::endl; + std::cout << " 5: Additive (Total path sum)" << std::endl; + std::cout << " Press [q] to quit" << std::endl; + std::cout << "=========================================" << std::endl; - return 0; + viewer.ZoomAuto(); + viewer.Start(); + + return 0; } diff --git a/src/Vtk/Math/testing/vtkVoxImageTest.cpp b/src/Vtk/Math/testing/vtkVoxImageTest.cpp index c98f0b7..13e8314 100644 --- a/src/Vtk/Math/testing/vtkVoxImageTest.cpp +++ b/src/Vtk/Math/testing/vtkVoxImageTest.cpp @@ -23,7 +23,6 @@ //////////////////////////////////////////////////////////////////////////////*/ -#include "Vtk/Math/vtkVoxImage.h" #include "Vtk/Math/vtkVoxImage.h" #include "Vtk/uLibVtkViewer.h" @@ -46,7 +45,7 @@ BOOST_AUTO_TEST_CASE(vtkVoxImageConstruction) { img.InitVoxels(zero); img[Vector3i(3, 3, 3)] = nonzero; - Vtk::VoxImage vtk_img(img); + Vtk::VoxImage vtk_img(&img); vtk_img.SaveToXMLFile("test_vtkvoximage.vti"); if (std::getenv("CTEST_PROJECT_NAME") == nullptr) { diff --git a/src/Vtk/Math/vtkAssembly.cpp b/src/Vtk/Math/vtkAssembly.cpp index 39999fe..c67ffd8 100644 --- a/src/Vtk/Math/vtkAssembly.cpp +++ b/src/Vtk/Math/vtkAssembly.cpp @@ -31,14 +31,14 @@ namespace Vtk { // ------------------------------------------------------------------ // Assembly::Assembly(uLib::Assembly *content) - : m_Content(content), + : ObjectWrapper(content), m_ChildContext(nullptr), m_BBoxActor(nullptr), m_VtkAsm(nullptr), m_InUpdate(false) { this->InstallPipe(); - if (m_Content) { - Object::connect(m_Content, &uLib::Assembly::Updated, + if (this->m_model) { + Object::connect(this->m_model.get(), &uLib::Assembly::Updated, this, &Assembly::Update); } } @@ -71,13 +71,13 @@ void Assembly::InstallPipe() { m_BBoxActor->GetProperty()->SetLineWidth(1.5); m_BBoxActor->GetProperty()->SetOpacity(0.6); m_BBoxActor->PickableOff(); - m_BBoxActor->SetVisibility(m_Content ? m_Content->GetShowBoundingBox() : false); + m_BBoxActor->SetVisibility(this->m_model ? this->m_model->GetShowBoundingBox() : false); m_VtkAsm->AddPart(m_BBoxActor); // 3. Build a child-objects context (auto-creates prop3ds for each child) - if (m_Content) { - m_ChildContext = new ObjectsContext(m_Content); + if (this->m_model) { + m_ChildContext = new ObjectsContext(this->m_model); // Link the children context's assembly into our group assembly if (auto* childProp = vtkProp3D::SafeDownCast(m_ChildContext->GetProp())) { m_VtkAsm->AddPart(childProp); @@ -93,10 +93,10 @@ void Assembly::Update() { if (m_InUpdate) return; m_InUpdate = true; - if (m_Content && m_VtkAsm) { + if (this->m_model && m_VtkAsm) { // Apply world matrix from the assembly content vtkNew m; - Matrix4fToVtk(m_Content->GetMatrix(), m); + Matrix4fToVtk(this->m_model->GetMatrix(), m); m_VtkAsm->SetUserMatrix(m); m_VtkAsm->Modified(); } @@ -110,33 +110,33 @@ void Assembly::Update() { void Assembly::SyncFromVtk() { if (m_InUpdate) return; - if (!m_Content || !m_VtkAsm) return; + if (!this->m_model || !m_VtkAsm) return; m_InUpdate = true; // VTK -> Model: Update world matrix (accounting for model parents) if (vtkProp3D* proxy = this->GetProxyProp()) { - m_Content->SetWorldMatrix(VtkToMatrix4f(proxy->GetUserMatrix())); - m_Content->FromMatrix(m_Content->GetMatrix()); + this->m_model->SetWorldMatrix(VtkToMatrix4f(proxy->GetUserMatrix())); + this->m_model->FromMatrix(this->m_model->GetMatrix()); } this->UpdateBoundingBox(); if (m_ChildContext) m_ChildContext->SyncFromVtk(); - m_Content->Updated(); // Notify change in model + this->m_model->Updated(); // Notify change in model m_InUpdate = false; } // ------------------------------------------------------------------ // void Assembly::UpdateBoundingBox() { - if (!m_Content || !m_BBoxActor) return; + if (!this->m_model || !m_BBoxActor) return; - m_BBoxActor->SetVisibility(m_Content->GetShowBoundingBox()); + m_BBoxActor->SetVisibility(this->m_model->GetShowBoundingBox()); Vector3f bbMin, bbMax; - m_Content->GetBoundingBox(bbMin, bbMax); + this->m_model->GetBoundingBox(bbMin, bbMax); // Avoid degenerate boxes Vector3f size = bbMax - bbMin; diff --git a/src/Vtk/Math/vtkAssembly.h b/src/Vtk/Math/vtkAssembly.h index 3223f0d..f1d8f98 100644 --- a/src/Vtk/Math/vtkAssembly.h +++ b/src/Vtk/Math/vtkAssembly.h @@ -12,8 +12,9 @@ #ifndef U_VTK_ASSEMBLY_H #define U_VTK_ASSEMBLY_H +#include "Core/ObjectFactory.h" #include "Math/Assembly.h" -#include "uLibVtkInterface.h" +#include "Vtk/uLibVtkInterface.h" class vtkActor; class vtkAssembly; // VTK library forward declaration (must be before namespace) @@ -34,7 +35,7 @@ class ObjectsContext; // forward * the VTK library class vtkAssembly for grouping, but the two * are distinct. */ -class Assembly : public Prop3D { +class Assembly : public Prop3D, public uLib::ObjectWrapper { public: uLibTypeMacro(Assembly, Prop3D) @@ -47,8 +48,8 @@ public: /** @brief Synchronizes the model from the VTK representation (VTK→model). */ virtual void SyncFromVtk() override; - virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; } - virtual uLib::ObjectsContext* GetChildren() override { return (uLib::ObjectsContext*)m_Content; } + virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_model.get(); } + virtual uLib::ObjectsContext* GetChildren() override { return (uLib::ObjectsContext*)m_model.get(); } /** * @brief Returns the prop3d managing child objects. @@ -61,7 +62,6 @@ private: void UpdateBoundingBox(); void InstallPipe(); - uLib::Assembly *m_Content; ObjectsContext *m_ChildContext; vtkActor *m_BBoxActor; ::vtkAssembly *m_VtkAsm; // VTK library assembly — NOT this class diff --git a/src/Vtk/Math/vtkContainerBox.cpp b/src/Vtk/Math/vtkContainerBox.cpp index d8cd48c..d969617 100644 --- a/src/Vtk/Math/vtkContainerBox.cpp +++ b/src/Vtk/Math/vtkContainerBox.cpp @@ -66,9 +66,10 @@ struct ContainerBoxData { ContainerBox::ContainerBox(ContainerBox::Content *content) - : d(new ContainerBoxData()), m_Content(content) { + : d(new ContainerBoxData()), ObjectWrapper(content) { this->InstallPipe(); - d->m_UpdateSignal = Object::connect(m_Content, &uLib::Object::Updated, this, &ContainerBox::Update); + d->m_UpdateSignal = + Object::connect(this->m_model.get(), &uLib::Object::Updated, this, &ContainerBox::Update); } ContainerBox::~ContainerBox() { @@ -83,13 +84,13 @@ vtkPolyData *ContainerBox::GetPolyData() const { void ContainerBox::Update() { RecursiveMutex::ScopedLock lock(this->m_UpdateMutex); - if (!m_Content) return; + if (!this->m_model) return; vtkProp3D* prop = vtkProp3D::SafeDownCast(this->GetProp()); if (prop) { // Apply the full volume matrix (TRS * m_LocalT) vtkNew m; - Matrix4fToVtk(m_Content->GetMatrix(), m); + Matrix4fToVtk(this->m_model->GetMatrix(), m); prop->SetUserMatrix(m); prop->Modified(); } @@ -104,7 +105,7 @@ void ContainerBox::Update() { void ContainerBox::SyncFromVtk() { RecursiveMutex::ScopedLock lock(this->m_UpdateMutex); - if (!m_Content) return; + if (!this->m_model) return; vtkProp3D* root = this->GetProxyProp(); if (!root) return; @@ -114,11 +115,11 @@ void ContainerBox::SyncFromVtk() { Matrix4f vtkWorld = VtkToMatrix4f(rootMat); // Synchronize TRS property members from the updated local matrix - m_Content->FromMatrix(vtkWorld); + this->m_model->FromMatrix(vtkWorld); // Since we modified the model, notify observers, but block the loop back to VTK // ConnectionBlock blocker(d->m_UpdateSignal); - m_Content->Updated(); + this->m_model->Updated(); } @@ -126,9 +127,9 @@ void ContainerBox::SyncFromVtk() { void ContainerBox::InstallPipe() { - if (!m_Content) + if (!this->m_model) return; - Content *c = m_Content; + Content *c = this->m_model; // CUBE vtkSmartPointer cube = vtkSmartPointer::New(); diff --git a/src/Vtk/Math/vtkContainerBox.h b/src/Vtk/Math/vtkContainerBox.h index d032b4c..f84bb7e 100644 --- a/src/Vtk/Math/vtkContainerBox.h +++ b/src/Vtk/Math/vtkContainerBox.h @@ -26,6 +26,7 @@ #ifndef U_VTKCONTAINERBOX_H #define U_VTKCONTAINERBOX_H +#include "Core/ObjectFactory.h" #include "Math/ContainerBox.h" #include "uLibVtkInterface.h" #include "vtkPolydata.h" @@ -37,11 +38,13 @@ namespace Vtk { struct ContainerBoxData; -class ContainerBox : public Prop3D, public Polydata { - +class ContainerBox : public Prop3D, + public Polydata, + public uLib::ObjectWrapper { + uLibTypeMacro(ContainerBox, Prop3D, Polydata) typedef uLib::ContainerBox Content; - + public: ContainerBox(Content *content); ~ContainerBox(); @@ -58,14 +61,15 @@ public: */ virtual void SyncFromVtk() override; - virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; } + virtual uLib::Object *GetContent() const override { + return (uLib::Object *)m_model.get(); + } protected: virtual void InstallPipe(); struct ContainerBoxData *d; - uLib::ContainerBox *m_Content; - + ULIB_DECLARE_PROPERTIES(ContainerBox) }; diff --git a/src/Vtk/Math/vtkCylinder.cpp b/src/Vtk/Math/vtkCylinder.cpp index 35a4588..e4a7351 100644 --- a/src/Vtk/Math/vtkCylinder.cpp +++ b/src/Vtk/Math/vtkCylinder.cpp @@ -38,9 +38,9 @@ namespace uLib { namespace Vtk { Cylinder::Cylinder(Cylinder::Content *content) - : m_Content(content), m_Actor(nullptr), m_VtkAsm(nullptr) { + : ObjectWrapper(content), m_Actor(nullptr), m_VtkAsm(nullptr) { this->InstallPipe(); - m_UpdateSignal = Object::connect(m_Content, &uLib::Object::Updated, this, &Cylinder::Update); + m_UpdateSignal = Object::connect(this->m_model.get(), &uLib::Object::Updated, this, &Cylinder::Update); } Cylinder::~Cylinder() { @@ -49,14 +49,14 @@ Cylinder::~Cylinder() { } void Cylinder::Update() { - if (!m_Content) + if (!this->m_model) return; vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp()); if (root) { // 1. Placement handled specifically from content (use TRS GetMatrix, not World) vtkNew m; - Matrix4fToVtk(m_Content->GetMatrix(), m); + Matrix4fToVtk(this->m_model->GetMatrix(), m); root->SetUserMatrix(m); // 2. Shape-local properties (Radius, Height, Axis alignment) go to the internal actor @@ -68,10 +68,10 @@ void Cylinder::Update() { // Initial source is centered Y-cylinder (Radial XZ [-1,1], Height Y [-0.5, 0.5]) // Apply Radius and Height scaling - alignment->Scale(m_Content->GetRadius(), m_Content->GetHeight(), m_Content->GetRadius()); + alignment->Scale(this->m_model->GetRadius(), this->m_model->GetHeight(), this->m_model->GetRadius()); // Apply Axis alignment - int axis = m_Content->GetAxis(); + int axis = this->m_model->GetAxis(); if (axis == 0) alignment->RotateZ(-90); // Y -> X else if (axis == 1) ; // Y -> Y (identity) else if (axis == 2) alignment->RotateX(90); // Y -> Z @@ -86,7 +86,7 @@ void Cylinder::Update() { } void Cylinder::SyncFromVtk() { - if (!m_Content) return; + if (!this->m_model) return; vtkProp3D* root = this->GetProxyProp(); if (!root) return; @@ -96,12 +96,12 @@ void Cylinder::SyncFromVtk() { Matrix4f vtkWorld = VtkToMatrix4f(rootMat); // Directly sync model from the world matrix - m_Content->FromMatrix(vtkWorld); - m_Content->Updated(); + this->m_model->FromMatrix(vtkWorld); + this->m_model->Updated(); } void Cylinder::InstallPipe() { - if (!m_Content) + if (!this->m_model) return; m_VtkAsm = ::vtkAssembly::New(); diff --git a/src/Vtk/Math/vtkCylinder.h b/src/Vtk/Math/vtkCylinder.h index 4450c7b..18401a3 100644 --- a/src/Vtk/Math/vtkCylinder.h +++ b/src/Vtk/Math/vtkCylinder.h @@ -26,6 +26,7 @@ #ifndef U_VTKCYLINDER_H #define U_VTKCYLINDER_H +#include "Core/ObjectFactory.h" #include "Math/Cylinder.h" #include "Vtk/uLibVtkInterface.h" #include @@ -41,7 +42,7 @@ namespace Vtk { * mathematical state of a Cylinder object. It manages the alignment * between VTK's Y-centered cylinder and uLib's Z-based coordinate system. */ -class Cylinder : public Prop3D { +class Cylinder : public Prop3D, public uLib::ObjectWrapper { typedef uLib::Cylinder Content; public: @@ -54,7 +55,9 @@ public: /** Synchronizes the uLib model matrix with the VTK actor specifically for gizmo interactions */ virtual void SyncFromVtk() override; - virtual uLib::Object* GetContent() const override { return (uLib::Object*)m_Content; } + virtual uLib::Object *GetContent() const override { + return (uLib::Object *)m_model.get(); + } protected: /** Sets up the VTK visualization pipeline */ @@ -62,7 +65,6 @@ protected: vtkActor *m_Actor; ::vtkAssembly *m_VtkAsm; - Content *m_Content; uLib::Connection m_UpdateSignal; }; diff --git a/src/Vtk/Math/vtkQuadMesh.cpp b/src/Vtk/Math/vtkQuadMesh.cpp index f3d5e1e..0f46e14 100644 --- a/src/Vtk/Math/vtkQuadMesh.cpp +++ b/src/Vtk/Math/vtkQuadMesh.cpp @@ -58,22 +58,22 @@ void QuadMesh::vtk2uLib_update() { << "number of quads = " << number_of_quads << "\n" << "//////\n"; - m_content.Points().clear(); + this->m_model->Points().clear(); for (int i = 0; i < number_of_points; ++i) { double *point = m_Poly->GetPoint(i); - m_content.Points().push_back(Vector3f(point[0], point[1], point[2])); + this->m_model->Points().push_back(Vector3f(point[0], point[1], point[2])); } - m_content.Quads().resize(number_of_quads); + this->m_model->Quads().resize(number_of_quads); m_Poly->GetPolys()->InitTraversal(); vtkSmartPointer idList = vtkSmartPointer::New(); for (int i = 0; i < number_of_quads; ++i) { m_Poly->GetPolys()->GetNextCell(idList); if (idList->GetNumberOfIds() == 4) { - m_content.Quads()[i](0) = idList->GetId(0); - m_content.Quads()[i](1) = idList->GetId(1); - m_content.Quads()[i](2) = idList->GetId(2); - m_content.Quads()[i](3) = idList->GetId(3); + this->m_model->Quads()[i](0) = idList->GetId(0); + this->m_model->Quads()[i](1) = idList->GetId(1); + this->m_model->Quads()[i](2) = idList->GetId(2); + this->m_model->Quads()[i](3) = idList->GetId(3); } } m_Poly->Modified(); @@ -81,23 +81,23 @@ void QuadMesh::vtk2uLib_update() { } void QuadMesh::uLib2vtk_update() { - vtkIdType number_of_points = m_content.Points().size(); - vtkIdType number_of_quads = m_content.Quads().size(); + vtkIdType number_of_points = this->m_model->Points().size(); + vtkIdType number_of_quads = this->m_model->Quads().size(); vtkSmartPointer points = vtkSmartPointer::New(); points->SetNumberOfPoints(number_of_points); for (vtkIdType i = 0; i < number_of_points; i++) { - Vector3f p = m_content.Points().at(i); + Vector3f p = this->m_model->Points().at(i); points->SetPoint(i, p(0), p(1), p(2)); } vtkSmartPointer polys = vtkSmartPointer::New(); for (vtkIdType i = 0; i < number_of_quads; i++) { vtkIdType a, b, c, d; - a = m_content.Quads().at(i)(0); - b = m_content.Quads().at(i)(1); - c = m_content.Quads().at(i)(2); - d = m_content.Quads().at(i)(3); + a = this->m_model->Quads().at(i)(0); + b = this->m_model->Quads().at(i)(1); + c = this->m_model->Quads().at(i)(2); + d = this->m_model->Quads().at(i)(3); polys->InsertNextCell(4); polys->InsertCellPoint(a); polys->InsertCellPoint(b); @@ -118,7 +118,7 @@ void QuadMesh::contentUpdate() { vmat = mat; } - Matrix4f transform = m_content.GetWorldMatrix(); + Matrix4f transform = this->m_model->GetWorldMatrix(); Matrix4fToVtk(transform, vmat); uLib2vtk_update(); @@ -133,30 +133,30 @@ void QuadMesh::Update() { if (!vmat) return; Matrix4f transform = VtkToMatrix4f(vmat); - m_content.SetMatrix(transform); - m_content.Updated(); + this->m_model->SetMatrix(transform); + this->m_model->Updated(); } // -------------------------------------------------------------------------- // -QuadMesh::QuadMesh(QuadMesh::Content &content) - : m_content(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) { +QuadMesh::QuadMesh(QuadMesh::Content *content) + : ObjectWrapper(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) { vtkSmartPointer mapper = vtkSmartPointer::New(); mapper->SetInputData(m_Poly); m_Actor->SetMapper(mapper); vtkNew vmat; - Matrix4fToVtk(m_content.GetWorldMatrix(), vmat); + Matrix4fToVtk(this->m_model->GetWorldMatrix(), vmat); m_Actor->SetUserMatrix(vmat); this->SetProp(m_Actor); - Object::connect(&m_content, &Content::Updated, this, &QuadMesh::contentUpdate); + Object::connect(this->m_model.get(), &Content::Updated, this, &QuadMesh::contentUpdate); this->contentUpdate(); } QuadMesh::~QuadMesh() { - Object::disconnect(&m_content, &Content::Updated, this, &QuadMesh::contentUpdate); + Object::disconnect(this->m_model.get(), &Content::Updated, this, &QuadMesh::contentUpdate); m_Poly->Delete(); m_Actor->Delete(); } diff --git a/src/Vtk/Math/vtkQuadMesh.h b/src/Vtk/Math/vtkQuadMesh.h index afae29c..71c1484 100644 --- a/src/Vtk/Math/vtkQuadMesh.h +++ b/src/Vtk/Math/vtkQuadMesh.h @@ -26,9 +26,10 @@ #ifndef VTKQUADMESH_H #define VTKQUADMESH_H +#include "Core/ObjectFactory.h" #include "Math/QuadMesh.h" -#include "Vtk/uLibVtkInterface.h" #include "Vtk/Math/vtkPolydata.h" +#include "Vtk/uLibVtkInterface.h" class vtkPolyData; class vtkActor; @@ -36,11 +37,13 @@ class vtkActor; namespace uLib { namespace Vtk { -class QuadMesh : public Prop3D, public Polydata { +class QuadMesh : public Prop3D, + public Polydata, + public uLib::ObjectWrapper { typedef uLib::QuadMesh Content; public: - QuadMesh(Content &content); + QuadMesh(Content *content); ~QuadMesh(); void ReadFromFile(const char *filename); @@ -56,12 +59,15 @@ public: virtual void contentUpdate(); virtual void Update(); + uLib::Object *GetContent() const override { + return (uLib::Object *)m_model.get(); + } private: void vtk2uLib_update(); void uLib2vtk_update(); - uLib::QuadMesh &m_content; + // ObjectWrapper provides m_model vtkPolyData *m_Poly; vtkActor *m_Actor; }; diff --git a/src/Vtk/Math/vtkStructuredGrid.cpp b/src/Vtk/Math/vtkStructuredGrid.cpp index 5932ecc..73d7170 100644 --- a/src/Vtk/Math/vtkStructuredGrid.cpp +++ b/src/Vtk/Math/vtkStructuredGrid.cpp @@ -39,8 +39,8 @@ namespace Vtk { ////// VTK STRUCTURED GRID ///////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -StructuredGrid::StructuredGrid(Content &content) - : m_Content(&content), m_Actor(vtkActor::New()), +StructuredGrid::StructuredGrid(Content *content) + : ObjectWrapper(content), m_Actor(vtkActor::New()), m_Transform(vtkTransform::New()) { this->InstallPipe(); @@ -54,10 +54,10 @@ StructuredGrid::~StructuredGrid() { void StructuredGrid::SetTransform(vtkTransform *t) { vtkMatrix4x4 *vmat = t->GetMatrix(); Matrix4f mat = VtkToMatrix4f(vmat); - m_Content->SetMatrix(mat); + this->m_model->SetMatrix(mat); vtkSmartPointer vmat2 = vtkSmartPointer::New(); - mat = m_Content->GetWorldMatrix(); + mat = this->m_model->GetWorldMatrix(); Matrix4fToVtk(mat, vmat2); m_Transform->SetMatrix(vmat2); m_Transform->Update(); @@ -65,7 +65,7 @@ void StructuredGrid::SetTransform(vtkTransform *t) { } void StructuredGrid::Update() { - if (!m_Content) return; + if (!this->m_model) return; vtkProp3D* actor = vtkProp3D::SafeDownCast(this->GetProp()); if (!actor) return; @@ -76,20 +76,20 @@ void StructuredGrid::Update() { Matrix4f transform = VtkToMatrix4f(vmat); // Update uLib model's affine transform - if (m_Content->GetParent()) { - Matrix4f localT = m_Content->GetParent()->GetWorldMatrix().inverse() * transform; - m_Content->SetMatrix(localT); + if (this->m_model->GetParent()) { + Matrix4f localT = this->m_model->GetParent()->GetWorldMatrix().inverse() * transform; + this->m_model->SetMatrix(localT); } else { - m_Content->SetMatrix(transform); + this->m_model->SetMatrix(transform); } - m_Content->Updated(); // Notify others (like raytracer) + this->m_model->Updated(); // Notify others (like raytracer) } void StructuredGrid::InstallPipe() { vtkSmartPointer cube = vtkSmartPointer::New(); - Vector3i dims = m_Content->GetDims(); + Vector3i dims = this->m_model->GetDims(); cube->SetBounds(0, dims(0), 0, dims(1), 0, dims(2)); cube->Update(); @@ -104,7 +104,7 @@ void StructuredGrid::InstallPipe() { m_Actor->GetProperty()->SetAmbient(0.7); vtkNew vmat; - Matrix4fToVtk(m_Content->GetWorldMatrix(), vmat); + Matrix4fToVtk(this->m_model->GetWorldMatrix(), vmat); m_Actor->SetUserMatrix(vmat); this->SetProp(m_Actor); diff --git a/src/Vtk/Math/vtkStructuredGrid.h b/src/Vtk/Math/vtkStructuredGrid.h index bb79422..c4a7f5d 100644 --- a/src/Vtk/Math/vtkStructuredGrid.h +++ b/src/Vtk/Math/vtkStructuredGrid.h @@ -41,28 +41,32 @@ #include "Vtk/Math/vtkDense.h" +#include "Core/ObjectFactory.h" #include "Math/StructuredGrid.h" #include "Vtk/uLibVtkInterface.h" namespace uLib { namespace Vtk { -class StructuredGrid : public Prop3D { +class StructuredGrid : public Prop3D, + public uLib::ObjectWrapper { typedef uLib::StructuredGrid Content; public: - StructuredGrid(Content &content); + StructuredGrid(Content *content); ~StructuredGrid(); void SetTransform(class vtkTransform *t); virtual void Update() override; + uLib::Object *GetContent() const override { + return (uLib::Object *)m_model.get(); + } private: void InstallPipe(); vtkActor *m_Actor; - uLib::StructuredGrid *m_Content; vtkTransform *m_Transform; }; diff --git a/src/Vtk/Math/vtkTriangleMesh.cpp b/src/Vtk/Math/vtkTriangleMesh.cpp index 5666586..60edb35 100644 --- a/src/Vtk/Math/vtkTriangleMesh.cpp +++ b/src/Vtk/Math/vtkTriangleMesh.cpp @@ -58,42 +58,42 @@ void TriangleMesh::vtk2uLib_update() { << "number of polys = " << number_of_triangles << "\n" << "//////\n"; - m_content.Points().clear(); + this->m_model->Points().clear(); for (int i = 0; i < number_of_points; ++i) { double *point = m_Poly->GetPoint(i); - m_content.Points().push_back(Vector3f(point[0], point[1], point[2])); + this->m_model->Points().push_back(Vector3f(point[0], point[1], point[2])); } - m_content.Triangles().resize(number_of_triangles); + this->m_model->Triangles().resize(number_of_triangles); m_Poly->GetPolys()->InitTraversal(); vtkSmartPointer idList = vtkSmartPointer::New(); for (int i = 0; i < number_of_triangles; ++i) { m_Poly->GetPolys()->GetNextCell(idList); - m_content.Triangles()[i](0) = idList->GetId(0); - m_content.Triangles()[i](1) = idList->GetId(1); - m_content.Triangles()[i](2) = idList->GetId(2); + this->m_model->Triangles()[i](0) = idList->GetId(0); + this->m_model->Triangles()[i](1) = idList->GetId(1); + this->m_model->Triangles()[i](2) = idList->GetId(2); } m_Poly->Modified(); m_Actor->GetMapper()->Update(); } void TriangleMesh::uLib2vtk_update() { - vtkIdType number_of_points = m_content.Points().size(); - vtkIdType number_of_triangles = m_content.Triangles().size(); + vtkIdType number_of_points = this->m_model->Points().size(); + vtkIdType number_of_triangles = this->m_model->Triangles().size(); vtkSmartPointer points = vtkSmartPointer::New(); points->SetNumberOfPoints(number_of_points); for (vtkIdType i = 0; i < number_of_points; i++) { - Vector3f p = m_content.Points().at(i); + Vector3f p = this->m_model->Points().at(i); points->SetPoint(i, p(0), p(1), p(2)); } vtkSmartPointer polys = vtkSmartPointer::New(); for (vtkIdType i = 0; i < number_of_triangles; i++) { vtkIdType a, b, c; - a = m_content.Triangles().at(i)(0); - b = m_content.Triangles().at(i)(1); - c = m_content.Triangles().at(i)(2); + a = this->m_model->Triangles().at(i)(0); + b = this->m_model->Triangles().at(i)(1); + c = this->m_model->Triangles().at(i)(2); polys->InsertNextCell(3); polys->InsertCellPoint(a); polys->InsertCellPoint(b); @@ -113,7 +113,7 @@ void TriangleMesh::contentUpdate() { vmat = mat; } - Matrix4f transform = m_content.GetWorldMatrix(); + Matrix4f transform = this->m_model->GetWorldMatrix(); Matrix4fToVtk(transform, vmat); uLib2vtk_update(); @@ -128,30 +128,30 @@ void TriangleMesh::Update() { if (!vmat) return; Matrix4f transform = VtkToMatrix4f(vmat); - m_content.SetMatrix(transform); - m_content.Updated(); + this->m_model->SetMatrix(transform); + this->m_model->Updated(); } // -------------------------------------------------------------------------- // -TriangleMesh::TriangleMesh(TriangleMesh::Content &content) - : m_content(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) { +TriangleMesh::TriangleMesh(TriangleMesh::Content *content) + : ObjectWrapper(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) { vtkSmartPointer mapper = vtkSmartPointer::New(); mapper->SetInputData(m_Poly); m_Actor->SetMapper(mapper); vtkNew vmat; - Matrix4fToVtk(m_content.GetWorldMatrix(), vmat); + Matrix4fToVtk(this->m_model->GetWorldMatrix(), vmat); m_Actor->SetUserMatrix(vmat); this->SetProp(m_Actor); - Object::connect(&m_content, &Content::Updated, this, &TriangleMesh::contentUpdate); + Object::connect(this->m_model.get(), &Content::Updated, this, &TriangleMesh::contentUpdate); this->contentUpdate(); } TriangleMesh::~TriangleMesh() { - Object::disconnect(&m_content, &Content::Updated, this, &TriangleMesh::contentUpdate); + Object::disconnect(this->m_model.get(), &Content::Updated, this, &TriangleMesh::contentUpdate); m_Poly->Delete(); m_Actor->Delete(); } diff --git a/src/Vtk/Math/vtkTriangleMesh.h b/src/Vtk/Math/vtkTriangleMesh.h index 17afe74..5487864 100644 --- a/src/Vtk/Math/vtkTriangleMesh.h +++ b/src/Vtk/Math/vtkTriangleMesh.h @@ -26,9 +26,10 @@ #ifndef VTKTRIANGLEMESH_H #define VTKTRIANGLEMESH_H +#include "Core/ObjectFactory.h" #include "Math/TriangleMesh.h" -#include "Vtk/uLibVtkInterface.h" #include "Vtk/Math/vtkPolydata.h" +#include "Vtk/uLibVtkInterface.h" class vtkPolyData; class vtkActor; @@ -36,11 +37,13 @@ class vtkActor; namespace uLib { namespace Vtk { -class TriangleMesh : public Prop3D, public Polydata { +class TriangleMesh : public Prop3D, + public Polydata, + public uLib::ObjectWrapper { typedef uLib::TriangleMesh Content; public: - TriangleMesh(Content &content); + TriangleMesh(Content *content); ~TriangleMesh(); void ReadFromFile(const char *filename); @@ -56,12 +59,15 @@ public: virtual void contentUpdate(); virtual void Update(); + uLib::Object *GetContent() const override { + return (uLib::Object *)m_model.get(); + } private: void vtk2uLib_update(); void uLib2vtk_update(); - uLib::TriangleMesh &m_content; + // ObjectWrapper provides m_model vtkPolyData *m_Poly; vtkActor *m_Actor; }; diff --git a/src/Vtk/Math/vtkVoxImage.cpp b/src/Vtk/Math/vtkVoxImage.cpp index d691b40..9e10f0f 100644 --- a/src/Vtk/Math/vtkVoxImage.cpp +++ b/src/Vtk/Math/vtkVoxImage.cpp @@ -61,13 +61,13 @@ namespace uLib { namespace Vtk { void VoxImage::UpdateFromContent() { - Vector3i ev_dims = m_Content.GetDims(); + Vector3i ev_dims = this->m_model->GetDims(); m_Image->SetDimensions(ev_dims.data()); - Vector3f ev_spacing = m_Content.GetSpacing(); + Vector3f ev_spacing = this->m_model->GetSpacing(); m_Image->SetSpacing(ev_spacing(0), ev_spacing(1), ev_spacing(2)); - Vector3f ev_pos = m_Content.GetPosition(); + Vector3f ev_pos = this->m_model->GetPosition(); m_Image->SetOrigin(ev_pos(0), ev_pos(1), ev_pos(2)); vtkFloatArray *array = @@ -78,14 +78,14 @@ void VoxImage::UpdateFromContent() { array->Delete(); } - array->SetNumberOfTuples(m_Content.GetDims().prod()); + array->SetNumberOfTuples(this->m_model->GetDims().prod()); Vector3i index(0, 0, 0); int i = 0; for (int zv = 0; zv < ev_dims(2); ++zv) { for (int yv = 0; yv < ev_dims(1); ++yv) { for (int xv = 0; xv < ev_dims(0); ++xv) { index << xv, yv, zv; - array->SetValue(i++, m_Content.GetValue(index)); + array->SetValue(i++, this->m_model->GetValue(index)); } } } @@ -94,13 +94,13 @@ void VoxImage::UpdateFromContent() { void VoxImage::UpdateToContent() { int *ext = m_Image->GetExtent(); int dims[3] = {ext[1] - ext[0] + 1, ext[3] - ext[2] + 1, ext[5] - ext[4] + 1}; - m_Content.SetDims(Vector3i(dims[0], dims[1], dims[2])); + this->m_model->SetDims(Vector3i(dims[0], dims[1], dims[2])); double *spacing = m_Image->GetSpacing(); - m_Content.SetSpacing(Vector3f(spacing[0], spacing[1], spacing[2])); + this->m_model->SetSpacing(Vector3f(spacing[0], spacing[1], spacing[2])); double *pos = m_Image->GetOrigin(); - m_Content.SetPosition(Vector3f(pos[0], pos[1], pos[2])); + this->m_model->SetPosition(Vector3f(pos[0], pos[1], pos[2])); vtkFloatArray *array = vtkFloatArray::SafeDownCast(m_Image->GetPointData()->GetScalars()); @@ -111,7 +111,7 @@ void VoxImage::UpdateToContent() { for (int yv = 0; yv < dims[1]; ++yv) { for (int xv = 0; xv < dims[0]; ++xv) { index << xv, yv, zv; - m_Content.SetValue(index, array->GetValue(i++)); + this->m_model->SetValue(index, array->GetValue(i++)); } } } @@ -124,8 +124,8 @@ void VoxImage::UpdateToContent() { //////////////////////////////////////////////////////////////////////////////// // VTK VOXIMAGE -VoxImage::VoxImage(Content &content) - : m_Content(content), m_Actor(vtkVolume::New()), +VoxImage::VoxImage(Content *content) + : ObjectWrapper(content), m_Actor(vtkVolume::New()), m_Asm(vtkAssembly::New()), m_Image(vtkImageData::New()), m_Outline(vtkCubeSource::New()), m_OutlineActor(vtkActor::New()), @@ -134,7 +134,7 @@ VoxImage::VoxImage(Content &content) // Transfer functions m_ColorFun = vtkColorTransferFunction::New(); m_OpacityFun = vtkPiecewiseFunction::New(); - m_UpdateConnection = Object::connect(&m_Content, &uLib::Object::Updated, this, &VoxImage::Update); + m_UpdateConnection = Object::connect(this->m_model.get(), &uLib::Object::Updated, this, &VoxImage::Update); UpdateFromContent(); InstallPipe(); @@ -314,8 +314,8 @@ void VoxImage::SyncFromVtk() { if (rootMat) { Matrix4f vtkLocal = VtkToMatrix4f(rootMat); // Synchronize TRS from VTK, compensating for local volume offset - m_Content.FromMatrix(vtkLocal); // * m_Content.GetLocalMatrix().inverse()); - m_Content.Updated(); + this->m_model->FromMatrix(vtkLocal); // * this->m_model->GetLocalMatrix().inverse()); + this->m_model->Updated(); } } } @@ -323,11 +323,11 @@ void VoxImage::SyncFromVtk() { void VoxImage::Update() { if (auto *root = vtkProp3D::SafeDownCast(this->GetProp())) { vtkNew m; - Matrix4fToVtk(m_Content.GetMatrix(), m); // * m_Content.GetLocalMatrix(), m); + Matrix4fToVtk(this->m_model->GetMatrix(), m); // * this->m_model->GetLocalMatrix(), m); root->SetUserMatrix(m); root->Modified(); // std::cout << "[VoxImage::Update] Set Proxy UserMatrix:" << std::endl; - // std::cout << m_Content.GetMatrix() << std::endl; + // std::cout << this->m_model->GetMatrix() << std::endl; } setShadingPreset(m_ShadingPreset); m_Actor->Update(); diff --git a/src/Vtk/Math/vtkVoxImage.h b/src/Vtk/Math/vtkVoxImage.h index b04a651..7503fe3 100644 --- a/src/Vtk/Math/vtkVoxImage.h +++ b/src/Vtk/Math/vtkVoxImage.h @@ -26,15 +26,16 @@ #ifndef U_VTKVOXIMAGE_H #define U_VTKVOXIMAGE_H +#include #include #include #include #include #include -#include #include +#include "Core/ObjectFactory.h" #include "Vtk/uLibVtkInterface.h" class vtkImageData; @@ -45,18 +46,21 @@ class vtkPiecewiseFunction; namespace uLib { namespace Vtk { -class VoxImage : public Prop3D { +class VoxImage : public Prop3D, + public uLib::ObjectWrapper { public: typedef Abstract::VoxImage Content; - VoxImage(Content &content); + VoxImage(Content *content); ~VoxImage(); void UpdateFromContent(); void UpdateToContent(); - uLib::Object* GetContent() const override { return (uLib::Object*)&m_Content; } + uLib::Object *GetContent() const override { + return (uLib::Object *)m_model.get(); + } vtkProp3D *GetProp() override { return m_Asm; } @@ -74,7 +78,8 @@ public: void Update() override; void SyncFromVtk() override; - void serialize_display(uLib::Archive::display_properties_archive & ar, const unsigned int version = 0) override; + void serialize_display(uLib::Archive::display_properties_archive &ar, + const unsigned int version = 0) override; protected: void InstallPipe(); @@ -90,7 +95,7 @@ private: vtkXMLImageDataReader *m_Reader; vtkXMLImageDataWriter *m_Writer; - VoxImage::Content &m_Content; + // ObjectWrapper provides m_model float m_Window; float m_Level; diff --git a/src/Vtk/vtkObjectsContext.cpp b/src/Vtk/vtkObjectsContext.cpp index 4d6a1fc..b73260b 100644 --- a/src/Vtk/vtkObjectsContext.cpp +++ b/src/Vtk/vtkObjectsContext.cpp @@ -1,24 +1,23 @@ #include "vtkObjectsContext.h" +#include "Vtk/Math/vtkAssembly.h" #include "Vtk/Math/vtkContainerBox.h" #include "Vtk/Math/vtkCylinder.h" -#include "Vtk/Math/vtkAssembly.h" #include "Vtk/Math/vtkVoxImage.h" #include "Vtk/HEP/Detectors/vtkDetectorChamber.h" #include "Vtk/HEP/Geant/vtkBoxSolid.h" +#include +#include #include #include -#include -#include -#include "Math/ContainerBox.h" -#include "Math/Cylinder.h" -#include "Math/Assembly.h" -#include "Math/VoxImage.h" #include "HEP/Detectors/DetectorChamber.h" #include "HEP/Geant/Solid.h" - +#include "Math/Assembly.h" +#include "Math/ContainerBox.h" +#include "Math/Cylinder.h" +#include "Math/VoxImage.h" namespace uLib { namespace Vtk { @@ -27,35 +26,41 @@ ObjectsContext::ObjectsContext(uLib::ObjectsContext *context) : m_Context(context), m_Assembly(::vtkAssembly::New()) { this->SetProp(m_Assembly); if (m_Context) { - Object::connect(m_Context, &uLib::ObjectsContext::ObjectAdded, this, &ObjectsContext::OnObjectAdded); - Object::connect(m_Context, &uLib::ObjectsContext::ObjectRemoved, this, &ObjectsContext::OnObjectRemoved); + Object::connect(m_Context, &uLib::ObjectsContext::ObjectAdded, this, + &ObjectsContext::OnObjectAdded); + Object::connect(m_Context, &uLib::ObjectsContext::ObjectRemoved, this, + &ObjectsContext::OnObjectRemoved); this->Synchronize(); } } ObjectsContext::~ObjectsContext() { - for (auto const& [obj, prop3d] : m_Prop3Ds) { + for (auto const &[obj, prop3d] : m_Prop3Ds) { delete prop3d; } m_Assembly->Delete(); } void ObjectsContext::Synchronize() { - if (!m_Context) return; + if (!m_Context) + return; // 1. Identify objects to add and remove - const auto& objects = m_Context->GetObjects(); - std::map currentObjects; - for (auto obj : objects) currentObjects[obj] = true; + const auto &objects = m_Context->GetObjects(); + std::map currentObjects; + for (auto obj : objects) + currentObjects[obj] = true; // Remove Prop3Ds for objects no longer in context - for (auto it = m_Prop3Ds.begin(); it != m_Prop3Ds.end(); ) { + for (auto it = m_Prop3Ds.begin(); it != m_Prop3Ds.end();) { if (currentObjects.find(it->first) == currentObjects.end()) { - it->second->DisconnectRenderer(nullptr); // If we have a ref to a renderer we should disconnect but Prop3D doesn't store it easily + it->second->DisconnectRenderer( + nullptr); // If we have a ref to a renderer we should disconnect but + // Prop3D doesn't store it easily // Actually Prop3D::DisconnectRenderer(vtkRenderer*) needs the renderer. // For now we just remove from assembly - if (auto* p3d = vtkProp3D::SafeDownCast(it->second->GetProp())) - m_Assembly->RemovePart(p3d); + if (auto *p3d = vtkProp3D::SafeDownCast(it->second->GetProp())) + m_Assembly->RemovePart(p3d); this->Prop3DRemoved(it->second); delete it->second; it = m_Prop3Ds.erase(it); @@ -67,92 +72,97 @@ void ObjectsContext::Synchronize() { // Add Prop3Ds for new objects for (auto obj : objects) { if (m_Prop3Ds.find(obj) == m_Prop3Ds.end()) { - Prop3D* prop3d = this->CreateProp3D(obj); + Prop3D *prop3d = this->CreateProp3D(obj); if (prop3d) { m_Prop3Ds[obj] = prop3d; - if (auto* p3d = vtkProp3D::SafeDownCast(prop3d->GetProp())) - m_Assembly->AddPart(p3d); + if (auto *p3d = vtkProp3D::SafeDownCast(prop3d->GetProp())) + m_Assembly->AddPart(p3d); this->Prop3DAdded(prop3d); } } } } -void ObjectsContext::OnObjectAdded(uLib::Object* obj) { - if (!obj) return; +void ObjectsContext::OnObjectAdded(uLib::Object *obj) { + if (!obj) + return; if (m_Prop3Ds.find(obj) == m_Prop3Ds.end()) { - Prop3D* prop3d = this->CreateProp3D(obj); + Prop3D *prop3d = this->CreateProp3D(obj); if (prop3d) { m_Prop3Ds[obj] = prop3d; - if (auto* p3d = vtkProp3D::SafeDownCast(prop3d->GetProp())) - m_Assembly->AddPart(p3d); + if (auto *p3d = vtkProp3D::SafeDownCast(prop3d->GetProp())) + m_Assembly->AddPart(p3d); this->Prop3DAdded(prop3d); } } } -void ObjectsContext::OnObjectRemoved(uLib::Object* obj) { - if (!obj) return; - auto it = m_Prop3Ds.find(obj); - if (it != m_Prop3Ds.end()) { - // For now we just remove from assembly. - // Prop3D::DisconnectRenderer(vtkRenderer*) needs the renderer, but we don't have it here easily. - if (auto* p3d = vtkProp3D::SafeDownCast(it->second->GetProp())) - m_Assembly->RemovePart(p3d); - this->Prop3DRemoved(it->second); - delete it->second; - m_Prop3Ds.erase(it); - } +void ObjectsContext::OnObjectRemoved(uLib::Object *obj) { + if (!obj) + return; + auto it = m_Prop3Ds.find(obj); + if (it != m_Prop3Ds.end()) { + // For now we just remove from assembly. + // Prop3D::DisconnectRenderer(vtkRenderer*) needs the renderer, but we don't + // have it here easily. + if (auto *p3d = vtkProp3D::SafeDownCast(it->second->GetProp())) + m_Assembly->RemovePart(p3d); + this->Prop3DRemoved(it->second); + delete it->second; + m_Prop3Ds.erase(it); + } } -Prop3D* ObjectsContext::GetProp3D(uLib::Object* obj) { +Prop3D *ObjectsContext::GetProp3D(uLib::Object *obj) { auto it = m_Prop3Ds.find(obj); - if (it != m_Prop3Ds.end()) return it->second; + if (it != m_Prop3Ds.end()) + return it->second; return nullptr; } void ObjectsContext::Update() { - for (auto const& [obj, prop3d] : m_Prop3Ds) { + for (auto const &[obj, prop3d] : m_Prop3Ds) { prop3d->Update(); } } void ObjectsContext::SyncFromVtk() { - for (auto const& [obj, prop3d] : m_Prop3Ds) { + for (auto const &[obj, prop3d] : m_Prop3Ds) { prop3d->SyncFromVtk(); } } -Prop3D* ObjectsContext::CreateProp3D(uLib::Object* obj) { - if (!obj) return nullptr; +Prop3D *ObjectsContext::CreateProp3D(uLib::Object *obj) { + if (!obj) + return nullptr; - if (auto* vox = dynamic_cast(obj)) { - return new VoxImage(*vox); - } else if (auto* box = dynamic_cast(obj)) { + if (auto *vox = dynamic_cast(obj)) { + return new VoxImage(vox); + } else if (auto *box = dynamic_cast(obj)) { return new ContainerBox(box); - } else if (auto* chamber = dynamic_cast(obj)) { + } else if (auto *chamber = dynamic_cast(obj)) { return new DetectorChamber(chamber); - } else if (auto* cylinder = dynamic_cast(obj)) { + } else if (auto *cylinder = dynamic_cast(obj)) { return new Cylinder(cylinder); - } else if (auto* assembly = dynamic_cast(obj)) { + } else if (auto *assembly = dynamic_cast(obj)) { return new Assembly(assembly); - } else if (auto* box = dynamic_cast(obj)) { + } else if (auto *box = dynamic_cast(obj)) { return new BoxSolid(box); } - + // Fallback if we don't know the exact class but it might be a context itself - if (auto subCtx = dynamic_cast(obj)) { - return new ObjectsContext(subCtx); + if (auto subCtx = dynamic_cast(obj)) { + return new ObjectsContext(subCtx); } return nullptr; } -void ObjectsContext::Prop3DAdded(Prop3D* prop3d) { +void ObjectsContext::Prop3DAdded(Prop3D *prop3d) { ULIB_SIGNAL_EMIT(ObjectsContext::Prop3DAdded, prop3d); } -void ObjectsContext::Prop3DRemoved(Prop3D* prop3d) { +void ObjectsContext::Prop3DRemoved(Prop3D *prop3d) { ULIB_SIGNAL_EMIT(ObjectsContext::Prop3DRemoved, prop3d); }