diff --git a/src/Core/ObjectsContext.h b/src/Core/ObjectsContext.h index 4264e61..f555dd2 100644 --- a/src/Core/ObjectsContext.h +++ b/src/Core/ObjectsContext.h @@ -9,7 +9,7 @@ namespace uLib { /** * @brief ObjectsContext represents a collection of Object instances. */ -class ObjectsContext : public Object { +class ObjectsContext : virtual public Object { public: ObjectsContext(); virtual ~ObjectsContext(); diff --git a/src/Core/Property.h b/src/Core/Property.h index b33c6ea..0696818 100644 --- a/src/Core/Property.h +++ b/src/Core/Property.h @@ -137,6 +137,11 @@ public: void serialize(Archive::hrt_iarchive & ar, const unsigned int v) override { serialize_impl(ar, v); } void serialize(Archive::log_archive & ar, const unsigned int v) override { serialize_impl(ar, v); } + virtual void Updated() override { + PropertyBase::Updated(); + this->PropertyChanged(); + } + private: std::string m_name; std::string m_units; diff --git a/src/HEP/Geant/EmitterPrimary.hh b/src/HEP/Geant/EmitterPrimary.hh index 67401f6..8c81d28 100644 --- a/src/HEP/Geant/EmitterPrimary.hh +++ b/src/HEP/Geant/EmitterPrimary.hh @@ -23,7 +23,7 @@ class G4Event; namespace uLib { namespace Geant { -class EmitterPrimary : public G4VUserPrimaryGeneratorAction, public Object, public AffineTransform +class EmitterPrimary : public G4VUserPrimaryGeneratorAction, public AffineTransform { public: diff --git a/src/Math/Assembly.h b/src/Math/Assembly.h index 7440062..9ee9242 100644 --- a/src/Math/Assembly.h +++ b/src/Math/Assembly.h @@ -45,6 +45,7 @@ namespace uLib { */ class Assembly : public ObjectsContext, public AffineTransform { public: + uLibTypeMacro(Assembly, ObjectsContext, AffineTransform) virtual const char *GetClassName() const override { return "Assembly"; } Assembly(); diff --git a/src/Math/ContainerBox.h b/src/Math/ContainerBox.h index dc8fba4..2a2f926 100644 --- a/src/Math/ContainerBox.h +++ b/src/Math/ContainerBox.h @@ -44,16 +44,17 @@ namespace uLib { * that defines the box's specific origin and size relative to its own * coordinate system. */ -class ContainerBox : public AffineTransform, public Object { - - typedef AffineTransform BaseClass; +class ContainerBox : public AffineTransform { public: + uLibTypeMacro(ContainerBox, AffineTransform) + + virtual const char * GetClassName() const override { return "ContainerBox"; } + //////////////////////////////////////////////////////////////////////////// // PROPERTIES // - Property p_Size; - Property p_Origin; - virtual const char * GetClassName() const { return "ContainerBox"; } + Vector3f Size; + Vector3f Origin; /** * @brief Default constructor. @@ -61,10 +62,10 @@ public: */ ContainerBox() : m_LocalT(this), // BaseClass is Parent of m_LocalTransform - p_Size(this, "Size", Vector3f(1.0f, 1.0f, 1.0f)), - p_Origin(this, "Origin", Vector3f(0.0f, 0.0f, 0.0f)) { - Object::connect(&p_Size, &Property::PropertyChanged, this, &ContainerBox::SyncSize); - Object::connect(&p_Origin, &Property::PropertyChanged, this, &ContainerBox::SyncOrigin); + Size(1.0f, 1.0f, 1.0f), + Origin(0.0f, 0.0f, 0.0f) { + ULIB_ACTIVATE_PROPERTIES(*this); + this->Sync(); } /** @@ -73,11 +74,10 @@ public: */ ContainerBox(const Vector3f &size) : m_LocalT(this), - p_Size(this, "Size", size), - p_Origin(this, "Origin", Vector3f(0.0f, 0.0f, 0.0f)) { - Object::connect(&p_Size, &Property::PropertyChanged, this, &ContainerBox::SyncSize); - Object::connect(&p_Origin, &Property::PropertyChanged, this, &ContainerBox::SyncOrigin); - this->SetSize(size); + Size(size), + Origin(0.0f, 0.0f, 0.0f) { + ULIB_ACTIVATE_PROPERTIES(*this); + this->Sync(); } /** @@ -85,13 +85,21 @@ public: * @param copy The ContainerBox instance to copy from. */ ContainerBox(const ContainerBox ©) - : m_LocalT(copy.m_LocalT), // Copy local transform state + : m_LocalT(this), // Reset parent to the new object AffineTransform(copy), - p_Size(this, "Size", copy.p_Size), - p_Origin(this, "Origin", copy.p_Origin) { - m_LocalT.SetParent(this); // Reset parent to the new object - Object::connect(&p_Size, &Property::PropertyChanged, this, &ContainerBox::SyncSize); - Object::connect(&p_Origin, &Property::PropertyChanged, this, &ContainerBox::SyncOrigin); + Size(copy.Size), + Origin(copy.Origin) { + ULIB_ACTIVATE_PROPERTIES(*this); + this->Sync(); + } + + /** + * @brief Serialization template for property registration and persistence. + */ + template + void serialize(ArchiveT & ar, const unsigned int version) { + ar & HRP(Size); + ar & HRP(Origin); } /** @@ -99,7 +107,7 @@ public: * @param v The origin position vector. */ void SetOrigin(const Vector3f &v) { - p_Origin = v; + Origin = v; m_LocalT.SetPosition(v); } @@ -115,7 +123,7 @@ public: * @param v The size vector (width, height, depth). */ void SetSize(const Vector3f &v) { - p_Size = v; + Size = v; Vector3f pos = this->GetOrigin(); m_LocalT = AffineTransform(this); // regenerate local transform m_LocalT.Scale(v); @@ -194,26 +202,27 @@ public: } /** Translate using transformation chain */ - using BaseClass::Translate; + using AffineTransform::Translate; /** Rotate using transformation chain */ - using BaseClass::Rotate; + using AffineTransform::Rotate; /** Scale using transformation chain */ - using BaseClass::Scale; + using AffineTransform::Scale; signals: - // signal to emit when the box is updated // - virtual void Updated() override { ULIB_SIGNAL_EMIT(ContainerBox::Updated); } - -private slots: - void SyncSize() { - this->SetSize(p_Size); + /** Signal emitted when properties change */ + virtual void Updated() override { + this->Sync(); + ULIB_SIGNAL_EMIT(ContainerBox::Updated); } - void SyncOrigin() { - this->SetOrigin(p_Origin); +private: + /** Synchronizes internal transformation with properties */ + void Sync() { + this->SetOrigin(Origin); + this->SetSize(Size); } diff --git a/src/Math/Cylinder.h b/src/Math/Cylinder.h index b7f2505..a9b33ce 100644 --- a/src/Math/Cylinder.h +++ b/src/Math/Cylinder.h @@ -39,10 +39,17 @@ namespace uLib { * The cylinder orientation is defined by the Axis property (0=X, 1=Y, 2=Z). * By default, it is aligned with the Y axis (Axis=1). */ -class Cylinder : public AffineTransform, public Object { +class Cylinder : public AffineTransform { public: - uLibTypeMacro(Cylinder, Object) + uLibTypeMacro(Cylinder, AffineTransform) + + /** + * @brief PROPERTIES + */ + float Radius; + float Height; + int Axis; virtual const char * GetClassName() const override { return "Cylinder"; } @@ -51,7 +58,7 @@ public: */ Cylinder() : m_LocalT(this), Radius(1.0), Height(1.0), Axis(1) { ULIB_ACTIVATE_PROPERTIES(*this); - UpdateLocalMatrix(); + this->Sync(); } /** @@ -60,7 +67,7 @@ public: Cylinder(float radius, float height, int axis = 1) : m_LocalT(this), Radius(radius), Height(height), Axis(axis) { ULIB_ACTIVATE_PROPERTIES(*this); - UpdateLocalMatrix(); + this->Sync(); } /** @@ -69,7 +76,7 @@ public: Cylinder(const Cylinder ©) : m_LocalT(this), AffineTransform(copy), Radius(copy.Radius), Height(copy.Height), Axis(copy.Axis) { ULIB_ACTIVATE_PROPERTIES(*this); - this->UpdateLocalMatrix(); + this->Sync(); } /** @@ -85,7 +92,7 @@ public: /** Sets the radius of the cylinder */ inline void SetRadius(float r) { Radius = r; - UpdateLocalMatrix(); + this->Sync(); } /** Gets the radius of the cylinder */ @@ -94,7 +101,7 @@ public: /** Sets the height of the cylinder */ inline void SetHeight(float h) { Height = h; - UpdateLocalMatrix(); + this->Sync(); } /** Gets the height of the cylinder */ @@ -103,7 +110,7 @@ public: /** Sets the main axis (0=X, 1=Y, 2=Z) */ inline void SetAxis(int axis) { Axis = axis; - UpdateLocalMatrix(); + this->Sync(); } /** Gets the main axis */ @@ -157,25 +164,33 @@ public: return Vector3f(r, theta, h); } + /** Translate using transformation chain */ + using AffineTransform::Translate; + + /** Rotate using transformation chain */ + using AffineTransform::Rotate; + + /** Scale using transformation chain */ + using AffineTransform::Scale; + signals: /** Signal emitted when properties change */ virtual void Updated() override { - this->UpdateLocalMatrix(); + this->Sync(); ULIB_SIGNAL_EMIT(Cylinder::Updated); } private: - /** Recalculates the internal local matrix based on dimensions and axis */ - void UpdateLocalMatrix() { - m_LocalT = AffineTransform(this); - if (Axis == 0) m_LocalT.Scale(Vector3f(Height, Radius, Radius)); - else if (Axis == 1) m_LocalT.Scale(Vector3f(Radius, Height, Radius)); - else m_LocalT.Scale(Vector3f(Radius, Radius, Height)); - } + /** Synchronizes internal transformation with properties */ + void Sync() { + m_LocalT = AffineTransform(this); + if (Axis == 0) m_LocalT.Scale(Vector3f(Height, Radius, Radius)); + else if (Axis == 1) m_LocalT.Scale(Vector3f(Radius, Height, Radius)); + else m_LocalT.Scale(Vector3f(Radius, Radius, Height)); + } - float Radius; - float Height; - int Axis; + +private: AffineTransform m_LocalT; }; diff --git a/src/Math/Geometry.h b/src/Math/Geometry.h index 7c35e2b..5322b68 100644 --- a/src/Math/Geometry.h +++ b/src/Math/Geometry.h @@ -35,10 +35,11 @@ namespace uLib { -class Geometry : public AffineTransform, public Object { +class Geometry : public AffineTransform { public: + uLibTypeMacro(Geometry, AffineTransform) - virtual const char * GetClassName() const { return "Geometry"; } + virtual const char * GetClassName() const override { return "Geometry"; } virtual Vector3f ToLinear(const Vector3f& curved_space) const { return curved_space; @@ -70,6 +71,7 @@ public: class CylindricalGeometry : public Geometry { public: + uLibTypeMacro(CylindricalGeometry, Geometry) CylindricalGeometry() {} Vector3f ToLinear(const Vector3f& cylindrical) const { @@ -88,9 +90,10 @@ public: class SphericalGeometry : public Geometry { public: + uLibTypeMacro(SphericalGeometry, Geometry) SphericalGeometry() {} - virtual const char * GetClassName() const { return "SphericalGeometry"; } + virtual const char * GetClassName() const override { return "SphericalGeometry"; } Vector3f ToLinear(const Vector3f& spherical) const { float r = spherical.x(); @@ -112,9 +115,10 @@ public: class ToroidalGeometry : public Geometry { public: + uLibTypeMacro(ToroidalGeometry, Geometry) ToroidalGeometry(float Rtor) : m_Rtor(Rtor) {} - virtual const char * GetClassName() const { return "ToroidalGeometry"; } + virtual const char * GetClassName() const override { return "ToroidalGeometry"; } Vector3f ToLinear(const Vector3f& toroidal) const { float r = toroidal.x(); diff --git a/src/Math/QuadMesh.h b/src/Math/QuadMesh.h index e98d5ce..7652c0f 100644 --- a/src/Math/QuadMesh.h +++ b/src/Math/QuadMesh.h @@ -34,11 +34,12 @@ namespace uLib { -class QuadMesh : public AffineTransform, public Object +class QuadMesh : public AffineTransform { public: + uLibTypeMacro(QuadMesh, AffineTransform) - virtual const char * GetClassName() const { return "QuadMesh"; } + virtual const char * GetClassName() const override { return "QuadMesh"; } void PrintSelf(std::ostream &o); diff --git a/src/Math/Transform.h b/src/Math/Transform.h index 73cfacd..70ab729 100644 --- a/src/Math/Transform.h +++ b/src/Math/Transform.h @@ -50,6 +50,7 @@ #define U_TRANSFORM_H #include +#include "Math/Units.h" #include "Math/Dense.h" @@ -59,27 +60,65 @@ namespace uLib { ///////// AFFINE TRANSFORM WRAPPER ////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// -class AffineTransform { +class AffineTransform : virtual public Object { +public: + uLibTypeMacro(AffineTransform, Object) + + /** + * @brief Grouped transformation parameters for property-based control. + */ + struct { + Vector3f Position = Vector3f::Zero(); + Vector3f Orientation = Vector3f::Zero(); + Vector3f Scale = Vector3f::Ones(); + + template + void serialize(ArchiveT & ar, const unsigned int version) { + ar & HRPU(Position, "mm"); + ar & HRPU(Orientation, "deg"); + ar & HRP(Scale); + } + } Transform; + protected: Eigen::Affine3f m_T; AffineTransform *m_Parent; + public: AffineTransform() : m_T(Matrix4f::Identity()), m_Parent(NULL) - {} + { + ULIB_ACTIVATE_PROPERTIES(*this); + this->Sync(); + } virtual ~AffineTransform() {} AffineTransform(AffineTransform *parent) : m_T(Matrix4f::Identity()), m_Parent(parent) - {} + { + ULIB_ACTIVATE_PROPERTIES(*this); + this->Sync(); + } AffineTransform(const AffineTransform ©) : m_T(copy.m_T), - m_Parent(copy.m_Parent) - {} + m_Parent(copy.m_Parent), + Transform(copy.Transform) + { + ULIB_ACTIVATE_PROPERTIES(*this); + this->Sync(); + } + + /** + * @brief Registration of properties in groups. + */ + template + void serialize(ArchiveT & ar, const unsigned int version) { + ar & boost::serialization::make_nvp("Transform", Transform); + } Eigen::Affine3f& GetTransform() { return m_T; } @@ -87,7 +126,11 @@ public: void SetParent(AffineTransform *name) { this->m_Parent = name; } - void SetMatrix (Matrix4f mat) { m_T.matrix() = mat; } + void SetMatrix (Matrix4f mat) { + m_T.matrix() = mat; + this->UpdatePropertiesFromMatrix(); + } + Matrix4f GetMatrix() const { return m_T.matrix(); } Matrix4f GetWorldMatrix() const @@ -96,32 +139,51 @@ public: else return m_Parent->GetWorldMatrix() * m_T.matrix(); // T = B * A // } - void SetPosition(const Vector3f v) { this->m_T.translation() = v; } + void SetPosition(const Vector3f v) { + this->Transform.Position = v; + this->Sync(); + } - Vector3f GetPosition() const { return this->m_T.translation(); } + Vector3f GetPosition() const { return this->Transform.Position; } - void SetRotation(const Matrix3f m) { this->m_T.linear() = m; } + void SetRotation(const Matrix3f m) { + this->m_T.linear() = m; + this->UpdatePropertiesFromMatrix(); + } Matrix3f GetRotation() const { return this->m_T.rotation(); } - void Translate(const Vector3f v) { this->m_T.translate(v); } - - void Scale(const Vector3f v) { this->m_T.scale(v); } - - Vector3f GetScale() const { - return Vector3f(m_T.linear().col(0).norm(), - m_T.linear().col(1).norm(), - m_T.linear().col(2).norm()); + void Translate(const Vector3f v) { + this->Transform.Position += v; + this->Sync(); } + void Scale(const Vector3f v) { + this->Transform.Scale = this->Transform.Scale.cwiseProduct(v); + this->Sync(); + } - void Rotate(const Matrix3f m) { this->m_T.rotate(m); } + Vector3f GetScale() const { return this->Transform.Scale; } + + void SetOrientation(const Vector3f v) { + this->Transform.Orientation = v; + this->Sync(); + } + + Vector3f GetOrientation() const { return this->Transform.Orientation; } + + + void Rotate(const Matrix3f m) { + this->m_T.rotate(m); + this->UpdatePropertiesFromMatrix(); + } void Rotate(const float angle, Vector3f axis) { - axis.normalize(); // prehaps not necessary ( see eigens ) + axis.normalize(); Eigen::AngleAxisf ax(angle,axis); this->m_T.rotate(Eigen::Quaternion(ax)); + this->UpdatePropertiesFromMatrix(); } void Rotate(const Vector3f euler_axis) { @@ -129,17 +191,14 @@ public: Rotate(angle,euler_axis); } - void PreRotate(const Matrix3f m) { this->m_T.prerotate(m); } + void PreRotate(const Matrix3f m) { this->m_T.prerotate(m); this->UpdatePropertiesFromMatrix(); } void QuaternionRotate(const Vector4f q) - { this->m_T.rotate(Eigen::Quaternion(q)); } + { this->m_T.rotate(Eigen::Quaternion(q)); this->UpdatePropertiesFromMatrix(); } void EulerYZYRotate(const Vector3f e) { - Matrix3f mat; - mat = Eigen::AngleAxisf(e.x(), Vector3f::UnitY()) - * Eigen::AngleAxisf(e.y(), Vector3f::UnitZ()) - * Eigen::AngleAxisf(e.z(), Vector3f::UnitY()); - m_T.rotate(mat); + this->Transform.Orientation = e; + this->Sync(); } void FlipAxes(int first, int second) @@ -147,7 +206,61 @@ public: Matrix3f mat = Matrix3f::Identity(); mat.col(first).swap(mat.col(second)); m_T.rotate(mat); + this->UpdatePropertiesFromMatrix(); } + + /** + * @brief Decomposes the internal matrix m_T back into Position, Orientation, and Scale properties. + */ + void UpdatePropertiesFromMatrix() { + // 1. Position + Transform.Position = m_T.translation(); + + // 2. Scale + Matrix3f linear = m_T.linear(); + Transform.Scale(0) = linear.col(0).norm(); + Transform.Scale(1) = linear.col(1).norm(); + Transform.Scale(2) = linear.col(2).norm(); + + // 3. Rotation (Normalization removes scale) + Matrix3f rotation = linear; + if (Transform.Scale(0) > 1e-6) rotation.col(0) /= Transform.Scale(0); + if (Transform.Scale(1) > 1e-6) rotation.col(1) /= Transform.Scale(1); + if (Transform.Scale(2) > 1e-6) rotation.col(2) /= Transform.Scale(2); + + // Euler YZY (indices 1, 2, 1) + Vector3f euler = rotation.eulerAngles(1, 2, 1); + Transform.Orientation = euler / CLHEP::degree; + + // Notify properties + PropertyBase* p; + if ((p = this->GetProperty("Transform.Position"))) p->Updated(); + if ((p = this->GetProperty("Transform.Orientation"))) p->Updated(); + if ((p = this->GetProperty("Transform.Scale"))) p->Updated(); + } + +signals: + /** Signal emitted when properties change */ + virtual void Updated() override { + this->Sync(); + ULIB_SIGNAL_EMIT(AffineTransform::Updated); + } + +private: + /** Synchronizes m_T with properties */ + void Sync() { + m_T = Eigen::Affine3f::Identity(); + m_T.translate(Transform.Position); + + // Orientation (using YZY order as implied by EulerYZYRotate) + Matrix3f mat; + mat = Eigen::AngleAxisf(Transform.Orientation.x() * CLHEP::degree, Vector3f::UnitY()) + * Eigen::AngleAxisf(Transform.Orientation.y() * CLHEP::degree, Vector3f::UnitZ()) + * Eigen::AngleAxisf(Transform.Orientation.z() * CLHEP::degree, Vector3f::UnitY()); + m_T.rotate(mat); + + m_T.scale(Transform.Scale); + } }; diff --git a/src/Math/TriangleMesh.h b/src/Math/TriangleMesh.h index 4acfe58..94f5582 100644 --- a/src/Math/TriangleMesh.h +++ b/src/Math/TriangleMesh.h @@ -37,11 +37,12 @@ namespace uLib { -class TriangleMesh : public AffineTransform, public Object +class TriangleMesh : public AffineTransform { public: + uLibTypeMacro(TriangleMesh, AffineTransform) - virtual const char * GetClassName() const { return "TriangleMesh"; } + virtual const char * GetClassName() const override { return "TriangleMesh"; } void PrintSelf(std::ostream &o); diff --git a/src/Vtk/uLibVtkInterface.cxx b/src/Vtk/uLibVtkInterface.cxx index 59f21e3..2163f24 100644 --- a/src/Vtk/uLibVtkInterface.cxx +++ b/src/Vtk/uLibVtkInterface.cxx @@ -41,6 +41,7 @@ #include #include "vtkViewport.h" #include "uLibVtkInterface.h" +#include "Math/Transform.h" #include #include #include @@ -484,7 +485,7 @@ void Puppet::SetSelected(bool selected) if (!pd->m_Selectable) return; if (pd->m_Selected == selected) return; pd->m_Selected = selected; - pd->UpdateHighlight(); + pd->UpdateHighlight();0 } bool Puppet::IsSelected() const @@ -498,8 +499,25 @@ void Puppet::Update() if (root) { pd->ApplyAppearance(root); - // Apply transformation if it's a Prop3D - if (auto* p3d = vtkProp3D::SafeDownCast(root)) { + // Handle transformation synchronization from content + if (auto* content = dynamic_cast(GetContent())) { + pd->m_Position = content->GetPosition().cast(); + pd->m_Orientation = content->GetOrientation().cast(); + pd->m_Scale = content->GetScale().cast(); + + if (auto* p3d = vtkProp3D::SafeDownCast(root)) { + vtkNew vmat; + const Matrix4f& emat = content->GetMatrix(); + for(int i=0; i<4; ++i) for(int j=0; j<4; ++j) vmat->SetElement(i, j, emat(i,j)); + p3d->SetUserMatrix(vmat); + + // Clear base transform to avoid double-application + p3d->SetPosition(0,0,0); + p3d->SetOrientation(0,0,0); + p3d->SetScale(1,1,1); + } + } + else if (auto* p3d = vtkProp3D::SafeDownCast(root)) { p3d->SetPosition(pd->m_Position.data()); p3d->SetOrientation(pd->m_Orientation.data()); p3d->SetScale(pd->m_Scale.data()); @@ -539,23 +557,42 @@ void Puppet::Update() } } + void Puppet::SyncFromVtk() { vtkProp* root = this->GetProp(); if (auto* p3d = vtkProp3D::SafeDownCast(root)) { - double pos[3], ori[3], scale[3]; - p3d->GetPosition(pos); - p3d->GetOrientation(ori); - p3d->GetScale(scale); - - // Update properties - for (int i=0; i<3; ++i) { - pd->m_Position(i) = pos[i]; - pd->m_Orientation(i) = ori[i]; - pd->m_Scale(i) = scale[i]; + // Handle content synchronization if it's an AffineTransform + if (auto* content = dynamic_cast(GetContent())) { + vtkMatrix4x4* vmat = p3d->GetUserMatrix(); + if (vmat) { + Matrix4f emat; + for (int i=0; i<4; ++i) + for (int j=0; j<4; ++j) + emat(i, j) = vmat->GetElement(i, j); + content->SetMatrix(emat); + + // Re-sync internal puppet properties from the now-updated content + pd->m_Position = content->GetPosition().cast(); + pd->m_Orientation = content->GetOrientation().cast(); + pd->m_Scale = content->GetScale().cast(); + } + } + else { + // Update internal puppet properties directly from base components + // only if no content exists (old behavior) + double pos[3], ori[3], scale[3]; + p3d->GetPosition(pos); + p3d->GetOrientation(ori); + p3d->GetScale(scale); + for (int i=0; i<3; ++i) { + pd->m_Position(i) = pos[i]; + pd->m_Orientation(i) = ori[i]; + pd->m_Scale(i) = scale[i]; + } } - // Get the properties from the object + // Notify puppet properties updated if (auto* propPos = this->GetProperty("Position")) propPos->Updated(); if (auto* propOri = this->GetProperty("Orientation")) propOri->Updated(); if (auto* propScale = this->GetProperty("Scale")) propScale->Updated(); diff --git a/src/Vtk/vtkObjectsContext.cpp b/src/Vtk/vtkObjectsContext.cpp index 13121d9..4e17ea0 100644 --- a/src/Vtk/vtkObjectsContext.cpp +++ b/src/Vtk/vtkObjectsContext.cpp @@ -110,17 +110,16 @@ void vtkObjectsContext::Update() { Puppet* vtkObjectsContext::CreatePuppet(uLib::Object* obj) { if (!obj) return nullptr; - const char* className = obj->GetClassName(); - if (std::strcmp(className, "ContainerBox") == 0) { - return new vtkContainerBox(static_cast(obj)); - } else if (std::strcmp(className, "DetectorChamber") == 0) { - return new vtkDetectorChamber(static_cast(obj)); - } else if (std::strcmp(className, "Cylinder") == 0) { - return new vtkCylinder(static_cast(obj)); - } else if (std::strcmp(className, "VoxImage") == 0) { - return new vtkVoxImage(*static_cast(obj)); - } else if (std::strcmp(className, "Assembly") == 0) { - return new Assembly(static_cast(obj)); + if (auto* box = dynamic_cast(obj)) { + return new vtkContainerBox(box); + } else if (auto* chamber = dynamic_cast(obj)) { + return new vtkDetectorChamber(chamber); + } else if (auto* cylinder = dynamic_cast(obj)) { + return new vtkCylinder(cylinder); + } else if (auto* vox = dynamic_cast(obj)) { + return new vtkVoxImage(*vox); + } else if (auto* assembly = dynamic_cast(obj)) { + return new Assembly(assembly); } // Fallback if we don't know the exact class but it might be a context itself