diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 4e164d49a2d..bf02d8ef034 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -13,6 +13,9 @@ Release date: September 2019 ### IO Streams - **Breaking change:** The API of `CGAL::Color` has been cleaned up. +###3D Boolean Operations on Nef Polyhedra +- Added a function to convert a Nef_polyhedron_3 to a polygon soup: + - `CGAL::convert_nef_to_polygon_soup()` Release 4.14 ------------ diff --git a/Nef_3/doc/Nef_3/CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h b/Nef_3/doc/Nef_3/CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h index 7f074eb22fb..0db3c62a408 100644 --- a/Nef_3/doc/Nef_3/CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h +++ b/Nef_3/doc/Nef_3/CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h @@ -5,9 +5,47 @@ namespace CGAL { /// Note that contrary to `Nef_polyhedron_3::convert_to_polyhedron()`, the output is not triangulated /// (but faces with more than one connected component of the boundary). /// The polygon mesh can be triangulated by setting `triangulate_all_faces` to `true` or by calling the function `triangulate_faces()`. +/// @tparam Nef_polyhedron an object of type `Nef_polyhedron_3`. +/// @tparam Polygon_mesh a model of `MutableFaceGraph` with an internal property map for `CGAL::vertex_point_t`. +/// +/// The points from `nef` to `pm` are converted using +/// `CGAL::Cartesian_converter`. +/// `NefKernel` and `TargetKernel` are deduced using `CGAL::Kernel_traits` +/// from the point type of `nef` and the value type of the vertex_point_map of `tm`. +/// +/// @param nef the input. +/// @param pm the output. +/// @param triangulate_all_faces indicates whether all the faces must be triangulated. +/// /// \pre `Polygon_mesh` must have an internal point property map with value type being `Nef_polyhedron_3::Point_3`. /// \pre `nef.simple()` template void convert_nef_polyhedron_to_polygon_mesh(const Nef_polyhedron& nef, Polygon_mesh& pm, bool triangulate_all_faces = false); + + /// \ingroup PkgNef3IOFunctions + /// Converts an objet of type `Nef_polyhedron_3` into a polygon soup. + /// The polygons can be triangulated by setting `triangulate_all_faces` to `true`. + /// @tparam Nef_polyhedron an object of type `Nef_polyhedron_3`. + /// @tparam PointRange a model of the concept `BackInsertionSequence` + /// whose `value_type` is the point type + /// @tparam PolygonRange a model of the concept + /// `BackInsertionSequence` whose `value_type` is a model of the concept + /// `BackInsertionSequence` whose + /// `value_type` is `std::size_t`. + /// + /// The points from `nef` to `points` are converted using + /// `CGAL::Cartesian_converter`. + /// `NefKernel` and `OutputKernel` are deduced using `CGAL::Kernel_traits` + /// from the point types. + /// + /// @param nef the input. + /// @param points the output points of the soup + /// @param polygons the output polygons of the soup. + /// @param triangulate_all_faces indicates whether all polygons must be triangulated. + template + void convert_nef_polyhedron_to_polygon_soup(const Nef_polyhedron& nef, + PointRange& points, + PolygonRange& polygons, + bool triangulate_all_faces = false); } diff --git a/Nef_3/doc/Nef_3/PackageDescription.txt b/Nef_3/doc/Nef_3/PackageDescription.txt index 1983bd8077e..b8a0ab9c5e1 100644 --- a/Nef_3/doc/Nef_3/PackageDescription.txt +++ b/Nef_3/doc/Nef_3/PackageDescription.txt @@ -60,6 +60,7 @@ a simple OpenGL visualization for debugging and illustrations. \cgalCRPSection{Functions} - `CGAL::OFF_to_nef_3()` - `CGAL::convert_nef_polyhedron_to_polygon_mesh()` +- `CGAL::convert_nef_polyhedron_to_polygon_soup()` - \link PkgNef3IOFunctions `CGAL::operator<<()` \endlink - \link PkgNef3IOFunctions `CGAL::operator>>()` \endlink diff --git a/Nef_3/include/CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h b/Nef_3/include/CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h index 75824666229..909b46148be 100644 --- a/Nef_3/include/CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h +++ b/Nef_3/include/CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h @@ -42,15 +42,17 @@ namespace CGAL{ namespace nef_to_pm{ // Visitor used to collect and index vertices of a shell -template +template struct Shell_vertex_index_visitor { - typedef boost::unordered_map Vertex_index_map; - std::vector& points; + typedef boost::unordered_map< + typename Nef_polyhedron::Vertex_const_handle, std::size_t> Vertex_index_map; + typedef typename PointRange::value_type Point_3; + PointRange& points; Vertex_index_map vertex_indices; const Converter& converter; - Shell_vertex_index_visitor(std::vector& points, const Converter& converter) + Shell_vertex_index_visitor(PointRange& points, const Converter& converter) :points(points), converter(converter) {} @@ -80,16 +82,17 @@ struct FaceInfo2 }; //Visitor used to collect polygons -template +template struct Shell_polygons_visitor { typedef boost::unordered_map Vertex_index_map; + typedef typename PolygonRange::value_type Polygon; Vertex_index_map& vertex_indices; - std::vector< std::vector >& polygons; + PolygonRange& polygons; bool triangulate_all_faces; Shell_polygons_visitor(Vertex_index_map& vertex_indices, - std::vector< std::vector >& polygons, + PolygonRange& polygons, bool triangulate_all_faces) : vertex_indices( vertex_indices ) , polygons(polygons) @@ -146,22 +149,22 @@ struct Shell_polygons_visitor { if (is_marked) { - polygons.push_back( std::vector() ); + polygons.push_back( Polygon() ); polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[2]]); - polygons.push_back( std::vector() ); + polygons.push_back( Polygon() ); polygons.back().push_back(vertex_indices[v[2]]); polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[3]]); } else { - polygons.push_back( std::vector() ); + polygons.push_back( Polygon() ); polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[2]]); - polygons.push_back( std::vector() ); + polygons.push_back( Polygon() ); polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[2]]); polygons.back().push_back(vertex_indices[v[3]]); @@ -171,22 +174,22 @@ struct Shell_polygons_visitor { if (is_marked) { - polygons.push_back( std::vector() ); + polygons.push_back( Polygon() ); polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[3]]); - polygons.push_back( std::vector() ); + polygons.push_back( Polygon() ); polygons.back().push_back(vertex_indices[v[3]]); polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[2]]); } else { - polygons.push_back( std::vector() ); + polygons.push_back( Polygon() ); polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[3]]); polygons.back().push_back(vertex_indices[v[1]]); - polygons.push_back( std::vector() ); + polygons.push_back( Polygon() ); polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[3]]); polygons.back().push_back(vertex_indices[v[2]]); @@ -197,7 +200,7 @@ struct Shell_polygons_visitor case 3: { // create a new polygon - polygons.push_back( std::vector() ); + polygons.push_back( Polygon() ); fc = f->facet_cycles_begin(); se = typename Nef_polyhedron::SHalfedge_const_handle(fc); CGAL_assertion(se!=0); @@ -288,7 +291,7 @@ struct Shell_polygons_visitor queue.pop_back(); if (e.first->info().visited) continue; e.first->info().visited=true; - polygons.resize(polygons.size()+1); + polygons.push_back(Polygon()); if (is_marked) for (int i=2; i>=0; --i) polygons.back().push_back(e.first->vertex(i)->info()); @@ -320,21 +323,21 @@ struct Shell_polygons_visitor {} }; -template +template void collect_polygon_mesh_info( - std::vector& points, - std::vector< std::vector >& polygons, + PointRange& points, + PolygonRange& polygons, Nef_polyhedron& nef, typename Nef_polyhedron::Shell_entry_const_iterator shell, const Converter& converter, bool triangulate_all_faces) { // collect points and set vertex indices - Shell_vertex_index_visitor vertex_index_visitor(points, converter); + Shell_vertex_index_visitor vertex_index_visitor(points, converter); nef.visit_shell_objects(typename Nef_polyhedron::SFace_const_handle(shell), vertex_index_visitor); // collect polygons - Shell_polygons_visitor polygon_visitor( + Shell_polygons_visitor polygon_visitor( vertex_index_visitor.vertex_indices, polygons, triangulate_all_faces); @@ -343,16 +346,18 @@ void collect_polygon_mesh_info( } //end of namespace nef_to_pm -template +template < class Nef_polyhedron, typename PolygonRange, typename PointRange> void convert_nef_polyhedron_to_polygon_soup(const Nef_polyhedron& nef, - std::vector& points, - std::vector< std::vector >& polygons, + PointRange& points, + PolygonRange& polygons, bool triangulate_all_faces = false) { typedef typename Nef_polyhedron::Point_3 Point_3; typedef typename Kernel_traits::Kernel Nef_Kernel; + typedef typename PointRange::value_type Out_Point; + typedef typename Kernel_traits::Kernel Output_kernel; + typedef Cartesian_converter Converter; - typedef typename Output_kernel::Point_3 Out_point; typename Nef_polyhedron::Volume_const_iterator vol_it = nef.volumes_begin(), vol_end = nef.volumes_end(); if ( Nef_polyhedron::Infi_box::extended_kernel() ) ++vol_it; // skip Infi_box @@ -361,23 +366,22 @@ void convert_nef_polyhedron_to_polygon_soup(const Nef_polyhedron& nef, Converter to_output; for (;vol_it!=vol_end;++vol_it) - nef_to_pm::collect_polygon_mesh_info(points, - polygons, - nef, - vol_it->shells_begin(), - to_output, - triangulate_all_faces); + nef_to_pm::collect_polygon_mesh_info(points, + polygons, + nef, + vol_it->shells_begin(), + to_output, + triangulate_all_faces); } template void convert_nef_polyhedron_to_polygon_mesh(const Nef_polyhedron& nef, Polygon_mesh& pm, bool triangulate_all_faces = false) { typedef typename boost::property_traits::type>::value_type PM_Point; - typedef typename Kernel_traits::Kernel PM_Kernel; std::vector points; - std::vector< std::vector > polygons; - convert_nef_polyhedron_to_polygon_soup(nef, points, polygons, triangulate_all_faces); + std::vector > polygons; + convert_nef_polyhedron_to_polygon_soup(nef, points, polygons, triangulate_all_faces); Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, pm); } diff --git a/Nef_3/test/Nef_3/test_nef_to_soup.cpp b/Nef_3/test/Nef_3/test_nef_to_soup.cpp new file mode 100644 index 00000000000..c81a85cd526 --- /dev/null +++ b/Nef_3/test/Nef_3/test_nef_to_soup.cpp @@ -0,0 +1,50 @@ +#include +#include +#include + +#include +#include +#include + +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel EPEC; +typedef CGAL::Exact_predicates_inexact_constructions_kernel EPIC; + +int main() +{ + typedef CGAL::Nef_polyhedron_3< EPEC > Nef_polyhedron; + typedef CGAL::Polyhedron_3< EPEC > Polyhedron; + typedef CGAL::Polyhedron_3< EPIC > PolygonMesh; + typedef typename EPIC::Point_3 Point; + typedef std::list > PolygonRange; + typedef std::list PointRange; + + typename EPEC::RT n, d; + std::istringstream str_n("6369051672525773"); + str_n >> n; + std::istringstream str_d("4503599627370496"); + str_d >> d; + + EPEC::Point_3 p(n, 0, 0, d); + EPEC::Point_3 q(0, n, 0, d); + EPEC::Point_3 r(0, 0, n, d); + EPEC::Point_3 s(0, 0, 0, 1); + + std::cout << " build...\n"; + Polyhedron P; + P.make_tetrahedron( p, q, r, s); + Nef_polyhedron nef( P ); + PointRange points; + PolygonRange polygons; + std::cout << " convert...\n"; + CGAL::convert_nef_polyhedron_to_polygon_soup(nef, points, polygons); + CGAL_assertion(points.size() == 4); + CGAL_assertion(polygons.size() == 4); + PolygonMesh pm; + CGAL::convert_nef_polyhedron_to_polygon_mesh< + Nef_polyhedron, + PolygonMesh>(nef, pm); + + return 0; +} diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h index f1ef6e53093..c64834abc5a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h @@ -44,12 +44,12 @@ namespace Polygon_mesh_processing namespace internal { template + , typename PointRange + , typename PolygonRange> class Polygon_soup_to_polygon_mesh { - const std::vector& _points; - const std::vector& _polygons; + const PointRange& _points; + const PolygonRange& _polygons; typedef typename boost::property_map::type Vpmap; typedef typename boost::property_traits::value_type Point_3; @@ -57,15 +57,17 @@ class Polygon_soup_to_polygon_mesh typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename PolygonRange::value_type Polygon; + typedef typename PointRange::value_type Point; public: /** * The constructor for modifier object. * @param points points of the soup of polygons. - * @param polygons each element in the vector describes a polygon using the index of the points in the vector. + * @param polygons each element in the range describes a polygon using the index of the points in the range. */ - Polygon_soup_to_polygon_mesh(const std::vector& points, - const std::vector& polygons) + Polygon_soup_to_polygon_mesh(const PointRange& points, + const PolygonRange& polygons) : _points(points), _polygons(polygons) { } @@ -195,10 +197,13 @@ public: * @pre the input polygon soup describes a consistently oriented * polygon mesh. * - * @tparam PolygonMesh a model of `MutableFaceGraph` with an internal point property map - * @tparam Point a point type that has an operator `[]` to access coordinates - * @tparam Polygon a `std::vector` containing the indices - * of the points of the face + * @tparam PolygonMesh a model of `MutableFaceGraph` with an internal point + * property map + * @tparam PointRange a model of the concepts `RandomAccessContainer` and + * `BackInsertionSequence` whose value type is the point type + * @tparam PolygonRange a model of the concept `RandomAccessContainer` whose + * `value_type` is a model of the concept `RandomAccessContainer` whose `value_type` is `std::size_t`. + * * @param points points of the soup of polygons * @param polygons each element in the vector describes a polygon using the index of the points in `points` @@ -211,16 +216,16 @@ public: * \sa `CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh()` * */ - template + template void polygon_soup_to_polygon_mesh( - const std::vector& points, - const std::vector& polygons, + const PointRange& points, + const PolygonRange& polygons, PolygonMesh& out) { CGAL_precondition_msg(is_polygon_soup_a_polygon_mesh(polygons), "Input soup needs to be a polygon mesh!"); - internal::Polygon_soup_to_polygon_mesh + internal::Polygon_soup_to_polygon_mesh converter(points, polygons); converter(out); }