diff --git a/Sofa/Component/Topology/Mapping/CMakeLists.txt b/Sofa/Component/Topology/Mapping/CMakeLists.txt
index f39826a9308..ce20badac38 100644
--- a/Sofa/Component/Topology/Mapping/CMakeLists.txt
+++ b/Sofa/Component/Topology/Mapping/CMakeLists.txt
@@ -8,6 +8,7 @@ set(HEADER_FILES
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/init.h
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/CenterPointTopologicalMapping.h
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/Edge2QuadTopologicalMapping.h
+ ${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/Hexa2PrismTopologicalMapping.h
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/Hexa2QuadTopologicalMapping.h
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/Hexa2TetraTopologicalMapping.h
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/IdentityTopologicalMapping.h
@@ -21,6 +22,7 @@ set(SOURCE_FILES
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/init.cpp
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/CenterPointTopologicalMapping.cpp
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/Edge2QuadTopologicalMapping.cpp
+ ${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/Hexa2PrismTopologicalMapping.cpp
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/Hexa2QuadTopologicalMapping.cpp
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/Hexa2TetraTopologicalMapping.cpp
${SOFACOMPONENTTOPOLOGYMAPPING_SOURCE_DIR}/IdentityTopologicalMapping.cpp
diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2PrismTopologicalMapping.cpp b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2PrismTopologicalMapping.cpp
new file mode 100644
index 00000000000..0211e3ab7bc
--- /dev/null
+++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2PrismTopologicalMapping.cpp
@@ -0,0 +1,122 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#include
+#include
+
+namespace sofa::component::topology::mapping
+{
+
+void registerHexa2PrismTopologicalMapping(sofa::core::ObjectFactory* factory)
+{
+ factory->registerObjects(core::ObjectRegistrationData("Topological mapping where HexahedronSetTopology is converted to PrismSetTopology")
+ .add< Hexa2PrismTopologicalMapping >());
+}
+
+Hexa2PrismTopologicalMapping::Hexa2PrismTopologicalMapping()
+{
+ m_inputType = geometry::ElementType::HEXAHEDRON;
+ m_outputType = geometry::ElementType::PRISM;
+}
+
+void Hexa2PrismTopologicalMapping::init()
+{
+ Inherit1::init();
+
+ if (toModel == nullptr)
+ {
+ msg_error() << "No target topology container found.";
+ this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid);
+ return;
+ }
+
+ convertHexaToPrisms();
+}
+
+void Hexa2PrismTopologicalMapping::convertHexaToPrisms()
+{
+ // Clear output topology
+ toModel->clear();
+
+ // Set the same number of points
+ toModel->setNbPoints(fromModel->getNbPoints());
+
+ auto Loc2GlobVec = sofa::helper::getWriteOnlyAccessor(Loc2GlobDataVec);
+ Loc2GlobVec.clear();
+ Glob2LocMap.clear();
+
+ const sofa::Size nbCubes = fromModel->getNbHexahedra();
+
+ static constexpr std::size_t numberPrismsInHexa = 2;
+ Loc2GlobVec.reserve(nbCubes * numberPrismsInHexa);
+
+ // Tessellation of each cube into 2 triangular prisms
+ // Hexahedron vertices:
+ // Y n3---------n2
+ // ^ / /|
+ // | / / |
+ // n7---------n6 |
+ // | | |
+ // | n0------|--n1
+ // | / | /
+ // |/ |/
+ // n4---------n5-->X
+ // /
+ // /
+ // Z
+ //
+ // Decomposition into 2 prisms:
+ // - Prism 1: vertices [0, 5, 1] (bottom triangle) and [3, 6, 2] (top triangle)
+ // - Prism 2: vertices [0, 4, 5] (bottom triangle) and [3, 7, 6] (top triangle)
+
+ for (size_t i = 0; i < nbCubes; ++i)
+ {
+ core::topology::BaseMeshTopology::Hexa c = fromModel->getHexahedron(i);
+
+ // Standard decomposition ensuring face consistency between neighbors
+ toModel->addPrism(c[0], c[5], c[1], c[3], c[6], c[2]); // Prism 1
+ toModel->addPrism(c[0], c[4], c[5], c[3], c[7], c[6]); // Prism 2
+
+ for (unsigned j = 0; j < numberPrismsInHexa; ++j)
+ {
+ Loc2GlobVec.push_back(i);
+ }
+ Glob2LocMap[i] = static_cast(Loc2GlobVec.size()) - 1;
+ }
+
+ // Need to fully init the target topology
+ toModel->init();
+
+ this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid);
+}
+
+Index Hexa2PrismTopologicalMapping::getFromIndex(Index /*ind*/)
+{
+ return sofa::InvalidID;
+}
+
+void Hexa2PrismTopologicalMapping::updateTopologicalMappingTopDown()
+{
+ msg_warning() << "Method Hexa2PrismTopologicalMapping::updateTopologicalMappingTopDown() not yet implemented!";
+ // TODO...
+}
+
+} // namespace sofa::component::topology::mapping
diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2PrismTopologicalMapping.h b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2PrismTopologicalMapping.h
new file mode 100644
index 00000000000..8956879df6b
--- /dev/null
+++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2PrismTopologicalMapping.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+* SOFA, Simulation Open-Framework Architecture *
+* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
+* *
+* This program is free software; you can redistribute it and/or modify it *
+* under the terms of the GNU Lesser General Public License as published by *
+* the Free Software Foundation; either version 2.1 of the License, or (at *
+* your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, but WITHOUT *
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
+* for more details. *
+* *
+* You should have received a copy of the GNU Lesser General Public License *
+* along with this program. If not, see . *
+*******************************************************************************
+* Authors: The SOFA Team and external contributors (see Authors.txt) *
+* *
+* Contact information: contact@sofa-framework.org *
+******************************************************************************/
+#pragma once
+
+#include
+#include
+
+namespace sofa::component::topology::mapping
+{
+
+class SOFA_COMPONENT_TOPOLOGY_MAPPING_API Hexa2PrismTopologicalMapping : public sofa::core::topology::TopologicalMapping
+{
+public:
+ SOFA_CLASS(Hexa2PrismTopologicalMapping, sofa::core::topology::TopologicalMapping);
+
+ virtual void init() override;
+ virtual Index getFromIndex(Index ind) override;
+ virtual void updateTopologicalMappingTopDown() override;
+
+protected:
+ Hexa2PrismTopologicalMapping();
+
+ void convertHexaToPrisms();
+};
+
+} // namespace sofa::component::topology::mapping
diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2TetraTopologicalMapping.cpp b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2TetraTopologicalMapping.cpp
index 28e13d64e9b..e42d04d76a0 100644
--- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2TetraTopologicalMapping.cpp
+++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/Hexa2TetraTopologicalMapping.cpp
@@ -68,34 +68,17 @@ void Hexa2TetraTopologicalMapping::init()
Inherit1::init();
- if (!this->checkTopologyInputTypes()) // method will display error message if false
+ if (toModel == nullptr)
{
- this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid);
- return;
- }
-
- TetrahedronSetTopologyModifier* to_tstm { nullptr };
- toModel->getContext()->get(to_tstm);
- if (!to_tstm)
- {
- msg_error() << "No TetrahedronSetTopologyModifier found in the Tetrahedron topology Node.";
+ msg_error() << "No target topology container found.";
this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid);
return;
}
// INITIALISATION of TETRAHEDRAL mesh from HEXAHEDRAL mesh :
- TetrahedronSetTopologyContainer *to_tstc { nullptr };
- toModel->getContext()->get(to_tstc);
- if (!to_tstc)
- {
- msg_error() << "No TetrahedronSetTopologyContainer found in the Tetrahedron topology Node.";
- this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid);
- return;
- }
-
// Clear output topology
- to_tstc->clear();
+ toModel->clear();
// Set the same number of points
toModel->setNbPoints(fromModel->getNbPoints());
@@ -165,21 +148,21 @@ void Hexa2TetraTopologicalMapping::init()
if(!swapped)
{
- to_tstc->addTetra(c[0],c[5],c[1],c[6]);
- to_tstc->addTetra(c[0],c[1],c[3],c[6]);
- to_tstc->addTetra(c[1],c[3],c[6],c[2]);
- to_tstc->addTetra(c[6],c[3],c[0],c[7]);
- to_tstc->addTetra(c[6],c[7],c[0],c[5]);
- to_tstc->addTetra(c[7],c[5],c[4],c[0]);
+ toModel->addTetra(c[0],c[5],c[1],c[6]);
+ toModel->addTetra(c[0],c[1],c[3],c[6]);
+ toModel->addTetra(c[1],c[3],c[6],c[2]);
+ toModel->addTetra(c[6],c[3],c[0],c[7]);
+ toModel->addTetra(c[6],c[7],c[0],c[5]);
+ toModel->addTetra(c[7],c[5],c[4],c[0]);
}
else
{
- to_tstc->addTetra(c[0],c[5],c[6],c[1]);
- to_tstc->addTetra(c[0],c[1],c[6],c[3]);
- to_tstc->addTetra(c[1],c[3],c[2],c[6]);
- to_tstc->addTetra(c[6],c[3],c[7],c[0]);
- to_tstc->addTetra(c[6],c[7],c[5],c[0]);
- to_tstc->addTetra(c[7],c[5],c[0],c[4]);
+ toModel->addTetra(c[0],c[5],c[6],c[1]);
+ toModel->addTetra(c[0],c[1],c[6],c[3]);
+ toModel->addTetra(c[1],c[3],c[2],c[6]);
+ toModel->addTetra(c[6],c[3],c[7],c[0]);
+ toModel->addTetra(c[6],c[7],c[5],c[0]);
+ toModel->addTetra(c[7],c[5],c[0],c[4]);
}
for (int j = 0; j < numberTetraInHexa; j++)
{
diff --git a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/init.cpp b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/init.cpp
index 7a520cdffd2..c8be6966b7d 100644
--- a/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/init.cpp
+++ b/Sofa/Component/Topology/Mapping/src/sofa/component/topology/mapping/init.cpp
@@ -28,6 +28,7 @@ namespace sofa::component::topology::mapping
extern void registerCenterPointTopologicalMapping(sofa::core::ObjectFactory* factory);
extern void registerEdge2QuadTopologicalMapping(sofa::core::ObjectFactory* factory);
+extern void registerHexa2PrismTopologicalMapping(sofa::core::ObjectFactory* factory);
extern void registerHexa2QuadTopologicalMapping(sofa::core::ObjectFactory* factory);
extern void registerHexa2TetraTopologicalMapping(sofa::core::ObjectFactory* factory);
extern void registerIdentityTopologicalMapping(sofa::core::ObjectFactory* factory);
@@ -62,6 +63,7 @@ void registerObjects(sofa::core::ObjectFactory* factory)
{
registerCenterPointTopologicalMapping(factory);
registerEdge2QuadTopologicalMapping(factory);
+ registerHexa2PrismTopologicalMapping(factory);
registerHexa2QuadTopologicalMapping(factory);
registerHexa2TetraTopologicalMapping(factory);
registerIdentityTopologicalMapping(factory);
diff --git a/Sofa/framework/Core/src/sofa/core/visual/DrawMesh.h b/Sofa/framework/Core/src/sofa/core/visual/DrawMesh.h
index cc1df95ff66..d08445b1fb4 100644
--- a/Sofa/framework/Core/src/sofa/core/visual/DrawMesh.h
+++ b/Sofa/framework/Core/src/sofa/core/visual/DrawMesh.h
@@ -361,6 +361,87 @@ struct SOFA_CORE_API DrawElementMesh
}
};
+template<>
+struct SOFA_CORE_API DrawElementMesh
+ : public BaseDrawMesh, 5>
+{
+ using ElementType = sofa::geometry::Prism;
+ friend BaseDrawMesh;
+ static constexpr std::size_t NumberTrianglesInPrism = 2;
+ static constexpr std::size_t NumberQuadsInPrism = 3;
+
+ static constexpr ColorContainer defaultColors {
+ sofa::type::RGBAColor::green(),
+ sofa::type::RGBAColor::teal(),
+ sofa::type::RGBAColor::navy(),
+ sofa::type::RGBAColor::gold(),
+ sofa::type::RGBAColor::purple()
+ };
+
+private:
+ template
+ void doDraw(
+ sofa::helper::visual::DrawTool* drawTool,
+ const PositionContainer& position,
+ sofa::core::topology::BaseMeshTopology* topology,
+ const IndicesContainer& elementIndices,
+ const ColorContainer& colors)
+ {
+ if (!topology)
+ return;
+
+ const auto& elements = topology->getPrisms();
+
+ // Allocate space for rendering points
+ renderedPoints[0].resize(elementIndices.size() * sofa::geometry::Triangle::NumberOfNodes);
+ renderedPoints[1].resize(elementIndices.size() * sofa::geometry::Triangle::NumberOfNodes);
+ renderedPoints[2].resize(elementIndices.size() * sofa::geometry::Quad::NumberOfNodes);
+ renderedPoints[3].resize(elementIndices.size() * sofa::geometry::Quad::NumberOfNodes);
+ renderedPoints[4].resize(elementIndices.size() * sofa::geometry::Quad::NumberOfNodes);
+
+ std::array renderedPointId {};
+
+ for (auto i : elementIndices)
+ {
+ const auto& prism = elements[i];
+ const auto center = this->elementCenter(position, prism);
+
+ const auto drawTriangle = [&](sofa::Index bufferId, sofa::Index v0, sofa::Index v1, sofa::Index v2)
+ {
+ const std::array vertexIndices { prism[v0], prism[v1], prism[v2] };
+ for (std::size_t k = 0; k < sofa::geometry::Triangle::NumberOfNodes; ++k)
+ {
+ const auto p = this->applyElementSpace(position[vertexIndices[k]], center);
+ renderedPoints[bufferId][renderedPointId[bufferId]++] = sofa::type::toVec3(p);
+ }
+ };
+
+ drawTriangle(0, 0, 1, 2);
+ drawTriangle(1, 5, 4, 3);
+
+ const auto drawQuad = [&](sofa::Index bufferId, sofa::Index v0, sofa::Index v1, sofa::Index v2, sofa::Index v3)
+ {
+ const std::array vertexIndices { prism[v0], prism[v1], prism[v2], prism[v3] };
+ for (std::size_t k = 0; k < sofa::geometry::Quad::NumberOfNodes; ++k)
+ {
+ const auto p = this->applyElementSpace(position[vertexIndices[k]], center);
+ renderedPoints[bufferId][renderedPointId[bufferId]++] = sofa::type::toVec3(p);
+ }
+ };
+
+ drawQuad(2, 0, 2, 5, 3);
+ drawQuad(3, 0, 3, 4, 1);
+ drawQuad(4, 1, 4, 5, 2);
+ }
+
+ drawTool->drawTriangles(renderedPoints[0], colors[0]);
+ drawTool->drawTriangles(renderedPoints[1], colors[1]);
+ drawTool->drawQuads(renderedPoints[2], colors[2]);
+ drawTool->drawQuads(renderedPoints[3], colors[3]);
+ drawTool->drawQuads(renderedPoints[4], colors[4]);
+ }
+};
+
template<>
struct SOFA_CORE_API DrawElementMesh
: public BaseDrawMesh, 6>
@@ -460,6 +541,7 @@ class SOFA_CORE_API DrawMesh
{
drawElements(drawTool, position, topology);
drawElements(drawTool, position, topology);
+ drawElements(drawTool, position, topology);
}
template
@@ -477,8 +559,9 @@ class SOFA_CORE_API DrawMesh
const auto hasTetra = !topology->getTetrahedra().empty();
const auto hasHexa = !topology->getHexahedra().empty();
+ const auto hasPrism = !topology->getPrisms().empty();
- const bool hasVolumeElements = hasTetra || hasHexa;
+ const bool hasVolumeElements = hasTetra || hasHexa || hasPrism;
if (!hasSurfaceElements && !hasVolumeElements)
{
@@ -503,7 +586,8 @@ class SOFA_CORE_API DrawMesh
DrawElementMesh,
DrawElementMesh,
DrawElementMesh,
- DrawElementMesh
+ DrawElementMesh,
+ DrawElementMesh
> m_meshes;
};
diff --git a/Sofa/framework/Geometry/src/sofa/geometry/Prism.h b/Sofa/framework/Geometry/src/sofa/geometry/Prism.h
index 0bdcdc48431..3dc55a7e5fb 100644
--- a/Sofa/framework/Geometry/src/sofa/geometry/Prism.h
+++ b/Sofa/framework/Geometry/src/sofa/geometry/Prism.h
@@ -33,6 +33,19 @@ struct Prism
static constexpr ElementType Element_type = ElementType::PRISM;
Prism() = delete;
+
+ // CONVENTION : indices ordering for the nodes of a prism :
+ //
+ // 5
+ // / | \
+ // / | \
+ // 3---+----4
+ // | | |
+ // | 2 |
+ // | / \ |
+ // |/ \|
+ // 0--------1
+ //
};
using Pentahedron SOFA_ATTRIBUTE_DEPRECATED("v25.12", "v26.06", "Pentahedron is renamed to Prism") = Prism;
diff --git a/examples/Component/SolidMechanics/FEM/TetrahedronHyperelasticityFEMForceField.scn b/examples/Component/SolidMechanics/FEM/TetrahedronHyperelasticityFEMForceField.scn
index 278dcc80140..fa3fdef7756 100644
--- a/examples/Component/SolidMechanics/FEM/TetrahedronHyperelasticityFEMForceField.scn
+++ b/examples/Component/SolidMechanics/FEM/TetrahedronHyperelasticityFEMForceField.scn
@@ -51,9 +51,7 @@
-
-
-
+
@@ -75,9 +73,7 @@
-
-
-
+
@@ -100,9 +96,7 @@
-
-
-
+
@@ -125,9 +119,7 @@
-
-
-
+
@@ -149,9 +141,7 @@
-
-
-
+
diff --git a/examples/Component/Topology/Mapping/Hexa2PrismTopologicalMapping.scn b/examples/Component/Topology/Mapping/Hexa2PrismTopologicalMapping.scn
new file mode 100644
index 00000000000..00196cbadc0
--- /dev/null
+++ b/examples/Component/Topology/Mapping/Hexa2PrismTopologicalMapping.scn
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+