Changes after Surface_reconstruction_points_3/Point_set_processing_3 submission review by AF (12):

Moved keep_largest_connected_components() to HalfedgeDS_decorator and Polyhedron_3 classes.
This commit is contained in:
Laurent Saboret 2009-06-15 13:09:47 +00:00
parent 4a71c24908
commit 94690fd34f
18 changed files with 374 additions and 466 deletions

View File

@ -3,7 +3,7 @@
% +------------------------------------------------------------------------+ % +------------------------------------------------------------------------+
% | 22.03.1999 Lutz Kettner % | 22.03.1999 Lutz Kettner
% | Package: HalfedgeDS % | Package: HalfedgeDS
% | % |
\RCSdef{\RCSHalfedgeDSdecoratorRev}{$Id$} \RCSdef{\RCSHalfedgeDSdecoratorRev}{$Id$}
\RCSdefDate{\RCSHalfedgeDSdecoratorDate}{$Date$} \RCSdefDate{\RCSHalfedgeDSdecoratorDate}{$Date$}
% +------------------------------------------------------------------------+ % +------------------------------------------------------------------------+
@ -17,7 +17,7 @@
\begin{ccRefClass}{HalfedgeDS_decorator<HDS>} \begin{ccRefClass}{HalfedgeDS_decorator<HDS>}
\ccDefinition \ccDefinition
The classes \ccc{CGAL::HalfedgeDS_items_decorator<HDS>}, The classes \ccc{CGAL::HalfedgeDS_items_decorator<HDS>},
\ccc{CGAL::HalfedgeDS_decorator<HDS>}, and \ccc{CGAL::HalfedgeDS_decorator<HDS>}, and
\ccc{CGAL::HalfedgeDS_const_decorator<HDS>} provide additional functions \ccc{CGAL::HalfedgeDS_const_decorator<HDS>} provide additional functions
@ -90,7 +90,7 @@ incidence relations except if mentioned otherwise.
\ccMethod{void vertices_pop_front();}{ \ccMethod{void vertices_pop_front();}{
removes the first vertex if vertices are supported. removes the first vertex if vertices are supported.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
\ccGlue \ccGlue
\ccMethod{void vertices_pop_back();}{ \ccMethod{void vertices_pop_back();}{
@ -98,17 +98,17 @@ incidence relations except if mentioned otherwise.
\ccGlue \ccGlue
\ccMethod{void vertices_erase( Vertex_handle v);}{ \ccMethod{void vertices_erase( Vertex_handle v);}{
removes the vertex $v$ if vertices are supported. removes the vertex $v$ if vertices are supported.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
\ccGlue \ccGlue
\ccMethod{void vertices_erase( Vertex_handle first, Vertex_handle last);}{ \ccMethod{void vertices_erase( Vertex_handle first, Vertex_handle last);}{
removes the range $[\ccc{first},\ccc{last})$ if vertices removes the range $[\ccc{first},\ccc{last})$ if vertices
are supported. \ccCommentHeading{Requirement} \ccc{Supports_removal} are supported. \ccCommentHeading{Requirement} \ccc{Supports_removal}
$\equiv$ \ccc{CGAL::Tag_true}.} $\equiv$ \ccc{CGAL::Tag_true}.}
\ccMethod{void faces_pop_front();}{ \ccMethod{void faces_pop_front();}{
removes the first face if faces are supported. removes the first face if faces are supported.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
\ccGlue \ccGlue
\ccMethod{void faces_pop_back();}{ \ccMethod{void faces_pop_back();}{
@ -120,7 +120,7 @@ incidence relations except if mentioned otherwise.
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
\ccGlue \ccGlue
\ccMethod{void faces_erase( Face_handle first, Face_handle last);}{ \ccMethod{void faces_erase( Face_handle first, Face_handle last);}{
removes the range $[\ccc{first},\ccc{last})$ if faces are removes the range $[\ccc{first},\ccc{last})$ if faces are
supported. \ccCommentHeading{Requirement} \ccc{Supports_removal} supported. \ccCommentHeading{Requirement} \ccc{Supports_removal}
$\equiv$ \ccc{CGAL::Tag_true}.} $\equiv$ \ccc{CGAL::Tag_true}.}
@ -129,18 +129,24 @@ incidence relations except if mentioned otherwise.
incident to the face into border edges or removes them from the incident to the face into border edges or removes them from the
halfedge data structure if they were already border edges. If this halfedge data structure if they were already border edges. If this
creates isolated vertices they get removed as well. See creates isolated vertices they get removed as well. See
\ccc{make_hole(h)} for a more specialized variant. \ccc{make_hole(h)} for a more specialized variant.
\ccPrecond \ccc{h->is_border() == false}. \ccPrecond \ccc{h->is_border() == false}.
\ccCommentHeading{Requirement} If faces are supported, \ccCommentHeading{Requirement} If faces are supported,
\ccc{Supports_removal} $\equiv$ \ccc{CGAL::Tag_true}.} \ccc{Supports_removal} $\equiv$ \ccc{CGAL::Tag_true}.}
\ccMethod{void erase_connected_component( Halfedge_handle h);} \ccMethod{void erase_connected_component( Halfedge_handle h);}
{removes the vertices, halfedges, and faces that belong to the {removes the vertices, halfedges, and faces that belong to the
connected component of $h$. \ccPrecond For all halfedges $g$ in the connected component of $h$. \ccPrecond For all halfedges $g$ in the
connected component \ccc{g.next() != Halfedge_handle()}. connected component \ccc{g.next() != Halfedge_handle()}.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
\ccMethod{unsigned int keep_largest_connected_components(unsigned int nb_components_to_keep);}
{Erases the small connected components and the isolated vertices.
Keep \ccc{nb_components_to_keep} largest connected components.
Returns the number of connected components erased (ignoring isolated vertices).
\ccCommentHeading{Requirement} supports vertices, halfedges, and removal operation.}
% ----------------------------------------- % -----------------------------------------
\ccHeading{Modifying Functions (For Border Halfedges)} \ccHeading{Modifying Functions (For Border Halfedges)}
@ -148,8 +154,8 @@ incidence relations except if mentioned otherwise.
\ccMethod{Halfedge_handle make_hole( Halfedge_handle h);} \ccMethod{Halfedge_handle make_hole( Halfedge_handle h);}
{removes the face incident to \ccc{h} from \ccc{hds} and creates a hole. {removes the face incident to \ccc{h} from \ccc{hds} and creates a hole.
\ccPrecond \ccc{h != Halfedge_handle()} and \ccc{!(h->is_border())}. \ccPrecond \ccc{h != Halfedge_handle()} and \ccc{!(h->is_border())}.
\ccCommentHeading{Requirement} If faces are supported, \ccCommentHeading{Requirement} If faces are supported,
\ccc{Supports_removal} $\equiv$ \ccc{CGAL::Tag_true}.} \ccc{Supports_removal} $\equiv$ \ccc{CGAL::Tag_true}.}
\ccMethod{Halfedge_handle fill_hole( Halfedge_handle h);} \ccMethod{Halfedge_handle fill_hole( Halfedge_handle h);}
@ -162,27 +168,27 @@ incidence relations except if mentioned otherwise.
Returns \ccc{h}. Returns \ccc{h}.
\ccPrecond \ccc{h != Halfedge_handle()} and \ccc{h->is_border()}.} \ccPrecond \ccc{h != Halfedge_handle()} and \ccc{h->is_border()}.}
\ccMethod{Halfedge_handle add_face_to_border( Halfedge_handle h, \ccMethod{Halfedge_handle add_face_to_border( Halfedge_handle h,
Halfedge_handle g);} Halfedge_handle g);}
{extends the surface with a new face from \ccc{hds} into the hole {extends the surface with a new face from \ccc{hds} into the hole
incident to $h$ and $g$. It creates a new edge connecting the vertex incident to $h$ and $g$. It creates a new edge connecting the vertex
denoted by $g$ with the vertex denoted by $h$ and fills this separated denoted by $g$ with the vertex denoted by $h$ and fills this separated
part of the hole with a new face, such that the new face is incident part of the hole with a new face, such that the new face is incident
to $g$. Returns the new halfedge that is incident to the new face. to $g$. Returns the new halfedge that is incident to the new face.
\ccPrecond \ccc{h != Halfedge_handle()}, \ccc{g != Halfedge_handle()}, \ccPrecond \ccc{h != Halfedge_handle()}, \ccc{g != Halfedge_handle()},
\ccc{h->is_border()}, \ccc{g->is_border()} and $g$ can be reached \ccc{h->is_border()}, \ccc{g->is_border()} and $g$ can be reached
along the hole starting with $h$.} along the hole starting with $h$.}
\ccMethod{Halfedge_handle add_face_to_border( Halfedge_handle h, \ccMethod{Halfedge_handle add_face_to_border( Halfedge_handle h,
Halfedge_handle g, Halfedge_handle g,
const Face& f);} const Face& f);}
{extends the surface with a copy of face $f$ into the hole {extends the surface with a copy of face $f$ into the hole
incident to $h$ and $g$. It creates a new edge connecting the tip of incident to $h$ and $g$. It creates a new edge connecting the tip of
$g$ with the tip of $h$ and fills this separated part of the hole with a $g$ with the tip of $h$ and fills this separated part of the hole with a
copy of face $f$, such that the new face is incident to $g$. Returns copy of face $f$, such that the new face is incident to $g$. Returns
the new halfedge that is incident to the new face. the new halfedge that is incident to the new face.
\ccPrecond \ccc{h != Halfedge_handle()}, \ccc{g != Halfedge_handle()}, \ccPrecond \ccc{h != Halfedge_handle()}, \ccc{g != Halfedge_handle()},
\ccc{h->is_border()}, \ccc{g->is_border()} and $g$ can be reached \ccc{h->is_border()}, \ccc{g->is_border()} and $g$ can be reached
along the hole starting with $h$.} along the hole starting with $h$.}
% ----------------------------------------- % -----------------------------------------
@ -192,14 +198,14 @@ incidence relations except if mentioned otherwise.
The following Euler operations modify consistently the combinatorial The following Euler operations modify consistently the combinatorial
structure of the halfedge data structure. The geometry remains unchanged. structure of the halfedge data structure. The geometry remains unchanged.
Note that well known graph operations are also captured with these Note that well known graph operations are also captured with these
Euler operators, for example an edge contraction is equal to a Euler operators, for example an edge contraction is equal to a
\ccc{join_vertex()} operation, or an edge removal to \ccc{join_face()}. \ccc{join_vertex()} operation, or an edge removal to \ccc{join_face()}.
Given a halfedge data structure \ccc{hds} and a halfedge handle $h$ Given a halfedge data structure \ccc{hds} and a halfedge handle $h$
four special applications of the Euler operators are worth mentioning: four special applications of the Euler operators are worth mentioning:
\ccc{split_vertex(h,h)} results in an antenna emanating from the tip \ccc{split_vertex(h,h)} results in an antenna emanating from the tip
of \ccc{h}; \ccc{split_vertex(h,h->next()->opposite())} results in an edge of \ccc{h}; \ccc{split_vertex(h,h->next()->opposite())} results in an edge
split of the halfedge \ccc{h->next} with a new vertex in-between; split of the halfedge \ccc{h->next} with a new vertex in-between;
\ccc{split_face(h,h)} results in a loop directly following \ccc{h}; \ccc{split_face(h,h)} results in a loop directly following \ccc{h};
and \ccc{split_face(h,h->next())} results in a bridge parallel to and \ccc{split_face(h,h->next())} results in a bridge parallel to
@ -224,9 +230,9 @@ the halfedge \ccc{h->next} with a new face in-between.
with a new diagonal between the two vertices denoted by \ccc{h} and with a new diagonal between the two vertices denoted by \ccc{h} and
\ccc{g} respectively. The second (new) face obtained from \ccc{g} respectively. The second (new) face obtained from
\ccc{hds} is a copy of the first face. Returns \ccc{h->next()} after the \ccc{hds} is a copy of the first face. Returns \ccc{h->next()} after the
operation, i.e., the new diagonal. The new face is to the right of the operation, i.e., the new diagonal. The new face is to the right of the
new diagonal, the old face is to the left. The time is proportional new diagonal, the old face is to the left. The time is proportional
to the distance from \ccc{h} to \ccc{g} around the face.} to the distance from \ccc{h} to \ccc{g} around the face.}
\ccMethod{Halfedge_handle join_face( Halfedge_handle h);} \ccMethod{Halfedge_handle join_face( Halfedge_handle h);}
{joins the two faces incident to $h$. The face incident to {joins the two faces incident to $h$. The face incident to
@ -250,16 +256,16 @@ the halfedge \ccc{h->next} with a new face in-between.
and connects them with a new edge. The second (new) vertex and connects them with a new edge. The second (new) vertex
obtained from \ccc{hds} is a copy of the first vertex. Returns obtained from \ccc{hds} is a copy of the first vertex. Returns
\ccc{h->next()->opposite()} after the operation, i.e., the new edge \ccc{h->next()->opposite()} after the operation, i.e., the new edge
in the orientation towards the new vertex. The time is proportional in the orientation towards the new vertex. The time is proportional
to the distance from \ccc{h} to \ccc{g} around the vertex.} to the distance from \ccc{h} to \ccc{g} around the vertex.}
\ccMethod{Halfedge_handle join_vertex( Halfedge_handle h);} \ccMethod{Halfedge_handle join_vertex( Halfedge_handle h);}
{joins the two vertices incident to $h$. The vertex denoted by {joins the two vertices incident to $h$. The vertex denoted by
\ccc{h->opposite()} gets removed by \ccc{hds}. Returns the predecessor of \ccc{h->opposite()} gets removed by \ccc{hds}. Returns the predecessor of
$h$ around the vertex, i.e., \ccc{h->opposite()->prev()}. The invariant $h$ around the vertex, i.e., \ccc{h->opposite()->prev()}. The invariant
\ccc{join_vertex( split_vertex( h, g))} returns $h$ \ccc{join_vertex( split_vertex( h, g))} returns $h$
and keeps the polyhedron unchanged. and keeps the polyhedron unchanged.
The time is proportional to the degree of the vertex removed and The time is proportional to the degree of the vertex removed and
the time to compute \ccc{h->prev()} and \ccc{h->opposite()->prev()}. the time to compute \ccc{h->prev()} and \ccc{h->opposite()->prev()}.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
@ -281,30 +287,30 @@ the halfedge \ccc{h->next} with a new face in-between.
\ccMethod{Halfedge_handle create_center_vertex( Halfedge_handle h);} \ccMethod{Halfedge_handle create_center_vertex( Halfedge_handle h);}
{barycentric triangulation of \ccc{h->face()}. Creates a new vertex, {barycentric triangulation of \ccc{h->face()}. Creates a new vertex,
a copy of \ccc{h->vertex()}, and connects it to each vertex incident a copy of \ccc{h->vertex()}, and connects it to each vertex incident
to \ccc{h->face()} splitting \ccc{h->face()} into triangles. to \ccc{h->face()} splitting \ccc{h->face()} into triangles.
\ccc{h} remains incident to the original face, all other triangles \ccc{h} remains incident to the original face, all other triangles
are copies of this face. Returns the halfedge \ccc{h->next()} are copies of this face. Returns the halfedge \ccc{h->next()}
after the operation, i.e., a halfedge pointing to the new vertex. after the operation, i.e., a halfedge pointing to the new vertex.
The time is proportional to the size of the face. The time is proportional to the size of the face.
\ccPrecond \ccc{h} is not a border halfedge.} \ccPrecond \ccc{h} is not a border halfedge.}
\ccMethod{Halfedge_handle erase_center_vertex( Halfedge_handle g);} \ccMethod{Halfedge_handle erase_center_vertex( Halfedge_handle g);}
{reverses \ccc{create_center_vertex}. Erases the {reverses \ccc{create_center_vertex}. Erases the
vertex pointed to by \ccc{g} and all incident halfedges thereby vertex pointed to by \ccc{g} and all incident halfedges thereby
merging all incident faces. Only \ccc{g->face()} remains. merging all incident faces. Only \ccc{g->face()} remains.
The neighborhood of \ccc{g->vertex()} may not be triangulated, The neighborhood of \ccc{g->vertex()} may not be triangulated,
it can have larger faces. Returns the halfedge \ccc{g->prev()}. it can have larger faces. Returns the halfedge \ccc{g->prev()}.
Thus, the invariant \ccc{h == erase_center_vertex( Thus, the invariant \ccc{h == erase_center_vertex(
create_center_vertex(h))} holds if \ccc{h} is not a border halfedge. create_center_vertex(h))} holds if \ccc{h} is not a border halfedge.
The time is proportional to the sum of the size of all incident faces. The time is proportional to the sum of the size of all incident faces.
\ccPrecond None of the incident faces of \ccc{g->vertex()} is \ccPrecond None of the incident faces of \ccc{g->vertex()} is
a hole. There are at least two distinct faces incident a hole. There are at least two distinct faces incident
to the faces that are incident to \ccc{g->vertex()}. (This to the faces that are incident to \ccc{g->vertex()}. (This
prevents the operation from collapsing a volume into two faces prevents the operation from collapsing a volume into two faces
glued together with opposite orientations, such as would glued together with opposite orientations, such as would
happen with any vertex of a tetrahedron.) happen with any vertex of a tetrahedron.)
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
\newpage \newpage
@ -324,14 +330,14 @@ the halfedge \ccc{h->next} with a new face in-between.
</CENTER> </CENTER>
\end{ccHtmlOnly} \end{ccHtmlOnly}
\ccMethod{Halfedge_handle split_loop( Halfedge_handle h, \ccMethod{Halfedge_handle split_loop( Halfedge_handle h,
Halfedge_handle i, Halfedge_handle i,
Halfedge_handle j);} Halfedge_handle j);}
{cuts the halfedge data structure into two parts along the cycle $(h,i,j)$. {cuts the halfedge data structure into two parts along the cycle $(h,i,j)$.
Three new vertices (one copy for each vertex in the cycle) and three Three new vertices (one copy for each vertex in the cycle) and three
new halfedges (one copy for each halfedge in the cycle), and two new new halfedges (one copy for each halfedge in the cycle), and two new
triangles are created. $h,i,j$ will be incident to the first new triangle. triangles are created. $h,i,j$ will be incident to the first new triangle.
The return value will be the halfedge incident to the second new triangle The return value will be the halfedge incident to the second new triangle
which is the copy of \ccc{h-opposite()}. which is the copy of \ccc{h-opposite()}.
\ccPrecond $h,i,j$ denote distinct, consecutive vertices of the \ccPrecond $h,i,j$ denote distinct, consecutive vertices of the
halfedge data structure and form a cycle: i.e., \ccc{h->vertex() == halfedge data structure and form a cycle: i.e., \ccc{h->vertex() ==
@ -339,22 +345,22 @@ the halfedge \ccc{h->next} with a new face in-between.
h->opposite()->vertex()}.} h->opposite()->vertex()}.}
\ccMethod{Halfedge_handle join_loop( Halfedge_handle h, Halfedge_handle g);} \ccMethod{Halfedge_handle join_loop( Halfedge_handle h, Halfedge_handle g);}
{glues the boundary of the two faces denoted by $h$ and $g$ together {glues the boundary of the two faces denoted by $h$ and $g$ together
and returns $h$. Both faces and the vertices along the face denoted and returns $h$. Both faces and the vertices along the face denoted
by $g$ gets removed. Both faces may be holes. The invariant by $g$ gets removed. Both faces may be holes. The invariant
\ccc{join_loop( h, split_loop( h, i, j))} returns $h$ and keeps the \ccc{join_loop( h, split_loop( h, i, j))} returns $h$ and keeps the
data structure unchanged. data structure unchanged.
\ccPrecond The faces denoted by $h$ and $g$ are different and have \ccPrecond The faces denoted by $h$ and $g$ are different and have
equal degree (i.e., number of edges). equal degree (i.e., number of edges).
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
% ----------------------------------------- % -----------------------------------------
\ccHeading{Validness Checks} \ccHeading{Validness Checks}
\ccThree{Halfe}{dge_handlehds.split_f}{} \ccThree{Halfe}{dge_handlehds.split_f}{}
These operations are the same as for These operations are the same as for
\ccc{CGAL::HalfedgeDS_const_decorator<HDS>}. \ccc{CGAL::HalfedgeDS_const_decorator<HDS>}.
\begin{ccTexOnly} \begin{ccTexOnly}
See their documentation on page~\pageref{pageHalfedgeDSconstDecoratorRef}. See their documentation on page~\pageref{pageHalfedgeDSconstDecoratorRef}.

View File

@ -17,7 +17,7 @@
// //
// $URL$ // $URL$
// $Id$ // $Id$
// //
// //
// Author(s) : Lutz Kettner <kettner@mpi-sb.mpg.de> // Author(s) : Lutz Kettner <kettner@mpi-sb.mpg.de>
@ -26,9 +26,13 @@
#include <CGAL/HalfedgeDS_items_decorator.h> #include <CGAL/HalfedgeDS_items_decorator.h>
#include <CGAL/HalfedgeDS_const_decorator.h> #include <CGAL/HalfedgeDS_const_decorator.h>
#include <vector> #include <CGAL/HalfedgeDS_iterator.h>
#include <CGAL/IO/Verbose_ostream.h> #include <CGAL/IO/Verbose_ostream.h>
#include <vector>
#include <map>
#include <list>
CGAL_BEGIN_NAMESPACE CGAL_BEGIN_NAMESPACE
template < class p_HDS > template < class p_HDS >
@ -761,6 +765,53 @@ public:
} }
} }
/// Erases the small connected components and the isolated vertices.
///
/// @commentheading Preconditions:
/// supports vertices, halfedges, and removal operation.
///
/// @commentheading Template Parameters:
/// @param nb_components_to_keep the number of large connected components to keep.
///
/// @return the number of connected components erased (ignoring isolated vertices).
unsigned int keep_largest_connected_components(unsigned int nb_components_to_keep)
{
Assert_compile_time_tag(Supports_removal(), Tag_true());
Assert_compile_time_tag(Supports_vertex_halfedge(), Tag_true());
unsigned int nb_erased_components = 0,
nb_isolated_vertices = 0;
// Gets list of connected components, ordered by size (i.e. number of vertices)
std::vector<Vertex_handle> components;
get_connected_components(std::back_inserter(components));
// Erases all connected components but the largest
while (components.size() > nb_components_to_keep)
{
Vertex_handle vertex = *(components.begin());
// Removes component from list
components.erase(components.begin());
if (vertex->halfedge() != NULL) // if not isolated vertex
{
erase_connected_component(vertex->halfedge());
nb_erased_components++;
}
else // if isolated vertex
{
vertices_erase(vertex);
nb_isolated_vertices++;
}
}
// if (nb_isolated_vertices > 0)
// std::cerr << " Erased " << nb_isolated_vertices << " isolated vertices\n";
return nb_erased_components;
}
// Implementing These Functions. // Implementing These Functions.
// ==================================================== // ====================================================
// Creation of New Elements // Creation of New Elements
@ -829,6 +880,123 @@ private:
hds->faces_pop_back(); hds->faces_pop_back();
} }
/// Helper type for keep_largest_connected_components():
///
/// Possible values of a vertex tag.
enum { tag_free, tag_done };
/// Helper method for keep_largest_connected_components():
///
/// Gets any vertex with tag == tag_free.
///
/// @return a list of pairs (component's size (number of vertices), a vertex of the component),
/// ordered by size.
Vertex_handle get_any_free_vertex(
/*const*/ std::map<Vertex*, int>& tags) ///< container holding the tag of all vertices
{
for (Vertex_iterator it = hds->vertices_begin(); it != hds->vertices_end(); it++)
{
if (tags[&*it] == tag_free)
return it;
}
return NULL;
}
/// Helper method for keep_largest_connected_components():
///
/// Tag a "free" connected component as "done".
///
/// @return the size (number of vertices) of the component.
unsigned int tag_component(
Vertex_handle pSeedVertex, ///< one vertex of the connected component
std::map<Vertex*, int>& tags) ///< container holding the tag of all vertices
{
// Circulator category.
typedef typename Halfedge::Supports_halfedge_prev Supports_prev;
typedef HalfedgeDS_circulator_traits<Supports_prev> Ctr;
typedef typename Ctr::iterator_category circulator_category;
// Circulator around a vertex
typedef I_HalfedgeDS_vertex_circ< Halfedge_handle, circulator_category>
Halfedge_around_vertex_circulator;
unsigned int number_of_vertices = 0; // size (number of vertices) of the component
std::list<Vertex_handle> vertices;
vertices.push_front(pSeedVertex);
while (!vertices.empty())
{
Vertex_handle pVertex = vertices.front();
vertices.pop_front();
// Skip vertex if already done
if (tags[&*pVertex] == tag_done)
continue;
// Mark vertex done
tags[&*pVertex] = tag_done;
number_of_vertices++;
// Add vertex's "free" neighbors to the list
Halfedge_around_vertex_circulator neighbor_cir, neighbor_end;
neighbor_cir = pVertex->vertex_begin();
neighbor_end = neighbor_cir;
CGAL_For_all(neighbor_cir,neighbor_end)
{
Vertex_handle neighbor = neighbor_cir->opposite()->vertex();
if (tags[&*neighbor] == tag_free)
vertices.push_front(neighbor);
}
}
return number_of_vertices;
}
/// Helper method for keep_largest_connected_components():
///
/// Computes the list of all connected components of the polyhedron.
/// Returns it as a list of components ordered by size.
///
/// @commentheading Template Parameters:
/// @param OutputIterator value_type must be Vertex_handle.
template<typename OutputIterator>
void get_connected_components(
OutputIterator output) ///< output iterator over vertex handles
{
// Implementation note:
// We tag vertices instead of halfedges to save a factor 6.
// The drawback is that we require the Polyhedron_3<Traits> to support vertices.
// TODO: replace std::map by a property map to tag vertices.
Assert_compile_time_tag(Supports_halfedge_vertex(), Tag_true());
std::map<Vertex*, int> tags;
// list of all connected components of a polyhedron, ordered by size.
std::multimap<unsigned int, Vertex_handle> components;
// Tag all mesh vertices as "free".
for (Vertex_iterator it = hds->vertices_begin(); it != hds->vertices_end(); it++)
{
tags[&*it] = tag_free;
}
// Record each component
Vertex_handle seed_vertex = NULL;
while((seed_vertex = get_any_free_vertex(tags)) != NULL)
{
// Tag it as "done" and compute its size (number of vertices)
unsigned int number_of_vertices = tag_component(seed_vertex, tags);
// Add component to ordered list
components.insert(std::make_pair(number_of_vertices, seed_vertex));
}
// Copy ordered list to output iterator
typename std::multimap<unsigned int, Vertex_handle>::iterator src;
for (src = components.begin(); src != components.end(); ++src)
*output++ = src->second;
}
// Others // Others
// ---------------------------------- // ----------------------------------
public: public:

View File

@ -3,7 +3,7 @@
% +------------------------------------------------------------------------+ % +------------------------------------------------------------------------+
% | 17.03.1999 Lutz Kettner % | 17.03.1999 Lutz Kettner
% | Package: Polyhedron % | Package: Polyhedron
% | % |
\RCSdef{\RCSPolyhedronRev}{$Id$} \RCSdef{\RCSPolyhedronRev}{$Id$}
\RCSdefDate{\RCSPolyhedronDate}{$Date$} \RCSdefDate{\RCSPolyhedronDate}{$Date$}
% +------------------------------------------------------------------------+ % +------------------------------------------------------------------------+
@ -17,7 +17,7 @@
\begin{ccRefClass}{Polyhedron_3<Traits>} \begin{ccRefClass}{Polyhedron_3<Traits>}
\ccDefinition \ccDefinition
A polyhedral surface \ccClassTemplateName\ consists of vertices $V$, A polyhedral surface \ccClassTemplateName\ consists of vertices $V$,
edges $E$, facets $F$ and an incidence relation on them. Each edge is edges $E$, facets $F$ and an incidence relation on them. Each edge is
represented by two halfedges with opposite orientations. represented by two halfedges with opposite orientations.
@ -105,7 +105,7 @@ template parameters:
\>\ccc{class Alloc = CGAL_ALLOCATOR(int)>}\\ \>\ccc{class Alloc = CGAL_ALLOCATOR(int)>}\\
\ccc{class Polyhedron_3;} \ccc{class Polyhedron_3;}
\end{tabbing} \end{tabbing}
The first parameter requires a model of the \ccc{PolyhedronTraits_3} The first parameter requires a model of the \ccc{PolyhedronTraits_3}
concept as argument, for example \ccc{CGAL::Polyhedron_traits_3}. The concept as argument, for example \ccc{CGAL::Polyhedron_traits_3}. The
second parameter expects a model of the \ccc{PolyhedronItems_3} second parameter expects a model of the \ccc{PolyhedronItems_3}
@ -114,7 +114,7 @@ preselected. The third parameter is a class template. A model of the
\ccc{HalfedgeDS} concept is expected. By default, the class \ccc{HalfedgeDS} concept is expected. By default, the class
\ccc{CGAL::HalfedgeDS_default} is preselected, which is a list based \ccc{CGAL::HalfedgeDS_default} is preselected, which is a list based
implementation of the halfedge data structure. implementation of the halfedge data structure.
The fourth parameter \ccc{Alloc} requires a standard allocator for The fourth parameter \ccc{Alloc} requires a standard allocator for
\stl\ container classes. The \ccc{rebind} mechanism from \ccc{Alloc} \stl\ container classes. The \ccc{rebind} mechanism from \ccc{Alloc}
will be used to create appropriate allocators internally. A default is will be used to create appropriate allocators internally. A default is
provided with the macro \ccc{CGAL_ALLOCATOR(int)} from the provided with the macro \ccc{CGAL_ALLOCATOR(int)} from the
@ -163,11 +163,11 @@ assignable to their non-mutable counterparts. Both circulators are
assignable to the \ccc{Halfedge_iterator}. The iterators are assignable to the \ccc{Halfedge_iterator}. The iterators are
assignable to the respective handle types. Wherever the handles appear assignable to the respective handle types. Wherever the handles appear
in function parameter lists, the corresponding iterators can be used as in function parameter lists, the corresponding iterators can be used as
well. For convenience, the \ccc{Edge_iterator} enumerates every other well. For convenience, the \ccc{Edge_iterator} enumerates every other
halfedge. It is based on the \ccc{CGAL::N_step_adaptor} class. For halfedge. It is based on the \ccc{CGAL::N_step_adaptor} class. For
convenience, the \ccc{Point_iterator} enumerates all points in the polyhedral convenience, the \ccc{Point_iterator} enumerates all points in the polyhedral
surface in the same order as the \ccc{Vertex_iterator}, but with the surface in the same order as the \ccc{Vertex_iterator}, but with the
value type \ccc{Point}. It is based on the \ccc{CGAL::Iterator_project} value type \ccc{Point}. It is based on the \ccc{CGAL::Iterator_project}
adaptor. Similarly, a \ccc{Plane_iterator} is provided. adaptor. Similarly, a \ccc{Plane_iterator} is provided.
\ccNestedType{Vertex_handle}{handle to vertex.} \ccNestedType{Vertex_handle}{handle to vertex.}
@ -249,12 +249,12 @@ supported or not.
\ccc{capacity} changes all iterators and circulators \ccc{capacity} changes all iterators and circulators
might invalidate.} might invalidate.}
\ccMethod{Halfedge_handle make_tetrahedron();}{a tetrahedron is added to the \ccMethod{Halfedge_handle make_tetrahedron();}{a tetrahedron is added to the
polyhedral surface. Returns a halfedge of the tetrahedron.} polyhedral surface. Returns a halfedge of the tetrahedron.}
\ccMethod{Halfedge_handle make_tetrahedron(const Point& p1, \ccMethod{Halfedge_handle make_tetrahedron(const Point& p1,
const Point& p2, const Point& p2,
const Point& p3, const Point& p3,
const Point& p4);}{ const Point& p4);}{
a tetrahedron is added to the polyhedral surface with its a tetrahedron is added to the polyhedral surface with its
vertices initialized to $p_1, p_2, p_3$, and $p_4$. Returns that vertices initialized to $p_1, p_2, p_3$, and $p_4$. Returns that
@ -269,7 +269,7 @@ supported or not.
halfedge of the triangle.} halfedge of the triangle.}
\vspace{-3mm} \vspace{-3mm}
\ccMethod{Halfedge_handle make_triangle(const Point& p1, \ccMethod{Halfedge_handle make_triangle(const Point& p1,
const Point& p2, const Point& p2,
const Point& p3);}{ const Point& p3);}{
a triangle with border edges is added to the polyhedral surface with its a triangle with border edges is added to the polyhedral surface with its
@ -356,7 +356,7 @@ supported or not.
\ccMethod{bool is_pure_triangle() const;}{returns \ccc{true} if all \ccMethod{bool is_pure_triangle() const;}{returns \ccc{true} if all
facets are triangles.} facets are triangles.}
\ccMethod{bool is_pure_quad() const;}{returns \ccc{true} if all \ccMethod{bool is_pure_quad() const;}{returns \ccc{true} if all
facets are quadrilaterals.} facets are quadrilaterals.}
@ -403,7 +403,7 @@ unchanged.
with a new diagonal between the two vertices denoted by \ccc{h} and with a new diagonal between the two vertices denoted by \ccc{h} and
\ccc{g} respectively. The second (new) facet is a copy of the \ccc{g} respectively. The second (new) facet is a copy of the
first facet. Returns \ccc{h->next()} after the first facet. Returns \ccc{h->next()} after the
operation, i.e., the new diagonal. The new face is to the right of the operation, i.e., the new diagonal. The new face is to the right of the
new diagonal, the old face is to the left. The time is new diagonal, the old face is to the left. The time is
proportional to the distance from \ccc{h} to \ccc{g} around the facet. proportional to the distance from \ccc{h} to \ccc{g} around the facet.
\ccPrecond \ccc{h} and \ccc{g} are incident to the same facet. \ccPrecond \ccc{h} and \ccc{g} are incident to the same facet.
@ -419,7 +419,7 @@ unchanged.
facet removed and the time to compute \ccc{h->prev()}. facet removed and the time to compute \ccc{h->prev()}.
\ccPrecond The degree of both vertices incident to $h$ is at least \ccPrecond The degree of both vertices incident to $h$ is at least
three (no antennas). three (no antennas).
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
\begin{ccHtmlOnly} \begin{ccHtmlOnly}
@ -432,35 +432,35 @@ unchanged.
Halfedge_handle g);} Halfedge_handle g);}
{splits the vertex incident to \ccc{h} and \ccc{g} into two vertices, {splits the vertex incident to \ccc{h} and \ccc{g} into two vertices,
the old vertex remains and a new copy is created, the old vertex remains and a new copy is created,
and connects them with a new edge. Let \ccc{hnew} be and connects them with a new edge. Let \ccc{hnew} be
\ccc{h->next()->opposite()} after the split, i.e., a halfedge \ccc{h->next()->opposite()} after the split, i.e., a halfedge
of the new edge. The split regroups the halfedges around the two of the new edge. The split regroups the halfedges around the two
vertices. The halfedge sequence \ccc{hnew}, \ccc{g->next()->opposite()}, vertices. The halfedge sequence \ccc{hnew}, \ccc{g->next()->opposite()},
\ldots, \ccc{h} remains around the old vertex, while the \ldots, \ccc{h} remains around the old vertex, while the
halfedge sequence \ccc{hnew->opposite()}, \ccc{h->next()->opposite()} halfedge sequence \ccc{hnew->opposite()}, \ccc{h->next()->opposite()}
(before the split), \ldots, \ccc{g} is regrouped around the new (before the split), \ldots, \ccc{g} is regrouped around the new
vertex. The split returns \ccc{hnew}, i.e., the new halfedge incident vertex. The split returns \ccc{hnew}, i.e., the new halfedge incident
to the old vertex. The time is proportional to the distance from to the old vertex. The time is proportional to the distance from
\ccc{h} to \ccc{g} around the vertex. \ccc{h} to \ccc{g} around the vertex.
\ccPrecond \ccc{h} and \ccc{g} are incident to the same vertex. \ccPrecond \ccc{h} and \ccc{g} are incident to the same vertex.
\ccc{h != g} (antennas are not allowed). \ccc{h != g} (antennas are not allowed).
\ccCommentHeading{Note} A special application of the split is \ccCommentHeading{Note} A special application of the split is
\ccc{split_vertex(h,h->next()->opposite())} which is equivalent to an \ccc{split_vertex(h,h->next()->opposite())} which is equivalent to an
edge split of the halfedge \ccc{h->next()} that creates a new edge split of the halfedge \ccc{h->next()} that creates a new
vertex on the halfedge \ccc{h->next()}. See also \ccc{split_edge(h)} vertex on the halfedge \ccc{h->next()}. See also \ccc{split_edge(h)}
below.} below.}
\ccMethod{Halfedge_handle join_vertex( Halfedge_handle h);} \ccMethod{Halfedge_handle join_vertex( Halfedge_handle h);}
{joins the two vertices incident to $h$. The vertex denoted by {joins the two vertices incident to $h$. The vertex denoted by
\ccc{h->opposite()} gets removed. Returns the predecessor of \ccc{h->opposite()} gets removed. Returns the predecessor of
$h$ around the vertex, i.e., \ccc{h->opposite()->prev()}. $h$ around the vertex, i.e., \ccc{h->opposite()->prev()}.
The invariant \ccc{join_vertex( split_vertex( h, g))} returns The invariant \ccc{join_vertex( split_vertex( h, g))} returns
$h$ and keeps the polyhedron unchanged. $h$ and keeps the polyhedron unchanged.
The time is proportional to the degree of the vertex removed and The time is proportional to the degree of the vertex removed and
the time to compute \ccc{h->prev()} and \ccc{h->opposite()->prev()}. the time to compute \ccc{h->prev()} and \ccc{h->opposite()->prev()}.
\ccPrecond The size of both facets incident to $h$ is at least \ccPrecond The size of both facets incident to $h$ is at least
four (no multi-edges). four (no multi-edges).
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
\ccMethod{Halfedge_handle split_edge( Halfedge_handle h);}{ \ccMethod{Halfedge_handle split_edge( Halfedge_handle h);}{
@ -468,7 +468,7 @@ unchanged.
that is a copy of \ccc{h->opposite()->vertex()}. Is equivalent to that is a copy of \ccc{h->opposite()->vertex()}. Is equivalent to
\ccc{split_vertex( h->prev(), h->opposite())}. The call of \ccc{prev()} \ccc{split_vertex( h->prev(), h->opposite())}. The call of \ccc{prev()}
can make this method slower than a direct call of \ccc{split_vertex()} can make this method slower than a direct call of \ccc{split_vertex()}
if the previous halfedge is already known and computing it would be if the previous halfedge is already known and computing it would be
costly when the halfedge data structure does not support the \ccc{prev()} costly when the halfedge data structure does not support the \ccc{prev()}
member function. Returns the new halfedge \ccc{hnew} pointing to the member function. Returns the new halfedge \ccc{hnew} pointing to the
inserted vertex. The new halfedge is followed by the old halfedge, i.e., inserted vertex. The new halfedge is followed by the old halfedge, i.e.,
@ -476,7 +476,7 @@ unchanged.
\ccMethod{Halfedge_handle flip_edge( Halfedge_handle h);} \ccMethod{Halfedge_handle flip_edge( Halfedge_handle h);}
{performs an edge flip. It returns $h$ after rotating the edge $h$ one {performs an edge flip. It returns $h$ after rotating the edge $h$ one
vertex in the direction of the face orientation. vertex in the direction of the face orientation.
\ccPrecond \ccc{h != Halfedge_handle()} and both facets incident \ccPrecond \ccc{h != Halfedge_handle()} and both facets incident
to $h$ are triangles.} to $h$ are triangles.}
@ -496,9 +496,9 @@ unchanged.
\ccMethod{Halfedge_handle create_center_vertex( Halfedge_handle h);} \ccMethod{Halfedge_handle create_center_vertex( Halfedge_handle h);}
{barycentric triangulation of \ccc{h->facet()}. Creates a new vertex, {barycentric triangulation of \ccc{h->facet()}. Creates a new vertex,
a copy of \ccc{h->vertex()}, and connects it to each vertex incident a copy of \ccc{h->vertex()}, and connects it to each vertex incident
to \ccc{h->facet()} splitting \ccc{h->facet()} into triangles. to \ccc{h->facet()} splitting \ccc{h->facet()} into triangles.
\ccc{h} remains incident to the original facet, all other triangles \ccc{h} remains incident to the original facet, all other triangles
are copies of this facet. Returns the halfedge \ccc{h->next()} are copies of this facet. Returns the halfedge \ccc{h->next()}
after the operation, i.e., a halfedge pointing to the new vertex. after the operation, i.e., a halfedge pointing to the new vertex.
The time is proportional to the size of the facet. The time is proportional to the size of the facet.
@ -507,15 +507,15 @@ unchanged.
\ccMethod{Halfedge_handle erase_center_vertex( Halfedge_handle g);} \ccMethod{Halfedge_handle erase_center_vertex( Halfedge_handle g);}
{reverses \ccc{create_center_vertex}. Erases the {reverses \ccc{create_center_vertex}. Erases the
vertex pointed to by \ccc{g} and all incident halfedges thereby vertex pointed to by \ccc{g} and all incident halfedges thereby
merging all incident facets. Only \ccc{g->facet()} remains. merging all incident facets. Only \ccc{g->facet()} remains.
The neighborhood of \ccc{g->vertex()} may not be triangulated, The neighborhood of \ccc{g->vertex()} may not be triangulated,
it can have larger facets. Returns the halfedge \ccc{g->prev()}. it can have larger facets. Returns the halfedge \ccc{g->prev()}.
Thus, the invariant \ccc{h == erase_center_vertex( Thus, the invariant \ccc{h == erase_center_vertex(
create_center_vertex(h))} holds if \ccc{h} is not a border halfedge. create_center_vertex(h))} holds if \ccc{h} is not a border halfedge.
The time is proportional to the sum of the size of all incident facets. The time is proportional to the sum of the size of all incident facets.
\ccPrecond None of the incident facets of \ccc{g->vertex()} is \ccPrecond None of the incident facets of \ccc{g->vertex()} is
a hole. There are at least two distinct facets incident a hole. There are at least two distinct facets incident
to the facets that are incident to \ccc{g->vertex()}. (This to the facets that are incident to \ccc{g->vertex()}. (This
prevents the operation from collapsing a volume into two facets prevents the operation from collapsing a volume into two facets
glued together with opposite orientations, such as would glued together with opposite orientations, such as would
happen with any vertex of a tetrahedron.) happen with any vertex of a tetrahedron.)
@ -546,10 +546,10 @@ unchanged.
Halfedge_handle j);} Halfedge_handle j);}
{cuts the polyhedron into two parts along the cycle $(h,i,j)$ (edge \ccc{j} {cuts the polyhedron into two parts along the cycle $(h,i,j)$ (edge \ccc{j}
runs on the backside of the three dimensional figure above). runs on the backside of the three dimensional figure above).
Three new vertices (one copy for each vertex in the cycle) and three Three new vertices (one copy for each vertex in the cycle) and three
new halfedges (one copy for each halfedge in the cycle), and two new new halfedges (one copy for each halfedge in the cycle), and two new
triangles are created. $h,i,j$ will be incident to the first new triangle. triangles are created. $h,i,j$ will be incident to the first new triangle.
The return value will be the halfedge incident to the second new triangle The return value will be the halfedge incident to the second new triangle
which is the copy of \ccc{h-opposite()}. which is the copy of \ccc{h-opposite()}.
\ccPrecond $h,i,j$ denote distinct, consecutive vertices of the \ccPrecond $h,i,j$ denote distinct, consecutive vertices of the
polyhedron and form a cycle: i.e., \ccc{h->vertex() == polyhedron and form a cycle: i.e., \ccc{h->vertex() ==
@ -560,25 +560,25 @@ unchanged.
\ccMethod{Halfedge_handle join_loop( Halfedge_handle h, \ccMethod{Halfedge_handle join_loop( Halfedge_handle h,
Halfedge_handle g);} Halfedge_handle g);}
{glues the boundary of the two facets denoted by $h$ and $g$ together {glues the boundary of the two facets denoted by $h$ and $g$ together
and returns $h$. Both facets and the vertices along the facet denoted and returns $h$. Both facets and the vertices along the facet denoted
by $g$ gets removed. Both facets may be holes. The invariant by $g$ gets removed. Both facets may be holes. The invariant
\ccc{join_loop( h, split_loop( h, i, j))} returns $h$ and keeps the \ccc{join_loop( h, split_loop( h, i, j))} returns $h$ and keeps the
polyhedron unchanged. polyhedron unchanged.
\ccPrecond The facets denoted by $h$ and $g$ are different and have \ccPrecond The facets denoted by $h$ and $g$ are different and have
equal degree (i.e., number of edges). equal degree (i.e., number of edges).
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
% +-----------------------------------+ % +-----------------------------------+
\ccHeading{Modifying Facets and Holes} \ccHeading{Modifying Facets and Holes}
\ccMethod{Halfedge_handle make_hole( Halfedge_handle h);} \ccMethod{Halfedge_handle make_hole( Halfedge_handle h);}
{removes the incident facet of $h$ and changes all halfedges incident {removes the incident facet of $h$ and changes all halfedges incident
to the facet into border edges. Returns $h$. to the facet into border edges. Returns $h$.
See \ccc{erase_facet(h)} for a more generalized variant. See \ccc{erase_facet(h)} for a more generalized variant.
\ccPrecond None of the incident halfedges of the facet is a border edge. \ccPrecond None of the incident halfedges of the facet is a border edge.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
\ccMethod{Halfedge_handle fill_hole( Halfedge_handle h);}{ \ccMethod{Halfedge_handle fill_hole( Halfedge_handle h);}{
@ -596,26 +596,26 @@ unchanged.
\begin{ccHtmlOnly} \begin{ccHtmlOnly}
<CENTER> <CENTER>
<img src="fig/add_facet1.gif" <img src="fig/add_facet1.gif"
alt="Modifying Facets and Holes: add_vertex_and_facet_to_border()"><P> alt="Modifying Facets and Holes: add_vertex_and_facet_to_border()"><P>
</CENTER> </CENTER>
\end{ccHtmlOnly} \end{ccHtmlOnly}
\ccMethod{Halfedge_handle add_vertex_and_facet_to_border( \ccMethod{Halfedge_handle add_vertex_and_facet_to_border(
Halfedge_handle h, Halfedge_handle g);} Halfedge_handle h, Halfedge_handle g);}
{creates a new facet within the hole incident to $h$ {creates a new facet within the hole incident to $h$
and $g$ by connecting the tip of $g$ with the tip of $h$ and $g$ by connecting the tip of $g$ with the tip of $h$
with two new halfedges and a new vertex and filling this separated with two new halfedges and a new vertex and filling this separated
part of the hole with a new facet, such that the new facet is part of the hole with a new facet, such that the new facet is
incident to $g$. Returns the halfedge of the new edge that is incident to $g$. Returns the halfedge of the new edge that is
incident to the new facet and the new vertex. incident to the new facet and the new vertex.
\ccPrecond \ccc{h->is_border()}, \ccc{g->is_border()}, \ccc{h != g}, \ccPrecond \ccc{h->is_border()}, \ccc{g->is_border()}, \ccc{h != g},
and $g$ can be reached along the same hole starting with $h$.} and $g$ can be reached along the same hole starting with $h$.}
\begin{ccHtmlOnly} \begin{ccHtmlOnly}
<CENTER> <CENTER>
<img src="./fig/add_facet2.gif" <img src="./fig/add_facet2.gif"
alt="Modifying Facets and Holes: add_facet_to_border()"><P> alt="Modifying Facets and Holes: add_facet_to_border()"><P>
</CENTER> </CENTER>
\end{ccHtmlOnly} \end{ccHtmlOnly}
@ -625,9 +625,9 @@ unchanged.
{creates a new facet within the hole incident to $h$ and $g$ by {creates a new facet within the hole incident to $h$ and $g$ by
connecting the vertex denoted by $g$ with the vertex denoted by $h$ connecting the vertex denoted by $g$ with the vertex denoted by $h$
with a new halfedge and filling this separated part of the hole with with a new halfedge and filling this separated part of the hole with
a new facet, such that the new facet is incident to $g$. a new facet, such that the new facet is incident to $g$.
Returns the halfedge of the new edge that is incident to the new facet. Returns the halfedge of the new edge that is incident to the new facet.
\ccPrecond \ccc{h->is_border()}, \ccc{g->is_border()}, \ccc{h != g}, \ccPrecond \ccc{h->is_border()}, \ccc{g->is_border()}, \ccc{h != g},
\ccc{h->next() != g}, and $g$ can be reached along the same hole \ccc{h->next() != g}, and $g$ can be reached along the same hole
starting with $h$.} starting with $h$.}
@ -636,20 +636,26 @@ unchanged.
\ccHeading{Erasing} \ccHeading{Erasing}
\ccMethod{void erase_facet( Halfedge_handle h);} \ccMethod{void erase_facet( Halfedge_handle h);}
{removes the incident facet of $h$ and changes all halfedges incident {removes the incident facet of $h$ and changes all halfedges incident
to the facet into border edges or removes them from the to the facet into border edges or removes them from the
polyhedral surface if they were already border edges. polyhedral surface if they were already border edges.
If this creates isolated vertices they get removed as well. If this creates isolated vertices they get removed as well.
See \ccc{make_hole(h)} for a more specialized variant. See \ccc{make_hole(h)} for a more specialized variant.
\ccPrecond \ccc{h->is_border() == false}. \ccCommentHeading{Requirement} \ccPrecond \ccc{h->is_border() == false}. \ccCommentHeading{Requirement}
\ccc{Supports_removal} $\equiv$ \ccc{CGAL::Tag_true}.} \ccc{Supports_removal} $\equiv$ \ccc{CGAL::Tag_true}.}
\ccMethod{void erase_connected_component( Halfedge_handle h);} \ccMethod{void erase_connected_component( Halfedge_handle h);}
{removes the vertices, halfedges, and facets that belong to the {removes the vertices, halfedges, and facets that belong to the
connected component of $h$. connected component of $h$.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$ \ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.} \ccc{CGAL::Tag_true}.}
\ccMethod{unsigned int keep_largest_connected_components(unsigned int nb_components_to_keep);}
{Erases the small connected components and the isolated vertices.
Keep \ccc{nb_components_to_keep} largest connected components.
Returns the number of connected components erased (ignoring isolated vertices).
\ccCommentHeading{Requirement} supports vertices, halfedges, and removal operation.}
\ccMethod{void clear();} \ccMethod{void clear();}
{removes all vertices, halfedges, and facets.} {removes all vertices, halfedges, and facets.}
@ -658,7 +664,7 @@ unchanged.
\ccHeading{Operations with Border Halfedges} \ccHeading{Operations with Border Halfedges}
\begin{ccAdvanced} \begin{ccAdvanced}
Halfedges incident to a hole are called {\em border halfedges}. An Halfedges incident to a hole are called {\em border halfedges}. An
halfedge is a {\em border edge\/} if itself or its opposite halfedge halfedge is a {\em border edge\/} if itself or its opposite halfedge
are border halfedges. The only requirement to work with border are border halfedges. The only requirement to work with border
@ -684,7 +690,7 @@ automatically updated.
{sorts halfedges such that the non-border edges precede the {sorts halfedges such that the non-border edges precede the
border edges. For each border edge the halfedge iterator will border edges. For each border edge the halfedge iterator will
reference the halfedge incident to the facet right before the reference the halfedge incident to the facet right before the
halfedge incident to the hole.} halfedge incident to the hole.}
\ccMethod{size_type size_of_border_halfedges() const;} \ccMethod{size_type size_of_border_halfedges() const;}
{number of border halfedges. {number of border halfedges.
@ -721,7 +727,7 @@ automatically updated.
{reverses facet orientations (incl.\ plane equations if supported).} {reverses facet orientations (incl.\ plane equations if supported).}
\ccMethod{bool is_valid( bool verbose = false, int level = 0) const;} \ccMethod{bool is_valid( bool verbose = false, int level = 0) const;}
{returns \ccc{true} if the polyhedral surface is combinatorially {returns \ccc{true} if the polyhedral surface is combinatorially
consistent. If \ccc{verbose} is \ccc{true}, statistics are consistent. If \ccc{verbose} is \ccc{true}, statistics are
printed to \ccc{cerr}. For \ccc{level == 1} the normalization of the printed to \ccc{cerr}. For \ccc{level == 1} the normalization of the
border edges is checked too. This method checks in particular level 3 of border edges is checked too. This method checks in particular level 3 of
@ -731,7 +737,7 @@ automatically updated.
distinct.} distinct.}
\ccMethod{bool normalized_border_is_valid( bool verbose = false) const;}{% \ccMethod{bool normalized_border_is_valid( bool verbose = false) const;}{%
returns \ccc{true} if the border halfedges are in normalized returns \ccc{true} if the border halfedges are in normalized
representation, which is when enumerating all halfedges with the representation, which is when enumerating all halfedges with the
iterator: The non-border edges precede the border edges and for iterator: The non-border edges precede the border edges and for
border edges, the second halfedge is the border halfedge. The halfedge border edges, the second halfedge is the border halfedge. The halfedge

View File

@ -13,7 +13,7 @@
// //
// $URL$ // $URL$
// $Id$ // $Id$
// //
// //
// Author(s) : Lutz Kettner <kettner@mpi-sb.mpg.de>) // Author(s) : Lutz Kettner <kettner@mpi-sb.mpg.de>)
@ -111,9 +111,9 @@ public:
return Halfedge_around_vertex_const_circulator( this->halfedge()); return Halfedge_around_vertex_const_circulator( this->halfedge());
} }
// the degree of the vertex, i.e., edges emanating from this vertex // the degree of the vertex, i.e., edges emanating from this vertex
std::size_t vertex_degree() const { std::size_t vertex_degree() const {
return this->halfedge()->vertex_degree(); return this->halfedge()->vertex_degree();
} }
size_type degree() const { return vertex_degree(); } //backwards compatible size_type degree() const { return vertex_degree(); } //backwards compatible
@ -286,20 +286,20 @@ public:
HDS::halfedge_handle(this)); HDS::halfedge_handle(this));
} }
// the degree of the incident vertex, i.e., edges emanating from this // the degree of the incident vertex, i.e., edges emanating from this
// vertex // vertex
std::size_t vertex_degree() const { std::size_t vertex_degree() const {
return circulator_size( vertex_begin()); return circulator_size( vertex_begin());
} }
// the degree of the incident facet, i.e., edges on the boundary of this // the degree of the incident facet, i.e., edges on the boundary of this
// facet // facet
std::size_t facet_degree() const { std::size_t facet_degree() const {
return circulator_size( facet_begin()); return circulator_size( facet_begin());
} }
// returns true if the incident vertex has exactly two incident edges // returns true if the incident vertex has exactly two incident edges
bool is_bivalent() const { bool is_bivalent() const {
CGAL_precondition( this != &* (this->next()->opposite())); CGAL_precondition( this != &* (this->next()->opposite()));
return (this == &* (this->next()->opposite()->next()->opposite())); return (this == &* (this->next()->opposite()->next()->opposite()));
} }
@ -410,7 +410,7 @@ public:
return Halfedge_around_facet_const_circulator( this->halfedge()); return Halfedge_around_facet_const_circulator( this->halfedge());
} }
// the degree of the incident facet, i.e., edges on the boundary of this // the degree of the incident facet, i.e., edges on the boundary of this
// facet // facet
std::size_t facet_degree() const {return this->halfedge()->facet_degree();} std::size_t facet_degree() const {return this->halfedge()->facet_degree();}
size_type size() const { return facet_degree(); } // backwards compatible size_type size() const { return facet_degree(); } // backwards compatible
@ -463,7 +463,7 @@ template < class PolyhedronTraits_3,
#ifndef CGAL_CFG_NO_TMPL_IN_TMPL_PARAM #ifndef CGAL_CFG_NO_TMPL_IN_TMPL_PARAM
template < class T, class I, class A> template < class T, class I, class A>
#endif #endif
class T_HDS = HalfedgeDS_default, class T_HDS = HalfedgeDS_default,
class Alloc = CGAL_ALLOCATOR(int)> class Alloc = CGAL_ALLOCATOR(int)>
class Polyhedron_3 { class Polyhedron_3 {
// //
@ -873,7 +873,7 @@ public:
// Combinatorial Predicates // Combinatorial Predicates
bool is_closed() const { bool is_closed() const {
for ( Halfedge_const_iterator i = halfedges_begin(); for ( Halfedge_const_iterator i = halfedges_begin();
i != halfedges_end(); ++i) { i != halfedges_end(); ++i) {
if ( i->is_border()) if ( i->is_border())
@ -883,14 +883,14 @@ public:
} }
private: private:
bool is_pure_bivalent( Tag_true) const { bool is_pure_bivalent( Tag_true) const {
for ( Vertex_const_iterator i = vertices_begin(); for ( Vertex_const_iterator i = vertices_begin();
i != vertices_end(); ++i) i != vertices_end(); ++i)
if ( ! i->is_bivalent()) if ( ! i->is_bivalent())
return false; return false;
return true; return true;
} }
bool is_pure_bivalent( Tag_false) const { bool is_pure_bivalent( Tag_false) const {
for ( Halfedge_const_iterator i = halfedges_begin(); for ( Halfedge_const_iterator i = halfedges_begin();
i != halfedges_end(); ++i) i != halfedges_end(); ++i)
if ( ! i->is_bivalent()) if ( ! i->is_bivalent())
@ -900,19 +900,19 @@ private:
public: public:
// returns true if all vertices have exactly two incident edges // returns true if all vertices have exactly two incident edges
bool is_pure_bivalent() const { bool is_pure_bivalent() const {
return is_pure_bivalent( Supports_vertex_halfedge()); return is_pure_bivalent( Supports_vertex_halfedge());
} }
private: private:
bool is_pure_trivalent( Tag_true) const { bool is_pure_trivalent( Tag_true) const {
for ( Vertex_const_iterator i = vertices_begin(); for ( Vertex_const_iterator i = vertices_begin();
i != vertices_end(); ++i) i != vertices_end(); ++i)
if ( ! i->is_trivalent()) if ( ! i->is_trivalent())
return false; return false;
return true; return true;
} }
bool is_pure_trivalent( Tag_false) const { bool is_pure_trivalent( Tag_false) const {
for ( Halfedge_const_iterator i = halfedges_begin(); for ( Halfedge_const_iterator i = halfedges_begin();
i != halfedges_end(); ++i) i != halfedges_end(); ++i)
if ( ! i->is_trivalent()) if ( ! i->is_trivalent())
@ -922,19 +922,19 @@ private:
public: public:
// returns true if all vertices have exactly three incident edges // returns true if all vertices have exactly three incident edges
bool is_pure_trivalent() const { bool is_pure_trivalent() const {
return is_pure_trivalent( Supports_vertex_halfedge()); return is_pure_trivalent( Supports_vertex_halfedge());
} }
private: private:
bool is_pure_triangle( Tag_true) const { bool is_pure_triangle( Tag_true) const {
for ( Facet_const_iterator i = facets_begin(); for ( Facet_const_iterator i = facets_begin();
i != facets_end(); ++i) i != facets_end(); ++i)
if ( ! i->is_triangle()) if ( ! i->is_triangle())
return false; return false;
return true; return true;
} }
bool is_pure_triangle( Tag_false) const { bool is_pure_triangle( Tag_false) const {
for ( Halfedge_const_iterator i = halfedges_begin(); for ( Halfedge_const_iterator i = halfedges_begin();
i != halfedges_end(); ++i) i != halfedges_end(); ++i)
if ( ! i->is_border() && ! i->is_triangle()) if ( ! i->is_border() && ! i->is_triangle())
@ -944,19 +944,19 @@ private:
public: public:
// returns true if all facets are triangles // returns true if all facets are triangles
bool is_pure_triangle() const { bool is_pure_triangle() const {
return is_pure_triangle( Supports_facet_halfedge()); return is_pure_triangle( Supports_facet_halfedge());
} }
private: private:
bool is_pure_quad( Tag_true) const { bool is_pure_quad( Tag_true) const {
for ( Facet_const_iterator i = facets_begin(); for ( Facet_const_iterator i = facets_begin();
i != facets_end(); ++i) i != facets_end(); ++i)
if ( ! i->is_quad()) if ( ! i->is_quad())
return false; return false;
return true; return true;
} }
bool is_pure_quad( Tag_false) const { bool is_pure_quad( Tag_false) const {
for ( Halfedge_const_iterator i = halfedges_begin(); for ( Halfedge_const_iterator i = halfedges_begin();
i != halfedges_end(); ++i) i != halfedges_end(); ++i)
if ( ! i->is_border() && ! i->is_quad()) if ( ! i->is_border() && ! i->is_quad())
@ -966,7 +966,7 @@ private:
public: public:
// returns true if all facets are quadrilaterals // returns true if all facets are quadrilaterals
bool is_pure_quad() const { bool is_pure_quad() const {
return is_pure_quad( Supports_facet_halfedge()); return is_pure_quad( Supports_facet_halfedge());
} }
@ -1376,6 +1376,21 @@ public:
D.erase_connected_component(h); D.erase_connected_component(h);
} }
/// Erases the small connected components and the isolated vertices.
///
/// @commentheading Preconditions:
/// supports vertices, halfedges, and removal operation.
///
/// @commentheading Template Parameters:
/// @param nb_components_to_keep the number of large connected components to keep.
///
/// @return the number of connected components erased (ignoring isolated vertices).
unsigned int keep_largest_connected_components(unsigned int nb_components_to_keep)
{
HalfedgeDS_decorator<HDS> D(hds);
return D.keep_largest_connected_components(nb_components_to_keep);
}
void clear() { hds.clear(); } void clear() { hds.clear(); }
// removes all vertices, halfedges, and facets. // removes all vertices, halfedges, and facets.

View File

@ -214,7 +214,7 @@ typename Poly::Halfedge_handle make_cube_3( Poly& P) {
h->next()->vertex()->point() = Point( 1, 0, 1); h->next()->vertex()->point() = Point( 1, 0, 1);
g->next()->vertex()->point() = Point( 0, 1, 1); g->next()->vertex()->point() = Point( 0, 1, 1);
g->opposite()->vertex()->point() = Point( 1, 1, 0); // Fig. (c) g->opposite()->vertex()->point() = Point( 1, 1, 0); // Fig. (c)
Halfedge_handle f = P.split_facet( g->next(), Halfedge_handle f = P.split_facet( g->next(),
g->next()->next()->next()); // Fig. (d) g->next()->next()->next()); // Fig. (d)
Halfedge_handle e = P.split_edge( f); Halfedge_handle e = P.split_edge( f);
e->vertex()->point() = Point( 1, 1, 1); // Fig. (e) e->vertex()->point() = Point( 1, 1, 1); // Fig. (e)
@ -425,10 +425,10 @@ void test_Polyhedron() {
CGAL_assertion( h->facet_degree() == 3); CGAL_assertion( h->facet_degree() == 3);
CGAL_assertion( h->facet()->facet_degree() == 3); CGAL_assertion( h->facet()->facet_degree() == 3);
CGAL_assertion( P.is_pure_triangle()); CGAL_assertion( P.is_pure_triangle());
CGAL_assertion( 2 == halfedgeds_connected_components(P, CGAL_assertion( 2 == halfedgeds_connected_components(P,
CGAL::Emptyset_iterator())); CGAL::Emptyset_iterator()));
CGAL_assertion_code( const Polyhedron& Pq(P);) CGAL_assertion_code( const Polyhedron& Pq(P);)
CGAL_assertion( 2 == halfedgeds_connected_components(Pq, CGAL_assertion( 2 == halfedgeds_connected_components(Pq,
CGAL::Emptyset_iterator())); CGAL::Emptyset_iterator()));
P.normalize_border(); P.normalize_border();
CGAL_assertion( P.is_valid( false, 1)); CGAL_assertion( P.is_valid( false, 1));
@ -594,7 +594,7 @@ void test_Polyhedron() {
CGAL_assertion( P.is_valid()); CGAL_assertion( P.is_valid());
CGAL_assertion( P.is_triangle( h)); CGAL_assertion( P.is_triangle( h));
CGAL_assertion_code( Halfedge_handle g = CGAL_assertion_code( Halfedge_handle g =
P.add_vertex_and_facet_to_border( P.add_vertex_and_facet_to_border(
h->next()->opposite(), h->next()->opposite(),
h->opposite());) h->opposite());)
@ -633,6 +633,14 @@ void test_Polyhedron() {
CGAL_assertion( P.size_of_vertices() == 4); CGAL_assertion( P.size_of_vertices() == 4);
CGAL_assertion( P.size_of_halfedges() == 12); CGAL_assertion( P.size_of_halfedges() == 12);
CGAL_assertion( P.size_of_facets() == 4); CGAL_assertion( P.size_of_facets() == 4);
P.make_triangle();
unsigned int nb_erased_components = P.keep_largest_connected_components(1);
CGAL_assertion( nb_erased_components == 1 );
CGAL_assertion( P.is_valid());
CGAL_assertion( P.is_tetrahedron( g));
CGAL_assertion( P.size_of_vertices() == 4);
CGAL_assertion( P.size_of_halfedges() == 12);
CGAL_assertion( P.size_of_facets() == 4);
P.erase_facet( g); P.erase_facet( g);
CGAL_assertion( P.is_valid()); CGAL_assertion( P.is_valid());
CGAL_assertion( P.size_of_vertices() == 4); CGAL_assertion( P.size_of_vertices() == 4);
@ -1165,7 +1173,7 @@ void test_min_Polyhedron() {
CGAL_assertion( P.is_valid()); CGAL_assertion( P.is_valid());
CGAL_assertion( P.is_triangle( h)); CGAL_assertion( P.is_triangle( h));
CGAL_assertion_code( Halfedge_handle g = CGAL_assertion_code( Halfedge_handle g =
P.add_vertex_and_facet_to_border( P.add_vertex_and_facet_to_border(
h->next()->opposite(), h->next()->opposite(),
h->opposite());) h->opposite());)

View File

@ -26,6 +26,8 @@ endforeach()
# Require packages new or improved since CGAL 3.4 # Require packages new or improved since CGAL 3.4
include_directories (BEFORE ../../../../AABB_tree/include) include_directories (BEFORE ../../../../AABB_tree/include)
include_directories (BEFORE ../../../../Surface_mesher/include) include_directories (BEFORE ../../../../Surface_mesher/include)
include_directories (BEFORE ../../../../Polyhedron/include/)
include_directories (BEFORE ../../../../HalfedgeDS/include/)
include_directories (BEFORE ../../../../Point_set_processing_3/include) include_directories (BEFORE ../../../../Point_set_processing_3/include)
# Include this package's headers first # Include this package's headers first

View File

@ -16,7 +16,6 @@
// This package // This package
#include <CGAL/APSS_reconstruction_function.h> #include <CGAL/APSS_reconstruction_function.h>
#include <CGAL/IO/output_surface_facets_to_polyhedron.h> #include <CGAL/IO/output_surface_facets_to_polyhedron.h>
#include <CGAL/keep_largest_connected_components.h>
// APSS implicit function // APSS implicit function
@ -127,11 +126,11 @@ Polyhedron* APSS_reconstruct(const Point_set& points,
std::cerr << "Erases small connected components...\n"; std::cerr << "Erases small connected components...\n";
unsigned int nb_erased_components = unsigned int nb_erased_components =
CGAL::keep_largest_connected_components(*output_mesh, 1/* keep largest component only*/); output_mesh->keep_largest_connected_components( 1 /* keep largest component only*/ );
// Prints status // Prints status
std::cerr << "Erases small connected components: " << task_timer.time() << " seconds, " std::cerr << "Erases small connected components: " << task_timer.time() << " seconds, "
<< nb_erased_components << " components erased" << nb_erased_components << " component(s) erased"
<< std::endl; << std::endl;
task_timer.reset(); task_timer.reset();

View File

@ -1,6 +1,6 @@
# This is the CMake script for compiling the Surface_reconstruction_points_3 MFC demo. # This is the CMake script for compiling the Surface_reconstruction_points_3 MFC demo.
project( Poisson ) project( Poisson )
CMAKE_MINIMUM_REQUIRED(VERSION 2.4.5) CMAKE_MINIMUM_REQUIRED(VERSION 2.4.5)
@ -13,6 +13,8 @@ endif(COMMAND cmake_policy)
# Require packages new or improved since CGAL 3.4 # Require packages new or improved since CGAL 3.4
include_directories (BEFORE ../../../../AABB_tree/include) include_directories (BEFORE ../../../../AABB_tree/include)
include_directories (BEFORE ../../../../Surface_mesher/include) include_directories (BEFORE ../../../../Surface_mesher/include)
include_directories (BEFORE ../../../../Polyhedron/include/)
include_directories (BEFORE ../../../../HalfedgeDS/include/)
include_directories (BEFORE ../../../../Point_set_processing_3/include) include_directories (BEFORE ../../../../Point_set_processing_3/include)
# Include this package's headers first # Include this package's headers first
@ -25,11 +27,11 @@ if ( CGAL_FOUND )
include( CGAL_CreateSingleSourceCGALProgram ) include( CGAL_CreateSingleSourceCGALProgram )
endif() endif()
# This demo requires MFC # This demo requires MFC
if (MSVC) if (MSVC)
message( STATUS "MFC library found" ) message( STATUS "MFC library found" )
ADD_DEFINITIONS( "-D_AFXDLL" ) ADD_DEFINITIONS( "-D_AFXDLL" )
SET(CMAKE_MFC_FLAG 2) SET(CMAKE_MFC_FLAG 2)
endif() endif()
# This demo requires OpenGL # This demo requires OpenGL
@ -45,7 +47,7 @@ if(OPENGL_FOUND)
link_libraries( ${OPENGL_LIBRARIES} ) link_libraries( ${OPENGL_LIBRARIES} )
endif() endif()
# This demo requires TAUCS # This demo requires TAUCS
find_package(TAUCS) find_package(TAUCS)
if(TAUCS_FOUND) if(TAUCS_FOUND)
include( ${TAUCS_USE_FILE} ) include( ${TAUCS_USE_FILE} )
@ -83,9 +85,9 @@ if(CGAL_FOUND AND MSVC AND OPENGL_FOUND AND TAUCS_FOUND)
# Creates Poisson executable # Creates Poisson executable
ADD_EXECUTABLE(Poisson WIN32 ChildFrm.cpp DialogOptions.cpp director.cpp MainFrm.cpp Poisson.cpp PoissonDoc.cpp PoissonView.cpp Poisson.rc) ADD_EXECUTABLE(Poisson WIN32 ChildFrm.cpp DialogOptions.cpp director.cpp MainFrm.cpp Poisson.cpp PoissonDoc.cpp PoissonView.cpp Poisson.rc)
# Link the executable to CGAL and third-party libraries # Link the executable to CGAL and third-party libraries
if ( CGAL_AUTO_LINK_ENABLED ) if ( CGAL_AUTO_LINK_ENABLED )
target_link_libraries(Poisson ${CGAL_3RD_PARTY_LIBRARIES} ) target_link_libraries(Poisson ${CGAL_3RD_PARTY_LIBRARIES} )
else() else()
target_link_libraries(Poisson ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ) target_link_libraries(Poisson ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} )

View File

@ -30,7 +30,7 @@ The quality of the reconstruction highly depends on both the quality of input no
The radius property should correspond to the local point spacing which can be intuitively defined as the average distance to its {\em natural} one ring neighbors. It defines the {\em surface definition domain} as the union of these balls. Outside this union of balls, the surface is not defined. Therefore, if the balls do not overlap enough, then some holes might appear. If no radius is provided, then they are automatically computed from a basic estimate of the local density based on the 16 nearest neighbors. The radius property should correspond to the local point spacing which can be intuitively defined as the average distance to its {\em natural} one ring neighbors. It defines the {\em surface definition domain} as the union of these balls. Outside this union of balls, the surface is not defined. Therefore, if the balls do not overlap enough, then some holes might appear. If no radius is provided, then they are automatically computed from a basic estimate of the local density based on the 16 nearest neighbors.
APSS reconstruction may create small {\em ghost} connected components close to the reconstructed surface that you should delete with e.g. \ccc{keep_largest_connected_components}(). APSS reconstruction may create small {\em ghost} connected components close to the reconstructed surface that you should delete with e.g. \ccc{Polyhedron_3::keep_largest_connected_components}().
%END-AUTO(\ccDefinition) %END-AUTO(\ccDefinition)
@ -164,7 +164,6 @@ Returns a point located inside the inferred surface.
\ccSeeAlso \ccSeeAlso
\ccRefIdfierPage{CGAL::Poisson_reconstruction_function<GeomTraits, ReconstructionTriangulation_3>} \\ \ccRefIdfierPage{CGAL::Poisson_reconstruction_function<GeomTraits, ReconstructionTriangulation_3>} \\
\ccRefIdfierPage{CGAL::keep_largest_connected_components<Polyhedron>} \\
\ccExample \ccExample

View File

@ -1,7 +1,7 @@
% +------------------------------------------------------------------------+ % +------------------------------------------------------------------------+
% | Reference manual page: Surface_reconstruction_points_3/intro.tex % | Reference manual page: Surface_reconstruction_points_3/intro.tex
% +------------------------------------------------------------------------+ % +------------------------------------------------------------------------+
% | 06.01.2009 Pierre Alliez, Laurent Saboret, Gael Guennebaud, Mariette Yvinec % | 06.01.2009 Pierre Alliez, Laurent Saboret
% | Package: Surface_reconstruction_points_3 % | Package: Surface_reconstruction_points_3
% | % |
% | % |
@ -23,9 +23,3 @@ Note that since reconstruction methods often require pre-processing a point set
\ccRefIdfierPage{CGAL::Poisson_reconstruction_function<GeomTraits, ReconstructionTriangulation_3>} \\ \ccRefIdfierPage{CGAL::Poisson_reconstruction_function<GeomTraits, ReconstructionTriangulation_3>} \\
\ccRefIdfierPage{CGAL::APSS_reconstruction_function<GeomTraits>} \\ \ccRefIdfierPage{CGAL::APSS_reconstruction_function<GeomTraits>} \\
\subsection{Functions}
\ccRefIdfierPage{CGAL::output_surface_facets_to_polyhedron} \\
\ccRefIdfierPage{CGAL::keep_largest_connected_components<Polyhedron>} \\

View File

@ -1,58 +0,0 @@
% +------------------------------------------------------------------------+
% | Reference manual page: keep_largest_connected_components.tex
% +------------------------------------------------------------------------+
% | 16.04.2009 Pierre Alliez, Laurent Saboret, Gael Guennebaud
% | Package: Surface_reconstruction_points_3
% |
\RCSdef{\RCSerasesmallpolyhedronconnectedcomponentsRev}{$Id$}
\RCSdefDate{\RCSerasesmallpolyhedronconnectedcomponentsDate}{$Date$}
% |
\ccRefPageBegin
%%RefPage: end of header, begin of main body
% +------------------------------------------------------------------------+
\begin{ccRefFunction}{keep_largest_connected_components<Polyhedron>}
%% \ccHtmlCrossLink{} %% add further rules for cross referencing links
%% \ccHtmlIndexC[function]{} %% add further index entries
\ccDefinition
\ccc{keep_largest_connected_components<Polyhedron>} erases the small connected components of a polyhedron.
% The section below is automatically generated. Do not edit!
%START-AUTO(\ccDefinition)
% Reduce left margin
\ccThree{123456789012345}{6789012}{}
\ccFunction{template<class Polyhedron> unsigned int keep_largest_connected_components(Polyhedron& polyhedron, unsigned int nb_components_to_keep);}
{
Erases small connected components of a polyhedron.
\ccCommentHeading{Template Parameters} \\
\ccc{Polyhedron}: an instance of \ccc{Polyhedron_3<Traits>} that supports vertices and removal operation. \ccc{nb_components_to_keep}: the number of large connected components to keep.
\ccCommentHeading{Returns} the number of connected components erased.
}
\ccGlue
%END-AUTO(\ccDefinition)
\ccInclude{CGAL/keep_largest_connected_components.h}
\ccSeeAlso
\ccRefIdfierPage{CGAL::Polyhedron_3<Traits>} \\
\ccExample
See \ccc{APSS_reconstruction.cpp} example.
\end{ccRefFunction}
% +------------------------------------------------------------------------+
%%RefPage: end of main body, begin of footer
\ccRefPageEnd
% EOF
% +------------------------------------------------------------------------+

View File

@ -8,8 +8,6 @@
\input{Surface_reconstruction_points_3_ref/intro.tex} \input{Surface_reconstruction_points_3_ref/intro.tex}
\input{Surface_reconstruction_points_3_ref/APSS_reconstruction_function.tex} \input{Surface_reconstruction_points_3_ref/APSS_reconstruction_function.tex}
\input{Surface_reconstruction_points_3_ref/keep_largest_connected_components.tex}
\input{Surface_reconstruction_points_3_ref/output_surface_facets_to_polyhedron.tex}
\input{Surface_reconstruction_points_3_ref/Poisson_reconstruction_function.tex} \input{Surface_reconstruction_points_3_ref/Poisson_reconstruction_function.tex}
%% EOF %% EOF

View File

@ -23,7 +23,6 @@
#include <CGAL/point_set_property_map.h> #include <CGAL/point_set_property_map.h>
#include <CGAL/IO/read_xyz_points.h> #include <CGAL/IO/read_xyz_points.h>
#include <CGAL/IO/output_surface_facets_to_polyhedron.h> #include <CGAL/IO/output_surface_facets_to_polyhedron.h>
#include <CGAL/keep_largest_connected_components.h>
#include "compute_normal.h" #include "compute_normal.h"
@ -273,11 +272,11 @@ int main(int argc, char * argv[])
std::cerr << "Erases small connected components...\n"; std::cerr << "Erases small connected components...\n";
unsigned int nb_erased_components = unsigned int nb_erased_components =
CGAL::keep_largest_connected_components(output_mesh, 1/* keep largest component only*/); output_mesh.keep_largest_connected_components( 1 /* keep largest component only*/ );
// Prints status // Prints status
std::cerr << "Erases small connected components: " << task_timer.time() << " seconds, " std::cerr << "Erases small connected components: " << task_timer.time() << " seconds, "
<< nb_erased_components << " components erased" << nb_erased_components << " component(s) erased"
<< std::endl; << std::endl;
task_timer.reset(); task_timer.reset();

View File

@ -12,6 +12,8 @@ endif(COMMAND cmake_policy)
# Require packages new or improved since CGAL 3.4 # Require packages new or improved since CGAL 3.4
include_directories (BEFORE ../../../Surface_mesher/include/) include_directories (BEFORE ../../../Surface_mesher/include/)
include_directories (BEFORE ../../../Polyhedron/include/)
include_directories (BEFORE ../../../HalfedgeDS/include/)
include_directories (BEFORE ../../../Point_set_processing_3/include/) include_directories (BEFORE ../../../Point_set_processing_3/include/)
# Include this package's headers first # Include this package's headers first

View File

@ -59,7 +59,7 @@ CGAL_BEGIN_NAMESPACE
/// ///
/// APSS reconstruction may create small "ghost" connected components /// APSS reconstruction may create small "ghost" connected components
/// close to the reconstructed surface that you should delete with e.g. /// close to the reconstructed surface that you should delete with e.g.
/// keep_largest_connected_components(). /// Polyhedron_3::keep_largest_connected_components().
/// ///
/// @heading Is Model for the Concepts: /// @heading Is Model for the Concepts:
/// Model of the ImplicitFunction concept. /// Model of the ImplicitFunction concept.

View File

@ -1,233 +0,0 @@
// Copyright (c) 2005-2009 INRIA (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
//
// Author(s) : Laurent Saboret, Pierre Alliez
#ifndef CGAL_POLYHEDRON_CONNECTED_COMPONENTS_H
#define CGAL_POLYHEDRON_CONNECTED_COMPONENTS_H
#include <CGAL/Polyhedron_3.h>
#include <CGAL/point_set_processing_assertions.h>
#include <map>
#include <list>
CGAL_BEGIN_NAMESPACE
// ----------------------------------------------------------------------------
// Private section
// ----------------------------------------------------------------------------
namespace CGALi {
/// Possible values of a vertex tag.
enum { tag_free, tag_done };
/// Gets any vertex with tag == tag_free.
///
/// @commentheading Template Parameters:
/// @param Polyhedron an instance of CGAL::Polyhedron_3<Traits>.
///
/// @return a list of pairs (component's size (number of vertices), a vertex of the component),
/// ordered by size.
template<class Polyhedron>
typename Polyhedron::Vertex_handle
get_any_free_vertex(Polyhedron& polyhedron,
std::map<typename Polyhedron::Vertex*, int>& tags)
{
typedef typename Polyhedron::Vertex_handle Vertex_handle;
typedef typename Polyhedron::Vertex_iterator Vertex_iterator;
for (Vertex_iterator it = polyhedron.vertices_begin();
it != polyhedron.vertices_end();
it++)
{
if (tags[&*it] == tag_free)
return it;
}
return NULL;
}
/// Tag a "free" connected component as "done".
///
/// @commentheading Template Parameters:
/// @param Polyhedron an instance of CGAL::Polyhedron_3<Traits>.
///
/// @return the size (number of vertices) of the component.
template<class Polyhedron>
unsigned int tag_component(Polyhedron& polyhedron,
typename Polyhedron::Vertex_handle pSeedVertex,
std::map<typename Polyhedron::Vertex*, int>& tags)
{
typedef typename Polyhedron::Vertex_handle Vertex_handle;
typedef typename Polyhedron::Vertex_iterator Vertex_iterator;
typedef typename Polyhedron::Halfedge_around_vertex_circulator
Halfedge_around_vertex_circulator;
unsigned int number_of_vertices = 0; // size (number of vertices) of the component
std::list<Vertex_handle> vertices;
vertices.push_front(pSeedVertex);
while (!vertices.empty())
{
Vertex_handle pVertex = vertices.front();
vertices.pop_front();
// Skip vertex if already done
if (tags[&*pVertex] == tag_done)
continue;
// Mark vertex done
tags[&*pVertex] = tag_done;
number_of_vertices++;
// Add vertex's "free" neighbors to the list
Halfedge_around_vertex_circulator neighbor_cir, neighbor_end;
neighbor_cir = pVertex->vertex_begin();
neighbor_end = neighbor_cir;
CGAL_For_all(neighbor_cir,neighbor_end)
{
Vertex_handle neighbor = neighbor_cir->opposite()->vertex();
if (tags[&*neighbor] == tag_free)
vertices.push_front(neighbor);
}
}
return number_of_vertices;
}
} /* namespace CGALi */
// ----------------------------------------------------------------------------
// Public section
// ----------------------------------------------------------------------------
/// Computes the list of all connected components of a polyhedron.
/// Returns it as a list of components ordered by size.
///
/// @commentheading Template Parameters:
/// @param Polyhedron an instance of CGAL::Polyhedron_3<Traits> that supports vertices.
/// @param OutputIterator value_type must be Polyhedron::Vertex_handle.
template<class Polyhedron,
typename OutputIterator>
void
get_polyhedron_connected_components(
Polyhedron& polyhedron, ///< input polyhedron
OutputIterator output) ///< output iterator over vertex handles
{
// Implementation note:
// We tag vertices instead of halfedges to save a factor 6.
// The drawback is that we require the Polyhedron_3<Traits> to support vertices.
// TODO: replace std::map by a property map to tag vertices.
Assert_compile_time_tag(typename Polyhedron::Supports_halfedge_vertex(), Tag_true());
std::map<typename Polyhedron::Vertex*, int> tags;
typedef typename Polyhedron::Vertex_handle Vertex_handle;
typedef typename Polyhedron::Vertex_iterator Vertex_iterator;
// list of all connected components of a polyhedron, ordered by size.
std::multimap<unsigned int, Vertex_handle> components;
// Tag all mesh vertices as "free".
for (Vertex_iterator it = polyhedron.vertices_begin();
it != polyhedron.vertices_end();
it++)
{
tags[&*it] = CGALi::tag_free;
}
// Record each component
Vertex_handle seed_vertex = NULL;
while((seed_vertex = CGALi::get_any_free_vertex(polyhedron, tags)) != NULL)
{
// Tag it as "done" and compute its size (number of vertices)
unsigned int number_of_vertices = CGALi::tag_component(polyhedron, seed_vertex, tags);
// Add component to ordered list
components.insert(std::make_pair(number_of_vertices, seed_vertex));
}
// Copy ordered list to output iterator
typename std::multimap<unsigned int, Vertex_handle>::iterator src;
for (src = components.begin(); src != components.end(); ++src)
*output++ = src->second;
}
/// Erases small connected components of a polyhedron.
///
/// @commentheading Template Parameters:
/// @param Polyhedron an instance of CGAL::Polyhedron_3<Traits> that supports
/// vertices and removal operation.
/// @param nb_components_to_keep the number of large connected components to keep.
///
/// @return the number of connected components erased.
template<class Polyhedron>
unsigned int
keep_largest_connected_components(Polyhedron& polyhedron, unsigned int nb_components_to_keep)
{
Assert_compile_time_tag(typename Polyhedron::Supports_removal(), Tag_true());
typedef typename Polyhedron::Vertex_handle Vertex_handle;
unsigned int nb_erased_components = 0,
nb_isolated_vertices = 0;
// Gets list of connected components, ordered by size (number of vertices)
std::vector<Vertex_handle> components;
CGAL::get_polyhedron_connected_components(polyhedron, std::back_inserter(components));
// Erases all connected components but the largest
while (components.size() > nb_components_to_keep)
{
Vertex_handle vertex = *(components.begin());
// Removes component from list
components.erase(components.begin());
if (vertex->halfedge() != NULL) // if not isolated vertex
{
CGAL_TRACE_STREAM << " Erases connected component\n";
polyhedron.erase_connected_component(vertex->halfedge());
nb_erased_components++;
}
else // if isolated vertex
{
// TODO: erase isolated vertices?
// Note: Polyhedron_3 does not export HalfedgeDS::vertices_erase(Vertex_handle v)
nb_isolated_vertices++;
}
}
if (nb_isolated_vertices > 0)
CGAL_TRACE_STREAM << " Skipped " << nb_isolated_vertices << " isolated vertices\n";
return nb_erased_components;
}
CGAL_END_NAMESPACE
#endif // CGAL_POLYHEDRON_CONNECTED_COMPONENTS_H

View File

@ -23,7 +23,6 @@
#include <CGAL/point_set_property_map.h> #include <CGAL/point_set_property_map.h>
#include <CGAL/IO/read_xyz_points.h> #include <CGAL/IO/read_xyz_points.h>
#include <CGAL/IO/output_surface_facets_to_polyhedron.h> #include <CGAL/IO/output_surface_facets_to_polyhedron.h>
#include <CGAL/keep_largest_connected_components.h>
#include "compute_normal.h" #include "compute_normal.h"
@ -285,12 +284,12 @@ int main(int argc, char * argv[])
std::cerr << "Erases small connected components...\n"; std::cerr << "Erases small connected components...\n";
unsigned int nb_erased_components = unsigned int nb_erased_components =
CGAL::keep_largest_connected_components(output_mesh, 1/* keep largest component only*/); output_mesh.keep_largest_connected_components( 1 /* keep largest component only*/ );
// Prints status // Prints status
/*long*/ memory = CGAL::Memory_sizer().virtual_size(); /*long*/ memory = CGAL::Memory_sizer().virtual_size();
std::cerr << "Erases small connected components: " << task_timer.time() << " seconds, " std::cerr << "Erases small connected components: " << task_timer.time() << " seconds, "
<< nb_erased_components << " components erased, " << nb_erased_components << " component(s) erased, "
<< (memory>>20) << " Mb allocated" << (memory>>20) << " Mb allocated"
<< std::endl; << std::endl;
task_timer.reset(); task_timer.reset();

View File

@ -12,6 +12,8 @@ endif(COMMAND cmake_policy)
# Require packages new or improved since CGAL 3.4 # Require packages new or improved since CGAL 3.4
include_directories (BEFORE ../../../Surface_mesher/include/) include_directories (BEFORE ../../../Surface_mesher/include/)
include_directories (BEFORE ../../../Polyhedron/include/)
include_directories (BEFORE ../../../HalfedgeDS/include/)
include_directories (BEFORE ../../../Point_set_processing_3/include/) include_directories (BEFORE ../../../Point_set_processing_3/include/)
# Include this package's headers first # Include this package's headers first