diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.h index 770ea885bd2..b69b3e00f00 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.h @@ -25,11 +25,12 @@ #include #include #include -#include -#include -#include +#include #include +#include +#include #include +#include namespace sofa::component::solidmechanics::fem::elastic { @@ -177,6 +178,8 @@ protected : typedef FastTetrahedralCorotationalForceFieldData ExtraData; ExtraData m_data; + + core::visual::DrawElementMesh m_drawMesh; }; #if !defined(SOFA_COMPONENT_INTERACTIONFORCEFIELD_FASTTETRAHEDRALCOROTATIONALFORCEFIELD_CPP) diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.inl b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.inl index 434e54e7261..f498d5d9ecc 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.inl +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/FastTetrahedralCorotationalForceField.inl @@ -672,50 +672,7 @@ void FastTetrahedralCorotationalForceField::draw(const core::visual:: if (vparams->displayFlags().getShowWireFrame()) vparams->drawTool()->setPolygonMode(0, true); - - std::vector< type::Vec3 > points[4]; - for (size_t i = 0; il_topology->getNbTetrahedra(); ++i) - { - const core::topology::BaseMeshTopology::Tetrahedron t = this->l_topology->getTetrahedron(i); - - const auto& [a, b, c, d] = t.array(); - Coord center = (x[a] + x[b] + x[c] + x[d])*0.125; - Coord pa = (x[a] + center)*(Real)0.666667; - Coord pb = (x[b] + center)*(Real)0.666667; - Coord pc = (x[c] + center)*(Real)0.666667; - Coord pd = (x[d] + center)*(Real)0.666667; - - // glColor4f(0,0,1,1); - points[0].push_back(pa); - points[0].push_back(pb); - points[0].push_back(pc); - - // glColor4f(0,0.5,1,1); - points[1].push_back(pb); - points[1].push_back(pc); - points[1].push_back(pd); - - // glColor4f(0,1,1,1); - points[2].push_back(pc); - points[2].push_back(pd); - points[2].push_back(pa); - - // glColor4f(0.5,1,1,1); - points[3].push_back(pd); - points[3].push_back(pa); - points[3].push_back(pb); - } - - vparams->drawTool()->drawTriangles(points[0], d_drawColor1.getValue()); - vparams->drawTool()->drawTriangles(points[1], d_drawColor2.getValue()); - vparams->drawTool()->drawTriangles(points[2], d_drawColor3.getValue()); - vparams->drawTool()->drawTriangles(points[3], d_drawColor4.getValue()); - - if (vparams->displayFlags().getShowWireFrame()) - vparams->drawTool()->setPolygonMode(0, false); - - - + m_drawMesh.drawAllElements(vparams->drawTool(), x, this->l_topology.get()); } } // namespace sofa::component::solidmechanics::fem::elastic diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.h index 27af165194a..88902931200 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.h @@ -20,15 +20,13 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #pragma once -#include - #include - -#include -#include -#include - +#include #include +#include +#include +#include +#include namespace sofa::component::solidmechanics::fem::elastic { @@ -198,6 +196,8 @@ class HexahedralFEMForceField : virtual public BaseLinearElasticityFEMForceField protected: type::Mat<8,3,int> _coef; ///< coef of each vertices to compute the strain stress matrix + + core::visual::DrawElementMesh m_drawMesh; }; #if !defined(SOFA_COMPONENT_FORCEFIELD_HEXAHEDRALFEMFORCEFIELD_CPP) diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.inl b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.inl index 949d5421c4f..cfe1019acd8 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.inl +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedralFEMForceField.inl @@ -659,9 +659,6 @@ void HexahedralFEMForceField::draw(const core::visual::VisualParams* if (!this->mstate) return; const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); - vparams->drawTool()->disableLighting(); - std::vector colorVector; - std::vector vertices; const VecCoord& x = this->mstate->read(core::vec_id::read_access::position)->getValue(); @@ -670,92 +667,7 @@ void HexahedralFEMForceField::draw(const core::visual::VisualParams* vparams->drawTool()->setPolygonMode(0, true); } - for(size_t i = 0 ; il_topology->getNbHexahedra(); ++i) - { - const core::topology::BaseMeshTopology::Hexahedron &t=this->l_topology->getHexahedron(i); - - Index a = t[0]; - Index b = t[1]; - Index d = t[2]; - Index c = t[3]; - Index e = t[4]; - Index f = t[5]; - Index h = t[6]; - Index g = t[7]; - - Coord center = (x[a]+x[b]+x[c]+x[d]+x[e]+x[g]+x[f]+x[h])*0.125; - Real percentage = (Real) 0.15; - Coord p0 = x[a]-(x[a]-center)*percentage; - Coord p1 = x[b]-(x[b]-center)*percentage; - Coord p2 = x[c]-(x[c]-center)*percentage; - Coord p3 = x[d]-(x[d]-center)*percentage; - Coord p4 = x[e]-(x[e]-center)*percentage; - Coord p5 = x[f]-(x[f]-center)*percentage; - Coord p6 = x[g]-(x[g]-center)*percentage; - Coord p7 = x[h]-(x[h]-center)*percentage; - - constexpr sofa::type::RGBAColor color1(0.7f, 0.7f, 0.1f, 1.0f); - colorVector.push_back(color1); - colorVector.push_back(color1); - colorVector.push_back(color1); - colorVector.push_back(color1); - vertices.push_back(DataTypes::getCPos(p5)); - vertices.push_back(DataTypes::getCPos(p1)); - vertices.push_back(DataTypes::getCPos(p3)); - vertices.push_back(DataTypes::getCPos(p7)); - - constexpr sofa::type::RGBAColor color2(0.7f, 0.0f, 0.0f, 1.0f); - colorVector.push_back(color2); - colorVector.push_back(color2); - colorVector.push_back(color2); - colorVector.push_back(color2); - vertices.push_back(DataTypes::getCPos(p1)); - vertices.push_back(DataTypes::getCPos(p0)); - vertices.push_back(DataTypes::getCPos(p2)); - vertices.push_back(DataTypes::getCPos(p3)); - - constexpr sofa::type::RGBAColor color3(0.0f, 0.7f, 0.0f, 1.0f); - colorVector.push_back(color3); - colorVector.push_back(color3); - colorVector.push_back(color3); - colorVector.push_back(color3); - vertices.push_back(DataTypes::getCPos(p0)); - vertices.push_back(DataTypes::getCPos(p4)); - vertices.push_back(DataTypes::getCPos(p6)); - vertices.push_back(DataTypes::getCPos(p2)); - - constexpr sofa::type::RGBAColor color4(0.0f, 0.0f, 0.7f, 1.0f); - colorVector.push_back(color4); - colorVector.push_back(color4); - colorVector.push_back(color4); - colorVector.push_back(color4); - vertices.push_back(DataTypes::getCPos(p4)); - vertices.push_back(DataTypes::getCPos(p5)); - vertices.push_back(DataTypes::getCPos(p7)); - vertices.push_back(DataTypes::getCPos(p6)); - - constexpr sofa::type::RGBAColor color5(0.1f, 0.7f, 0.7f, 1.0f); - colorVector.push_back(color5); - colorVector.push_back(color5); - colorVector.push_back(color5); - colorVector.push_back(color5); - vertices.push_back(DataTypes::getCPos(p7)); - vertices.push_back(DataTypes::getCPos(p3)); - vertices.push_back(DataTypes::getCPos(p2)); - vertices.push_back(DataTypes::getCPos(p6)); - - constexpr sofa::type::RGBAColor color6(0.1f, 0.7f, 0.7f, 1.0f); - colorVector.push_back(color6); - colorVector.push_back(color6); - colorVector.push_back(color6); - colorVector.push_back(color6); - vertices.push_back(DataTypes::getCPos(p1)); - vertices.push_back(DataTypes::getCPos(p5)); - vertices.push_back(DataTypes::getCPos(p4)); - vertices.push_back(DataTypes::getCPos(p0)); - } - vparams->drawTool()->drawQuads(vertices,colorVector); - + m_drawMesh.drawAllElements(vparams->drawTool(), x, this->l_topology.get()); } } // namespace sofa::component::solidmechanics::fem::elastic diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.h index 81171ce7709..bf5cd2251dc 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.h @@ -20,17 +20,17 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #pragma once -#include - #include -#include +#include #include -#include -#include -#include #include -#include +#include +#include +#include #include +#include +#include +#include namespace sofa::component::solidmechanics::fem::elastic { @@ -222,6 +222,8 @@ class HexahedronFEMForceField : virtual void accumulateForceSmall( WDataRefVecDeriv &f, RDataRefVecCoord &p, sofa::Index i, const Element&elem ); bool _alreadyInit; + + core::visual::DrawElementMesh m_drawMesh; }; #if !defined(SOFA_COMPONENT_FORCEFIELD_HEXAHEDRONFEMFORCEFIELD_CPP) diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.inl b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.inl index af0cb62553b..6d94c939400 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.inl +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/HexahedronFEMForceField.inl @@ -1212,8 +1212,6 @@ void HexahedronFEMForceField::draw(const core::visual::VisualParams* const VecCoord& x = this->mstate->read(core::vec_id::read_access::position)->getValue(); - vparams->drawTool()->setLightingEnabled(false); - if(_sparseGrid ) { vparams->drawTool()->enableBlending(); @@ -1222,104 +1220,8 @@ void HexahedronFEMForceField::draw(const core::visual::VisualParams* if (vparams->displayFlags().getShowWireFrame()) vparams->drawTool()->setPolygonMode(0,true); - const Real percentage = d_drawPercentageOffset.getValue(); - const Real oneMinusPercentage = static_cast(1) - percentage; - - const auto* indexedElements = this->getIndexedElements(); - - sofa::type::fixed_array, 6 > quads; //one list of quads per hexahedron face - sofa::type::fixed_array, 6> colors; //one list of quads per hexahedron face - - for (auto& q : quads) - { - q.reserve(indexedElements->size() * 4); - } - for (auto& c : colors) - { - c.reserve(indexedElements->size() * 4); - } - - sofa::Index i {}; - for (const auto& element : *indexedElements) - { - const Coord& a = x[element[0]]; - const Coord& b = x[element[1]]; - const Coord& c = x[element[2]]; - const Coord& d = x[element[3]]; - const Coord& e = x[element[4]]; - const Coord& f = x[element[5]]; - const Coord& g = x[element[6]]; - const Coord& h = x[element[7]]; - - const Coord center = (a + b + c + d + e + f + g + h ) * static_cast(0.125); - const Coord centerPercent = center * percentage; - - const Coord pa = a * oneMinusPercentage + centerPercent; - const Coord pb = b * oneMinusPercentage + centerPercent; - const Coord pc = c * oneMinusPercentage + centerPercent; - const Coord pd = d * oneMinusPercentage + centerPercent; - const Coord pe = e * oneMinusPercentage + centerPercent; - const Coord pf = f * oneMinusPercentage + centerPercent; - const Coord pg = g * oneMinusPercentage + centerPercent; - const Coord ph = h * oneMinusPercentage + centerPercent; - - quads[0].emplace_back(pa); - quads[0].emplace_back(pb); - quads[0].emplace_back(pc); - quads[0].emplace_back(pd); - - quads[1].emplace_back(pe); - quads[1].emplace_back(pf); - quads[1].emplace_back(pg); - quads[1].emplace_back(ph); - - quads[2].emplace_back(pc); - quads[2].emplace_back(pd); - quads[2].emplace_back(ph); - quads[2].emplace_back(pg); - - quads[3].emplace_back(pa); - quads[3].emplace_back(pb); - quads[3].emplace_back(pf); - quads[3].emplace_back(pe); - - quads[4].emplace_back(pa); - quads[4].emplace_back(pd); - quads[4].emplace_back(ph); - quads[4].emplace_back(pe); - - quads[5].emplace_back(pb); - quads[5].emplace_back(pc); - quads[5].emplace_back(pg); - quads[5].emplace_back(pf); - - const float stiffnessCoef = _sparseGrid ? _sparseGrid->getStiffnessCoef(i) : 1.0f; - sofa::type::fixed_array quadColors { - sofa::type::RGBAColor(0.7f,0.7f,0.1f,stiffnessCoef), - sofa::type::RGBAColor(0.7f,0.0f,0.0f,stiffnessCoef), - sofa::type::RGBAColor(0.0f,0.7f,0.0f,stiffnessCoef), - sofa::type::RGBAColor(0.0f,0.0f,0.7f,stiffnessCoef), - sofa::type::RGBAColor(0.1f,0.7f,0.7f,stiffnessCoef), - sofa::type::RGBAColor(0.7f,0.1f,0.7f,stiffnessCoef) - }; - - for (unsigned int j = 0; j < 6; ++j) - { - auto& faceColors = colors[j]; - const auto& color = quadColors[j]; - for (unsigned int k = 0; k < 4; ++k) - { - faceColors.emplace_back(color); - } - } - - ++i; - } - - for (unsigned int j = 0; j < 6; ++j) - { - vparams->drawTool()->drawQuads(quads[j], colors[j]); - } + m_drawMesh.elementSpace = d_drawPercentageOffset.getValue(); + m_drawMesh.drawAllElements(vparams->drawTool(), x, this->l_topology.get()); } diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.h index bb48014af31..d5116e2f8ea 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.h @@ -22,14 +22,14 @@ #pragma once #include #include - #include #include -#include -#include -#include -#include +#include #include +#include +#include +#include +#include // corotational tetrahedron from // @InProceedings{NPF05, @@ -250,6 +250,8 @@ class TetrahedralCorotationalFEMForceField : public BaseLinearElasticityFEMForce void printStiffnessMatrix(int idTetra); + core::visual::DrawElementMesh m_drawMesh; + }; #if !defined(SOFA_COMPONENT_FORCEFIELD_TETRAHEDRALCOROTATIONALFEMFORCEFIELD_CPP) diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.inl b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.inl index a574c00230a..680b6709850 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.inl +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TetrahedralCorotationalFEMForceField.inl @@ -1353,49 +1353,13 @@ void TetrahedralCorotationalFEMForceField::draw(const core::visual::V if (d_drawing.getValue()) { - const sofa::Size nbrTetra = this->l_topology->getNbTetrahedra(); - std::vector< type::Vec3 > points[4]; - points[0].reserve(nbrTetra * 3); - points[1].reserve(nbrTetra * 3); - points[2].reserve(nbrTetra * 3); - points[3].reserve(nbrTetra * 3); - - for(Size i = 0 ; i< nbrTetra; ++i) - { - const core::topology::BaseMeshTopology::Tetrahedron t=this->l_topology->getTetrahedron(i); - - const auto& [a, b, c, d] = t.array(); - Coord center = (x[a] + x[b] + x[c] + x[d]) * 0.125; - Coord pa = (x[a] + center) * (Real)0.666667; - Coord pb = (x[b] + center) * (Real)0.666667; - Coord pc = (x[c] + center) * (Real)0.666667; - Coord pd = (x[d] + center) * (Real)0.666667; - - points[0].push_back(pa); - points[0].push_back(pb); - points[0].push_back(pc); - - points[1].push_back(pb); - points[1].push_back(pc); - points[1].push_back(pd); - - points[2].push_back(pc); - points[2].push_back(pd); - points[2].push_back(pa); - - points[3].push_back(pd); - points[3].push_back(pa); - points[3].push_back(pb); - } - - vparams->drawTool()->drawTriangles(points[0], d_drawColor1.getValue()); - vparams->drawTool()->drawTriangles(points[1], d_drawColor2.getValue()); - vparams->drawTool()->drawTriangles(points[2], d_drawColor3.getValue()); - vparams->drawTool()->drawTriangles(points[3], d_drawColor4.getValue()); + std::array colors { + d_drawColor1.getValue(), + d_drawColor2.getValue(), + d_drawColor3.getValue(), + d_drawColor4.getValue()}; + m_drawMesh.drawAllElements(vparams->drawTool(), x, this->l_topology.get(), colors); } - - if (vparams->displayFlags().getShowWireFrame()) - vparams->drawTool()->setPolygonMode(0,false); } diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.h b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.h index b17f79a837b..b7a64ba2234 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.h +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.h @@ -21,12 +21,12 @@ ******************************************************************************/ #pragma once -#include -#include #include - -#include +#include +#include +#include #include +#include // corotational triangle from // @InProceedings{NPF05, @@ -156,6 +156,8 @@ class TriangleFEMForceField : public BaseLinearElasticityFEMForceField m_triangleUtils; + + core::visual::DrawElementMesh m_drawMesh; }; diff --git a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.inl b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.inl index 3348ff01e90..6ddcda0fb9f 100644 --- a/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.inl +++ b/Sofa/Component/SolidMechanics/FEM/Elastic/src/sofa/component/solidmechanics/fem/elastic/TriangleFEMForceField.inl @@ -546,31 +546,13 @@ void TriangleFEMForceField::draw(const core::visual::VisualParams* vp return; const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle(); - vparams->drawTool()->disableLighting(); if (vparams->displayFlags().getShowWireFrame()) vparams->drawTool()->setPolygonMode(0, true); - std::vector colorVector; - std::vector vertices; - const VecCoord& x = this->mstate->read(core::vec_id::read_access::position)->getValue(); - typename VecElement::const_iterator it; - for (it = _indexedElements->begin(); it != _indexedElements->end(); ++it) - { - const auto& [a, b, c] = it->array(); - - colorVector.push_back(sofa::type::RGBAColor::green()); - vertices.push_back(sofa::type::Vec3(x[a])); - colorVector.push_back(sofa::type::RGBAColor(0, 0.5, 0.5, 1)); - vertices.push_back(sofa::type::Vec3(x[b])); - colorVector.push_back(sofa::type::RGBAColor(0, 0, 1, 1)); - vertices.push_back(sofa::type::Vec3(x[c])); - } - vparams->drawTool()->drawTriangles(vertices, colorVector); - - + m_drawMesh.drawAllElements(vparams->drawTool(), x, this->l_topology.get()); } diff --git a/Sofa/Component/SolidMechanics/FEM/HyperElastic/src/sofa/component/solidmechanics/fem/hyperelastic/TetrahedronHyperelasticityFEMDrawing.h b/Sofa/Component/SolidMechanics/FEM/HyperElastic/src/sofa/component/solidmechanics/fem/hyperelastic/TetrahedronHyperelasticityFEMDrawing.h index a411b930afa..cc2b7c647b2 100644 --- a/Sofa/Component/SolidMechanics/FEM/HyperElastic/src/sofa/component/solidmechanics/fem/hyperelastic/TetrahedronHyperelasticityFEMDrawing.h +++ b/Sofa/Component/SolidMechanics/FEM/HyperElastic/src/sofa/component/solidmechanics/fem/hyperelastic/TetrahedronHyperelasticityFEMDrawing.h @@ -20,19 +20,17 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #pragma once -#include - -#include -#include - #include -#include -#include -#include -#include #include +#include +#include #include - +#include +#include +#include +#include +#include +#include namespace sofa::component::solidmechanics::fem::hyperelastic { @@ -42,116 +40,74 @@ void selectColors(const std::string& materialName, sofa::type::RGBAColor& color1 { if (materialName == material::BoyceAndArruda::Name) { - color1 = type::RGBAColor(0.0, 1.0, 0.0, 1.0); - color2 = type::RGBAColor(0.5, 1.0, 0.0, 1.0); - color3 = type::RGBAColor(1.0, 1.0, 0.0, 1.0); + color1 = type::RGBAColor::green(); + color2 = type::RGBAColor::lime(); + color3 = type::RGBAColor::yellow(); color4 = type::RGBAColor(1.0, 1.0, 0.5, 1.0); } else if (materialName == material::STVenantKirchhoff::Name) { - color1 = type::RGBAColor(1.0,0.0,0.0,1.0); - color2 = type::RGBAColor(1.0,0.0,0.5,1.0); - color3 = type::RGBAColor(1.0,1.0,0.0,1.0); + color1 = type::RGBAColor::red(); + color2 = type::RGBAColor::pink(); + color3 = type::RGBAColor::yellow(); color4 = type::RGBAColor(1.0,0.5,1.0,1.0); } else if (materialName == material::NeoHookean::Name) { - color1 = type::RGBAColor(0.0, 1.0, 1.0, 1.0); + color1 = type::RGBAColor::cyan(); color2 = type::RGBAColor(0.5, 0.0, 1.0, 1.0); - color3 = type::RGBAColor(1.0, 0.0, 1.0, 1.0); + color3 = type::RGBAColor::magenta(); color4 = type::RGBAColor(1.0, 0.5, 1.0, 1.0); } else if (materialName == material::MooneyRivlin::Name) { - color1 = type::RGBAColor(0.0, 1.0, 0.0, 1.0); + color1 = type::RGBAColor::green(); color2 = type::RGBAColor(0.0, 1.0, 0.5, 1.0); - color3 = type::RGBAColor(0.0, 1.0, 1.0, 1.0); + color3 = type::RGBAColor::cyan(); color4 = type::RGBAColor(0.5, 1.0, 1.0, 1.0); } else if (materialName == material::VerondaWestman::Name) { - color1 = type::RGBAColor(0.0, 1.0, 0.0, 1.0); + color1 = type::RGBAColor::green(); color2 = type::RGBAColor(0.5, 1.0, 0.0, 1.0); color3 = type::RGBAColor(1.0, 1.0, 0.0, 1.0); color4 = type::RGBAColor(1.0, 1.0, 0.5, 1.0); } else if (materialName == material::Costa::Name) { - color1 = type::RGBAColor(0.0, 1.0, 0.0, 1.0); + color1 = type::RGBAColor::green(); color2 = type::RGBAColor(0.5, 1.0, 0.0, 1.0); color3 = type::RGBAColor(1.0, 1.0, 0.0, 1.0); color4 = type::RGBAColor(1.0, 1.0, 0.5, 1.0); } else if (materialName == material::Ogden::Name) { - color1 = type::RGBAColor(0.0, 1.0, 0.0, 1.0); + color1 = type::RGBAColor::green(); color2 = type::RGBAColor(0.5, 1.0, 0.0, 1.0); color3 = type::RGBAColor(1.0, 1.0, 0.0, 1.0); color4 = type::RGBAColor(1.0, 1.0, 0.5, 1.0); } else { - color1 = type::RGBAColor(0.0, 1.0, 0.0, 1.0); + color1 = type::RGBAColor::green(); color2 = type::RGBAColor(0.5, 1.0, 0.0, 1.0); color3 = type::RGBAColor(1.0, 1.0, 0.0, 1.0); color4 = type::RGBAColor(1.0, 1.0, 0.5, 1.0); } } -template +template void drawHyperelasticTets(const core::visual::VisualParams* vparams, const typename DataTypes::VecCoord& x, core::topology::BaseMeshTopology* topology, const std::string& materialName, - const sofa::type::vector& indicesToDraw) + const IndicesContainer& indices) { - std::vector points[4]; - for(auto& p : points) - { - p.reserve(3 * indicesToDraw.size()); - } - - const auto& tetrahedra = topology->getTetrahedra(); - - for(const auto i : indicesToDraw) - { - const auto t = tetrahedra[i]; - - const Index a = t[0]; - const Index b = t[1]; - const Index c = t[2]; - const Index d = t[3]; - - const auto center = (x[a] + x[b] + x[c] + x[d]) * 0.125; - const auto pa = (x[a] + center) * 0.666667; - const auto pb = (x[b] + center) * 0.666667; - const auto pc = (x[c] + center) * 0.666667; - const auto pd = (x[d] + center) * 0.666667; - - points[0].push_back(pa); - points[0].push_back(pb); - points[0].push_back(pc); - - points[1].push_back(pb); - points[1].push_back(pc); - points[1].push_back(pd); - - points[2].push_back(pc); - points[2].push_back(pd); - points[2].push_back(pa); - - points[3].push_back(pd); - points[3].push_back(pa); - points[3].push_back(pb); - } - std::array colors; selectColors(materialName, colors[0], colors[1], colors[2], colors[3]); - vparams->drawTool()->drawTriangles(points[0], colors[0]); - vparams->drawTool()->drawTriangles(points[1], colors[1]); - vparams->drawTool()->drawTriangles(points[2], colors[2]); - vparams->drawTool()->drawTriangles(points[3], colors[3]); + core::visual::DrawElementMesh drawer; + drawer.drawSomeElements(vparams->drawTool(), x, topology, indices, colors); } template @@ -160,9 +116,8 @@ void drawHyperelasticTets(const core::visual::VisualParams* vparams, core::topology::BaseMeshTopology* topology, const std::string& materialName) { - sofa::type::vector allIndices(topology->getNbTetrahedra()); - std::iota(allIndices.begin(), allIndices.end(), static_cast(0)); - drawHyperelasticTets(vparams, x, topology, materialName, allIndices); + const auto indices = sofa::helper::IotaView(static_cast(0), topology->getNbTetrahedra()); + drawHyperelasticTets(vparams, x, topology, materialName, indices); } diff --git a/Sofa/Component/Visual/CMakeLists.txt b/Sofa/Component/Visual/CMakeLists.txt index a3f9e277011..e81df5befdd 100644 --- a/Sofa/Component/Visual/CMakeLists.txt +++ b/Sofa/Component/Visual/CMakeLists.txt @@ -17,6 +17,7 @@ set(HEADER_FILES ${SOFACOMPONENTVISUAL_SOURCE_DIR}/Visual3DText.h ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualBoundingBox.h ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualGrid.h + ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualMesh.h ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualModelImpl.h ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualPointCloud.h ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualPointCloud.inl @@ -38,6 +39,7 @@ set(SOURCE_FILES ${SOFACOMPONENTVISUAL_SOURCE_DIR}/Visual3DText.cpp ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualBoundingBox.cpp ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualGrid.cpp + ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualMesh.cpp ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualModelImpl.cpp ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualPointCloud.cpp ${SOFACOMPONENTVISUAL_SOURCE_DIR}/VisualStyle.cpp diff --git a/Sofa/Component/Visual/src/sofa/component/visual/VisualMesh.cpp b/Sofa/Component/Visual/src/sofa/component/visual/VisualMesh.cpp new file mode 100644 index 00000000000..ebe816f329c --- /dev/null +++ b/Sofa/Component/Visual/src/sofa/component/visual/VisualMesh.cpp @@ -0,0 +1,92 @@ +/****************************************************************************** +* 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 +#include + +namespace sofa::component::visual +{ + +void registerVisualMesh(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(core::ObjectRegistrationData("Render a mesh") + .add() + ); +} + +VisualMesh::VisualMesh() + : d_position(initData(&d_position, "position", "The position of the vertices of mesh")) + , d_elementSpace(initData(&d_elementSpace, 0.15_sreal, "elementSpace", + "The space between element (scalar between 0 and 1)")) + , l_topology(initLink("topology", "Link to a topology containing elements")) +{ +} + +void VisualMesh::init() +{ + VisualModel::init(); + + if (!this->isComponentStateInvalid()) + { + this->validateTopology(); + } + + if (!this->isComponentStateInvalid()) + { + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid); + } +} + +void VisualMesh::doDrawVisual(const core::visual::VisualParams* vparams) +{ + auto* drawTool = vparams->drawTool(); + + vparams->drawTool()->disableLighting(); + + const auto& positionAccessor = sofa::helper::getReadAccessor(d_position); + + m_drawMesh.setElementSpace(d_elementSpace.getValue()); + m_drawMesh.draw(drawTool, positionAccessor.ref(), l_topology.get()); +} + +void VisualMesh::validateTopology() +{ + 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()); + } + + if (l_topology == nullptr) + { + msg_error() << "No topology component found at path: " << this->l_topology.getLinkedPath() + << ", nor in current context: " << this->getContext()->name + << ". Object must have a BaseMeshTopology. " + << "The list of available BaseMeshTopology components is: " + << sofa::core::ObjectFactory::getInstance() + ->listClassesDerivedFrom(); + this->d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid); + } +} + +} // namespace sofa::component::visual diff --git a/Sofa/Component/Visual/src/sofa/component/visual/VisualMesh.h b/Sofa/Component/Visual/src/sofa/component/visual/VisualMesh.h new file mode 100644 index 00000000000..ba7c447f30c --- /dev/null +++ b/Sofa/Component/Visual/src/sofa/component/visual/VisualMesh.h @@ -0,0 +1,56 @@ +/****************************************************************************** +* 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 +#include +#include + +namespace sofa::component::visual +{ + +class VisualMesh : public core::visual::VisualModel +{ +public: + SOFA_CLASS(VisualMesh, core::visual::VisualModel); + + Data> d_position; + Data d_elementSpace; + + /// The topology will give access to the elements + sofa::SingleLink l_topology; + + void init() override; + +protected: + + VisualMesh(); + + void doDrawVisual(const core::visual::VisualParams* vparams) override; + + core::visual::DrawMesh m_drawMesh; + + void validateTopology(); +}; + +} diff --git a/Sofa/Component/Visual/src/sofa/component/visual/init.cpp b/Sofa/Component/Visual/src/sofa/component/visual/init.cpp index 27ee33e1bb0..5d5258908f7 100644 --- a/Sofa/Component/Visual/src/sofa/component/visual/init.cpp +++ b/Sofa/Component/Visual/src/sofa/component/visual/init.cpp @@ -40,6 +40,7 @@ extern void registerVisualPointCloud(sofa::core::ObjectFactory* factory); extern void registerVisualStyle(sofa::core::ObjectFactory* factory); extern void registerVisualTransform(sofa::core::ObjectFactory* factory); extern void registerVisualVectorField(sofa::core::ObjectFactory* factory); +extern void registerVisualMesh(sofa::core::ObjectFactory* factory); extern "C" { SOFA_EXPORT_DYNAMIC_LIBRARY void initExternalModule(); @@ -79,6 +80,7 @@ void registerObjects(sofa::core::ObjectFactory* factory) registerVisualStyle(factory); registerVisualTransform(factory); registerVisualVectorField(factory); + registerVisualMesh(factory); } void init() diff --git a/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.cpp b/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.cpp index f1605162c45..59f013e468c 100644 --- a/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.cpp +++ b/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.cpp @@ -427,32 +427,47 @@ void BaseViewer::drawSelection(sofa::core::visual::VisualParams* vparams) if(m_showSelectedObjectSurfaces && !positions.empty()) { - auto triangles = object->findData("triangles"); - if(triangles) + if (const auto topology = object->toBaseMeshTopology()) { - auto d_triangles = dynamic_cast>*>(triangles); - if(d_triangles) + m_drawMeshContainer[object].drawSurface(drawTool, positions, topology); + } + else + { + auto triangles = object->findData("triangles"); + if(triangles) { - std::vector tripoints; - for(auto indices : d_triangles->getValue()) + auto d_triangles = dynamic_cast>*>(triangles); + if(d_triangles) { - if(indices[0] < positions.size() && - indices[1] < positions.size() && - indices[2] < positions.size()) + std::vector tripoints; + for(auto indices : d_triangles->getValue()) { - tripoints.push_back(positions[indices[0]]); - tripoints.push_back(positions[indices[1]]); - tripoints.push_back(positions[indices[1]]); - tripoints.push_back(positions[indices[2]]); - tripoints.push_back(positions[indices[2]]); - tripoints.push_back(positions[indices[0]]); + if(indices[0] < positions.size() && + indices[1] < positions.size() && + indices[2] < positions.size()) + { + tripoints.push_back(positions[indices[0]]); + tripoints.push_back(positions[indices[1]]); + tripoints.push_back(positions[indices[1]]); + tripoints.push_back(positions[indices[2]]); + tripoints.push_back(positions[indices[2]]); + tripoints.push_back(positions[indices[0]]); + } } + drawTool->drawLines(tripoints, size, m_selectionColor); } - drawTool->drawLines(tripoints, size, m_selectionColor); } } } + if(m_showSelectedObjectVolumes && !positions.empty()) + { + if (const auto topology = object->toBaseMeshTopology()) + { + m_drawMeshContainer[object].drawVolume(drawTool, positions, topology); + } + } + if(m_showSelectedObjectIndices && !positions.empty() && validBox) { const float scale = (box.maxBBox() - box.minBBox()).norm() * m_visualScaling; diff --git a/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.h b/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.h index 96812349250..c4b593fada9 100644 --- a/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.h +++ b/Sofa/GUI/Common/src/sofa/gui/common/BaseViewer.h @@ -20,19 +20,17 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ #pragma once -#include - +#include +#include +#include +#include #include - +#include #include #include #include -#include -#include #include -#include - #include namespace sofa::component::setting @@ -174,6 +172,7 @@ class SOFA_GUI_COMMON_API BaseViewer std::string _screenshotDirectory; std::set currentSelection; + std::unordered_map m_drawMeshContainer; }; } // namespace sofa::gui::common diff --git a/Sofa/framework/Core/CMakeLists.txt b/Sofa/framework/Core/CMakeLists.txt index e28798a6ade..4de5aa87e99 100644 --- a/Sofa/framework/Core/CMakeLists.txt +++ b/Sofa/framework/Core/CMakeLists.txt @@ -210,6 +210,7 @@ set(HEADER_FILES ${SRC_ROOT}/visual/BaseVisualStyle.h ${SRC_ROOT}/visual/Data[DisplayFlags].h ${SRC_ROOT}/visual/DisplayFlags.h + ${SRC_ROOT}/visual/DrawMesh.h ${SRC_ROOT}/visual/FlagTreeItem.h ${SRC_ROOT}/visual/Shader.h ${SRC_ROOT}/visual/Tristate.h @@ -342,6 +343,7 @@ set(SOURCE_FILES ${SRC_ROOT}/topology/TopologySubsetIndices.cpp ${SRC_ROOT}/visual/Data[DisplayFlags].cpp ${SRC_ROOT}/visual/DisplayFlags.cpp + ${SRC_ROOT}/visual/DrawMesh.cpp ${SRC_ROOT}/visual/FlagTreeItem.cpp ${SRC_ROOT}/visual/Shader.cpp ${SRC_ROOT}/visual/VisualLoop.cpp diff --git a/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.cpp b/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.cpp index 7eb1494c17d..bbca664a8ee 100644 --- a/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.cpp +++ b/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.cpp @@ -36,6 +36,48 @@ BaseMeshTopology::BaseMeshTopology() addAlias(&fileTopology,"fileTopology"); } +template <> +Size BaseMeshTopology::getNbElements() +{ + return getNbEdges(); +} + +template <> +Size BaseMeshTopology::getNbElements() +{ + return getNbTriangles(); +} + +template <> +Size BaseMeshTopology::getNbElements() +{ + return getNbQuads(); +} + +template <> +Size BaseMeshTopology::getNbElements() +{ + return getNbTetrahedra(); +} + +template <> +Size BaseMeshTopology::getNbElements() +{ + return getNbHexahedra(); +} + +template <> +Size BaseMeshTopology::getNbElements() +{ + return getNbPrisms(); +} + +template <> +Size BaseMeshTopology::getNbElements() +{ + return getNbPyramids(); +} + /// Returns the set of edges adjacent to a given vertex. const BaseMeshTopology::EdgesAroundVertex& BaseMeshTopology::getEdgesAroundVertex(PointID) { diff --git a/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.h b/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.h index 98d314bbe98..78bedc85b30 100644 --- a/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.h +++ b/Sofa/framework/Core/src/sofa/core/topology/BaseMeshTopology.h @@ -121,6 +121,21 @@ class SOFA_CORE_API BaseMeshTopology : public core::topology::Topology virtual Size getNbPrisms() { return Size(getPrisms().size()); } virtual Size getNbPyramids() { return Size(getPyramids().size()); } + /** + * @brief Returns the number of elements of a specific type + * @tparam ElementType The type of element (e.g., sofa::geometry::Triangle, + * sofa::geometry::Tetrahedron) + * + * Example: + * @code + * sofa::core::topology::BaseMeshTopology* topology = ...; + * Size nbTriangles = topology->getNbElements(); + * Size nbTetrahedra = topology->getNbElements(); + * @endcode + */ + template + Size getNbElements(); + virtual const Edge getEdge(EdgeID i) { return getEdges()[i]; } virtual const Triangle getTriangle(TriangleID i) { return getTriangles()[i]; } virtual const Quad getQuad(QuadID i) { return getQuads()[i]; } @@ -324,4 +339,15 @@ class SOFA_CORE_API BaseMeshTopology : public core::topology::Topology bool removeInNode( objectmodel::BaseNode* node ) override; }; + +template<> SOFA_CORE_API Size BaseMeshTopology::getNbElements(); +template<> SOFA_CORE_API Size BaseMeshTopology::getNbElements(); +template<> SOFA_CORE_API Size BaseMeshTopology::getNbElements(); +template<> SOFA_CORE_API Size BaseMeshTopology::getNbElements(); +template<> SOFA_CORE_API Size BaseMeshTopology::getNbElements(); +template<> SOFA_CORE_API Size BaseMeshTopology::getNbElements(); +template<> SOFA_CORE_API Size BaseMeshTopology::getNbElements(); + + + } // namespace sofa::core::topology diff --git a/Sofa/framework/Core/src/sofa/core/visual/DrawMesh.cpp b/Sofa/framework/Core/src/sofa/core/visual/DrawMesh.cpp new file mode 100644 index 00000000000..d077ad4a027 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/visual/DrawMesh.cpp @@ -0,0 +1,32 @@ +/****************************************************************************** +* 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 + +namespace sofa::core::visual +{ + +void DrawMesh::setElementSpace(SReal elementSpace) +{ + std::apply([elementSpace](auto&&... mesh){ ((mesh.elementSpace = elementSpace), ...); }, m_meshes); +} + +} // namespace sofa::core::visual diff --git a/Sofa/framework/Core/src/sofa/core/visual/DrawMesh.h b/Sofa/framework/Core/src/sofa/core/visual/DrawMesh.h new file mode 100644 index 00000000000..3514ce48e50 --- /dev/null +++ b/Sofa/framework/Core/src/sofa/core/visual/DrawMesh.h @@ -0,0 +1,380 @@ +/****************************************************************************** +* 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 +#include +#include +#include + +#include + +namespace sofa::core::visual +{ + +/** + * @class BaseDrawMesh + * @brief Base class for mesh drawing using Curiously Recurring Template Pattern (CRTP) + */ +template +struct BaseDrawMesh +{ + static constexpr std::size_t NumberColors { NumberColors_ }; + using ColorContainer = std::array; + + SReal elementSpace { 0.125_sreal }; + + /** + * @brief Draws all elements of the mesh using provided colors. + * + * This function draws all elements of the mesh (from index 0 to the total number of elements) + * using the specified colors. It serves as a convenience wrapper that calls \ref + * drawSomeElements with all element indices. + * + * @tparam PositionContainer The type of the position container (e.g., + * sofa::type::vector) + * @param drawTool The drawing tool to use for rendering + * @param position The container of vertex positions + * @param topology The mesh topology + * @param colors The colors to use for each element. If not specified, the default colors of the + * derived class are used. + */ + template + void drawAllElements( + sofa::helper::visual::DrawTool* drawTool, + const PositionContainer& position, + sofa::core::topology::BaseMeshTopology* topology, + const ColorContainer& colors = Derived::defaultColors) + { + const auto totalNbElements = topology->getNbElements(); + const auto elementsToDraw = sofa::helper::IotaView(static_cast(0), totalNbElements); + drawSomeElements(drawTool, position, topology, elementsToDraw, colors); + } + + /** + * @brief Draws a subset of elements of the mesh using provided colors. + * + * This function draws a specific subset of elements (specified by element indices) using the + * provided colors. + * + * @tparam PositionContainer The type of the position container (e.g., + * sofa::type::vector) + * @tparam IndicesContainer The type of container holding element indices (e.g., + * sofa::type::vector) + * @param drawTool The drawing tool to use for rendering + * @param position The container of vertex positions + * @param topology The mesh topology + * @param elementIndices The indices of elements to draw + * @param colors The colors to use for each element. If not specified, the default colors of the + * derived class are used. + */ + template + void drawSomeElements( + sofa::helper::visual::DrawTool* drawTool, + const PositionContainer& position, + sofa::core::topology::BaseMeshTopology* topology, + const IndicesContainer& elementIndices, + const ColorContainer& colors = Derived::defaultColors) + { + if (!drawTool) + return; + if (!topology) + return; + + const auto stateLifeCycle = drawTool->makeStateLifeCycle(); + drawTool->disableLighting(); + + static_cast(*this).doDraw(drawTool, position, topology, elementIndices, colors); + } + +protected: + template + PositionType applyElementSpace(const PositionType& position, const PositionType& elementCenter) const + { + return (position - elementCenter) * (1._sreal - elementSpace) + elementCenter; + } + + template + static typename PositionContainer::value_type elementCenter(const PositionContainer& position, const ElementType& element) + { + typename PositionContainer::value_type center{}; + for (sofa::Size vId = 0; vId < element.size(); ++vId) + { + center += position[element[vId]]; + } + center /= element.size(); + return center; + } + + /** + * @brief Pre-allocated point buffers for rendering different color channels + * + * This static array holds pre-allocated vertex position buffers for each color channel. + * + * Key characteristics: + * - Each buffer corresponds to one of the `NumberColors` color channels (e.g., 3 for triangles) + * - Designed for efficient reuse across multiple drawing calls without reallocation + */ + std::array, NumberColors> renderedPoints; +}; + +template +struct DrawElementMesh{}; + +template<> +struct SOFA_CORE_API DrawElementMesh + : public BaseDrawMesh, 3> +{ + using ElementType = sofa::geometry::Triangle; + friend BaseDrawMesh; + static constexpr ColorContainer defaultColors { + sofa::type::RGBAColor::green(), + sofa::type::RGBAColor::teal(), + sofa::type::RGBAColor::blue() + }; + +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->getTriangles(); + + const auto size = (elementIndices.size() / NumberColors + 1) * sofa::geometry::Triangle::NumberOfNodes; + for ( auto& p : renderedPoints) + { + p.resize(size); + } + + std::array renderedPointId {}; + for (auto i : elementIndices) + { + const auto& element = elements[i]; + + const auto center = this->elementCenter(position, element); + + for (std::size_t j = 0; j < sofa::geometry::Triangle::NumberOfNodes; ++j) + { + const auto p = this->applyElementSpace(position[element[j]], center); + renderedPoints[i % NumberColors][renderedPointId[i%NumberColors]++] = sofa::type::toVec3(p); + } + } + + for (std::size_t j = 0; j < NumberColors; ++j) + { + drawTool->drawTriangles(renderedPoints[j], colors[j]); + } + } +}; + +template<> +struct SOFA_CORE_API DrawElementMesh + : public BaseDrawMesh, 4> +{ + using ElementType = sofa::geometry::Tetrahedron; + friend BaseDrawMesh; + static constexpr std::size_t NumberTrianglesInTetrahedron = 4; + + static constexpr ColorContainer defaultColors { + sofa::type::RGBAColor::blue(), + sofa::type::RGBAColor::black(), + sofa::type::RGBAColor::azure(), + sofa::type::RGBAColor::cyan() + }; + +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->getTetrahedra(); + const auto& facets = topology->getTriangles(); + + for ( auto& p : renderedPoints) + { + p.resize(elementIndices.size() * sofa::geometry::Triangle::NumberOfNodes); + } + + for (auto i : elementIndices) + { + const auto& element = elements[i]; + const auto& facetsInElement = topology->getTrianglesInTetrahedron(i); + assert(facetsInElement.size() == NumberTrianglesInTetrahedron); + + const auto center = this->elementCenter(position, element); + + for (std::size_t j = 0; j < NumberTrianglesInTetrahedron; ++j) + { + const auto faceId = facetsInElement[j]; + std::size_t k {}; + for (const auto vertexId : facets[faceId]) + { + const auto p = this->applyElementSpace(position[vertexId], center); + renderedPoints[j][i * sofa::geometry::Triangle::NumberOfNodes + k] = sofa::type::toVec3(p); + ++k; + } + } + } + + for (std::size_t j = 0; j < NumberTrianglesInTetrahedron; ++j) + { + drawTool->drawTriangles(renderedPoints[j], colors[j]); + } + } +}; + +template<> +struct SOFA_CORE_API DrawElementMesh + : public BaseDrawMesh, 6> +{ + using ElementType = sofa::geometry::Hexahedron; + friend BaseDrawMesh; + static constexpr std::size_t NumberQuadsInHexahedron = 6; + + static constexpr ColorContainer defaultColors { + sofa::type::RGBAColor(0.7f,0.7f,0.1f,1.f), + sofa::type::RGBAColor(0.7f,0.0f,0.0f,1.f), + sofa::type::RGBAColor(0.0f,0.7f,0.0f,1.f), + sofa::type::RGBAColor(0.0f,0.0f,0.7f,1.f), + sofa::type::RGBAColor(0.1f,0.7f,0.7f,1.f), + sofa::type::RGBAColor(0.7f,0.1f,0.7f,1.f) + }; + +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->getHexahedra(); + const auto& facets = topology->getQuads(); + + for ( auto& p : renderedPoints) + { + p.resize(elementIndices.size() * sofa::geometry::Quad::NumberOfNodes); + } + + std::size_t renderedPointId {}; + for (auto i : elementIndices) + { + const auto& element = elements[i]; + const auto& facetsInElement = topology->getQuadsInHexahedron(i); + assert(facetsInElement.size() == NumberTrianglesInTetrahedron); + + const auto center = this->elementCenter(position, element); + + for (std::size_t j = 0; j < NumberQuadsInHexahedron; ++j) + { + const auto faceId = facetsInElement[j]; + std::size_t k {}; + for (const auto vertexId : facets[faceId]) + { + const auto p = this->applyElementSpace(position[vertexId], center); + renderedPoints[j][i * sofa::geometry::Quad::NumberOfNodes + k] = sofa::type::toVec3(p); + ++k; + } + } + } + + for (std::size_t j = 0; j < NumberQuadsInHexahedron; ++j) + { + drawTool->drawQuads(renderedPoints[j], colors[j]); + } + } +}; + +class SOFA_CORE_API DrawMesh +{ +public: + + template + void drawElements( + sofa::helper::visual::DrawTool* drawTool, + const PositionContainer& position, + sofa::core::topology::BaseMeshTopology* topology, + const typename DrawElementMesh::ColorContainer& colors = DrawElementMesh::defaultColors) + { + std::get>(m_meshes).drawAllElements(drawTool, position, topology, colors); + } + + void setElementSpace(SReal elementSpace); + + template + void drawSurface(sofa::helper::visual::DrawTool* drawTool, const PositionContainer& position, sofa::core::topology::BaseMeshTopology* topology) + { + drawElements(drawTool, position, topology); + } + + template + void drawVolume(sofa::helper::visual::DrawTool* drawTool, const PositionContainer& position, sofa::core::topology::BaseMeshTopology* topology) + { + drawElements(drawTool, position, topology); + drawElements(drawTool, position, topology); + } + + template + void draw(sofa::helper::visual::DrawTool* drawTool, const PositionContainer& position, sofa::core::topology::BaseMeshTopology* topology) + { + if (!topology) + { + return; + } + + const auto hasTetra = topology && !topology->getTetrahedra().empty(); + const auto hasHexa = topology && !topology->getHexahedra().empty(); + + if (!hasTetra && !hasHexa) + { + drawSurface(drawTool, position, topology); + } + drawVolume(drawTool, position, topology); + } + +private: + std::tuple< + DrawElementMesh, + DrawElementMesh, + DrawElementMesh + > m_meshes; +}; + +} // namespace sofa::core::visual diff --git a/Sofa/framework/Helper/CMakeLists.txt b/Sofa/framework/Helper/CMakeLists.txt index 75767d7a130..5de5b85a719 100644 --- a/Sofa/framework/Helper/CMakeLists.txt +++ b/Sofa/framework/Helper/CMakeLists.txt @@ -70,6 +70,7 @@ set(HEADER_FILES ${SRC_ROOT}/hash.h ${SRC_ROOT}/init.h ${SRC_ROOT}/integer_id.h + ${SRC_ROOT}/IotaView.h ${SRC_ROOT}/accessor/ReadAccessor.h ${SRC_ROOT}/accessor/ReadAccessorFixedArray.h ${SRC_ROOT}/accessor/ReadAccessorVector.h diff --git a/Sofa/framework/Helper/src/sofa/helper/IotaView.h b/Sofa/framework/Helper/src/sofa/helper/IotaView.h new file mode 100644 index 00000000000..26ab73b751e --- /dev/null +++ b/Sofa/framework/Helper/src/sofa/helper/IotaView.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +namespace sofa::helper +{ + +/** + * Simple alternative to std::ranges::iota_view, compatible with pre-C++20 + */ +template +class IotaView +{ +public: + struct iota_iterator + { + using value_type = T; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + using reference = T&; + using pointer = T*; + + explicit iota_iterator(T val) : val_(val) {} + + T operator*() const { return val_; } + iota_iterator& operator++() { ++val_; return *this; } + bool operator!=(const iota_iterator& other) const { return val_ != other.val_; } + + private: + T val_; + }; + + using iterator = iota_iterator; + using value_type = T; + + IotaView(T start, T end) : m_start(start), m_end(end) {} + + iterator begin() const { return iterator(m_start); } + iterator end() const { return iterator(m_end); } + + [[nodiscard]] T size() const { return m_end - m_start; } + [[nodiscard]] T operator[](T i) const { return m_start + i; } + T front() const { return m_start; } + T back() const { return m_end - 1; } + [[nodiscard]] bool empty() const { return m_start == m_end; } + +private: + T m_start; + T m_end; +}; + + +} diff --git a/Sofa/framework/Helper/test/CMakeLists.txt b/Sofa/framework/Helper/test/CMakeLists.txt index b6120ff71b9..67aa4c3fe8b 100644 --- a/Sofa/framework/Helper/test/CMakeLists.txt +++ b/Sofa/framework/Helper/test/CMakeLists.txt @@ -5,6 +5,7 @@ project(Sofa.Helper_test) set(SOURCE_FILES DiffLib_test.cpp Factory_test.cpp + IotaView_test.cpp KdTree_test.cpp NameDecoder_test.cpp OptionsGroup_test.cpp diff --git a/Sofa/framework/Helper/test/IotaView_test.cpp b/Sofa/framework/Helper/test/IotaView_test.cpp new file mode 100644 index 00000000000..9e1d22b386e --- /dev/null +++ b/Sofa/framework/Helper/test/IotaView_test.cpp @@ -0,0 +1,44 @@ +#include +#include + +namespace sofa +{ + +TEST(IotaView, loop) +{ + const auto range = sofa::helper::IotaView{0, 10}; + + int i = 0; + for (const auto value : range) + { + EXPECT_EQ(value, i); + ++i; + } +} + +TEST(IotaView, empty) +{ + { + const auto range = sofa::helper::IotaView{0, 10}; + EXPECT_FALSE(range.empty()); + } + { + const auto range = sofa::helper::IotaView{0, 0}; + EXPECT_TRUE(range.empty()); + } +} + +TEST(IotaView, size) +{ + const auto range = sofa::helper::IotaView{0, 10}; + EXPECT_EQ(range.size(), 10); +} + +TEST(IotaView, access) +{ + const auto range = sofa::helper::IotaView{4, 10}; + EXPECT_EQ(range[0], 4); + EXPECT_EQ(range[9], 4+9); +} + +} diff --git a/Sofa/framework/Type/src/sofa/type/RGBAColor.cpp b/Sofa/framework/Type/src/sofa/type/RGBAColor.cpp index 79c4aebe25a..2b51746e826 100644 --- a/Sofa/framework/Type/src/sofa/type/RGBAColor.cpp +++ b/Sofa/framework/Type/src/sofa/type/RGBAColor.cpp @@ -199,7 +199,8 @@ const std::map stringToColorMap { {"olive", g_olive}, {"maroon", g_maroon}, {"silver", g_silver}, - {"gold", g_gold} + {"gold", g_gold}, + {"azure", g_azure} }; SOFA_TYPE_API std::istream& operator>>(std::istream& i, RGBAColor& t) diff --git a/Sofa/framework/Type/src/sofa/type/RGBAColor.h b/Sofa/framework/Type/src/sofa/type/RGBAColor.h index af9aac7c0a0..2e68a2a63cd 100644 --- a/Sofa/framework/Type/src/sofa/type/RGBAColor.h +++ b/Sofa/framework/Type/src/sofa/type/RGBAColor.h @@ -90,6 +90,7 @@ class SOFA_TYPE_API RGBAColor constexpr static const RGBAColor& maroon(); constexpr static const RGBAColor& silver(); constexpr static const RGBAColor& gold(); + constexpr static const RGBAColor& azure(); /// @brief enlight a color by a given factor. static RGBAColor lighten(const RGBAColor& in, const SReal factor); @@ -270,6 +271,7 @@ constexpr RGBAColor g_olive { 0.5f, 0.5f, 0.0f, 1.0f }; constexpr RGBAColor g_maroon { 0.5f, 0.0f, 0.0f, 1.0f }; constexpr RGBAColor g_silver { 0.75f, 0.75f, 0.75f, 1.0f }; constexpr RGBAColor g_gold { 1.0f, 0.84f, 0.0f, 1.0f }; +constexpr RGBAColor g_azure { 0.0f, 0.5, 1.0f, 1.0f }; constexpr const RGBAColor& RGBAColor::white() { return g_white; } constexpr const RGBAColor& RGBAColor::black() { return g_black; } @@ -293,7 +295,7 @@ constexpr const RGBAColor& RGBAColor::olive() { return g_olive ; } constexpr const RGBAColor& RGBAColor::maroon() { return g_maroon; } constexpr const RGBAColor& RGBAColor::silver() { return g_silver; } constexpr const RGBAColor& RGBAColor::gold() { return g_gold ; } - +constexpr const RGBAColor& RGBAColor::azure() { return g_azure ; } } // namespace sofa::type diff --git a/examples/Component/Visual/VisualMesh.scn b/examples/Component/Visual/VisualMesh.scn new file mode 100644 index 00000000000..7a67077d6a8 --- /dev/null +++ b/examples/Component/Visual/VisualMesh.scn @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +