Merge pull request #3599 from maxGimeno/Nef_3-Document_Nef_3_to_Polygon_soup-GF

Nef_3 : Document convert_nef_polyhedron_to_polygon_soup-GF
This commit is contained in:
Sébastien Loriot 2019-04-23 09:52:26 +02:00
commit ca755e35a8
6 changed files with 151 additions and 50 deletions

View File

@ -13,6 +13,9 @@ Release date: September 2019
### IO Streams ### IO Streams
- **Breaking change:** The API of `CGAL::Color` has been cleaned up. - **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 Release 4.14
------------ ------------

View File

@ -5,9 +5,47 @@ namespace CGAL {
/// Note that contrary to `Nef_polyhedron_3::convert_to_polyhedron()`, the output is not triangulated /// 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). /// (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()`. /// 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, TargetKernel>`.
/// `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 `Polygon_mesh` must have an internal point property map with value type being `Nef_polyhedron_3::Point_3`.
/// \pre `nef.simple()` /// \pre `nef.simple()`
template <class Nef_polyhedron, class Polygon_mesh> template <class Nef_polyhedron, class Polygon_mesh>
void convert_nef_polyhedron_to_polygon_mesh(const Nef_polyhedron& nef, Polygon_mesh& pm, bool triangulate_all_faces = false); 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, OutputKernel>`.
/// `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 <class Nef_polyhedron, typename PolygonRange, typename PointRange>
void convert_nef_polyhedron_to_polygon_soup(const Nef_polyhedron& nef,
PointRange& points,
PolygonRange& polygons,
bool triangulate_all_faces = false);
} }

View File

@ -60,6 +60,7 @@ a simple OpenGL visualization for debugging and illustrations.
\cgalCRPSection{Functions} \cgalCRPSection{Functions}
- `CGAL::OFF_to_nef_3()` - `CGAL::OFF_to_nef_3()`
- `CGAL::convert_nef_polyhedron_to_polygon_mesh()` - `CGAL::convert_nef_polyhedron_to_polygon_mesh()`
- `CGAL::convert_nef_polyhedron_to_polygon_soup()`
- \link PkgNef3IOFunctions `CGAL::operator<<()` \endlink - \link PkgNef3IOFunctions `CGAL::operator<<()` \endlink
- \link PkgNef3IOFunctions `CGAL::operator>>()` \endlink - \link PkgNef3IOFunctions `CGAL::operator>>()` \endlink

View File

