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 @@ + + + + + + + + + + + + + + + + + + + + + + + +