refactor: migrate vtk classes to use ObjectWrapper for model management and update registration logic

This commit is contained in:
AndreaRigoni
2026-04-09 10:38:45 +00:00
parent 64a87e97e3
commit db76513e79
27 changed files with 479 additions and 349 deletions

View File

@@ -1,29 +1,31 @@
#ifndef U_CORE_OBJECTFACTORY_H #ifndef U_CORE_OBJECTFACTORY_H
#define U_CORE_OBJECTFACTORY_H #define U_CORE_OBJECTFACTORY_H
#include <string>
#include <map>
#include <vector>
#include <functional>
#include "Core/Object.h" #include "Core/Object.h"
#include <functional>
#include <map>
#include <string>
#include <type_traits>
#include <vector>
namespace uLib { 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 { class ObjectFactory {
public: public:
typedef std::function<Object*()> FactoryFunction; typedef std::function<Object *()> FactoryFunction;
/** @brief Get the singleton instance. */ /** @brief Get the singleton instance. */
static ObjectFactory& Instance(); static ObjectFactory &Instance();
/** @brief Register a factory function for a given class name. */ /** @brief Register a factory function for a given class name. */
void Register(const std::string& className, FactoryFunction func); void Register(const std::string &className, FactoryFunction func);
/** @brief Create a new instance of the specified class. */ /** @brief Create a new instance of the specified class. */
Object* Create(const std::string& className); Object *Create(const std::string &className);
/** @brief Get the names of all registered classes. */ /** @brief Get the names of all registered classes. */
std::vector<std::string> GetRegisteredClasses() const; std::vector<std::string> GetRegisteredClasses() const;
@@ -33,8 +35,8 @@ private:
~ObjectFactory() = default; ~ObjectFactory() = default;
// Prevent copy and assignment // Prevent copy and assignment
ObjectFactory(const ObjectFactory&) = delete; ObjectFactory(const ObjectFactory &) = delete;
ObjectFactory& operator=(const ObjectFactory&) = delete; ObjectFactory &operator=(const ObjectFactory &) = delete;
std::map<std::string, FactoryFunction> m_factoryMap; std::map<std::string, FactoryFunction> m_factoryMap;
}; };
@@ -42,11 +44,11 @@ private:
/** /**
* @brief Helper class to statically register a factory function. * @brief Helper class to statically register a factory function.
*/ */
template <typename T> template <typename T> class ObjectRegistrar {
class ObjectRegistrar {
public: public:
ObjectRegistrar(const std::string& className) { ObjectRegistrar(const std::string &className) {
ObjectFactory::Instance().Register(className, []() -> Object* { return new T(); }); ObjectFactory::Instance().Register(className,
[]() -> Object * { return new T(); });
} }
}; };
@@ -58,10 +60,62 @@ public:
* Put this in the .cpp file of the class. * Put this in the .cpp file of the class.
*/ */
#define ULIB_REGISTER_OBJECT(className) \ #define ULIB_REGISTER_OBJECT(className) \
static uLib::ObjectRegistrar<className> ULIB_REG_CONCAT(g_ObjectRegistrar_, __LINE__)(#className); static uLib::ObjectRegistrar<className> ULIB_REG_CONCAT( \
g_ObjectRegistrar_, __LINE__)(#className);
#define ULIB_REGISTER_OBJECT_NAME(className, registeredName) \ #define ULIB_REGISTER_OBJECT_NAME(className, registeredName) \
static uLib::ObjectRegistrar<className> ULIB_REG_CONCAT(g_ObjectRegistrar_, __LINE__)(registeredName); static uLib::ObjectRegistrar<className> ULIB_REG_CONCAT( \
g_ObjectRegistrar_, __LINE__)(registeredName);
template <typename T> class ObjectWrapper {
public:
ObjectWrapper(const std::string &className) {
ObjectFactory::Instance().Register(className,
[]() -> Object * { return new T(); });
}
ObjectWrapper(T *model) : m_model(model) {}
template <typename U = T,
typename = std::enable_if_t<std::is_default_constructible_v<U>>>
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<T> m_model;
};
} // namespace uLib } // namespace uLib

View File

@@ -28,6 +28,7 @@
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <type_traits>
#include <utility> #include <utility>
namespace uLib { namespace uLib {
@@ -50,7 +51,11 @@ public:
* If ptr is nullptr, a new T is allocated (legacy behavior). * If ptr is nullptr, a new T is allocated (legacy behavior).
*/ */
explicit SmartPointer(T* ptr = nullptr) : m_counter(nullptr) { explicit SmartPointer(T* ptr = nullptr) : m_counter(nullptr) {
if (!ptr) ptr = new T(); if (!ptr) {
if constexpr (std::is_default_constructible_v<T>) {
ptr = new T();
}
}
if (ptr) m_counter = new ReferenceCounter(ptr); if (ptr) m_counter = new ReferenceCounter(ptr);
} }
@@ -156,6 +161,11 @@ public:
*/ */
T* get() const noexcept { return m_counter ? m_counter->ptr : nullptr; } 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. * @brief Returns the number of SmartPointers sharing ownership.
*/ */

View File

@@ -3,6 +3,7 @@
set( TESTS set( TESTS
SmartVectorTest SmartVectorTest
SmartPointerTest SmartPointerTest
ObjectWrapperTest
VectorTest VectorTest
ObjectFlagsTest ObjectFlagsTest
ObjectParametersTest ObjectParametersTest

View File

@@ -0,0 +1,26 @@
#include "Core/ObjectFactory.h"
#include <iostream>
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<Default> w1;
std::cout << "Testing ObjectWrapper with Non-Default Constructible type..." << std::endl;
NonDefault nd(10);
uLib::ObjectWrapper<NonDefault> w2(&nd);
// The following would NOT compile without SFINAE:
// uLib::ObjectWrapper<NonDefault> w3;
std::cout << "Tests passed (compilation and manual instantiation)!" << std::endl;
return 0;
}

View File

@@ -1,12 +1,12 @@
#include "Core/ObjectFactory.h" #include "Core/ObjectFactory.h"
#include "Math/Assembly.h"
#include "Math/ContainerBox.h" #include "Math/ContainerBox.h"
#include "Math/Cylinder.h" #include "Math/Cylinder.h"
#include "Math/Geometry.h" #include "Math/Geometry.h"
#include "Math/TriangleMesh.h"
#include "Math/QuadMesh.h" #include "Math/QuadMesh.h"
#include "Math/VoxImage.h"
#include "Math/Assembly.h"
#include "Math/StructuredData.h" #include "Math/StructuredData.h"
#include "Math/TriangleMesh.h"
#include "Math/VoxImage.h"
namespace uLib { namespace uLib {
@@ -14,8 +14,6 @@ ULIB_REGISTER_OBJECT(TRS)
ULIB_REGISTER_OBJECT(ContainerBox) ULIB_REGISTER_OBJECT(ContainerBox)
ULIB_REGISTER_OBJECT(Cylinder) ULIB_REGISTER_OBJECT(Cylinder)
ULIB_REGISTER_OBJECT(Assembly) ULIB_REGISTER_OBJECT(Assembly)
ULIB_REGISTER_OBJECT(CylindricalGeometry)
ULIB_REGISTER_OBJECT(SphericalGeometry)
ULIB_REGISTER_OBJECT(TriangleMesh) ULIB_REGISTER_OBJECT(TriangleMesh)
ULIB_REGISTER_OBJECT(QuadMesh) ULIB_REGISTER_OBJECT(QuadMesh)
ULIB_REGISTER_OBJECT_NAME(VoxImage<Voxel>, "VoxImage") ULIB_REGISTER_OBJECT_NAME(VoxImage<Voxel>, "VoxImage")

View File

@@ -73,13 +73,13 @@ DetectorChamber::~DetectorChamber() {
} }
DetectorChamber::Content *DetectorChamber::GetContent() const { DetectorChamber::Content *DetectorChamber::GetContent() const {
return static_cast<Content *>(m_Content); return static_cast<Content *>(this->m_model.get());
} }
void DetectorChamber::Update() { void DetectorChamber::Update() {
this->BaseClass::Update(); this->BaseClass::Update();
if (!m_Content) return; if (!this->m_model) return;
Content *c = this->GetContent(); Content *c = this->GetContent();
Vector3f size = c->GetSize(); Vector3f size = c->GetSize();
HLine3f plane = c->GetProjectionPlane(); HLine3f plane = c->GetProjectionPlane();

View File

@@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(vtkVoxRaytracerRepresentationTest) {
grid.SetSpacing(Vector3f(1, 1, 1)); grid.SetSpacing(Vector3f(1, 1, 1));
grid.SetPosition(Vector3f(0, 0, 0)); grid.SetPosition(Vector3f(0, 0, 0));
Vtk::StructuredGrid v_grid(grid); Vtk::StructuredGrid v_grid(&grid);
// voxraytracer // // voxraytracer //
VoxRaytracer rt(grid); VoxRaytracer rt(grid);

View File

@@ -23,7 +23,6 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#include "Vtk/Math/vtkQuadMesh.h"
#include "Vtk/Math/vtkQuadMesh.h" #include "Vtk/Math/vtkQuadMesh.h"
#include "Vtk/uLibVtkViewer.h" #include "Vtk/uLibVtkViewer.h"
@@ -42,7 +41,7 @@ BOOST_AUTO_TEST_CASE(vtkQuadMeshConstruction) {
mesh.AddQuad(Vector4i(0, 1, 2, 3)); mesh.AddQuad(Vector4i(0, 1, 2, 3));
Vtk::QuadMesh v_mesh(mesh); Vtk::QuadMesh v_mesh(&mesh);
Object::connect(&mesh, &QuadMesh::Updated, [&mesh]() { Object::connect(&mesh, &QuadMesh::Updated, [&mesh]() {
Vector3f points[4]; Vector3f points[4];
@@ -50,8 +49,8 @@ BOOST_AUTO_TEST_CASE(vtkQuadMeshConstruction) {
points[1] = mesh.GetPoint(1); points[1] = mesh.GetPoint(1);
points[2] = mesh.GetPoint(2); points[2] = mesh.GetPoint(2);
points[3] = mesh.GetPoint(3); points[3] = mesh.GetPoint(3);
std::cout << "mesh updated: " << points[0] << " " << points[1] std::cout << "mesh updated: " << points[0] << " " << points[1] << " "
<< " " << points[2] << " " << points[3] << std::endl; << points[2] << " " << points[3] << std::endl;
}); });
v_mesh.Update(); v_mesh.Update();

View File

@@ -23,7 +23,6 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#include "Vtk/Math/vtkStructuredGrid.h"
#include "Vtk/Math/vtkStructuredGrid.h" #include "Vtk/Math/vtkStructuredGrid.h"
#include "Vtk/uLibVtkViewer.h" #include "Vtk/uLibVtkViewer.h"
@@ -36,7 +35,7 @@ BOOST_AUTO_TEST_CASE(vtkStructuredGridTest) {
StructuredGrid grid(Vector3i(10, 10, 100)); StructuredGrid grid(Vector3i(10, 10, 100));
grid.SetSpacing(Vector3f(3, 1, 1)); grid.SetSpacing(Vector3f(3, 1, 1));
Vtk::StructuredGrid grid_viewer(grid); Vtk::StructuredGrid grid_viewer(&grid);
if (std::getenv("CTEST_PROJECT_NAME") == nullptr) { if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {
Vtk::Viewer viewer; Vtk::Viewer viewer;

View File

@@ -23,7 +23,6 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#include "Vtk/Math/vtkTriangleMesh.h"
#include "Vtk/Math/vtkTriangleMesh.h" #include "Vtk/Math/vtkTriangleMesh.h"
#include "Vtk/uLibVtkViewer.h" #include "Vtk/uLibVtkViewer.h"
@@ -40,15 +39,16 @@ BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction) {
mesh.AddPoint(Vector3f(1, 0, 0)); mesh.AddPoint(Vector3f(1, 0, 0));
mesh.AddTriangle(Vector3i(0, 1, 2)); mesh.AddTriangle(Vector3i(0, 1, 2));
Vtk::TriangleMesh v_mesh(mesh); Vtk::TriangleMesh v_mesh(&mesh);
Object::connect(&mesh, &TriangleMesh::Updated, [&mesh]() { Object::connect(&mesh, &TriangleMesh::Updated, [&mesh]() {
Vector3f points[3]; Vector3f points[3];
points[0] = mesh.GetPoint(0); points[0] = mesh.GetPoint(0);
points[1] = mesh.GetPoint(1); points[1] = mesh.GetPoint(1);
points[2] = mesh.GetPoint(2); points[2] = mesh.GetPoint(2);
std::cout << "mesh updated: " << points[0].transpose() << " " << points[1].transpose() std::cout << "mesh updated: " << points[0].transpose() << " "
<< " " << points[2].transpose() << std::endl; << points[1].transpose() << " " << points[2].transpose()
<< std::endl;
}); });
v_mesh.Update(); v_mesh.Update();
@@ -66,7 +66,7 @@ BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction) {
BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction2) { BOOST_AUTO_TEST_CASE(vtkTriangleMeshConstruction2) {
TriangleMesh mesh; TriangleMesh mesh;
Vtk::TriangleMesh v_mesh(mesh); Vtk::TriangleMesh v_mesh(&mesh);
v_mesh.ReadFromStlFile("capelluzzo.stl"); v_mesh.ReadFromStlFile("capelluzzo.stl");
v_mesh.Update(); v_mesh.Update();

View File

@@ -9,49 +9,52 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#include "Vtk/Math/vtkVoxImage.h"
#include "Vtk/Math/vtkVoxImage.h" #include "Vtk/Math/vtkVoxImage.h"
#include "Vtk/uLibVtkViewer.h" #include "Vtk/uLibVtkViewer.h"
#include <vtkSmartPointer.h>
#include <vtkCallbackCommand.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <iostream>
#include <cmath> #include <cmath>
#include <iostream>
#include <vtkCallbackCommand.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
using namespace uLib; using namespace uLib;
struct AppState { struct AppState {
std::vector<Vtk::VoxImage*> images; std::vector<Vtk::VoxImage *> images;
Vtk::Viewer* viewer; Vtk::Viewer *viewer;
}; };
void KeyPressCallbackFunction(vtkObject* caller, long unsigned int eventId, void* clientData, void* callData) { void KeyPressCallbackFunction(vtkObject *caller, long unsigned int eventId,
auto* interactor = static_cast<vtkRenderWindowInteractor*>(caller); void *clientData, void *callData) {
auto* state = static_cast<AppState*>(clientData); auto *interactor = static_cast<vtkRenderWindowInteractor *>(caller);
auto *state = static_cast<AppState *>(clientData);
std::string key = interactor->GetKeySym(); std::string key = interactor->GetKeySym();
if (key == "w") { if (key == "w") {
std::cout << "--> Switching all images to Wireframe Box" << std::endl; std::cout << "--> Switching all images to Wireframe Box" << std::endl;
for (auto* img : state->images) img->SetRepresentation(Vtk::Prop3D::Wireframe); for (auto *img : state->images)
img->SetRepresentation(Vtk::Prop3D::Wireframe);
state->viewer->GetRenderWindow()->Render(); state->viewer->GetRenderWindow()->Render();
} } else if (key == "s") {
else if (key == "s") { std::cout << "--> Switching all images to Surface (Volume Rendering)"
std::cout << "--> Switching all images to Surface (Volume Rendering)" << std::endl; << std::endl;
for (auto* img : state->images) img->SetRepresentation(Vtk::Prop3D::Surface); for (auto *img : state->images)
img->SetRepresentation(Vtk::Prop3D::Surface);
state->viewer->GetRenderWindow()->Render(); state->viewer->GetRenderWindow()->Render();
} } else if (key >= "0" && key <= "5") {
else if (key >= "0" && key <= "5") {
int preset = key[0] - '0'; int preset = key[0] - '0';
std::cout << "--> Switching all images to Rendering Preset " << preset << std::endl; std::cout << "--> Switching all images to Rendering Preset " << preset
for (auto* img : state->images) img->setShadingPreset(preset); << std::endl;
for (auto *img : state->images)
img->setShadingPreset(preset);
state->viewer->GetRenderWindow()->Render(); state->viewer->GetRenderWindow()->Render();
} }
} }
int main(int argc, char** argv) { int main(int argc, char **argv) {
float factor = 1.0e6f; float factor = 1.0e6f;
// --- Image 1: Spherical Shell --- // --- Image 1: Spherical Shell ---
@@ -66,7 +69,7 @@ int main(int argc, char** argv) {
float dx = x - 32.0f; float dx = x - 32.0f;
float dy = y - 32.0f; float dy = y - 32.0f;
float dz = z - 32.0f; float dz = z - 32.0f;
float dist = std::sqrt(dx*dx + dy*dy + dz*dz); float dist = std::sqrt(dx * dx + dy * dy + dz * dz);
Voxel v; Voxel v;
if (dist < 25.0f && dist > 10.0f) { if (dist < 25.0f && dist > 10.0f) {
v.Value = (40.0f * (25.0f - dist) / 15.0f) / factor; v.Value = (40.0f * (25.0f - dist) / 15.0f) / factor;
@@ -89,17 +92,19 @@ int main(int argc, char** argv) {
for (int x = 0; x < dims2(0); ++x) { for (int x = 0; x < dims2(0); ++x) {
Voxel v; Voxel v;
// Linear gradient along X, Y, Z // Linear gradient along X, Y, Z
float val = (float(x)/dims2(0) + float(y)/dims2(1) + float(z)/dims2(2)) / 3.0f; float val =
(float(x) / dims2(0) + float(y) / dims2(1) + float(z) / dims2(2)) /
3.0f;
v.Value = (40.0f * val) / factor; v.Value = (40.0f * val) / factor;
img2[Vector3i(x, y, z)] = v; img2[Vector3i(x, y, z)] = v;
} }
} }
} }
Vtk::VoxImage vtk_img1(img1); Vtk::VoxImage vtk_img1(&img1);
vtk_img1.setShadingPreset(0); vtk_img1.setShadingPreset(0);
Vtk::VoxImage vtk_img2(img2); Vtk::VoxImage vtk_img2(&img2);
vtk_img2.setShadingPreset(1); // Use Composite without MIP for variety vtk_img2.setShadingPreset(1); // Use Composite without MIP for variety
Vtk::Viewer viewer; Vtk::Viewer viewer;
@@ -113,7 +118,8 @@ int main(int argc, char** argv) {
state.images.push_back(&vtk_img2); state.images.push_back(&vtk_img2);
state.viewer = &viewer; state.viewer = &viewer;
vtkSmartPointer<vtkCallbackCommand> keyCallback = vtkSmartPointer<vtkCallbackCommand>::New(); vtkSmartPointer<vtkCallbackCommand> keyCallback =
vtkSmartPointer<vtkCallbackCommand>::New();
keyCallback->SetCallback(KeyPressCallbackFunction); keyCallback->SetCallback(KeyPressCallbackFunction);
keyCallback->SetClientData(&state); keyCallback->SetClientData(&state);
viewer.GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, keyCallback); viewer.GetInteractor()->AddObserver(vtkCommand::KeyPressEvent, keyCallback);

View File

@@ -23,7 +23,6 @@
//////////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////////*/
#include "Vtk/Math/vtkVoxImage.h"
#include "Vtk/Math/vtkVoxImage.h" #include "Vtk/Math/vtkVoxImage.h"
#include "Vtk/uLibVtkViewer.h" #include "Vtk/uLibVtkViewer.h"
@@ -46,7 +45,7 @@ BOOST_AUTO_TEST_CASE(vtkVoxImageConstruction) {
img.InitVoxels(zero); img.InitVoxels(zero);
img[Vector3i(3, 3, 3)] = nonzero; img[Vector3i(3, 3, 3)] = nonzero;
Vtk::VoxImage vtk_img(img); Vtk::VoxImage vtk_img(&img);
vtk_img.SaveToXMLFile("test_vtkvoximage.vti"); vtk_img.SaveToXMLFile("test_vtkvoximage.vti");
if (std::getenv("CTEST_PROJECT_NAME") == nullptr) { if (std::getenv("CTEST_PROJECT_NAME") == nullptr) {

View File

@@ -31,14 +31,14 @@ namespace Vtk {
// ------------------------------------------------------------------ // // ------------------------------------------------------------------ //
Assembly::Assembly(uLib::Assembly *content) Assembly::Assembly(uLib::Assembly *content)
: m_Content(content), : ObjectWrapper(content),
m_ChildContext(nullptr), m_ChildContext(nullptr),
m_BBoxActor(nullptr), m_BBoxActor(nullptr),
m_VtkAsm(nullptr), m_VtkAsm(nullptr),
m_InUpdate(false) { m_InUpdate(false) {
this->InstallPipe(); this->InstallPipe();
if (m_Content) { if (this->m_model) {
Object::connect(m_Content, &uLib::Assembly::Updated, Object::connect(this->m_model.get(), &uLib::Assembly::Updated,
this, &Assembly::Update); this, &Assembly::Update);
} }
} }
@@ -71,13 +71,13 @@ void Assembly::InstallPipe() {
m_BBoxActor->GetProperty()->SetLineWidth(1.5); m_BBoxActor->GetProperty()->SetLineWidth(1.5);
m_BBoxActor->GetProperty()->SetOpacity(0.6); m_BBoxActor->GetProperty()->SetOpacity(0.6);
m_BBoxActor->PickableOff(); 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); m_VtkAsm->AddPart(m_BBoxActor);
// 3. Build a child-objects context (auto-creates prop3ds for each child) // 3. Build a child-objects context (auto-creates prop3ds for each child)
if (m_Content) { if (this->m_model) {
m_ChildContext = new ObjectsContext(m_Content); m_ChildContext = new ObjectsContext(this->m_model);
// Link the children context's assembly into our group assembly // Link the children context's assembly into our group assembly
if (auto* childProp = vtkProp3D::SafeDownCast(m_ChildContext->GetProp())) { if (auto* childProp = vtkProp3D::SafeDownCast(m_ChildContext->GetProp())) {
m_VtkAsm->AddPart(childProp); m_VtkAsm->AddPart(childProp);
@@ -93,10 +93,10 @@ void Assembly::Update() {
if (m_InUpdate) return; if (m_InUpdate) return;
m_InUpdate = true; m_InUpdate = true;
if (m_Content && m_VtkAsm) { if (this->m_model && m_VtkAsm) {
// Apply world matrix from the assembly content // Apply world matrix from the assembly content
vtkNew<vtkMatrix4x4> m; vtkNew<vtkMatrix4x4> m;
Matrix4fToVtk(m_Content->GetMatrix(), m); Matrix4fToVtk(this->m_model->GetMatrix(), m);
m_VtkAsm->SetUserMatrix(m); m_VtkAsm->SetUserMatrix(m);
m_VtkAsm->Modified(); m_VtkAsm->Modified();
} }
@@ -110,33 +110,33 @@ void Assembly::Update() {
void Assembly::SyncFromVtk() { void Assembly::SyncFromVtk() {
if (m_InUpdate) return; if (m_InUpdate) return;
if (!m_Content || !m_VtkAsm) return; if (!this->m_model || !m_VtkAsm) return;
m_InUpdate = true; m_InUpdate = true;
// VTK -> Model: Update world matrix (accounting for model parents) // VTK -> Model: Update world matrix (accounting for model parents)
if (vtkProp3D* proxy = this->GetProxyProp()) { if (vtkProp3D* proxy = this->GetProxyProp()) {
m_Content->SetWorldMatrix(VtkToMatrix4f(proxy->GetUserMatrix())); this->m_model->SetWorldMatrix(VtkToMatrix4f(proxy->GetUserMatrix()));
m_Content->FromMatrix(m_Content->GetMatrix()); this->m_model->FromMatrix(this->m_model->GetMatrix());
} }
this->UpdateBoundingBox(); this->UpdateBoundingBox();
if (m_ChildContext) if (m_ChildContext)
m_ChildContext->SyncFromVtk(); m_ChildContext->SyncFromVtk();
m_Content->Updated(); // Notify change in model this->m_model->Updated(); // Notify change in model
m_InUpdate = false; m_InUpdate = false;
} }
// ------------------------------------------------------------------ // // ------------------------------------------------------------------ //
void Assembly::UpdateBoundingBox() { 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; Vector3f bbMin, bbMax;
m_Content->GetBoundingBox(bbMin, bbMax); this->m_model->GetBoundingBox(bbMin, bbMax);
// Avoid degenerate boxes // Avoid degenerate boxes
Vector3f size = bbMax - bbMin; Vector3f size = bbMax - bbMin;

View File

@@ -12,8 +12,9 @@
#ifndef U_VTK_ASSEMBLY_H #ifndef U_VTK_ASSEMBLY_H
#define U_VTK_ASSEMBLY_H #define U_VTK_ASSEMBLY_H
#include "Core/ObjectFactory.h"
#include "Math/Assembly.h" #include "Math/Assembly.h"
#include "uLibVtkInterface.h" #include "Vtk/uLibVtkInterface.h"
class vtkActor; class vtkActor;
class vtkAssembly; // VTK library forward declaration (must be before namespace) 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 * the VTK library class vtkAssembly for grouping, but the two
* are distinct. * are distinct.
*/ */
class Assembly : public Prop3D { class Assembly : public Prop3D, public uLib::ObjectWrapper<uLib::Assembly> {
public: public:
uLibTypeMacro(Assembly, Prop3D) uLibTypeMacro(Assembly, Prop3D)
@@ -47,8 +48,8 @@ public:
/** @brief Synchronizes the model from the VTK representation (VTK→model). */ /** @brief Synchronizes the model from the VTK representation (VTK→model). */
virtual void SyncFromVtk() override; 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(); }
virtual uLib::ObjectsContext* GetChildren() override { return (uLib::ObjectsContext*)m_Content; } virtual uLib::ObjectsContext* GetChildren() override { return (uLib::ObjectsContext*)m_model.get(); }
/** /**
* @brief Returns the prop3d managing child objects. * @brief Returns the prop3d managing child objects.
@@ -61,7 +62,6 @@ private:
void UpdateBoundingBox(); void UpdateBoundingBox();
void InstallPipe(); void InstallPipe();
uLib::Assembly *m_Content;
ObjectsContext *m_ChildContext; ObjectsContext *m_ChildContext;
vtkActor *m_BBoxActor; vtkActor *m_BBoxActor;
::vtkAssembly *m_VtkAsm; // VTK library assembly — NOT this class ::vtkAssembly *m_VtkAsm; // VTK library assembly — NOT this class

View File

@@ -66,9 +66,10 @@ struct ContainerBoxData {
ContainerBox::ContainerBox(ContainerBox::Content *content) ContainerBox::ContainerBox(ContainerBox::Content *content)
: d(new ContainerBoxData()), m_Content(content) { : d(new ContainerBoxData()), ObjectWrapper(content) {
this->InstallPipe(); 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() { ContainerBox::~ContainerBox() {
@@ -83,13 +84,13 @@ vtkPolyData *ContainerBox::GetPolyData() const {
void ContainerBox::Update() { void ContainerBox::Update() {
RecursiveMutex::ScopedLock lock(this->m_UpdateMutex); RecursiveMutex::ScopedLock lock(this->m_UpdateMutex);
if (!m_Content) return; if (!this->m_model) return;
vtkProp3D* prop = vtkProp3D::SafeDownCast(this->GetProp()); vtkProp3D* prop = vtkProp3D::SafeDownCast(this->GetProp());
if (prop) { if (prop) {
// Apply the full volume matrix (TRS * m_LocalT) // Apply the full volume matrix (TRS * m_LocalT)
vtkNew<vtkMatrix4x4> m; vtkNew<vtkMatrix4x4> m;
Matrix4fToVtk(m_Content->GetMatrix(), m); Matrix4fToVtk(this->m_model->GetMatrix(), m);
prop->SetUserMatrix(m); prop->SetUserMatrix(m);
prop->Modified(); prop->Modified();
} }
@@ -104,7 +105,7 @@ void ContainerBox::Update() {
void ContainerBox::SyncFromVtk() { void ContainerBox::SyncFromVtk() {
RecursiveMutex::ScopedLock lock(this->m_UpdateMutex); RecursiveMutex::ScopedLock lock(this->m_UpdateMutex);
if (!m_Content) return; if (!this->m_model) return;
vtkProp3D* root = this->GetProxyProp(); vtkProp3D* root = this->GetProxyProp();
if (!root) return; if (!root) return;
@@ -114,11 +115,11 @@ void ContainerBox::SyncFromVtk() {
Matrix4f vtkWorld = VtkToMatrix4f(rootMat); Matrix4f vtkWorld = VtkToMatrix4f(rootMat);
// Synchronize TRS property members from the updated local matrix // 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 // Since we modified the model, notify observers, but block the loop back to VTK
// ConnectionBlock blocker(d->m_UpdateSignal); // ConnectionBlock blocker(d->m_UpdateSignal);
m_Content->Updated(); this->m_model->Updated();
} }
@@ -126,9 +127,9 @@ void ContainerBox::SyncFromVtk() {
void ContainerBox::InstallPipe() { void ContainerBox::InstallPipe() {
if (!m_Content) if (!this->m_model)
return; return;
Content *c = m_Content; Content *c = this->m_model;
// CUBE // CUBE
vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New(); vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();

View File

@@ -26,6 +26,7 @@
#ifndef U_VTKCONTAINERBOX_H #ifndef U_VTKCONTAINERBOX_H
#define U_VTKCONTAINERBOX_H #define U_VTKCONTAINERBOX_H
#include "Core/ObjectFactory.h"
#include "Math/ContainerBox.h" #include "Math/ContainerBox.h"
#include "uLibVtkInterface.h" #include "uLibVtkInterface.h"
#include "vtkPolydata.h" #include "vtkPolydata.h"
@@ -37,7 +38,9 @@ namespace Vtk {
struct ContainerBoxData; struct ContainerBoxData;
class ContainerBox : public Prop3D, public Polydata { class ContainerBox : public Prop3D,
public Polydata,
public uLib::ObjectWrapper<uLib::ContainerBox> {
uLibTypeMacro(ContainerBox, Prop3D, Polydata) uLibTypeMacro(ContainerBox, Prop3D, Polydata)
typedef uLib::ContainerBox Content; typedef uLib::ContainerBox Content;
@@ -58,13 +61,14 @@ public:
*/ */
virtual void SyncFromVtk() override; 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: protected:
virtual void InstallPipe(); virtual void InstallPipe();
struct ContainerBoxData *d; struct ContainerBoxData *d;
uLib::ContainerBox *m_Content;
ULIB_DECLARE_PROPERTIES(ContainerBox) ULIB_DECLARE_PROPERTIES(ContainerBox)
}; };

View File

@@ -38,9 +38,9 @@ namespace uLib {
namespace Vtk { namespace Vtk {
Cylinder::Cylinder(Cylinder::Content *content) Cylinder::Cylinder(Cylinder::Content *content)
: m_Content(content), m_Actor(nullptr), m_VtkAsm(nullptr) { : ObjectWrapper(content), m_Actor(nullptr), m_VtkAsm(nullptr) {
this->InstallPipe(); 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() { Cylinder::~Cylinder() {
@@ -49,14 +49,14 @@ Cylinder::~Cylinder() {
} }
void Cylinder::Update() { void Cylinder::Update() {
if (!m_Content) if (!this->m_model)
return; return;
vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp()); vtkProp3D* root = vtkProp3D::SafeDownCast(this->GetProp());
if (root) { if (root) {
// 1. Placement handled specifically from content (use TRS GetMatrix, not World) // 1. Placement handled specifically from content (use TRS GetMatrix, not World)
vtkNew<vtkMatrix4x4> m; vtkNew<vtkMatrix4x4> m;
Matrix4fToVtk(m_Content->GetMatrix(), m); Matrix4fToVtk(this->m_model->GetMatrix(), m);
root->SetUserMatrix(m); root->SetUserMatrix(m);
// 2. Shape-local properties (Radius, Height, Axis alignment) go to the internal actor // 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]) // Initial source is centered Y-cylinder (Radial XZ [-1,1], Height Y [-0.5, 0.5])
// Apply Radius and Height scaling // 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 // Apply Axis alignment
int axis = m_Content->GetAxis(); int axis = this->m_model->GetAxis();
if (axis == 0) alignment->RotateZ(-90); // Y -> X if (axis == 0) alignment->RotateZ(-90); // Y -> X
else if (axis == 1) ; // Y -> Y (identity) else if (axis == 1) ; // Y -> Y (identity)
else if (axis == 2) alignment->RotateX(90); // Y -> Z else if (axis == 2) alignment->RotateX(90); // Y -> Z
@@ -86,7 +86,7 @@ void Cylinder::Update() {
} }
void Cylinder::SyncFromVtk() { void Cylinder::SyncFromVtk() {
if (!m_Content) return; if (!this->m_model) return;
vtkProp3D* root = this->GetProxyProp(); vtkProp3D* root = this->GetProxyProp();
if (!root) return; if (!root) return;
@@ -96,12 +96,12 @@ void Cylinder::SyncFromVtk() {
Matrix4f vtkWorld = VtkToMatrix4f(rootMat); Matrix4f vtkWorld = VtkToMatrix4f(rootMat);
// Directly sync model from the world matrix // Directly sync model from the world matrix
m_Content->FromMatrix(vtkWorld); this->m_model->FromMatrix(vtkWorld);
m_Content->Updated(); this->m_model->Updated();
} }
void Cylinder::InstallPipe() { void Cylinder::InstallPipe() {
if (!m_Content) if (!this->m_model)
return; return;
m_VtkAsm = ::vtkAssembly::New(); m_VtkAsm = ::vtkAssembly::New();

View File

@@ -26,6 +26,7 @@
#ifndef U_VTKCYLINDER_H #ifndef U_VTKCYLINDER_H
#define U_VTKCYLINDER_H #define U_VTKCYLINDER_H
#include "Core/ObjectFactory.h"
#include "Math/Cylinder.h" #include "Math/Cylinder.h"
#include "Vtk/uLibVtkInterface.h" #include "Vtk/uLibVtkInterface.h"
#include <vtkActor.h> #include <vtkActor.h>
@@ -41,7 +42,7 @@ namespace Vtk {
* mathematical state of a Cylinder object. It manages the alignment * mathematical state of a Cylinder object. It manages the alignment
* between VTK's Y-centered cylinder and uLib's Z-based coordinate system. * between VTK's Y-centered cylinder and uLib's Z-based coordinate system.
*/ */
class Cylinder : public Prop3D { class Cylinder : public Prop3D, public uLib::ObjectWrapper<uLib::Cylinder> {
typedef uLib::Cylinder Content; typedef uLib::Cylinder Content;
public: public:
@@ -54,7 +55,9 @@ public:
/** Synchronizes the uLib model matrix with the VTK actor specifically for gizmo interactions */ /** Synchronizes the uLib model matrix with the VTK actor specifically for gizmo interactions */
virtual void SyncFromVtk() override; 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: protected:
/** Sets up the VTK visualization pipeline */ /** Sets up the VTK visualization pipeline */
@@ -62,7 +65,6 @@ protected:
vtkActor *m_Actor; vtkActor *m_Actor;
::vtkAssembly *m_VtkAsm; ::vtkAssembly *m_VtkAsm;
Content *m_Content;
uLib::Connection m_UpdateSignal; uLib::Connection m_UpdateSignal;
}; };

View File

@@ -58,22 +58,22 @@ void QuadMesh::vtk2uLib_update() {
<< "number of quads = " << number_of_quads << "\n" << "number of quads = " << number_of_quads << "\n"
<< "//////\n"; << "//////\n";
m_content.Points().clear(); this->m_model->Points().clear();
for (int i = 0; i < number_of_points; ++i) { for (int i = 0; i < number_of_points; ++i) {
double *point = m_Poly->GetPoint(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(); m_Poly->GetPolys()->InitTraversal();
vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New(); vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New();
for (int i = 0; i < number_of_quads; ++i) { for (int i = 0; i < number_of_quads; ++i) {
m_Poly->GetPolys()->GetNextCell(idList); m_Poly->GetPolys()->GetNextCell(idList);
if (idList->GetNumberOfIds() == 4) { if (idList->GetNumberOfIds() == 4) {
m_content.Quads()[i](0) = idList->GetId(0); this->m_model->Quads()[i](0) = idList->GetId(0);
m_content.Quads()[i](1) = idList->GetId(1); this->m_model->Quads()[i](1) = idList->GetId(1);
m_content.Quads()[i](2) = idList->GetId(2); this->m_model->Quads()[i](2) = idList->GetId(2);
m_content.Quads()[i](3) = idList->GetId(3); this->m_model->Quads()[i](3) = idList->GetId(3);
} }
} }
m_Poly->Modified(); m_Poly->Modified();
@@ -81,23 +81,23 @@ void QuadMesh::vtk2uLib_update() {
} }
void QuadMesh::uLib2vtk_update() { void QuadMesh::uLib2vtk_update() {
vtkIdType number_of_points = m_content.Points().size(); vtkIdType number_of_points = this->m_model->Points().size();
vtkIdType number_of_quads = m_content.Quads().size(); vtkIdType number_of_quads = this->m_model->Quads().size();
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
points->SetNumberOfPoints(number_of_points); points->SetNumberOfPoints(number_of_points);
for (vtkIdType i = 0; i < number_of_points; i++) { 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)); points->SetPoint(i, p(0), p(1), p(2));
} }
vtkSmartPointer<vtkCellArray> polys = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkCellArray> polys = vtkSmartPointer<vtkCellArray>::New();
for (vtkIdType i = 0; i < number_of_quads; i++) { for (vtkIdType i = 0; i < number_of_quads; i++) {
vtkIdType a, b, c, d; vtkIdType a, b, c, d;
a = m_content.Quads().at(i)(0); a = this->m_model->Quads().at(i)(0);
b = m_content.Quads().at(i)(1); b = this->m_model->Quads().at(i)(1);
c = m_content.Quads().at(i)(2); c = this->m_model->Quads().at(i)(2);
d = m_content.Quads().at(i)(3); d = this->m_model->Quads().at(i)(3);
polys->InsertNextCell(4); polys->InsertNextCell(4);
polys->InsertCellPoint(a); polys->InsertCellPoint(a);
polys->InsertCellPoint(b); polys->InsertCellPoint(b);
@@ -118,7 +118,7 @@ void QuadMesh::contentUpdate() {
vmat = mat; vmat = mat;
} }
Matrix4f transform = m_content.GetWorldMatrix(); Matrix4f transform = this->m_model->GetWorldMatrix();
Matrix4fToVtk(transform, vmat); Matrix4fToVtk(transform, vmat);
uLib2vtk_update(); uLib2vtk_update();
@@ -133,30 +133,30 @@ void QuadMesh::Update() {
if (!vmat) return; if (!vmat) return;
Matrix4f transform = VtkToMatrix4f(vmat); Matrix4f transform = VtkToMatrix4f(vmat);
m_content.SetMatrix(transform); this->m_model->SetMatrix(transform);
m_content.Updated(); this->m_model->Updated();
} }
// -------------------------------------------------------------------------- // // -------------------------------------------------------------------------- //
QuadMesh::QuadMesh(QuadMesh::Content &content) QuadMesh::QuadMesh(QuadMesh::Content *content)
: m_content(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) { : ObjectWrapper(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) {
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New(); vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(m_Poly); mapper->SetInputData(m_Poly);
m_Actor->SetMapper(mapper); m_Actor->SetMapper(mapper);
vtkNew<vtkMatrix4x4> vmat; vtkNew<vtkMatrix4x4> vmat;
Matrix4fToVtk(m_content.GetWorldMatrix(), vmat); Matrix4fToVtk(this->m_model->GetWorldMatrix(), vmat);
m_Actor->SetUserMatrix(vmat); m_Actor->SetUserMatrix(vmat);
this->SetProp(m_Actor); 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(); this->contentUpdate();
} }
QuadMesh::~QuadMesh() { 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_Poly->Delete();
m_Actor->Delete(); m_Actor->Delete();
} }

View File

@@ -26,9 +26,10 @@
#ifndef VTKQUADMESH_H #ifndef VTKQUADMESH_H
#define VTKQUADMESH_H #define VTKQUADMESH_H
#include "Core/ObjectFactory.h"
#include "Math/QuadMesh.h" #include "Math/QuadMesh.h"
#include "Vtk/uLibVtkInterface.h"
#include "Vtk/Math/vtkPolydata.h" #include "Vtk/Math/vtkPolydata.h"
#include "Vtk/uLibVtkInterface.h"
class vtkPolyData; class vtkPolyData;
class vtkActor; class vtkActor;
@@ -36,11 +37,13 @@ class vtkActor;
namespace uLib { namespace uLib {
namespace Vtk { namespace Vtk {
class QuadMesh : public Prop3D, public Polydata { class QuadMesh : public Prop3D,
public Polydata,
public uLib::ObjectWrapper<uLib::QuadMesh> {
typedef uLib::QuadMesh Content; typedef uLib::QuadMesh Content;
public: public:
QuadMesh(Content &content); QuadMesh(Content *content);
~QuadMesh(); ~QuadMesh();
void ReadFromFile(const char *filename); void ReadFromFile(const char *filename);
@@ -56,12 +59,15 @@ public:
virtual void contentUpdate(); virtual void contentUpdate();
virtual void Update(); virtual void Update();
uLib::Object *GetContent() const override {
return (uLib::Object *)m_model.get();
}
private: private:
void vtk2uLib_update(); void vtk2uLib_update();
void uLib2vtk_update(); void uLib2vtk_update();
uLib::QuadMesh &m_content; // ObjectWrapper provides m_model
vtkPolyData *m_Poly; vtkPolyData *m_Poly;
vtkActor *m_Actor; vtkActor *m_Actor;
}; };

View File

@@ -39,8 +39,8 @@ namespace Vtk {
////// VTK STRUCTURED GRID ///////////////////////////////////////////////////// ////// VTK STRUCTURED GRID /////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
StructuredGrid::StructuredGrid(Content &content) StructuredGrid::StructuredGrid(Content *content)
: m_Content(&content), m_Actor(vtkActor::New()), : ObjectWrapper(content), m_Actor(vtkActor::New()),
m_Transform(vtkTransform::New()) { m_Transform(vtkTransform::New()) {
this->InstallPipe(); this->InstallPipe();
@@ -54,10 +54,10 @@ StructuredGrid::~StructuredGrid() {
void StructuredGrid::SetTransform(vtkTransform *t) { void StructuredGrid::SetTransform(vtkTransform *t) {
vtkMatrix4x4 *vmat = t->GetMatrix(); vtkMatrix4x4 *vmat = t->GetMatrix();
Matrix4f mat = VtkToMatrix4f(vmat); Matrix4f mat = VtkToMatrix4f(vmat);
m_Content->SetMatrix(mat); this->m_model->SetMatrix(mat);
vtkSmartPointer<vtkMatrix4x4> vmat2 = vtkSmartPointer<vtkMatrix4x4>::New(); vtkSmartPointer<vtkMatrix4x4> vmat2 = vtkSmartPointer<vtkMatrix4x4>::New();
mat = m_Content->GetWorldMatrix(); mat = this->m_model->GetWorldMatrix();
Matrix4fToVtk(mat, vmat2); Matrix4fToVtk(mat, vmat2);
m_Transform->SetMatrix(vmat2); m_Transform->SetMatrix(vmat2);
m_Transform->Update(); m_Transform->Update();
@@ -65,7 +65,7 @@ void StructuredGrid::SetTransform(vtkTransform *t) {
} }
void StructuredGrid::Update() { void StructuredGrid::Update() {
if (!m_Content) return; if (!this->m_model) return;
vtkProp3D* actor = vtkProp3D::SafeDownCast(this->GetProp()); vtkProp3D* actor = vtkProp3D::SafeDownCast(this->GetProp());
if (!actor) return; if (!actor) return;
@@ -76,20 +76,20 @@ void StructuredGrid::Update() {
Matrix4f transform = VtkToMatrix4f(vmat); Matrix4f transform = VtkToMatrix4f(vmat);
// Update uLib model's affine transform // Update uLib model's affine transform
if (m_Content->GetParent()) { if (this->m_model->GetParent()) {
Matrix4f localT = m_Content->GetParent()->GetWorldMatrix().inverse() * transform; Matrix4f localT = this->m_model->GetParent()->GetWorldMatrix().inverse() * transform;
m_Content->SetMatrix(localT); this->m_model->SetMatrix(localT);
} else { } 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() { void StructuredGrid::InstallPipe() {
vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New(); vtkSmartPointer<vtkCubeSource> cube = vtkSmartPointer<vtkCubeSource>::New();
Vector3i dims = m_Content->GetDims(); Vector3i dims = this->m_model->GetDims();
cube->SetBounds(0, dims(0), 0, dims(1), 0, dims(2)); cube->SetBounds(0, dims(0), 0, dims(1), 0, dims(2));
cube->Update(); cube->Update();
@@ -104,7 +104,7 @@ void StructuredGrid::InstallPipe() {
m_Actor->GetProperty()->SetAmbient(0.7); m_Actor->GetProperty()->SetAmbient(0.7);
vtkNew<vtkMatrix4x4> vmat; vtkNew<vtkMatrix4x4> vmat;
Matrix4fToVtk(m_Content->GetWorldMatrix(), vmat); Matrix4fToVtk(this->m_model->GetWorldMatrix(), vmat);
m_Actor->SetUserMatrix(vmat); m_Actor->SetUserMatrix(vmat);
this->SetProp(m_Actor); this->SetProp(m_Actor);

View File

@@ -41,28 +41,32 @@
#include "Vtk/Math/vtkDense.h" #include "Vtk/Math/vtkDense.h"
#include "Core/ObjectFactory.h"
#include "Math/StructuredGrid.h" #include "Math/StructuredGrid.h"
#include "Vtk/uLibVtkInterface.h" #include "Vtk/uLibVtkInterface.h"
namespace uLib { namespace uLib {
namespace Vtk { namespace Vtk {
class StructuredGrid : public Prop3D { class StructuredGrid : public Prop3D,
public uLib::ObjectWrapper<uLib::StructuredGrid> {
typedef uLib::StructuredGrid Content; typedef uLib::StructuredGrid Content;
public: public:
StructuredGrid(Content &content); StructuredGrid(Content *content);
~StructuredGrid(); ~StructuredGrid();
void SetTransform(class vtkTransform *t); void SetTransform(class vtkTransform *t);
virtual void Update() override; virtual void Update() override;
uLib::Object *GetContent() const override {
return (uLib::Object *)m_model.get();
}
private: private:
void InstallPipe(); void InstallPipe();
vtkActor *m_Actor; vtkActor *m_Actor;
uLib::StructuredGrid *m_Content;
vtkTransform *m_Transform; vtkTransform *m_Transform;
}; };

View File

@@ -58,42 +58,42 @@ void TriangleMesh::vtk2uLib_update() {
<< "number of polys = " << number_of_triangles << "\n" << "number of polys = " << number_of_triangles << "\n"
<< "//////\n"; << "//////\n";
m_content.Points().clear(); this->m_model->Points().clear();
for (int i = 0; i < number_of_points; ++i) { for (int i = 0; i < number_of_points; ++i) {
double *point = m_Poly->GetPoint(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(); m_Poly->GetPolys()->InitTraversal();
vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New(); vtkSmartPointer<vtkIdList> idList = vtkSmartPointer<vtkIdList>::New();
for (int i = 0; i < number_of_triangles; ++i) { for (int i = 0; i < number_of_triangles; ++i) {
m_Poly->GetPolys()->GetNextCell(idList); m_Poly->GetPolys()->GetNextCell(idList);
m_content.Triangles()[i](0) = idList->GetId(0); this->m_model->Triangles()[i](0) = idList->GetId(0);
m_content.Triangles()[i](1) = idList->GetId(1); this->m_model->Triangles()[i](1) = idList->GetId(1);
m_content.Triangles()[i](2) = idList->GetId(2); this->m_model->Triangles()[i](2) = idList->GetId(2);
} }
m_Poly->Modified(); m_Poly->Modified();
m_Actor->GetMapper()->Update(); m_Actor->GetMapper()->Update();
} }
void TriangleMesh::uLib2vtk_update() { void TriangleMesh::uLib2vtk_update() {
vtkIdType number_of_points = m_content.Points().size(); vtkIdType number_of_points = this->m_model->Points().size();
vtkIdType number_of_triangles = m_content.Triangles().size(); vtkIdType number_of_triangles = this->m_model->Triangles().size();
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
points->SetNumberOfPoints(number_of_points); points->SetNumberOfPoints(number_of_points);
for (vtkIdType i = 0; i < number_of_points; i++) { 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)); points->SetPoint(i, p(0), p(1), p(2));
} }
vtkSmartPointer<vtkCellArray> polys = vtkSmartPointer<vtkCellArray>::New(); vtkSmartPointer<vtkCellArray> polys = vtkSmartPointer<vtkCellArray>::New();
for (vtkIdType i = 0; i < number_of_triangles; i++) { for (vtkIdType i = 0; i < number_of_triangles; i++) {
vtkIdType a, b, c; vtkIdType a, b, c;
a = m_content.Triangles().at(i)(0); a = this->m_model->Triangles().at(i)(0);
b = m_content.Triangles().at(i)(1); b = this->m_model->Triangles().at(i)(1);
c = m_content.Triangles().at(i)(2); c = this->m_model->Triangles().at(i)(2);
polys->InsertNextCell(3); polys->InsertNextCell(3);
polys->InsertCellPoint(a); polys->InsertCellPoint(a);
polys->InsertCellPoint(b); polys->InsertCellPoint(b);
@@ -113,7 +113,7 @@ void TriangleMesh::contentUpdate() {
vmat = mat; vmat = mat;
} }
Matrix4f transform = m_content.GetWorldMatrix(); Matrix4f transform = this->m_model->GetWorldMatrix();
Matrix4fToVtk(transform, vmat); Matrix4fToVtk(transform, vmat);
uLib2vtk_update(); uLib2vtk_update();
@@ -128,30 +128,30 @@ void TriangleMesh::Update() {
if (!vmat) return; if (!vmat) return;
Matrix4f transform = VtkToMatrix4f(vmat); Matrix4f transform = VtkToMatrix4f(vmat);
m_content.SetMatrix(transform); this->m_model->SetMatrix(transform);
m_content.Updated(); this->m_model->Updated();
} }
// -------------------------------------------------------------------------- // // -------------------------------------------------------------------------- //
TriangleMesh::TriangleMesh(TriangleMesh::Content &content) TriangleMesh::TriangleMesh(TriangleMesh::Content *content)
: m_content(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) { : ObjectWrapper(content), m_Poly(vtkPolyData::New()), m_Actor(vtkActor::New()) {
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New(); vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(m_Poly); mapper->SetInputData(m_Poly);
m_Actor->SetMapper(mapper); m_Actor->SetMapper(mapper);
vtkNew<vtkMatrix4x4> vmat; vtkNew<vtkMatrix4x4> vmat;
Matrix4fToVtk(m_content.GetWorldMatrix(), vmat); Matrix4fToVtk(this->m_model->GetWorldMatrix(), vmat);
m_Actor->SetUserMatrix(vmat); m_Actor->SetUserMatrix(vmat);
this->SetProp(m_Actor); 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(); this->contentUpdate();
} }
TriangleMesh::~TriangleMesh() { 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_Poly->Delete();
m_Actor->Delete(); m_Actor->Delete();
} }

View File

@@ -26,9 +26,10 @@
#ifndef VTKTRIANGLEMESH_H #ifndef VTKTRIANGLEMESH_H
#define VTKTRIANGLEMESH_H #define VTKTRIANGLEMESH_H
#include "Core/ObjectFactory.h"
#include "Math/TriangleMesh.h" #include "Math/TriangleMesh.h"
#include "Vtk/uLibVtkInterface.h"
#include "Vtk/Math/vtkPolydata.h" #include "Vtk/Math/vtkPolydata.h"
#include "Vtk/uLibVtkInterface.h"
class vtkPolyData; class vtkPolyData;
class vtkActor; class vtkActor;
@@ -36,11 +37,13 @@ class vtkActor;
namespace uLib { namespace uLib {
namespace Vtk { namespace Vtk {
class TriangleMesh : public Prop3D, public Polydata { class TriangleMesh : public Prop3D,
public Polydata,
public uLib::ObjectWrapper<uLib::TriangleMesh> {
typedef uLib::TriangleMesh Content; typedef uLib::TriangleMesh Content;
public: public:
TriangleMesh(Content &content); TriangleMesh(Content *content);
~TriangleMesh(); ~TriangleMesh();
void ReadFromFile(const char *filename); void ReadFromFile(const char *filename);
@@ -56,12 +59,15 @@ public:
virtual void contentUpdate(); virtual void contentUpdate();
virtual void Update(); virtual void Update();
uLib::Object *GetContent() const override {
return (uLib::Object *)m_model.get();
}
private: private:
void vtk2uLib_update(); void vtk2uLib_update();
void uLib2vtk_update(); void uLib2vtk_update();
uLib::TriangleMesh &m_content; // ObjectWrapper provides m_model
vtkPolyData *m_Poly; vtkPolyData *m_Poly;
vtkActor *m_Actor; vtkActor *m_Actor;
}; };

View File

@@ -61,13 +61,13 @@ namespace uLib {
namespace Vtk { namespace Vtk {
void VoxImage::UpdateFromContent() { void VoxImage::UpdateFromContent() {
Vector3i ev_dims = m_Content.GetDims(); Vector3i ev_dims = this->m_model->GetDims();
m_Image->SetDimensions(ev_dims.data()); 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)); 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)); m_Image->SetOrigin(ev_pos(0), ev_pos(1), ev_pos(2));
vtkFloatArray *array = vtkFloatArray *array =
@@ -78,14 +78,14 @@ void VoxImage::UpdateFromContent() {
array->Delete(); array->Delete();
} }
array->SetNumberOfTuples(m_Content.GetDims().prod()); array->SetNumberOfTuples(this->m_model->GetDims().prod());
Vector3i index(0, 0, 0); Vector3i index(0, 0, 0);
int i = 0; int i = 0;
for (int zv = 0; zv < ev_dims(2); ++zv) { for (int zv = 0; zv < ev_dims(2); ++zv) {
for (int yv = 0; yv < ev_dims(1); ++yv) { for (int yv = 0; yv < ev_dims(1); ++yv) {
for (int xv = 0; xv < ev_dims(0); ++xv) { for (int xv = 0; xv < ev_dims(0); ++xv) {
index << xv, yv, zv; 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() { void VoxImage::UpdateToContent() {
int *ext = m_Image->GetExtent(); int *ext = m_Image->GetExtent();
int dims[3] = {ext[1] - ext[0] + 1, ext[3] - ext[2] + 1, ext[5] - ext[4] + 1}; 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(); 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(); 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 *array =
vtkFloatArray::SafeDownCast(m_Image->GetPointData()->GetScalars()); vtkFloatArray::SafeDownCast(m_Image->GetPointData()->GetScalars());
@@ -111,7 +111,7 @@ void VoxImage::UpdateToContent() {
for (int yv = 0; yv < dims[1]; ++yv) { for (int yv = 0; yv < dims[1]; ++yv) {
for (int xv = 0; xv < dims[0]; ++xv) { for (int xv = 0; xv < dims[0]; ++xv) {
index << xv, yv, zv; 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 // VTK VOXIMAGE
VoxImage::VoxImage(Content &content) VoxImage::VoxImage(Content *content)
: m_Content(content), m_Actor(vtkVolume::New()), : ObjectWrapper(content), m_Actor(vtkVolume::New()),
m_Asm(vtkAssembly::New()), m_Asm(vtkAssembly::New()),
m_Image(vtkImageData::New()), m_Outline(vtkCubeSource::New()), m_Image(vtkImageData::New()), m_Outline(vtkCubeSource::New()),
m_OutlineActor(vtkActor::New()), m_OutlineActor(vtkActor::New()),
@@ -134,7 +134,7 @@ VoxImage::VoxImage(Content &content)
// Transfer functions // Transfer functions
m_ColorFun = vtkColorTransferFunction::New(); m_ColorFun = vtkColorTransferFunction::New();
m_OpacityFun = vtkPiecewiseFunction::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(); UpdateFromContent();
InstallPipe(); InstallPipe();
@@ -314,8 +314,8 @@ void VoxImage::SyncFromVtk() {
if (rootMat) { if (rootMat) {
Matrix4f vtkLocal = VtkToMatrix4f(rootMat); Matrix4f vtkLocal = VtkToMatrix4f(rootMat);
// Synchronize TRS from VTK, compensating for local volume offset // Synchronize TRS from VTK, compensating for local volume offset
m_Content.FromMatrix(vtkLocal); // * m_Content.GetLocalMatrix().inverse()); this->m_model->FromMatrix(vtkLocal); // * this->m_model->GetLocalMatrix().inverse());
m_Content.Updated(); this->m_model->Updated();
} }
} }
} }
@@ -323,11 +323,11 @@ void VoxImage::SyncFromVtk() {
void VoxImage::Update() { void VoxImage::Update() {
if (auto *root = vtkProp3D::SafeDownCast(this->GetProp())) { if (auto *root = vtkProp3D::SafeDownCast(this->GetProp())) {
vtkNew<vtkMatrix4x4> m; vtkNew<vtkMatrix4x4> 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->SetUserMatrix(m);
root->Modified(); root->Modified();
// std::cout << "[VoxImage::Update] Set Proxy UserMatrix:" << std::endl; // 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); setShadingPreset(m_ShadingPreset);
m_Actor->Update(); m_Actor->Update();

View File

@@ -26,15 +26,16 @@
#ifndef U_VTKVOXIMAGE_H #ifndef U_VTKVOXIMAGE_H
#define U_VTKVOXIMAGE_H #define U_VTKVOXIMAGE_H
#include <vtkAssembly.h>
#include <vtkCubeSource.h> #include <vtkCubeSource.h>
#include <vtkImageData.h> #include <vtkImageData.h>
#include <vtkVolume.h> #include <vtkVolume.h>
#include <vtkXMLImageDataReader.h> #include <vtkXMLImageDataReader.h>
#include <vtkXMLImageDataWriter.h> #include <vtkXMLImageDataWriter.h>
#include <vtkAssembly.h>
#include <Math/VoxImage.h> #include <Math/VoxImage.h>
#include "Core/ObjectFactory.h"
#include "Vtk/uLibVtkInterface.h" #include "Vtk/uLibVtkInterface.h"
class vtkImageData; class vtkImageData;
@@ -45,18 +46,21 @@ class vtkPiecewiseFunction;
namespace uLib { namespace uLib {
namespace Vtk { namespace Vtk {
class VoxImage : public Prop3D { class VoxImage : public Prop3D,
public uLib::ObjectWrapper<uLib::Abstract::VoxImage> {
public: public:
typedef Abstract::VoxImage Content; typedef Abstract::VoxImage Content;
VoxImage(Content &content); VoxImage(Content *content);
~VoxImage(); ~VoxImage();
void UpdateFromContent(); void UpdateFromContent();
void UpdateToContent(); 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; } vtkProp3D *GetProp() override { return m_Asm; }
@@ -74,7 +78,8 @@ public:
void Update() override; void Update() override;
void SyncFromVtk() 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: protected:
void InstallPipe(); void InstallPipe();
@@ -90,7 +95,7 @@ private:
vtkXMLImageDataReader *m_Reader; vtkXMLImageDataReader *m_Reader;
vtkXMLImageDataWriter *m_Writer; vtkXMLImageDataWriter *m_Writer;
VoxImage::Content &m_Content; // ObjectWrapper provides m_model
float m_Window; float m_Window;
float m_Level; float m_Level;

View File

@@ -1,24 +1,23 @@
#include "vtkObjectsContext.h" #include "vtkObjectsContext.h"
#include "Vtk/Math/vtkAssembly.h"
#include "Vtk/Math/vtkContainerBox.h" #include "Vtk/Math/vtkContainerBox.h"
#include "Vtk/Math/vtkCylinder.h" #include "Vtk/Math/vtkCylinder.h"
#include "Vtk/Math/vtkAssembly.h"
#include "Vtk/Math/vtkVoxImage.h" #include "Vtk/Math/vtkVoxImage.h"
#include "Vtk/HEP/Detectors/vtkDetectorChamber.h" #include "Vtk/HEP/Detectors/vtkDetectorChamber.h"
#include "Vtk/HEP/Geant/vtkBoxSolid.h" #include "Vtk/HEP/Geant/vtkBoxSolid.h"
#include <cstring>
#include <iostream>
#include <vtkAssembly.h> #include <vtkAssembly.h>
#include <vtkPropCollection.h> #include <vtkPropCollection.h>
#include <iostream>
#include <cstring>
#include "Math/ContainerBox.h"
#include "Math/Cylinder.h"
#include "Math/Assembly.h"
#include "Math/VoxImage.h"
#include "HEP/Detectors/DetectorChamber.h" #include "HEP/Detectors/DetectorChamber.h"
#include "HEP/Geant/Solid.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 uLib {
namespace Vtk { namespace Vtk {
@@ -27,34 +26,40 @@ ObjectsContext::ObjectsContext(uLib::ObjectsContext *context)
: m_Context(context), m_Assembly(::vtkAssembly::New()) { : m_Context(context), m_Assembly(::vtkAssembly::New()) {
this->SetProp(m_Assembly); this->SetProp(m_Assembly);
if (m_Context) { if (m_Context) {
Object::connect(m_Context, &uLib::ObjectsContext::ObjectAdded, this, &ObjectsContext::OnObjectAdded); Object::connect(m_Context, &uLib::ObjectsContext::ObjectAdded, this,
Object::connect(m_Context, &uLib::ObjectsContext::ObjectRemoved, this, &ObjectsContext::OnObjectRemoved); &ObjectsContext::OnObjectAdded);
Object::connect(m_Context, &uLib::ObjectsContext::ObjectRemoved, this,
&ObjectsContext::OnObjectRemoved);
this->Synchronize(); this->Synchronize();
} }
} }
ObjectsContext::~ObjectsContext() { ObjectsContext::~ObjectsContext() {
for (auto const& [obj, prop3d] : m_Prop3Ds) { for (auto const &[obj, prop3d] : m_Prop3Ds) {
delete prop3d; delete prop3d;
} }
m_Assembly->Delete(); m_Assembly->Delete();
} }
void ObjectsContext::Synchronize() { void ObjectsContext::Synchronize() {
if (!m_Context) return; if (!m_Context)
return;
// 1. Identify objects to add and remove // 1. Identify objects to add and remove
const auto& objects = m_Context->GetObjects(); const auto &objects = m_Context->GetObjects();
std::map<uLib::Object*, bool> currentObjects; std::map<uLib::Object *, bool> currentObjects;
for (auto obj : objects) currentObjects[obj] = true; for (auto obj : objects)
currentObjects[obj] = true;
// Remove Prop3Ds for objects no longer in context // 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()) { 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. // Actually Prop3D::DisconnectRenderer(vtkRenderer*) needs the renderer.
// For now we just remove from assembly // For now we just remove from assembly
if (auto* p3d = vtkProp3D::SafeDownCast(it->second->GetProp())) if (auto *p3d = vtkProp3D::SafeDownCast(it->second->GetProp()))
m_Assembly->RemovePart(p3d); m_Assembly->RemovePart(p3d);
this->Prop3DRemoved(it->second); this->Prop3DRemoved(it->second);
delete it->second; delete it->second;
@@ -67,10 +72,10 @@ void ObjectsContext::Synchronize() {
// Add Prop3Ds for new objects // Add Prop3Ds for new objects
for (auto obj : objects) { for (auto obj : objects) {
if (m_Prop3Ds.find(obj) == m_Prop3Ds.end()) { if (m_Prop3Ds.find(obj) == m_Prop3Ds.end()) {
Prop3D* prop3d = this->CreateProp3D(obj); Prop3D *prop3d = this->CreateProp3D(obj);
if (prop3d) { if (prop3d) {
m_Prop3Ds[obj] = prop3d; m_Prop3Ds[obj] = prop3d;
if (auto* p3d = vtkProp3D::SafeDownCast(prop3d->GetProp())) if (auto *p3d = vtkProp3D::SafeDownCast(prop3d->GetProp()))
m_Assembly->AddPart(p3d); m_Assembly->AddPart(p3d);
this->Prop3DAdded(prop3d); this->Prop3DAdded(prop3d);
} }
@@ -78,26 +83,29 @@ void ObjectsContext::Synchronize() {
} }
} }
void ObjectsContext::OnObjectAdded(uLib::Object* obj) { void ObjectsContext::OnObjectAdded(uLib::Object *obj) {
if (!obj) return; if (!obj)
return;
if (m_Prop3Ds.find(obj) == m_Prop3Ds.end()) { if (m_Prop3Ds.find(obj) == m_Prop3Ds.end()) {
Prop3D* prop3d = this->CreateProp3D(obj); Prop3D *prop3d = this->CreateProp3D(obj);
if (prop3d) { if (prop3d) {
m_Prop3Ds[obj] = prop3d; m_Prop3Ds[obj] = prop3d;
if (auto* p3d = vtkProp3D::SafeDownCast(prop3d->GetProp())) if (auto *p3d = vtkProp3D::SafeDownCast(prop3d->GetProp()))
m_Assembly->AddPart(p3d); m_Assembly->AddPart(p3d);
this->Prop3DAdded(prop3d); this->Prop3DAdded(prop3d);
} }
} }
} }
void ObjectsContext::OnObjectRemoved(uLib::Object* obj) { void ObjectsContext::OnObjectRemoved(uLib::Object *obj) {
if (!obj) return; if (!obj)
return;
auto it = m_Prop3Ds.find(obj); auto it = m_Prop3Ds.find(obj);
if (it != m_Prop3Ds.end()) { if (it != m_Prop3Ds.end()) {
// For now we just remove from assembly. // For now we just remove from assembly.
// Prop3D::DisconnectRenderer(vtkRenderer*) needs the renderer, but we don't have it here easily. // Prop3D::DisconnectRenderer(vtkRenderer*) needs the renderer, but we don't
if (auto* p3d = vtkProp3D::SafeDownCast(it->second->GetProp())) // have it here easily.
if (auto *p3d = vtkProp3D::SafeDownCast(it->second->GetProp()))
m_Assembly->RemovePart(p3d); m_Assembly->RemovePart(p3d);
this->Prop3DRemoved(it->second); this->Prop3DRemoved(it->second);
delete it->second; delete it->second;
@@ -105,54 +113,56 @@ void ObjectsContext::OnObjectRemoved(uLib::Object* obj) {
} }
} }
Prop3D* ObjectsContext::GetProp3D(uLib::Object* obj) { Prop3D *ObjectsContext::GetProp3D(uLib::Object *obj) {
auto it = m_Prop3Ds.find(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; return nullptr;
} }
void ObjectsContext::Update() { void ObjectsContext::Update() {
for (auto const& [obj, prop3d] : m_Prop3Ds) { for (auto const &[obj, prop3d] : m_Prop3Ds) {
prop3d->Update(); prop3d->Update();
} }
} }
void ObjectsContext::SyncFromVtk() { void ObjectsContext::SyncFromVtk() {
for (auto const& [obj, prop3d] : m_Prop3Ds) { for (auto const &[obj, prop3d] : m_Prop3Ds) {
prop3d->SyncFromVtk(); prop3d->SyncFromVtk();
} }
} }
Prop3D* ObjectsContext::CreateProp3D(uLib::Object* obj) { Prop3D *ObjectsContext::CreateProp3D(uLib::Object *obj) {
if (!obj) return nullptr; if (!obj)
return nullptr;
if (auto* vox = dynamic_cast<uLib::Abstract::VoxImage*>(obj)) { if (auto *vox = dynamic_cast<uLib::Abstract::VoxImage *>(obj)) {
return new VoxImage(*vox); return new VoxImage(vox);
} else if (auto* box = dynamic_cast<uLib::ContainerBox*>(obj)) { } else if (auto *box = dynamic_cast<uLib::ContainerBox *>(obj)) {
return new ContainerBox(box); return new ContainerBox(box);
} else if (auto* chamber = dynamic_cast<uLib::DetectorChamber*>(obj)) { } else if (auto *chamber = dynamic_cast<uLib::DetectorChamber *>(obj)) {
return new DetectorChamber(chamber); return new DetectorChamber(chamber);
} else if (auto* cylinder = dynamic_cast<uLib::Cylinder*>(obj)) { } else if (auto *cylinder = dynamic_cast<uLib::Cylinder *>(obj)) {
return new Cylinder(cylinder); return new Cylinder(cylinder);
} else if (auto* assembly = dynamic_cast<uLib::Assembly*>(obj)) { } else if (auto *assembly = dynamic_cast<uLib::Assembly *>(obj)) {
return new Assembly(assembly); return new Assembly(assembly);
} else if (auto* box = dynamic_cast<uLib::Geant::BoxSolid*>(obj)) { } else if (auto *box = dynamic_cast<uLib::Geant::BoxSolid *>(obj)) {
return new BoxSolid(box); return new BoxSolid(box);
} }
// Fallback if we don't know the exact class but it might be a context itself // Fallback if we don't know the exact class but it might be a context itself
if (auto subCtx = dynamic_cast<uLib::ObjectsContext*>(obj)) { if (auto subCtx = dynamic_cast<uLib::ObjectsContext *>(obj)) {
return new ObjectsContext(subCtx); return new ObjectsContext(subCtx);
} }
return nullptr; return nullptr;
} }
void ObjectsContext::Prop3DAdded(Prop3D* prop3d) { void ObjectsContext::Prop3DAdded(Prop3D *prop3d) {
ULIB_SIGNAL_EMIT(ObjectsContext::Prop3DAdded, prop3d); ULIB_SIGNAL_EMIT(ObjectsContext::Prop3DAdded, prop3d);
} }
void ObjectsContext::Prop3DRemoved(Prop3D* prop3d) { void ObjectsContext::Prop3DRemoved(Prop3D *prop3d) {
ULIB_SIGNAL_EMIT(ObjectsContext::Prop3DRemoved, prop3d); ULIB_SIGNAL_EMIT(ObjectsContext::Prop3DRemoved, prop3d);
} }