From e3f798df999c54b7cb4ca62cdc8f2a0d8a50203c Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Thu, 29 Jan 2026 14:41:37 +0100 Subject: [PATCH 1/7] extract method --- .../src/sofa/core/behavior/SingleStateAccessor.h | 2 ++ .../src/sofa/core/behavior/SingleStateAccessor.inl | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Sofa/framework/Core/src/sofa/core/behavior/SingleStateAccessor.h b/Sofa/framework/Core/src/sofa/core/behavior/SingleStateAccessor.h index 2899ad2ffb5..280d8e622af 100644 --- a/Sofa/framework/Core/src/sofa/core/behavior/SingleStateAccessor.h +++ b/Sofa/framework/Core/src/sofa/core/behavior/SingleStateAccessor.h @@ -42,6 +42,8 @@ class SingleStateAccessor : public virtual StateAccessor MechanicalState* getMState(); const MechanicalState* getMState() const; + void validateMState(); + protected: explicit SingleStateAccessor(MechanicalState* mm = nullptr); diff --git a/Sofa/framework/Core/src/sofa/core/behavior/SingleStateAccessor.inl b/Sofa/framework/Core/src/sofa/core/behavior/SingleStateAccessor.inl index 3bc2ab405b2..95b09701a1b 100644 --- a/Sofa/framework/Core/src/sofa/core/behavior/SingleStateAccessor.inl +++ b/Sofa/framework/Core/src/sofa/core/behavior/SingleStateAccessor.inl @@ -31,15 +31,21 @@ void SingleStateAccessor::init() { Inherit1::init(); - d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); + if (!this->isComponentStateInvalid()) + { + this->validateMState(); + } +} +template +void SingleStateAccessor::validateMState() +{ if (!mstate.get()) { mstate.set(dynamic_cast< MechanicalState* >(getContext()->getMechanicalState())); if(!mstate) { - msg_error() << "No compatible MechanicalState found in the current context. " "This may be because there is no MechanicalState in the local context, " "or because the type is not compatible"; @@ -67,7 +73,7 @@ auto SingleStateAccessor::getMState() const -> const MechanicalState< return mstate.get(); } -template +template SingleStateAccessor::SingleStateAccessor(MechanicalState *mm) : Inherit1() , mstate(initLink("mstate", "MechanicalState used by this component"), mm) From ef939b642009e075f7de2a582fc7c33b0ac7a86f Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Thu, 29 Jan 2026 14:44:07 +0100 Subject: [PATCH 2/7] LineCollisionModel derives from SingleStateAccessor and TopologyAccessor --- .../collision/geometry/LineCollisionModel.h | 23 ++++++++------ .../collision/geometry/LineCollisionModel.inl | 30 ++++++++++--------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineCollisionModel.h b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineCollisionModel.h index bedf9ce17d0..8285d2992cc 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineCollisionModel.h +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineCollisionModel.h @@ -26,6 +26,8 @@ #include #include #include +#include +#include namespace sofa::component::collision::geometry @@ -73,10 +75,16 @@ class TLine : public core::TCollisionElementIterator; template -class LineCollisionModel : public core::CollisionModel +class LineCollisionModel : + public core::CollisionModel, + public virtual core::behavior::SingleStateAccessor, + public virtual core::behavior::TopologyAccessor { -public : - SOFA_CLASS(SOFA_TEMPLATE(LineCollisionModel, TDataTypes), core::CollisionModel); +public: + SOFA_CLASS3(SOFA_TEMPLATE(LineCollisionModel, TDataTypes), + core::CollisionModel, + core::behavior::SingleStateAccessor, + core::behavior::TopologyAccessor); enum LineFlag { @@ -130,7 +138,7 @@ public : bool canCollideWithElement(sofa::Index index, CollisionModel* model2, sofa::Index index2) override; - core::behavior::MechanicalState* getMechanicalState() { return mstate; } + core::behavior::MechanicalState* getMechanicalState() { return this->mstate.get(); } Deriv velocity(sofa::Index index)const; @@ -163,12 +171,9 @@ public : Data d_displayFreePosition; ///< Display Collision Model Points free position(in green) - /// Link to be set to the topology container in the component graph. - SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; - protected: - core::behavior::MechanicalState* mstate; - Topology* topology; + using sofa::core::behavior::SingleStateAccessor::mstate; + using sofa::core::behavior::TopologyAccessor::l_topology; PointCollisionModel* mpoints; int meshRevision; }; diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineCollisionModel.inl b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineCollisionModel.inl index 3722ca05cb7..b8aadc87d60 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineCollisionModel.inl +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/LineCollisionModel.inl @@ -21,7 +21,6 @@ ******************************************************************************/ #pragma once #include -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include namespace sofa::component::collision::geometry { @@ -39,8 +39,7 @@ template LineCollisionModel::LineCollisionModel() : d_bothSide(initData(&d_bothSide, false, "bothSide", "activate collision on both side of the line model (when surface normals are defined on these lines)") ) , d_displayFreePosition(initData(&d_displayFreePosition, false, "displayFreePosition", "Display Collision Model Points free position(in green)") ) - , l_topology(initLink("topology", "link to the topology container")) - , mstate(nullptr), topology(nullptr), meshRevision(-1) + , meshRevision(-1) { enum_type = LINE_TYPE; } @@ -57,21 +56,24 @@ template void LineCollisionModel::init() { this->CollisionModel::init(); - mstate = dynamic_cast< core::behavior::MechanicalState* > (getContext()->getMechanicalState()); - this->getContext()->get(mpoints); - if (mstate==nullptr) + if (!this->isComponentStateInvalid()) { - msg_error() << "LineModel requires a Vec3 Mechanical Model"; - return; + this->validateMState(); + } + + if (!this->isComponentStateInvalid()) + { + this->validateTopology(); } - if (l_topology.empty()) + if (this->isComponentStateInvalid()) { - msg_info() << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; - l_topology.set(this->getContext()->getMeshTopologyLink()); + return; } + this->getContext()->get(mpoints); + core::topology::BaseMeshTopology *bmt = l_topology.get(); msg_info() << "Topology path used: '" << l_topology.getLinkedPath() << "'"; @@ -541,15 +543,15 @@ template int LineCollisionModel::getLineFlags(sofa::Index i) { int f = 0; - if (topology) + if (l_topology) { sofa::core::topology::BaseMeshTopology::Edge e(elems[i].p[0], elems[i].p[1]); i = getElemEdgeIndex(i); - if (i < topology->getNbEdges()) + if (i < l_topology->getNbEdges()) { for (sofa::Index j=0; j<2; ++j) { - const auto& eav = topology->getEdgesAroundVertex(e[j]); + const auto& eav = l_topology->getEdgesAroundVertex(e[j]); if (eav[0] == (sofa::core::topology::BaseMeshTopology::EdgeID)i) f |= (FLAG_P1 << j); if (eav.size() == 1) From d05bc72ea3d6d2e20956ff41c9b518c83f40463d Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Thu, 29 Jan 2026 14:47:50 +0100 Subject: [PATCH 3/7] PointCollisionModel derives from SingleStateAccessor and TopologyAccessor --- .../collision/geometry/PointCollisionModel.h | 17 +++++++++++------ .../geometry/PointCollisionModel.inl | 19 ++++++++++--------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointCollisionModel.h b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointCollisionModel.h index 91cebd69ee8..a452a3052d7 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointCollisionModel.h +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointCollisionModel.h @@ -26,6 +26,8 @@ #include #include #include +#include +#include namespace sofa::component::collision::geometry { @@ -60,10 +62,16 @@ class TPoint : public core::TCollisionElementIterator; template -class PointCollisionModel : public core::CollisionModel +class PointCollisionModel : + public core::CollisionModel, + public virtual core::behavior::SingleStateAccessor, + public virtual core::behavior::TopologyAccessor { public: - SOFA_CLASS(SOFA_TEMPLATE(PointCollisionModel, TDataTypes), core::CollisionModel); + SOFA_CLASS3(SOFA_TEMPLATE(PointCollisionModel, TDataTypes), + core::CollisionModel, + core::behavior::SingleStateAccessor, + core::behavior::TopologyAccessor); typedef TDataTypes DataTypes; typedef DataTypes InDataTypes; @@ -129,16 +137,13 @@ class PointCollisionModel : public core::CollisionModel protected: - core::behavior::MechanicalState* mstate; + using sofa::core::behavior::SingleStateAccessor::mstate; Data d_computeNormals; ///< activate computation of normal vectors (required for some collision detection algorithms) Data d_displayFreePosition; ///< Display Collision Model Points free position(in green) VecDeriv normals; - /// Link to be set to the topology container in the component graph. - SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; - }; diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointCollisionModel.inl b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointCollisionModel.inl index 8a10d5227df..3199066300b 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointCollisionModel.inl +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/PointCollisionModel.inl @@ -28,6 +28,7 @@ #include #include #include +#include namespace sofa::component::collision::geometry { @@ -35,10 +36,8 @@ namespace sofa::component::collision::geometry template PointCollisionModel::PointCollisionModel() : d_bothSide(initData(&d_bothSide, false, "bothSide", "activate collision on both side of the point model (when surface normals are defined on these points)") ) - , mstate(nullptr) , d_computeNormals(initData(&d_computeNormals, false, "computeNormals", "activate computation of normal vectors (required for some collision detection algorithms)") ) , d_displayFreePosition(initData(&d_displayFreePosition, false, "displayFreePosition", "Display Collision Model Points free position(in green)") ) - , l_topology(initLink("topology", "link to the topology container")) { enum_type = POINT_TYPE; } @@ -53,18 +52,20 @@ template void PointCollisionModel::init() { this->CollisionModel::init(); - mstate = dynamic_cast< core::behavior::MechanicalState* > (getContext()->getMechanicalState()); - if (mstate==nullptr) + if (!this->isComponentStateInvalid()) { - msg_error() << "PointModel requires a Vec3 Mechanical Model"; - return; + this->validateMState(); } - if (l_topology.empty()) + if (!this->isComponentStateInvalid()) { - msg_info() << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; - l_topology.set(this->getContext()->getMeshTopologyLink()); + this->validateTopology(); + } + + if (this->isComponentStateInvalid()) + { + return; } const int npoints = mstate->getSize(); From 8a857c5406ee6c22aaab65e1c3df6b0ac0933f95 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Thu, 29 Jan 2026 14:51:35 +0100 Subject: [PATCH 4/7] RayCollisionModel derives from SingleStateAccessor --- .../collision/geometry/RayCollisionModel.cpp | 7 +++---- .../component/collision/geometry/RayCollisionModel.h | 11 ++++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayCollisionModel.cpp b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayCollisionModel.cpp index 08ec23ec121..e3766225d88 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayCollisionModel.cpp +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayCollisionModel.cpp @@ -70,13 +70,12 @@ void RayCollisionModel::init() { this->CollisionModel::init(); - mstate = dynamic_cast< core::behavior::MechanicalState* > (getContext()->getMechanicalState()); - if (mstate==nullptr) + if (!this->isComponentStateInvalid()) { - msg_error() << "RayCollisionModel requires a Vec3 Mechanical Model"; - return; + this->validateMState(); } + if (!this->isComponentStateInvalid()) { const int npoints = mstate->getSize(); resize(npoints); diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayCollisionModel.h b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayCollisionModel.h index 5e492069de7..1ca8a4378c0 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayCollisionModel.h +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/RayCollisionModel.h @@ -25,6 +25,7 @@ #include #include #include +#include namespace sofa::component::collision::response::contact { @@ -52,10 +53,14 @@ class SOFA_COMPONENT_COLLISION_GEOMETRY_API Ray : public core::TCollisionElement void setL(SReal newL); }; -class SOFA_COMPONENT_COLLISION_GEOMETRY_API RayCollisionModel : public core::CollisionModel +class SOFA_COMPONENT_COLLISION_GEOMETRY_API RayCollisionModel : + public core::CollisionModel, + public virtual sofa::core::behavior::SingleStateAccessor { public: - SOFA_CLASS(RayCollisionModel, core::CollisionModel); + SOFA_CLASS2(RayCollisionModel, + core::CollisionModel, + sofa::core::behavior::SingleStateAccessor); typedef sofa::defaulttype::Vec3Types InDataTypes; typedef sofa::defaulttype::Vec3Types DataTypes; @@ -95,7 +100,7 @@ class SOFA_COMPONENT_COLLISION_GEOMETRY_API RayCollisionModel : public core::Col Data d_defaultLength; ///< The default length for all rays in this collision model std::set contacts; - core::behavior::MechanicalState* mstate; + using sofa::core::behavior::SingleStateAccessor::mstate; }; From e5ccd9c197dd5666f02e175f03916b294b367091 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Thu, 29 Jan 2026 14:58:45 +0100 Subject: [PATCH 5/7] SphereCollisionModel derives from SingleStateAccessor --- .../collision/geometry/SphereCollisionModel.h | 12 ++++++--- .../geometry/SphereCollisionModel.inl | 25 +++++++------------ 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereCollisionModel.h b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereCollisionModel.h index 8df2d72d4eb..dc25ae87bfb 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereCollisionModel.h +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereCollisionModel.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace sofa::component::collision::geometry { @@ -80,10 +81,14 @@ sofa::type::Vec3 TSphere::getContactPointWithSurfacePoi template< class TDataTypes> -class SphereCollisionModel : public core::CollisionModel +class SphereCollisionModel : + public core::CollisionModel, + public virtual core::behavior::SingleStateAccessor { public: - SOFA_CLASS(SOFA_TEMPLATE(SphereCollisionModel, TDataTypes), core::CollisionModel); + SOFA_CLASS2(SOFA_TEMPLATE(SphereCollisionModel, TDataTypes), + core::CollisionModel, + core::behavior::SingleStateAccessor); typedef TDataTypes DataTypes; typedef DataTypes InDataTypes; @@ -170,8 +175,7 @@ class SphereCollisionModel : public core::CollisionModel void computeBBox(const core::ExecParams* params, bool onlyVisible=false) override; protected: - core::behavior::MechanicalState* mstate; - SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; + using sofa::core::behavior::SingleStateAccessor::mstate; }; template diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereCollisionModel.inl b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereCollisionModel.inl index f09615db20a..166b7a692f3 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereCollisionModel.inl +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/SphereCollisionModel.inl @@ -25,6 +25,7 @@ #include #include #include +#include #include using sofa::core::objectmodel::ComponentState ; @@ -37,7 +38,6 @@ SphereCollisionModel::SphereCollisionModel() : d_radius(initData(&d_radius, "listRadius", "Radius of each sphere")) , d_defaultRadius(initData(&d_defaultRadius, (SReal)(1.0), "radius", "Default radius")) , d_showImpostors(initData(&d_showImpostors, true, "showImpostors", "Draw spheres as impostors instead of \"real\" spheres")) - , mstate(nullptr) { enum_type = SPHERE_TYPE; } @@ -47,7 +47,6 @@ SphereCollisionModel::SphereCollisionModel(core::behavior::Mechanical : d_radius(initData(&d_radius, "listRadius", "Radius of each sphere")) , d_defaultRadius(initData(&d_defaultRadius, (SReal)(1.0), "radius", "Default radius")) , d_showImpostors(initData(&d_showImpostors, true, "showImpostors", "Draw spheres as impostors instead of \"real\" spheres")) - , mstate(_mstate) { enum_type = SPHERE_TYPE; } @@ -81,24 +80,18 @@ void SphereCollisionModel::init() msg_warning() << "Calling an already fully initialized component. You should use reinit instead." ; } - this->CollisionModel::init(); - mstate = dynamic_cast< core::behavior::MechanicalState* > (getContext()->getMechanicalState()); - if (mstate==nullptr) + if (!this->isComponentStateInvalid()) { - //TODO(dmarchal): The previous message was saying this only work for a vec3 mechanicalstate but there - // it seems that a mechanicalstate will work we well...where is the truth ? - msg_error(this) << "Missing a MechanicalObject with template '" << DataTypes::Name() << ". " - "This MechnicalObject stores the position of the spheres. When this one is missing the collision model is deactivated. \n" - "To remove this error message you can add to your scene a line . "; - d_componentState.setValue(ComponentState::Invalid) ; - - return; + this->validateMState(); } - const auto npoints = mstate->getSize(); - resize(npoints); + if (!this->isComponentStateInvalid()) + { + const auto npoints = mstate->getSize(); + resize(npoints); - d_componentState.setValue(ComponentState::Valid) ; + d_componentState.setValue(ComponentState::Valid) ; + } } From c4059467595477526759cde0e84891a03342c065 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Thu, 29 Jan 2026 15:02:43 +0100 Subject: [PATCH 6/7] TetrahedronCollisionModel derives from SingleStateAccessor and TopologyAccessor --- .../geometry/TetrahedronCollisionModel.cpp | 29 ++++++------------- .../geometry/TetrahedronCollisionModel.h | 17 +++++++---- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TetrahedronCollisionModel.cpp b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TetrahedronCollisionModel.cpp index 5ca5de27de8..b41c4b24e67 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TetrahedronCollisionModel.cpp +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TetrahedronCollisionModel.cpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace sofa::component::collision::geometry { @@ -42,10 +43,8 @@ void registerTetrahedronCollisionModel(sofa::core::ObjectFactory* factory) TetrahedronCollisionModel::TetrahedronCollisionModel() : tetra(nullptr) - , mstate(nullptr) , m_topology(nullptr) , m_topologyRevision(-1) - , l_topology(initLink("topology", "link to the topology container")) { enum_type = TETRAHEDRON_TYPE; } @@ -59,32 +58,22 @@ void TetrahedronCollisionModel::resize(sofa::Size size) void TetrahedronCollisionModel::init() { - if (l_topology.empty()) + this->CollisionModel::init(); + + if (!this->isComponentStateInvalid()) { - msg_info() << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; - l_topology.set(this->getContext()->getMeshTopologyLink()); + this->validateMState(); } - m_topology = l_topology.get(); - msg_info() << "Topology path used: '" << l_topology.getLinkedPath() << "'"; - - if (!m_topology) + if (!this->isComponentStateInvalid()) { - msg_error() << "No topology component found at path: " << l_topology.getLinkedPath() << ", nor in current context: " << this->getContext()->name << ". TetrahedronCollisionModel requires a BaseMeshTopology"; - sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - return; + this->validateTopology(); } - this->CollisionModel::init(); - mstate = dynamic_cast< core::behavior::MechanicalState* > (getContext()->getMechanicalState()); - - if (mstate==nullptr) + if (!this->isComponentStateInvalid()) { - msg_error() << "TetrahedronCollisionModel requires a Vec3 Mechanical Model"; - return; + updateFromTopology(); } - - updateFromTopology(); } diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TetrahedronCollisionModel.h b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TetrahedronCollisionModel.h index 5c93d0fb484..fe20289e44d 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TetrahedronCollisionModel.h +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TetrahedronCollisionModel.h @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -69,10 +71,16 @@ class Tetrahedron : public core::TCollisionElementIterator, + public virtual core::behavior::TopologyAccessor { public: - SOFA_CLASS(TetrahedronCollisionModel, core::CollisionModel); + SOFA_CLASS3(TetrahedronCollisionModel, + core::CollisionModel, + core::behavior::SingleStateAccessor, + core::behavior::TopologyAccessor); typedef defaulttype::Vec3Types InDataTypes; typedef defaulttype::Vec3Types DataTypes; @@ -94,7 +102,7 @@ class SOFA_COMPONENT_COLLISION_GEOMETRY_API TetrahedronCollisionModel : public c sofa::type::vector elems; const sofa::core::topology::BaseMeshTopology::SeqTetrahedra* tetra; - core::behavior::MechanicalState* mstate; + using sofa::core::behavior::SingleStateAccessor::mstate; sofa::core::topology::BaseMeshTopology* m_topology; @@ -123,8 +131,7 @@ class SOFA_COMPONENT_COLLISION_GEOMETRY_API TetrahedronCollisionModel : public c core::behavior::MechanicalState* getMechanicalState() { return mstate; } - /// Link to be set to the topology container in the component graph. - SingleLink l_topology; + using sofa::core::behavior::TopologyAccessor::l_topology; }; From b2dd218b8f480fdabddb4faa55399b299a4af1ec Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Thu, 29 Jan 2026 15:11:58 +0100 Subject: [PATCH 7/7] TriangleCollisionModel derives from SingleStateAccessor and TopologyAccessor --- .../geometry/TriangleCollisionModel.h | 23 ++-- .../geometry/TriangleCollisionModel.inl | 127 ++++++++---------- .../geometry/TriangleModelInRegularGrid.cpp | 11 +- .../geometry/TriangleOctreeCollisionModel.cpp | 8 +- 4 files changed, 76 insertions(+), 93 deletions(-) diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleCollisionModel.h b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleCollisionModel.h index 67673bb5100..99791d0ea41 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleCollisionModel.h +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleCollisionModel.h @@ -28,6 +28,8 @@ #include #include #include +#include +#include namespace sofa::component::collision::geometry { @@ -102,10 +104,16 @@ using Triangle = TTriangle; * The class \sa TTriangle is used to access specific triangle of this collision Model. */ template -class TriangleCollisionModel : public core::CollisionModel +class TriangleCollisionModel : + public core::CollisionModel, + public virtual core::behavior::SingleStateAccessor, + public virtual core::behavior::TopologyAccessor { public: - SOFA_CLASS(SOFA_TEMPLATE(TriangleCollisionModel, TDataTypes), core::CollisionModel); + SOFA_CLASS3(SOFA_TEMPLATE(TriangleCollisionModel, TDataTypes), + core::CollisionModel, + core::behavior::SingleStateAccessor, + core::behavior::TopologyAccessor); typedef TDataTypes DataTypes; typedef DataTypes InDataTypes; @@ -138,13 +146,10 @@ class TriangleCollisionModel : public core::CollisionModel Data d_bothSide; ///< activate collision on both side of the triangle model Data d_computeNormals; ///< set to false to disable computation of triangles normal Data d_useCurvature; ///< use the curvature of the mesh to avoid some self-intersection test - - /// Link to be set to the topology container in the component graph. - SingleLink, sofa::core::topology::BaseMeshTopology, BaseLink::FLAG_STOREPATH | BaseLink::FLAG_STRONGLINK> l_topology; protected: - core::behavior::MechanicalState* m_mstate; ///< Pointer to the corresponding MechanicalState - sofa::core::topology::BaseMeshTopology* m_topology; ///< Pointer to the corresponding Topology + using sofa::core::behavior::SingleStateAccessor::mstate; + using sofa::core::behavior::TopologyAccessor::l_topology; VecDeriv m_normals; ///< Vector of normal direction per triangle. @@ -185,8 +190,8 @@ class TriangleCollisionModel : public core::CollisionModel bool canCollideWithElement(sofa::Index index, CollisionModel* model2, sofa::Index index2) override; - core::behavior::MechanicalState* getMechanicalState() { return m_mstate; } - const core::behavior::MechanicalState* getMechanicalState() const { return m_mstate; } + core::behavior::MechanicalState* getMechanicalState() { return mstate; } + const core::behavior::MechanicalState* getMechanicalState() const { return mstate; } const VecCoord& getX() const { return(getMechanicalState()->read(core::vec_id::read_access::position)->getValue()); } const sofa::core::topology::BaseMeshTopology::SeqTriangles& getTriangles() const { return *m_triangles; } diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleCollisionModel.inl b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleCollisionModel.inl index 89a60fe878f..8af3f12c8ad 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleCollisionModel.inl +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleCollisionModel.inl @@ -29,6 +29,7 @@ #include #include #include +#include namespace sofa::component::collision::geometry { @@ -38,9 +39,6 @@ TriangleCollisionModel::TriangleCollisionModel() : d_bothSide(initData(&d_bothSide, false, "bothSide", "activate collision on both side of the triangle model") ) , d_computeNormals(initData(&d_computeNormals, true, "computeNormals", "set to false to disable computation of triangles normal")) , d_useCurvature(initData(&d_useCurvature, false, "useCurvature", "use the curvature of the mesh to avoid some self-intersection test")) - , l_topology(initLink("topology", "link to the topology container")) - , m_mstate(nullptr) - , m_topology(nullptr) , m_needsUpdate(true) , m_topologyRevision(-1) , m_pointModels(nullptr) @@ -59,54 +57,35 @@ void TriangleCollisionModel::resize(sofa::Size size) template void TriangleCollisionModel::init() { - if (l_topology.empty()) - { - msg_info() << "link to Topology container should be set to ensure right behavior. First Topology found in current context will be used."; - l_topology.set(this->getContext()->getMeshTopologyLink()); - } - - m_topology = l_topology.get(); - msg_info() << "Topology path used: '" << l_topology.getLinkedPath() << "'"; - - if (!m_topology) - { - msg_error() << "No topology component found at path: " << l_topology.getLinkedPath() << ", nor in current context: " << this->getContext()->name << ". TriangleCollisionModel requires a Triangular Topology"; - sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - return; - } - - // TODO epernod 2019-01-21: Check if this call super is needed. this->CollisionModel::init(); - m_mstate = dynamic_cast< core::behavior::MechanicalState* > (this->getContext()->getMechanicalState()); - - this->getContext()->get(m_pointModels); - // Check object pointer access - bool modelsOk = true; - if (m_mstate == nullptr) + if (!this->isComponentStateInvalid()) { - msg_error() << "No MechanicalState found. TriangleCollisionModel requires a Vec3 MechanicalState in the same Node."; - modelsOk = false; + this->validateMState(); } - if (!modelsOk) + if (!this->isComponentStateInvalid()) { - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - return; + this->validateTopology(); } - // check if topology is using triangles and quads at the same time. - if (m_topology->getNbQuads() != 0) + if (!this->isComponentStateInvalid()) { - updateFromTopology(); // in this case, need to create a single buffer with both topology - // updateNormals will be call in updateFromTopology - } - else - { - // just redirect to the topology buffer. - m_triangles = &m_topology->getTriangles(); - resize(m_topology->getNbTriangles()); - updateNormals(); + this->getContext()->get(m_pointModels); + + // check if topology is using triangles and quads at the same time. + if (l_topology->getNbQuads() != 0) + { + updateFromTopology(); // in this case, need to create a single buffer with both topology + // updateNormals will be call in updateFromTopology + } + else + { + // just redirect to the topology buffer. + m_triangles = &l_topology->getTriangles(); + resize(l_topology->getNbTriangles()); + updateNormals(); + } } } @@ -128,24 +107,24 @@ void TriangleCollisionModel::updateNormals() template void TriangleCollisionModel::updateFromTopology() { - const int revision = m_topology->getRevision(); + const int revision = l_topology->getRevision(); if (revision == m_topologyRevision) return; m_topologyRevision = revision; - const sofa::Size nquads = m_topology->getNbQuads(); - const sofa::Size ntris = m_topology->getNbTriangles(); + const sofa::Size nquads = l_topology->getNbQuads(); + const sofa::Size ntris = l_topology->getNbTriangles(); if (nquads == 0) // only triangles { resize(ntris); - m_triangles = &m_topology->getTriangles(); + m_triangles = &l_topology->getTriangles(); } else { const sofa::Size newsize = ntris+2*nquads; - const sofa::Size npoints = m_mstate->getSize(); + const sofa::Size npoints = mstate->getSize(); m_triangles = &m_internalTriangles; m_internalTriangles.resize(newsize); @@ -154,7 +133,7 @@ void TriangleCollisionModel::updateFromTopology() sofa::Index index = 0; for (sofa::Index i=0; igetTriangle(i); + core::topology::BaseMeshTopology::Triangle idx = l_topology->getTriangle(i); if (idx[0] >= npoints || idx[1] >= npoints || idx[2] >= npoints) { msg_error() << "Vertex index out of range in triangle " << i << ": " << idx[0] << " " << idx[1] << " " << idx[2] << " ( total points=" << npoints << ")"; @@ -167,7 +146,7 @@ void TriangleCollisionModel::updateFromTopology() } for (sofa::Index i=0; igetQuad(i); + core::topology::BaseMeshTopology::Quad idx = l_topology->getQuad(i); if (idx[0] >= npoints || idx[1] >= npoints || idx[2] >= npoints || idx[3] >= npoints) { msg_error() << "Vertex index out of range in quad " << i << ": " << idx[0] << " " << idx[1] << " " << idx[2] << " " << idx[3] << " ( total points=" << npoints << ")"; @@ -219,7 +198,7 @@ void TriangleCollisionModel::computeBoundingTree(int maxDepth) CubeCollisionModel* cubeModel = createPrevious(); // check first that topology didn't changed - if (m_topology->getRevision() != m_topologyRevision) + if (l_topology->getRevision() != m_topologyRevision) updateFromTopology(); if (m_needsUpdate && !cubeModel->empty()) @@ -232,7 +211,7 @@ void TriangleCollisionModel::computeBoundingTree(int maxDepth) m_needsUpdate=false; type::Vec3 minElem, maxElem; - const VecCoord& x = this->m_mstate->read(core::vec_id::read_access::position)->getValue(); + const VecCoord& x = this->mstate->read(core::vec_id::read_access::position)->getValue(); const bool calcNormals = d_computeNormals.getValue(); @@ -281,7 +260,7 @@ void TriangleCollisionModel::computeContinuousBoundingTree(SReal dt, CubeCollisionModel* cubeModel = createPrevious(); // check first that topology didn't changed - if (m_topology->getRevision() != m_topologyRevision) + if (l_topology->getRevision() != m_topologyRevision) updateFromTopology(); if (m_needsUpdate) cubeModel->resize(0); @@ -343,22 +322,22 @@ int TriangleCollisionModel::getTriangleFlags(Topology::TriangleID i) int f = 0; sofa::core::topology::BaseMeshTopology::Triangle t = (*m_triangles)[i]; - if (i < m_topology->getNbTriangles()) + if (i < l_topology->getNbTriangles()) { for (sofa::Index j=0; j<3; ++j) { - const sofa::core::topology::BaseMeshTopology::TrianglesAroundVertex& tav = m_topology->getTrianglesAroundVertex(t[j]); + const sofa::core::topology::BaseMeshTopology::TrianglesAroundVertex& tav = l_topology->getTrianglesAroundVertex(t[j]); if (tav[0] == (sofa::core::topology::BaseMeshTopology::TriangleID)i) { f |= (FLAG_P1 << j); } } - const sofa::core::topology::BaseMeshTopology::EdgesInTriangle& e = m_topology->getEdgesInTriangle(i); + const sofa::core::topology::BaseMeshTopology::EdgesInTriangle& e = l_topology->getEdgesInTriangle(i); for (sofa::Index j=0; j<3; ++j) { - const sofa::core::topology::BaseMeshTopology::TrianglesAroundEdge& tae = m_topology->getTrianglesAroundEdge(e[j]); + const sofa::core::topology::BaseMeshTopology::TrianglesAroundEdge& tae = l_topology->getTrianglesAroundEdge(e[j]); if (tae[0] == (sofa::core::topology::BaseMeshTopology::TriangleID)i) f |= (FLAG_E23 << j); if (tae.size() == 1) @@ -381,10 +360,10 @@ void TriangleCollisionModel::computeBBox(const core::ExecParams* para return; // check first that topology didn't changed - if (m_topology->getRevision() != m_topologyRevision) + if (l_topology->getRevision() != m_topologyRevision) updateFromTopology(); - const auto& positions = this->m_mstate->read(core::vec_id::read_access::position)->getValue(); + const auto& positions = this->mstate->read(core::vec_id::read_access::position)->getValue(); type::BoundingBox bbox; for(const auto& triangle : (*this->m_triangles)) @@ -416,7 +395,7 @@ void TriangleCollisionModel::drawCollisionModel(const core::visual::V { // In case topology has changed but drawing is called before the updateFromTopology has been // computed, just exit to avoid computation in drawing thread. - if (m_topology->getRevision() != m_topologyRevision) return; + if (l_topology->getRevision() != m_topologyRevision) return; if (d_bothSide.getValue() || vparams->displayFlags().getShowWireFrame()) vparams->drawTool()->setPolygonMode(0, vparams->displayFlags().getShowWireFrame()); @@ -463,26 +442,26 @@ void TriangleCollisionModel::drawCollisionModel(const core::visual::V } template -inline const typename DataTypes::Coord& TTriangle::p1() const { return this->model->m_mstate->read(core::vec_id::read_access::position)->getValue()[(*(this->model->m_triangles))[this->index][0]]; } +inline const typename DataTypes::Coord& TTriangle::p1() const { return this->model->mstate->read(core::vec_id::read_access::position)->getValue()[(*(this->model->m_triangles))[this->index][0]]; } template -inline const typename DataTypes::Coord& TTriangle::p2() const { return this->model->m_mstate->read(core::vec_id::read_access::position)->getValue()[(*(this->model->m_triangles))[this->index][1]]; } +inline const typename DataTypes::Coord& TTriangle::p2() const { return this->model->mstate->read(core::vec_id::read_access::position)->getValue()[(*(this->model->m_triangles))[this->index][1]]; } template -inline const typename DataTypes::Coord& TTriangle::p3() const { return this->model->m_mstate->read(core::vec_id::read_access::position)->getValue()[(*(this->model->m_triangles))[this->index][2]]; } +inline const typename DataTypes::Coord& TTriangle::p3() const { return this->model->mstate->read(core::vec_id::read_access::position)->getValue()[(*(this->model->m_triangles))[this->index][2]]; } template inline const typename DataTypes::Coord& TTriangle::p(Index i) const { - return this->model->m_mstate->read(core::vec_id::read_access::position)->getValue()[(*(this->model->m_triangles))[this->index][i]]; + return this->model->mstate->read(core::vec_id::read_access::position)->getValue()[(*(this->model->m_triangles))[this->index][i]]; } template inline const typename DataTypes::Coord& TTriangle::operator[](Index i) const { - return this->model->m_mstate->read(core::vec_id::read_access::position)->getValue()[(*(this->model->m_triangles))[this->index][i]]; + return this->model->mstate->read(core::vec_id::read_access::position)->getValue()[(*(this->model->m_triangles))[this->index][i]]; } template -inline const typename DataTypes::Coord& TTriangle::p1Free() const { return (this->model->m_mstate->read(sofa::core::vec_id::read_access::freePosition)->getValue())[(*(this->model->m_triangles))[this->index][0]]; } +inline const typename DataTypes::Coord& TTriangle::p1Free() const { return (this->model->mstate->read(sofa::core::vec_id::read_access::freePosition)->getValue())[(*(this->model->m_triangles))[this->index][0]]; } template -inline const typename DataTypes::Coord& TTriangle::p2Free() const { return (this->model->m_mstate->read(sofa::core::vec_id::read_access::freePosition)->getValue())[((*this->model->m_triangles))[this->index][1]]; } +inline const typename DataTypes::Coord& TTriangle::p2Free() const { return (this->model->mstate->read(sofa::core::vec_id::read_access::freePosition)->getValue())[((*this->model->m_triangles))[this->index][1]]; } template -inline const typename DataTypes::Coord& TTriangle::p3Free() const { return (this->model->m_mstate->read(sofa::core::vec_id::read_access::freePosition)->getValue())[(*(this->model->m_triangles))[this->index][2]]; } +inline const typename DataTypes::Coord& TTriangle::p3Free() const { return (this->model->mstate->read(sofa::core::vec_id::read_access::freePosition)->getValue())[(*(this->model->m_triangles))[this->index][2]]; } template inline typename TTriangle::Index TTriangle::p1Index() const { return (*(this->model->m_triangles))[this->index][0]; } @@ -492,13 +471,13 @@ template inline typename TTriangle::Index TTriangle::p3Index() const { return (*(this->model->m_triangles))[this->index][2]; } template -inline const typename DataTypes::Deriv& TTriangle::v1() const { return (this->model->m_mstate->read(core::vec_id::read_access::velocity)->getValue())[(*(this->model->m_triangles))[this->index][0]]; } +inline const typename DataTypes::Deriv& TTriangle::v1() const { return (this->model->mstate->read(core::vec_id::read_access::velocity)->getValue())[(*(this->model->m_triangles))[this->index][0]]; } template -inline const typename DataTypes::Deriv& TTriangle::v2() const { return this->model->m_mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(this->model->m_triangles))[this->index][1]]; } +inline const typename DataTypes::Deriv& TTriangle::v2() const { return this->model->mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(this->model->m_triangles))[this->index][1]]; } template -inline const typename DataTypes::Deriv& TTriangle::v3() const { return this->model->m_mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(this->model->m_triangles))[this->index][2]]; } +inline const typename DataTypes::Deriv& TTriangle::v3() const { return this->model->mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(this->model->m_triangles))[this->index][2]]; } template -inline const typename DataTypes::Deriv& TTriangle::v(Index i) const { return this->model->m_mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(this->model->m_triangles))[this->index][i]]; } +inline const typename DataTypes::Deriv& TTriangle::v(Index i) const { return this->model->mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(this->model->m_triangles))[this->index][i]]; } template inline const typename DataTypes::Deriv& TTriangle::n() const { return this->model->m_normals[this->index]; } @@ -509,11 +488,11 @@ template inline int TTriangle::flags() const { return this->model->getTriangleFlags(this->index); } template -inline bool TTriangle::hasFreePosition() const { return this->model->m_mstate->read(core::vec_id::read_access::freePosition)->isSet(); } +inline bool TTriangle::hasFreePosition() const { return this->model->mstate->read(core::vec_id::read_access::freePosition)->isSet(); } template -inline typename DataTypes::Deriv TriangleCollisionModel::velocity(sofa::Index index) const { return (m_mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(m_triangles))[index][0]] + m_mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(m_triangles))[index][1]] + - m_mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(m_triangles))[index][2]])/((Real)(3.0)); } +inline typename DataTypes::Deriv TriangleCollisionModel::velocity(sofa::Index index) const { return (mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(m_triangles))[index][0]] + mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(m_triangles))[index][1]] + + mstate->read(core::vec_id::read_access::velocity)->getValue()[(*(m_triangles))[index][2]])/((Real)(3.0)); } } //namespace sofa::component::collision::geometry diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleModelInRegularGrid.cpp b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleModelInRegularGrid.cpp index 31912c20506..f60d7637476 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleModelInRegularGrid.cpp +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleModelInRegularGrid.cpp @@ -61,17 +61,16 @@ void TriangleModelInRegularGrid::init() TriangleCollisionModel::init(); _topology = this->getContext()->getMeshTopology(); - m_mstate = dynamic_cast< core::behavior::MechanicalState* > (getContext()->getMechanicalState()); - if (!m_mstate) { msg_error() << "TriangleModelInRegularGrid requires a Vec3 Mechanical Model"; return; } - if (!m_topology) { msg_error() << "TriangleModelInRegularGrid requires a BaseMeshTopology"; return; } + if (!mstate) { msg_error() << "TriangleModelInRegularGrid requires a Vec3 Mechanical Model"; return; } + if (!l_topology) { msg_error() << "TriangleModelInRegularGrid requires a BaseMeshTopology"; return; } // Test if _topology depend on an higher topology (to compute Bounding Tree faster) and get it TopologicalMapping* _topoMapping = nullptr; vector topoVec; getContext()->get ( &topoVec, core::objectmodel::BaseContext::SearchRoot ); - _higher_topo = m_topology; - _higher_mstate = m_mstate; + _higher_topo = l_topology; + _higher_mstate = mstate; bool found = true; while ( found ) { @@ -111,7 +110,7 @@ void TriangleModelInRegularGrid::computeBoundingTree ( int ) m_needsUpdate=false; Vec3 minElem, maxElem; const VecCoord& xHigh =_higher_mstate->read(core::vec_id::read_access::position)->getValue(); - const VecCoord& x =m_mstate->read(core::vec_id::read_access::position)->getValue(); + const VecCoord& x =mstate->read(core::vec_id::read_access::position)->getValue(); // no hierarchy if ( empty() ) diff --git a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleOctreeCollisionModel.cpp b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleOctreeCollisionModel.cpp index 62abb5bdc39..0c59f89b986 100644 --- a/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleOctreeCollisionModel.cpp +++ b/Sofa/Component/Collision/Geometry/src/sofa/component/collision/geometry/TriangleOctreeCollisionModel.cpp @@ -84,16 +84,16 @@ void TriangleOctreeCollisionModel::computeBoundingTree(int maxDepth) updateFromTopology(); if (!isMoving() && !cubeModel->empty()) return; // No need to recompute BBox if immobile - const std::size_t size2=m_mstate->getSize(); + const std::size_t size2=mstate->getSize(); pNorms.resize(size2); for(sofa::Size i=0; iread(core::vec_id::read_access::position)->getValue()[0][0]; - maxElem[1]=minElem[1]=m_mstate->read(core::vec_id::read_access::position)->getValue()[0][1]; - maxElem[2]=minElem[2]=m_mstate->read(core::vec_id::read_access::position)->getValue()[0][2]; + maxElem[0]=minElem[0]=mstate->read(core::vec_id::read_access::position)->getValue()[0][0]; + maxElem[1]=minElem[1]=mstate->read(core::vec_id::read_access::position)->getValue()[0][1]; + maxElem[2]=minElem[2]=mstate->read(core::vec_id::read_access::position)->getValue()[0][2]; cubeModel->resize(1); // size = number of triangles for (std::size_t i=1; i