@ -42,15 +42,17 @@ namespace CGAL{
namespace nef_to_pm{ namespace nef_to_pm{
// Visitor used to collect and index vertices of a shell // Visitor used to collect and index vertices of a shell
template<class Nef_polyhedron, class Point_3, class Converter> template<class Nef_polyhedron, class PointRange, class Converter>
struct Shell_vertex_index_visitor struct Shell_vertex_index_visitor
{ {
typedef boost::unordered_map<typename Nef_polyhedron::Vertex_const_handle, std::size_t> Vertex_index_map; typedef boost::unordered_map<
std::vector<Point_3>& points; 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; Vertex_index_map vertex_indices;
const Converter& converter; const Converter& converter;
Shell_vertex_index_visitor(std::vector<Point_3>& points, const Converter& converter) Shell_vertex_index_visitor(PointRange& points, const Converter& converter)
:points(points), converter(converter) :points(points), converter(converter)
{} {}
@ -80,16 +82,17 @@ struct FaceInfo2
}; };
//Visitor used to collect polygons //Visitor used to collect polygons
template <class Nef_polyhedron> template <class Nef_polyhedron, typename PolygonRange>
struct Shell_polygons_visitor struct Shell_polygons_visitor
{ {
typedef boost::unordered_map<typename Nef_polyhedron::Vertex_const_handle, std::size_t> Vertex_index_map; typedef boost::unordered_map<typename Nef_polyhedron::Vertex_const_handle, std::size_t> Vertex_index_map;
typedef typename PolygonRange::value_type Polygon;
Vertex_index_map& vertex_indices; Vertex_index_map& vertex_indices;
std::vector< std::vector<std::size_t> >& polygons; PolygonRange& polygons;
bool triangulate_all_faces; bool triangulate_all_faces;
Shell_polygons_visitor(Vertex_index_map& vertex_indices, Shell_polygons_visitor(Vertex_index_map& vertex_indices,
std::vector< std::vector<std::size_t> >& polygons, PolygonRange& polygons,
bool triangulate_all_faces) bool triangulate_all_faces)
: vertex_indices( vertex_indices ) : vertex_indices( vertex_indices )
, polygons(polygons) , polygons(polygons)
@ -146,22 +149,22 @@ struct Shell_polygons_visitor
{ {
if (is_marked) if (is_marked)
{ {
polygons.push_back( std::vector<std::size_t>() ); polygons.push_back( Polygon() );
polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[0]]);
polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[1]]);
polygons.back().push_back(vertex_indices[v[2]]); polygons.back().push_back(vertex_indices[v[2]]);
polygons.push_back( std::vector<std::size_t>() ); polygons.push_back( Polygon() );
polygons.back().push_back(vertex_indices[v[2]]); polygons.back().push_back(vertex_indices[v[2]]);
polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[0]]);
polygons.back().push_back(vertex_indices[v[3]]); polygons.back().push_back(vertex_indices[v[3]]);
} }
else else
{ {
polygons.push_back( std::vector<std::size_t>() ); polygons.push_back( Polygon() );
polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[1]]);
polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[0]]);
polygons.back().push_back(vertex_indices[v[2]]); polygons.back().push_back(vertex_indices[v[2]]);
polygons.push_back( std::vector<std::size_t>() ); polygons.push_back( Polygon() );
polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[0]]);
polygons.back().push_back(vertex_indices[v[2]]); polygons.back().push_back(vertex_indices[v[2]]);
polygons.back().push_back(vertex_indices[v[3]]); polygons.back().push_back(vertex_indices[v[3]]);
@ -171,22 +174,22 @@ struct Shell_polygons_visitor
{ {
if (is_marked) if (is_marked)
{ {
polygons.push_back( std::vector<std::size_t>() ); polygons.push_back( Polygon() );
polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[0]]);
polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[1]]);
polygons.back().push_back(vertex_indices[v[3]]); polygons.back().push_back(vertex_indices[v[3]]);
polygons.push_back( std::vector<std::size_t>() ); polygons.push_back( Polygon() );
polygons.back().push_back(vertex_indices[v[3]]); polygons.back().push_back(vertex_indices[v[3]]);
polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[1]]);
polygons.back().push_back(vertex_indices[v[2]]); polygons.back().push_back(vertex_indices[v[2]]);
} }
else else
{ {
polygons.push_back( std::vector<std::size_t>() ); polygons.push_back( Polygon() );
polygons.back().push_back(vertex_indices[v[0]]); polygons.back().push_back(vertex_indices[v[0]]);
polygons.back().push_back(vertex_indices[v[3]]); polygons.back().push_back(vertex_indices[v[3]]);
polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[1]]);
polygons.push_back( std::vector<std::size_t>() ); polygons.push_back( Polygon() );
polygons.back().push_back(vertex_indices[v[1]]); polygons.back().push_back(vertex_indices[v[1]]);
polygons.back().push_back(vertex_indices[v[3]]); polygons.back().push_back(vertex_indices[v[3]]);
polygons.back().push_back(vertex_indices[v[2]]); polygons.back().push_back(vertex_indices[v[2]]);
@ -197,7 +200,7 @@ struct Shell_polygons_visitor
case 3: case 3:
{ {
// create a new polygon // create a new polygon
polygons.push_back( std::vector<std::size_t>() ); polygons.push_back( Polygon() );
fc = f->facet_cycles_begin(); fc = f->facet_cycles_begin();
se = typename Nef_polyhedron::SHalfedge_const_handle(fc); se = typename Nef_polyhedron::SHalfedge_const_handle(fc);
CGAL_assertion(se!=0); CGAL_assertion(se!=0);
@ -288,7 +291,7 @@ struct Shell_polygons_visitor
queue.pop_back(); queue.pop_back();
if (e.first->info().visited) continue; if (e.first->info().visited) continue;
e.first->info().visited=true; e.first->info().visited=true;
polygons.resize(polygons.size()+1); polygons.push_back(Polygon());
if (is_marked) if (is_marked)
for (int i=2; i>=0; --i) for (int i=2; i>=0; --i)
polygons.back().push_back(e.first->vertex(i)->info()); polygons.back().push_back(e.first->vertex(i)->info());
@ -320,21 +323,21 @@ struct Shell_polygons_visitor
{} {}
}; };
template <class Point_3, class Nef_polyhedron, class Converter> template <typename PointRange, class Nef_polyhedron, class Converter, typename PolygonRange>
void collect_polygon_mesh_info( void collect_polygon_mesh_info(
std::vector<Point_3>& points, PointRange& points,
std::vector< std::vector<std::size_t> >& polygons, PolygonRange& polygons,
Nef_polyhedron& nef, Nef_polyhedron& nef,
typename Nef_polyhedron::Shell_entry_const_iterator shell, typename Nef_polyhedron::Shell_entry_const_iterator shell,
const Converter& converter, const Converter& converter,
bool triangulate_all_faces) bool triangulate_all_faces)
{ {
// collect points and set vertex indices // collect points and set vertex indices
Shell_vertex_index_visitor<Nef_polyhedron, Point_3, Converter> vertex_index_visitor(points, converter); Shell_vertex_index_visitor<Nef_polyhedron, PointRange, Converter> vertex_index_visitor(points, converter);
nef.visit_shell_objects(typename Nef_polyhedron::SFace_const_handle(shell), vertex_index_visitor); nef.visit_shell_objects(typename Nef_polyhedron::SFace_const_handle(shell), vertex_index_visitor);
// collect polygons // collect polygons
Shell_polygons_visitor<Nef_polyhedron> polygon_visitor( Shell_polygons_visitor<Nef_polyhedron, PolygonRange> polygon_visitor(
vertex_index_visitor.vertex_indices, vertex_index_visitor.vertex_indices,
polygons, polygons,
triangulate_all_faces); triangulate_all_faces);
@ -343,16 +346,18 @@ void collect_polygon_mesh_info(
} //end of namespace nef_to_pm } //end of namespace nef_to_pm
template <class Output_kernel, class Nef_polyhedron> template < class Nef_polyhedron, typename PolygonRange, typename PointRange>
void convert_nef_polyhedron_to_polygon_soup(const Nef_polyhedron& nef, void convert_nef_polyhedron_to_polygon_soup(const Nef_polyhedron& nef,
std::vector<typename Output_kernel::Point_3>& points, PointRange& points,
std::vector< std::vector<std::size_t> >& polygons, PolygonRange& polygons,
bool triangulate_all_faces = false) bool triangulate_all_faces = false)
{ {
typedef typename Nef_polyhedron::Point_3 Point_3; typedef typename Nef_polyhedron::Point_3 Point_3;
typedef typename Kernel_traits<Point_3>::Kernel Nef_Kernel; typedef typename Kernel_traits<Point_3>::Kernel Nef_Kernel;
typedef typename PointRange::value_type Out_Point;
typedef typename Kernel_traits<Out_Point>::Kernel Output_kernel;
typedef Cartesian_converter<Nef_Kernel, Output_kernel> Converter; typedef Cartesian_converter<Nef_Kernel, Output_kernel> Converter;
typedef typename Output_kernel::Point_3 Out_point;
typename Nef_polyhedron::Volume_const_iterator vol_it = nef.volumes_begin(), typename Nef_polyhedron::Volume_const_iterator vol_it = nef.volumes_begin(),
vol_end = nef.volumes_end(); vol_end = nef.volumes_end();
if ( Nef_polyhedron::Infi_box::extended_kernel() ) ++vol_it; // skip Infi_box 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; Converter to_output;
for (;vol_it!=vol_end;++vol_it) for (;vol_it!=vol_end;++vol_it)
nef_to_pm::collect_polygon_mesh_info<Out_point>(points, nef_to_pm::collect_polygon_mesh_info(points,
polygons, polygons,
nef, nef,
vol_it->shells_begin(), vol_it->shells_begin(),
to_output, to_output,
triangulate_all_faces); triangulate_all_faces);
} }
template <class Nef_polyhedron, class Polygon_mesh> template <class Nef_polyhedron, class Polygon_mesh>
void convert_nef_polyhedron_to_polygon_mesh(const Nef_polyhedron& nef, Polygon_mesh& pm, bool triangulate_all_faces = false) void convert_nef_polyhedron_to_polygon_mesh(const Nef_polyhedron& nef, Polygon_mesh& pm, bool triangulate_all_faces = false)
{ {
typedef typename boost::property_traits<typename boost::property_map<Polygon_mesh, vertex_point_t>::type>::value_type PM_Point; typedef typename boost::property_traits<typename boost::property_map<Polygon_mesh, vertex_point_t>::type>::value_type PM_Point;
typedef typename Kernel_traits<PM_Point>::Kernel PM_Kernel;
std::vector<PM_Point> points; std::vector<PM_Point> points;
std::vector< std::vector<std::size_t> > polygons; std::vector<std::vector<std::size_t> > polygons;
convert_nef_polyhedron_to_polygon_soup<PM_Kernel>(nef, points, polygons, triangulate_all_faces); convert_nef_polyhedron_to_polygon_soup(nef, points, polygons, triangulate_all_faces);
Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, pm); Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, pm);
} }

