From 013013abe269afb13094b5189e5c9f5e649b6a79 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Mon, 9 Feb 2026 13:52:50 +0100 Subject: [PATCH 1/5] replace class member raw pointer with link --- .../Tetra2TriangleTopologicalMapping.cpp | 32 +++++++++---------- .../Tetra2TriangleTopologicalMapping.h | 3 +- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp index 11f6ebbe178..693024441df 100644 --- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp +++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp @@ -53,10 +53,10 @@ void registerTetra2TriangleTopologicalMapping(sofa::core::ObjectFactory* factory Tetra2TriangleTopologicalMapping::Tetra2TriangleTopologicalMapping() : sofa::core::topology::TopologicalMapping() + , l_topologyModifier(initLink("modifier", "Optional link to a topology modifier")) , d_flipNormals(initData(&d_flipNormals, bool(false), "flipNormals", "Flip Normal ? (Inverse point order when creating triangle)")) , d_noNewTriangles(initData(&d_noNewTriangles, bool(false), "noNewTriangles", "If true no new triangles are being created")) , d_noInitialTriangles(initData(&d_noInitialTriangles, bool(false), "noInitialTriangles", "If true the list of initial triangles is initially empty. Only additional triangles will be added in the list")) - , m_outTopoModifier(nullptr) { m_inputType = geometry::ElementType::TETRAHEDRON; m_outputType = geometry::ElementType::TRIANGLE; @@ -64,24 +64,24 @@ Tetra2TriangleTopologicalMapping::Tetra2TriangleTopologicalMapping() void Tetra2TriangleTopologicalMapping::init() { + sofa::core::topology::TopologicalMapping::init(); + if (!this->checkTopologyInputTypes()) // method will display error message if false { this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); return; } - container::dynamic::TriangleSetTopologyModifier* to_tstm; - toModel->getContext()->get(to_tstm); - if (!to_tstm) + l_topologyModifier.set(toModel->getContext()->get( + core::objectmodel::BaseContext::SearchDirection::SearchUp)); + + if (!l_topologyModifier) { msg_error() << "No TriangleSetTopologyModifier found in the output topology node '" << toModel->getContext()->getName() << "'."; this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); return; } - else { - m_outTopoModifier = to_tstm; - } // INITIALISATION of Triangle mesh from Tetrahedral mesh : @@ -162,7 +162,7 @@ void Tetra2TriangleTopologicalMapping::updateTopologicalMappingTopDown() case core::topology::ENDING_EVENT: { - m_outTopoModifier->notifyEndingEvent(); + l_topologyModifier->notifyEndingEvent(); break; } @@ -227,7 +227,7 @@ void Tetra2TriangleTopologicalMapping::updateTopologicalMappingTopDown() Loc2GlobVec.pop_back(); //pop last } - m_outTopoModifier->removeTriangles(triangles_to_remove, true, false); + l_topologyModifier->removeTriangles(triangles_to_remove, true, false); break; } @@ -279,7 +279,7 @@ void Tetra2TriangleTopologicalMapping::updateTopologicalMappingTopDown() } // add new elements to output topology - m_outTopoModifier->addTriangles(triangles_to_create); + l_topologyModifier->addTriangles(triangles_to_create); // remove elements not anymore on part of the border sofa::type::vector< BaseMeshTopology::TriangleID > local_triangleId_to_remove; @@ -312,7 +312,7 @@ void Tetra2TriangleTopologicalMapping::updateTopologicalMappingTopDown() } // remove old triangles - m_outTopoModifier->removeTriangles(local_triangleId_to_remove, true, false); + l_topologyModifier->removeTriangles(local_triangleId_to_remove, true, false); break; } case core::topology::TETRAHEDRAREMOVED: @@ -404,21 +404,21 @@ void Tetra2TriangleTopologicalMapping::updateTopologicalMappingTopDown() } } - m_outTopoModifier->addTriangles(triangles_to_create); + l_topologyModifier->addTriangles(triangles_to_create); break; } case core::topology::EDGESADDED: { const auto* edgeAdded = static_cast(*itBegin); - m_outTopoModifier->addEdges(edgeAdded->edgeArray, edgeAdded->ancestorsList, edgeAdded->coefs); + l_topologyModifier->addEdges(edgeAdded->edgeArray, edgeAdded->ancestorsList, edgeAdded->coefs); break; } case core::topology::POINTSADDED: { const auto* pointAdded = static_cast(*itBegin); - m_outTopoModifier->addPoints(sofa::Size(pointAdded->getNbAddedVertices()), pointAdded->ancestorsList, pointAdded->coefs, true); + l_topologyModifier->addPoints(sofa::Size(pointAdded->getNbAddedVertices()), pointAdded->ancestorsList, pointAdded->coefs, true); break; } @@ -436,7 +436,7 @@ void Tetra2TriangleTopologicalMapping::updateTopologicalMappingTopDown() Topology::SetIndices & tab_indices = indices; - m_outTopoModifier->removePoints(tab_indices, false); + l_topologyModifier->removePoints(tab_indices, false); break; } @@ -458,7 +458,7 @@ void Tetra2TriangleTopologicalMapping::updateTopologicalMappingTopDown() Topology::SetIndices & tab_indices = indices; Topology::SetIndices & inv_tab_indices = inv_indices; - m_outTopoModifier->renumberPoints(tab_indices, inv_tab_indices, false); + l_topologyModifier->renumberPoints(tab_indices, inv_tab_indices, false); break; } default: diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.h b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.h index e4b0f935cb8..976322f52fd 100644 --- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.h +++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.h @@ -80,12 +80,13 @@ class SOFA_COMPONENT_TOPOLOGY_MAPPING_API Tetra2TriangleTopologicalMapping : pub /// Method to check the topology mapping maps regarding the upper topology bool checkTopologies() override; + SingleLink l_topologyModifier; + protected: Data d_flipNormals; ///< Flip Normal ? (Inverse point order when creating triangle) Data d_noNewTriangles; ///< If true no new triangles are being created Data d_noInitialTriangles; ///< If true the list of initial triangles is initially empty. Only additional triangles will be added in the list sofa::type::vector addedTriangleIndex; - container::dynamic::TriangleSetTopologyModifier* m_outTopoModifier; ///< Pointer to the output topology modifier }; } //namespace sofa::component::topology::mapping From abb89a7669e421ae625db3659c431c6d60f5cd86 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Mon, 9 Feb 2026 15:13:27 +0100 Subject: [PATCH 2/5] Refactor `TopologicalMapping`: split `checkTopologyInputTypes` into dedicated helper methods --- .../sofa/core/topology/TopologicalMapping.cpp | 27 +++++++++++++++++-- .../sofa/core/topology/TopologicalMapping.h | 5 ++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Sofa/framework/Core/src/sofa/core/topology/TopologicalMapping.cpp b/Sofa/framework/Core/src/sofa/core/topology/TopologicalMapping.cpp index 72fb7de7b00..d46a347a7c1 100644 --- a/Sofa/framework/Core/src/sofa/core/topology/TopologicalMapping.cpp +++ b/Sofa/framework/Core/src/sofa/core/topology/TopologicalMapping.cpp @@ -81,21 +81,39 @@ void TopologicalMapping::dumpLoc2GlobVec() bool TopologicalMapping::checkTopologyInputTypes() +{ + bool res = checkMappingInputType(); + res = res && checkMappingOutputType(); + + res = res && compareInputTopologyType(); + res = res && compareOutputTopologyType(); + + return res; +} + +bool TopologicalMapping::checkMappingInputType() const { if (m_inputType == geometry::ElementType::UNKNOWN) { dmsg_error() << "The input ElementType has not been set. Define 'm_inputType' to the correct ElementType in the constructor."; return false; } + return true; +} +bool TopologicalMapping::checkMappingOutputType() const +{ if (m_outputType == geometry::ElementType::UNKNOWN) { dmsg_error() << "The output ElementType has not been set. Define 'm_outputType' to the correct ElementType in the constructor."; return false; } + return true; +} +bool TopologicalMapping::compareInputTopologyType() const +{ assert(fromModel.get()); - assert(toModel.get()); const ElementType inputTopologyType = fromModel->getTopologyType(); if (inputTopologyType != m_inputType) @@ -103,6 +121,12 @@ bool TopologicalMapping::checkTopologyInputTypes() msg_error() << "The type of the input topology '" << fromModel.getPath() << "' (" << elementTypeToString(inputTopologyType) << ") does not correspond to a valid '" << elementTypeToString(m_inputType) << "' topology."; return false; } + return true; +} + +bool TopologicalMapping::compareOutputTopologyType() const +{ + assert(toModel.get()); const ElementType outputTopologyType = toModel->getTopologyType(); if (outputTopologyType != m_outputType) @@ -110,7 +134,6 @@ bool TopologicalMapping::checkTopologyInputTypes() msg_error() << "The type of the output topology '" << toModel.getPath() << "' (" << elementTypeToString(outputTopologyType) << ") does not correspond to a valid '" << elementTypeToString(m_outputType) << "' topology."; return false; } - return true; } diff --git a/Sofa/framework/Core/src/sofa/core/topology/TopologicalMapping.h b/Sofa/framework/Core/src/sofa/core/topology/TopologicalMapping.h index b64096f1b01..3ec6f29fbf2 100644 --- a/Sofa/framework/Core/src/sofa/core/topology/TopologicalMapping.h +++ b/Sofa/framework/Core/src/sofa/core/topology/TopologicalMapping.h @@ -191,6 +191,11 @@ class SOFA_CORE_API TopologicalMapping : public virtual objectmodel::BaseObject protected: [[nodiscard]] bool checkTopologyInputTypes(); + [[nodiscard]] bool checkMappingInputType() const; + [[nodiscard]] bool checkMappingOutputType() const; + [[nodiscard]] bool compareInputTopologyType() const; + [[nodiscard]] bool compareOutputTopologyType() const; + public: /// Input source BaseTopology From f620fe9015a4afa6dc4b1fc5ce7426d944c26bcf Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Mon, 9 Feb 2026 15:15:01 +0100 Subject: [PATCH 3/5] mapping input and output is checked but not compared to the topology. This is to support MeshTopology which has a not well defined type. --- .../topology/mapping/Tetra2TriangleTopologicalMapping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp index 693024441df..d5928a8c56b 100644 --- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp +++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp @@ -66,7 +66,7 @@ void Tetra2TriangleTopologicalMapping::init() { sofa::core::topology::TopologicalMapping::init(); - if (!this->checkTopologyInputTypes()) // method will display error message if false + if (!this->checkMappingInputType() || !this->checkMappingOutputType()) { this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); return; From ac00ecd92951d5245a6ec58e0657472e71d8c710 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Mon, 9 Feb 2026 15:24:59 +0100 Subject: [PATCH 4/5] better support of topology modifier --- .../Tetra2TriangleTopologicalMapping.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp index d5928a8c56b..7ac73fe24d9 100644 --- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp +++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp @@ -72,15 +72,21 @@ void Tetra2TriangleTopologicalMapping::init() return; } - l_topologyModifier.set(toModel->getContext()->get( - core::objectmodel::BaseContext::SearchDirection::SearchUp)); + if (!l_topologyModifier) + { + msg_info() << "Looking for a component of type TriangleSetTopologyModifier " + "in the output topology context (" + << toModel->getContext()->getName() <<")."; + + l_topologyModifier.set(toModel->getContext()->get( + core::objectmodel::BaseContext::SearchDirection::SearchUp)); + } if (!l_topologyModifier) { - msg_error() << "No TriangleSetTopologyModifier found in the output topology node '" - << toModel->getContext()->getName() << "'."; - this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); - return; + msg_warning() << "No TriangleSetTopologyModifier found in output topology context (" + << toModel->getContext()->getName() << ") but has not been found. Dynamic " + "topological changes will not be supported."; } From c02c6dc625986bd70023c40a6da338201e304ad5 Mon Sep 17 00:00:00 2001 From: Alex Bilger Date: Mon, 9 Feb 2026 15:32:58 +0100 Subject: [PATCH 5/5] check for a valid topology modifier before updating the topology --- .../topology/mapping/Tetra2TriangleTopologicalMapping.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp index 7ac73fe24d9..a35827f6d7b 100644 --- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp +++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Tetra2TriangleTopologicalMapping.cpp @@ -150,6 +150,9 @@ void Tetra2TriangleTopologicalMapping::updateTopologicalMappingTopDown() if (this->d_componentState.getValue() != sofa::core::objectmodel::ComponentState::Valid) return; + if (!l_topologyModifier) + return; + SCOPED_TIMER("Update Tetra2TriangleTopologicalMapping"); auto itBegin=fromModel->beginChange(); @@ -473,7 +476,7 @@ void Tetra2TriangleTopologicalMapping::updateTopologicalMappingTopDown() }; ++itBegin; - } + } }