diff --git a/include/geode/geometry/basic_objects/polygon.hpp b/include/geode/geometry/basic_objects/polygon.hpp new file mode 100644 index 000000000..b7bebc1ec --- /dev/null +++ b/include/geode/geometry/basic_objects/polygon.hpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2019 - 2024 Geode-solutions + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#pragma once + +#include + +#include +#include + +namespace geode +{ + FORWARD_DECLARATION_DIMENSION_CLASS( BoundingBox ); + FORWARD_DECLARATION_DIMENSION_CLASS( OwnerPolygon ); + FORWARD_DECLARATION_DIMENSION_CLASS( Point ); + class OwnerPlane; + class Plane; + + template < index_t dimension > + using RefPoint = std::reference_wrapper< const Point< dimension > >; + ALIAS_2D_AND_3D( RefPoint ); +} // namespace geode + +namespace geode +{ + template < typename PointType, index_t dimension > + class GenericPolygon + { + public: + GenericPolygon( std::vector< PointType > vertices ) noexcept; + + GenericPolygon( + const GenericPolygon< PointType, dimension >& other ) noexcept; + GenericPolygon< PointType, dimension >& operator=( + const GenericPolygon< PointType, dimension >& other ) noexcept; + GenericPolygon( + GenericPolygon< PointType, dimension >&& other ) noexcept; + GenericPolygon< PointType, dimension >& operator=( + GenericPolygon< PointType, dimension >&& other ) noexcept; + + [[nodiscard]] Point< dimension > barycenter() const; + template < index_t T = dimension > + [[nodiscard]] + typename std::enable_if< T == 3, std::optional< Vector3D > >::type + normal() const; + template < index_t T = dimension > + [[nodiscard]] + typename std::enable_if< T == 3, std::optional< Plane > >::type + plane() const; + template < index_t T = dimension > + [[nodiscard]] + typename std::enable_if< T == 3, std::optional< OwnerPlane > >::type + owner_plane() const; + [[nodiscard]] index_t nb_vertices() const; + void set_point( index_t vertex, PointType point ); + [[nodiscard]] const std::vector< PointType >& vertices() const; + [[nodiscard]] BoundingBox< dimension > bounding_box() const; + [[nodiscard]] std::vector< std::array< index_t, 3 > > + triangulate() const; + [[nodiscard]] bool is_degenerated() const; + [[nodiscard]] std::string string() const; + + private: + std::vector< PointType > vertices_; + }; + + template < index_t dimension > + class OwnerPolygon : public GenericPolygon< Point< dimension >, dimension > + { + using Base = GenericPolygon< Point< dimension >, dimension >; + + public: + explicit OwnerPolygon( + std::vector< Point< dimension > > vertices ) noexcept; + + OwnerPolygon( const OwnerPolygon< dimension >& other ) noexcept; + OwnerPolygon< dimension >& operator=( + const OwnerPolygon< dimension >& other ) noexcept; + OwnerPolygon( OwnerPolygon< dimension >&& other ) noexcept; + OwnerPolygon< dimension >& operator=( + OwnerPolygon< dimension >&& other ) noexcept; + }; + ALIAS_2D_AND_3D( OwnerPolygon ); + + template < index_t dimension > + class Polygon : public GenericPolygon< RefPoint< dimension >, dimension > + { + using Base = GenericPolygon< RefPoint< dimension >, dimension >; + + public: + Polygon( std::vector< RefPoint< dimension > > vertices ) noexcept; + + Polygon( const Polygon< dimension >& other ) noexcept; + Polygon< dimension >& operator=( + const Polygon< dimension >& other ) noexcept; + Polygon( Polygon< dimension >&& other ) noexcept; + Polygon< dimension >& operator=( + Polygon< dimension >&& other ) noexcept; + }; + ALIAS_2D_AND_3D( Polygon ); +} // namespace geode diff --git a/include/geode/mesh/core/surface_mesh.hpp b/include/geode/mesh/core/surface_mesh.hpp index 967c5ce7f..28de91f6f 100644 --- a/include/geode/mesh/core/surface_mesh.hpp +++ b/include/geode/mesh/core/surface_mesh.hpp @@ -37,6 +37,7 @@ namespace geode { FORWARD_DECLARATION_DIMENSION_CLASS( Point ); + FORWARD_DECLARATION_DIMENSION_CLASS( Polygon ); FORWARD_DECLARATION_DIMENSION_CLASS( Vector ); FORWARD_DECLARATION_DIMENSION_CLASS( BoundingBox ); FORWARD_DECLARATION_DIMENSION_CLASS( SurfaceEdges ); @@ -210,6 +211,8 @@ namespace geode [[nodiscard]] std::optional< local_index_t > vertex_in_polygon( index_t polygon_id, index_t vertex_id ) const; + Polygon< dimension > polygon( index_t polygon_id ) const; + /*! * Return the index in the mesh of a given polygon edge vertex. * @param[in] polygon_edge Local index of edge in a polygon. diff --git a/src/geode/geometry/CMakeLists.txt b/src/geode/geometry/CMakeLists.txt index fa71fceeb..d88e30f3c 100644 --- a/src/geode/geometry/CMakeLists.txt +++ b/src/geode/geometry/CMakeLists.txt @@ -28,6 +28,7 @@ add_geode_library( "basic_objects/cylinder.cpp" "basic_objects/infinite_line.cpp" "basic_objects/plane.cpp" + "basic_objects/polygon.cpp" "basic_objects/segment.cpp" "basic_objects/sphere.cpp" "basic_objects/tetrahedron.cpp" @@ -62,6 +63,7 @@ add_geode_library( "basic_objects/cylinder.hpp" "basic_objects/infinite_line.hpp" "basic_objects/plane.hpp" + "basic_objects/polygon.hpp" "basic_objects/segment.hpp" "basic_objects/sphere.hpp" "basic_objects/tetrahedron.hpp" @@ -102,5 +104,6 @@ add_geode_library( ${PROJECT_NAME}::basic PRIVATE_DEPENDENCIES Async++ + earcut_hpp::earcut_hpp nanoflann::nanoflann ) diff --git a/src/geode/geometry/basic_objects/polygon.cpp b/src/geode/geometry/basic_objects/polygon.cpp new file mode 100644 index 000000000..94f13f180 --- /dev/null +++ b/src/geode/geometry/basic_objects/polygon.cpp @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2019 - 2024 Geode-solutions + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include + +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace mapbox +{ + namespace util + { + template < std::size_t coord, geode::index_t dimension > + struct nth< coord, geode::Point< dimension > > + { + inline static auto get( const geode::Point< dimension >& point ) + { + return point.value( coord ); + }; + }; + + template < std::size_t coord, geode::index_t dimension > + struct nth< coord, geode::RefPoint< dimension > > + { + inline static auto get( const geode::RefPoint< dimension >& point ) + { + return point.get().value( coord ); + }; + }; + } // namespace util +} // namespace mapbox + +namespace +{ + template < typename PointType > + std::array< std::vector< PointType >, 1 > polygon_points( + const geode::GenericPolygon< PointType, 2 >& polygon ) + { + return { { polygon.vertices() } }; + } + + template < typename PointType > + std::array< absl::FixedArray< geode::Point2D >, 1 > polygon_points( + const geode::GenericPolygon< PointType, 3 >& polygon ) + { + const auto& vertices = polygon.vertices(); + std::array< absl::FixedArray< geode::Point2D >, 1 > polygons{ + absl::FixedArray< geode::Point2D >( vertices.size() ) + }; + const auto normal = + polygon.normal().value_or( geode::Vector3D{ { 0, 0, 1 } } ); + const auto axis_to_remove = normal.most_meaningful_axis(); + for( const auto v : geode::LIndices{ vertices } ) + { + const geode::Point3D& point = vertices[v]; + polygons[0][v] = point.project_point( axis_to_remove ); + } + return polygons; + } +} // namespace + +namespace geode +{ + template < typename PointType, index_t dimension > + GenericPolygon< PointType, dimension >::GenericPolygon( + std::vector< PointType > vertices ) noexcept + : vertices_{ std::move( vertices ) } + { + } + + template < typename PointType, index_t dimension > + GenericPolygon< PointType, dimension >::GenericPolygon( + const GenericPolygon< PointType, dimension >& ) noexcept = default; + + template < typename PointType, index_t dimension > + GenericPolygon< PointType, dimension >& + GenericPolygon< PointType, dimension >::operator=( + const GenericPolygon< PointType, dimension >& ) noexcept = default; + + template < typename PointType, index_t dimension > + GenericPolygon< PointType, dimension >::GenericPolygon( + GenericPolygon< PointType, dimension >&& ) noexcept = default; + + template < typename PointType, index_t dimension > + GenericPolygon< PointType, dimension >& + GenericPolygon< PointType, dimension >::operator=( + GenericPolygon< PointType, dimension >&& ) noexcept = default; + + template < typename PointType, index_t dimension > + Point< dimension > + GenericPolygon< PointType, dimension >::barycenter() const + { + Point< dimension > barycenter; + for( const auto& point : vertices_ ) + { + barycenter += point; + } + return barycenter / nb_vertices(); + } + + template < typename PointType, index_t dimension > + template < index_t T > + typename std::enable_if< T == 3, std::optional< Vector3D > >::type + GenericPolygon< PointType, dimension >::normal() const + { + Vector3D normal; + const auto& p0 = vertices_[0]; + for( const auto v : Range{ 2, nb_vertices() } ) + { + const auto& p1 = vertices_[v - 1]; + const auto& p2 = vertices_[v]; + if( const auto triangle_normal = + Triangle< T >{ p0, p1, p2 }.normal() ) + { + normal += triangle_normal.value(); + } + } + try + { + return normal.normalize(); + } + catch( const OpenGeodeException& /*unused*/ ) + { + return std::nullopt; + } + } + + template < typename PointType, index_t dimension > + template < index_t T > + typename std::enable_if< T == 3, std::optional< Plane > >::type + GenericPolygon< PointType, dimension >::plane() const + { + if( const auto polygon_normal = this->normal() ) + { + return std::optional< Plane >{ std::in_place, + polygon_normal.value(), vertices_[0] }; + } + return std::nullopt; + } + + template < typename PointType, index_t dimension > + template < index_t T > + typename std::enable_if< T == 3, std::optional< OwnerPlane > >::type + GenericPolygon< PointType, dimension >::owner_plane() const + { + if( const auto polygon_normal = this->normal() ) + { + return std::optional< OwnerPlane >{ std::in_place, + polygon_normal.value(), vertices_[0] }; + } + return std::nullopt; + } + + template < typename PointType, index_t dimension > + void GenericPolygon< PointType, dimension >::set_point( + index_t vertex, PointType point ) + { + vertices_[vertex] = point; + } + + template < typename PointType, index_t dimension > + const std::vector< PointType >& + GenericPolygon< PointType, dimension >::vertices() const + { + return vertices_; + } + + template < typename PointType, index_t dimension > + BoundingBox< dimension > + GenericPolygon< PointType, dimension >::bounding_box() const + { + BoundingBox< dimension > bbox; + for( const auto& point : vertices_ ) + { + bbox.add_point( point ); + } + return bbox; + } + + template < typename PointType, index_t dimension > + index_t GenericPolygon< PointType, dimension >::nb_vertices() const + { + return vertices_.size(); + } + + template < typename PointType, index_t dimension > + std::vector< std::array< index_t, 3 > > + GenericPolygon< PointType, dimension >::triangulate() const + { + const std::array polygons{ vertices_ }; + const auto new_triangles = + mapbox::earcut< index_t >( polygon_points( *this ) ); + const auto nb_new_triangles = new_triangles.size() / 3; + std::vector< std::array< index_t, 3 > > result; + result.reserve( nb_new_triangles ); + for( const auto trgl : Range{ nb_new_triangles } ) + { + result.emplace_back( std::array< index_t, 3 >{ + new_triangles[3 * trgl], new_triangles[3 * trgl + 1], + new_triangles[3 * trgl + 2] } ); + } + return result; + } + + template < typename PointType, index_t dimension > + bool GenericPolygon< PointType, dimension >::is_degenerated() const + { + double max_length{ 0. }; + index_t max_length_edge{ 0 }; + for( const auto e : Range{ nb_vertices() } ) + { + const Point< dimension >& point0 = vertices_[e]; + const Point< dimension >& point1 = + vertices_[e == nb_vertices() - 1 ? 0 : e + 1]; + const auto cur_length = point_point_distance( point0, point1 ); + if( cur_length > max_length ) + { + max_length = cur_length; + max_length_edge = e; + } + } + if( max_length < GLOBAL_EPSILON ) + { + return true; + } + const auto next = + max_length_edge + 1 == nb_vertices() ? 0 : max_length_edge + 1; + const InfiniteLine< dimension > line{ Segment< dimension >{ + vertices_[max_length_edge], vertices_[next] } }; + for( const auto v : Range{ nb_vertices() } ) + { + if( v == max_length_edge || v == next ) + { + continue; + } + const Point< dimension >& point = vertices_[v]; + if( point_line_distance( point, line ) > GLOBAL_EPSILON ) + { + return false; + } + } + return true; + } + + template < typename PointType, index_t dimension > + std::string GenericPolygon< PointType, dimension >::string() const + { + std::string result{ "[" }; + auto sep = ""; + for( const Point< dimension >& point : vertices_ ) + { + absl::StrAppend( &result, sep, point.string() ); + sep = ", "; + } + result += "]"; + return result; + } + + template < index_t dimension > + OwnerPolygon< dimension >::OwnerPolygon( + std::vector< Point< dimension > > vertices ) noexcept + : Base{ std::move( vertices ) } + { + } + template < index_t dimension > + OwnerPolygon< dimension >::OwnerPolygon( + const OwnerPolygon< dimension >& ) noexcept = default; + template < index_t dimension > + OwnerPolygon< dimension >& OwnerPolygon< dimension >::operator=( + const OwnerPolygon< dimension >& ) noexcept = default; + template < index_t dimension > + OwnerPolygon< dimension >::OwnerPolygon( + OwnerPolygon< dimension >&& ) noexcept = default; + template < index_t dimension > + OwnerPolygon< dimension >& OwnerPolygon< dimension >::operator=( + OwnerPolygon< dimension >&& ) noexcept = default; + + template < index_t dimension > + Polygon< dimension >::Polygon( + std::vector< RefPoint< dimension > > vertices ) noexcept + : Base{ std::move( vertices ) } + { + } + template < index_t dimension > + Polygon< dimension >::Polygon( + const Polygon< dimension >& ) noexcept = default; + template < index_t dimension > + Polygon< dimension >& Polygon< dimension >::operator=( + const Polygon< dimension >& ) noexcept = default; + template < index_t dimension > + Polygon< dimension >::Polygon( Polygon< dimension >&& ) noexcept = default; + template < index_t dimension > + Polygon< dimension >& Polygon< dimension >::operator=( + Polygon< dimension >&& ) noexcept = default; + + template class opengeode_geometry_api GenericPolygon< Point< 2 >, 2 >; + template class opengeode_geometry_api GenericPolygon< Point< 3 >, 3 >; + template class opengeode_geometry_api GenericPolygon< RefPoint< 2 >, 2 >; + template class opengeode_geometry_api GenericPolygon< RefPoint< 3 >, 3 >; + template class opengeode_geometry_api OwnerPolygon< 2 >; + template class opengeode_geometry_api OwnerPolygon< 3 >; + template class opengeode_geometry_api Polygon< 2 >; + template class opengeode_geometry_api Polygon< 3 >; + + template opengeode_geometry_api std::optional< Vector3D > + GenericPolygon< Point< 3 >, 3 >::normal< 3 >() const; + template opengeode_geometry_api std::optional< Plane > + GenericPolygon< Point< 3 >, 3 >::plane< 3 >() const; + template opengeode_geometry_api std::optional< OwnerPlane > + GenericPolygon< Point< 3 >, 3 >::owner_plane< 3 >() const; + + template opengeode_geometry_api std::optional< Vector3D > + GenericPolygon< RefPoint< 3 >, 3 >::normal< 3 >() const; + template opengeode_geometry_api std::optional< Plane > + GenericPolygon< RefPoint< 3 >, 3 >::plane< 3 >() const; + template opengeode_geometry_api std::optional< OwnerPlane > + GenericPolygon< RefPoint< 3 >, 3 >::owner_plane< 3 >() const; +} // namespace geode diff --git a/src/geode/mesh/CMakeLists.txt b/src/geode/mesh/CMakeLists.txt index 9b338a66b..ffd4f796b 100644 --- a/src/geode/mesh/CMakeLists.txt +++ b/src/geode/mesh/CMakeLists.txt @@ -330,6 +330,5 @@ add_geode_library( ${PROJECT_NAME}::geometry PRIVATE_DEPENDENCIES Async++ - earcut_hpp::earcut_hpp ${PROJECT_NAME}::image ) diff --git a/src/geode/mesh/core/surface_mesh.cpp b/src/geode/mesh/core/surface_mesh.cpp index c44f2663c..c33eae82a 100644 --- a/src/geode/mesh/core/surface_mesh.cpp +++ b/src/geode/mesh/core/surface_mesh.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -1064,33 +1065,27 @@ namespace geode return area; } + template < index_t dimension > + Polygon< dimension > SurfaceMesh< dimension >::polygon( + index_t polygon_id ) const + { + check_polygon_id( *this, polygon_id ); + std::vector< std::reference_wrapper< const Point< dimension > > > + polygon; + for( const auto vertex : this->polygon_vertices( polygon_id ) ) + { + polygon.emplace_back( this->point( vertex ) ); + } + return Polygon< dimension >{ std::move( polygon ) }; + } + template < index_t dimension > template < index_t T > typename std::enable_if< T == 3, std::optional< Vector3D > >::type SurfaceMesh< dimension >::polygon_normal( index_t polygon_id ) const { check_polygon_id( *this, polygon_id ); - Vector3D normal; - const auto vertices = polygon_vertices( polygon_id ); - const auto& p0 = this->point( vertices[0] ); - for( const auto v : LRange{ 2, nb_polygon_vertices( polygon_id ) } ) - { - const auto& p1 = this->point( vertices[v - 1] ); - const auto& p2 = this->point( vertices[v] ); - if( const auto triangle_normal = - Triangle< T >{ p0, p1, p2 }.normal() ) - { - normal = normal + triangle_normal.value(); - } - } - try - { - return normal.normalize(); - } - catch( const OpenGeodeException& /*unused*/ ) - { - return std::nullopt; - } + return this->polygon( polygon_id ).normal(); } template < index_t dimension > @@ -1121,42 +1116,8 @@ namespace geode bool SurfaceMesh< dimension >::is_polygon_degenerated( index_t polygon_id ) const { - double max_length{ 0. }; - local_index_t max_length_edge{ 0 }; - for( const auto e : LRange{ nb_polygon_edges( polygon_id ) } ) - { - const auto cur_length = edge_length( PolygonEdge{ polygon_id, e } ); - if( cur_length > max_length ) - { - max_length = cur_length; - max_length_edge = e; - } - } - if( max_length < GLOBAL_EPSILON ) - { - return true; - } - const auto vertices = polygon_vertices( polygon_id ); - const auto next = - max_length_edge + 1 == nb_polygon_vertices( polygon_id ) - ? 0 - : max_length_edge + 1; - InfiniteLine< dimension > line{ Segment< dimension >{ - this->point( vertices[max_length_edge] ), - this->point( vertices[next] ) } }; - for( const auto v : LIndices{ vertices } ) - { - if( v == max_length_edge || v == next ) - { - continue; - } - if( point_line_distance( this->point( vertices[v] ), line ) - > GLOBAL_EPSILON ) - { - return false; - } - } - return true; + check_polygon_id( *this, polygon_id ); + return this->polygon( polygon_id ).is_degenerated(); } template < index_t dimension > diff --git a/src/geode/mesh/helpers/convert_surface_mesh.cpp b/src/geode/mesh/helpers/convert_surface_mesh.cpp index 2c390bf12..68778a653 100644 --- a/src/geode/mesh/helpers/convert_surface_mesh.cpp +++ b/src/geode/mesh/helpers/convert_surface_mesh.cpp @@ -23,11 +23,10 @@ #include -#include - #include #include +#include #include #include @@ -42,21 +41,6 @@ #include #include -namespace mapbox -{ - namespace util - { - template < std::size_t coord, geode::index_t dimension > - struct nth< coord, geode::Point< dimension > > - { - inline static auto get( const geode::Point< dimension >& point ) - { - return point.value( coord ); - }; - }; - } // namespace util -} // namespace mapbox - namespace { template < geode::index_t dimension > @@ -289,50 +273,6 @@ namespace *surface, *builder, grid, cells_to_densify ); return surface; } - - template < geode::index_t dimension > - std::array< absl::FixedArray< geode::Point2D >, 1 > polygon_points( - const geode::SurfaceMesh< dimension >& surface, - geode::index_t polygon_id, - absl::Span< const geode::index_t > vertices ); - - template <> - std::array< absl::FixedArray< geode::Point2D >, 1 > polygon_points( - const geode::SurfaceMesh< 2 >& surface, - geode::index_t /*unused*/, - absl::Span< const geode::index_t > vertices ) - { - std::array< absl::FixedArray< geode::Point2D >, 1 > polygons{ - absl::FixedArray< geode::Point2D >( vertices.size() ) - }; - auto& polygon = polygons[0]; - for( const auto v : geode::LIndices{ vertices } ) - { - polygon[v] = surface.point( vertices[v] ); - } - return polygons; - } - - template <> - std::array< absl::FixedArray< geode::Point2D >, 1 > polygon_points( - const geode::SurfaceMesh< 3 >& surface, - geode::index_t polygon_id, - absl::Span< const geode::index_t > vertices ) - { - std::array< absl::FixedArray< geode::Point2D >, 1 > polygons{ - absl::FixedArray< geode::Point2D >( vertices.size() ) - }; - auto& polygon = polygons[0]; - const auto normal = surface.polygon_normal( polygon_id ) - .value_or( geode::Vector3D{ { 0, 0, 1 } } ); - const auto axis_to_remove = normal.most_meaningful_axis(); - for( const auto v : geode::LIndices{ vertices } ) - { - polygon[v] = - surface.point( vertices[v] ).project_point( axis_to_remove ); - } - return polygons; - } } // namespace namespace geode @@ -428,18 +368,14 @@ namespace geode adj.value() ); } } - const auto polygons = ::polygon_points( surface, p, vertices ); - const auto new_triangles = - mapbox::earcut< index_t >( polygons ); + const auto new_triangles = surface.polygon( p ).triangulate(); absl::FixedArray< index_t > new_polygons( - new_triangles.size() / 3 ); + new_triangles.size() ); for( const auto trgl : LIndices{ new_polygons } ) { - const std::array triangle{ - vertices[new_triangles[3 * trgl]], - vertices[new_triangles[3 * trgl + 1]], - vertices[new_triangles[3 * trgl + 2]] - }; + const auto& new_triangle = new_triangles[trgl]; + const std::array triangle{ vertices[new_triangle[0]], + vertices[new_triangle[1]], vertices[new_triangle[2]] }; new_polygons[trgl] = builder.create_polygon( triangle ); for( const auto e : LRange{ 3 } ) { diff --git a/tests/mesh/test-convert-surface.cpp b/tests/mesh/test-convert-surface.cpp index 2393e578d..e51f5b67b 100644 --- a/tests/mesh/test-convert-surface.cpp +++ b/tests/mesh/test-convert-surface.cpp @@ -111,7 +111,8 @@ void triangulate_surface() geode::triangulate_surface_mesh( *surface, *builder ); geode::save_polygonal_surface( *surface, "triangulated_surface.og_psf3d" ); OPENGEODE_EXCEPTION( surface->nb_polygons() == 9, - "[Test] Number of polygons in TriangulatedSurface3D is not correct" ); + "[Test] Number of polygons in TriangulatedSurface3D is not correct: ", + surface->nb_polygons() ); } void test()