View File

@ -0,0 +1,50 @@
#include <CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Nef_polyhedron_3.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Nef_polyhedron_iostream_3.h>
#include <fstream>
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<std::list<std::size_t> > PolygonRange;
typedef std::list<Point> 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;
}

View File

@ -44,12 +44,12 @@ namespace Polygon_mesh_processing
namespace internal namespace internal
{ {
template <typename PM template <typename PM
, typename Point , typename PointRange
, typename Polygon> , typename PolygonRange>
class Polygon_soup_to_polygon_mesh class Polygon_soup_to_polygon_mesh
{ {
const std::vector<Point>& _points; const PointRange& _points;
const std::vector<Polygon>& _polygons; const PolygonRange& _polygons;
typedef typename boost::property_map<PM, CGAL::vertex_point_t>::type Vpmap; typedef typename boost::property_map<PM, CGAL::vertex_point_t>::type Vpmap;
typedef typename boost::property_traits<Vpmap>::value_type Point_3; typedef typename boost::property_traits<Vpmap>::value_type Point_3;
@ -57,15 +57,17 @@ class Polygon_soup_to_polygon_mesh
typedef typename boost::graph_traits<PM>::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits<PM>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<PM>::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits<PM>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<PM>::face_descriptor face_descriptor; typedef typename boost::graph_traits<PM>::face_descriptor face_descriptor;
typedef typename PolygonRange::value_type Polygon;
typedef typename PointRange::value_type Point;
public: public:
/** /**
* The constructor for modifier object. * The constructor for modifier object.
* @param points points of the soup of polygons. * @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<Point>& points, Polygon_soup_to_polygon_mesh(const PointRange& points,
const std::vector<Polygon>& polygons) const PolygonRange& polygons)
: _points(points), : _points(points),
_polygons(polygons) _polygons(polygons)
{ } { }
@ -195,10 +197,13 @@ public:
* @pre the input polygon soup describes a consistently oriented * @pre the input polygon soup describes a consistently oriented
* polygon mesh. * polygon mesh.
* *
* @tparam PolygonMesh a model of `MutableFaceGraph` with an internal point property map * @tparam PolygonMesh a model of `MutableFaceGraph` with an internal point
* @tparam Point a point type that has an operator `[]` to access coordinates * property map
* @tparam Polygon a `std::vector<std::size_t>` containing the indices * @tparam PointRange a model of the concepts `RandomAccessContainer` and
* of the points of the face * `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 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` * @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()` * \sa `CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh()`
* *
*/ */
template<class PolygonMesh, class Point, class Polygon> template<class PolygonMesh, class PointRange, class PolygonRange>
void polygon_soup_to_polygon_mesh( void polygon_soup_to_polygon_mesh(
const std::vector<Point>& points, const PointRange& points,
const std::vector<Polygon>& polygons, const PolygonRange& polygons,
PolygonMesh& out) PolygonMesh& out)
{ {
CGAL_precondition_msg(is_polygon_soup_a_polygon_mesh(polygons), CGAL_precondition_msg(is_polygon_soup_a_polygon_mesh(polygons),
"Input soup needs to be a polygon mesh!"); "Input soup needs to be a polygon mesh!");
internal::Polygon_soup_to_polygon_mesh<PolygonMesh, Point, Polygon> internal::Polygon_soup_to_polygon_mesh<PolygonMesh, PointRange, PolygonRange>
converter(points, polygons); converter(points, polygons);
converter(out); converter(out);
} }