diff --git a/include/geode/mesh/core/solid_mesh.h b/include/geode/mesh/core/solid_mesh.h index 38bd71299..018018a15 100644 --- a/include/geode/mesh/core/solid_mesh.h +++ b/include/geode/mesh/core/solid_mesh.h @@ -425,6 +425,13 @@ namespace geode Vector3D OPENGEODE_MESH_DEPRECATED polyhedron_facet_normal( const PolyhedronFacet& polyhedron_facet ) const; + /*! + * Return the area of a given PolyhedronFacet. + * @param[in] polyhedron_facet Local index of facet in polyhedron. + */ + double polyhedron_facet_area( + const PolyhedronFacet& polyhedron_facet ) const; + /*! * Return the normal of a given PolyhedronFacet. * @param[in] polyhedron_facet Local index of facet in polyhedron. diff --git a/src/geode/mesh/core/solid_mesh.cpp b/src/geode/mesh/core/solid_mesh.cpp index 0346b0c7e..e7eb9037a 100644 --- a/src/geode/mesh/core/solid_mesh.cpp +++ b/src/geode/mesh/core/solid_mesh.cpp @@ -800,6 +800,28 @@ namespace geode return volume; } + template < index_t dimension > + double SolidMesh< dimension >::polyhedron_facet_area( + const PolyhedronFacet& polyhedron_facet ) const + { + if( nb_polyhedron_facet_vertices( polyhedron_facet ) < 3 ) + { + return 0; + } + double area{ 0 }; + const auto direction = new_polyhedron_facet_normal( polyhedron_facet ) + .value_or( Vector3D{ { 0, 0, 1 } } ); + const auto vertices = polyhedron_facet_vertices( polyhedron_facet ); + const auto& p1 = this->point( vertices[0] ); + for( const auto i : LRange{ 1, vertices.size() - 1 } ) + { + const auto& p2 = this->point( vertices[i] ); + const auto& p3 = this->point( vertices[i + 1] ); + area += triangle_signed_area( { p1, p2, p3 }, direction ); + } + return area; + } + template < index_t dimension > Vector3D SolidMesh< dimension >::polyhedron_facet_normal( const PolyhedronFacet& polyhedron_facet ) const diff --git a/tests/mesh/test-tetrahedral-solid.cpp b/tests/mesh/test-tetrahedral-solid.cpp index 82b634ed1..3ac6e8bb7 100644 --- a/tests/mesh/test-tetrahedral-solid.cpp +++ b/tests/mesh/test-tetrahedral-solid.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -82,6 +83,21 @@ void test_polyhedron_volumes( const geode::TetrahedralSolid3D& solid ) } } +void test_polyhedron_facet_area( const geode::TetrahedralSolid3D& solid ) +{ + for( const auto p : geode::Range{ solid.nb_polyhedra() } ) + { + for( const auto f : geode::LRange{ solid.nb_polyhedron_facets( p ) } ) + { + auto actual = std::fabs( solid.polyhedron_facet_area( { p, f } ) ); + auto expected = geode::triangle_area( solid.triangle( { p, f } ) ); + OPENGEODE_EXCEPTION( + std::fabs( actual - expected ) < geode::global_epsilon, + "[Test] Not correct tetrahedron facet area computation" ); + } + } +} + void test_polyhedron_adjacencies( const geode::TetrahedralSolid3D& solid, geode::TetrahedralSolidBuilder3D& builder ) { @@ -369,6 +385,7 @@ void test() test_create_vertices( *solid, *builder ); test_create_tetrahedra( *solid, *builder ); test_polyhedron_volumes( *solid ); + test_polyhedron_facet_area( *solid ); test_polyhedron_adjacencies( *solid, *builder ); test_is_on_border( *solid ); test_io( *solid, absl::StrCat( "test.", solid->native_extension() ) );