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
% | Package: HalfedgeDS
% |
% |
\RCSdef{\RCSHalfedgeDSdecoratorRev}{$Id$}
\RCSdefDate{\RCSHalfedgeDSdecoratorDate}{$Date$}
% +------------------------------------------------------------------------+
@ -17,7 +17,7 @@
\begin{ccRefClass}{HalfedgeDS_decorator<HDS>}
\ccDefinition
The classes \ccc{CGAL::HalfedgeDS_items_decorator<HDS>},
\ccc{CGAL::HalfedgeDS_decorator<HDS>}, and
\ccc{CGAL::HalfedgeDS_const_decorator<HDS>} provide additional functions
@ -90,7 +90,7 @@ incidence relations except if mentioned otherwise.
\ccMethod{void vertices_pop_front();}{
removes the first vertex if vertices are supported.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.}
\ccGlue
\ccMethod{void vertices_pop_back();}{
@ -98,17 +98,17 @@ incidence relations except if mentioned otherwise.
\ccGlue
\ccMethod{void vertices_erase( Vertex_handle v);}{
removes the vertex $v$ if vertices are supported.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.}
\ccGlue
\ccMethod{void vertices_erase( Vertex_handle first, Vertex_handle last);}{
removes the range $[\ccc{first},\ccc{last})$ if vertices
are supported. \ccCommentHeading{Requirement} \ccc{Supports_removal}
removes the range $[\ccc{first},\ccc{last})$ if vertices
are supported. \ccCommentHeading{Requirement} \ccc{Supports_removal}
$\equiv$ \ccc{CGAL::Tag_true}.}
\ccMethod{void faces_pop_front();}{
removes the first face if faces are supported.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.}
\ccGlue
\ccMethod{void faces_pop_back();}{
@ -120,7 +120,7 @@ incidence relations except if mentioned otherwise.
\ccc{CGAL::Tag_true}.}
\ccGlue
\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}
$\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
halfedge data structure if they were already border edges. If this
creates isolated vertices they get removed as well. See
\ccc{make_hole(h)} for a more specialized variant.
\ccPrecond \ccc{h->is_border() == false}.
\ccc{make_hole(h)} for a more specialized variant.
\ccPrecond \ccc{h->is_border() == false}.
\ccCommentHeading{Requirement} If faces are supported,
\ccc{Supports_removal} $\equiv$ \ccc{CGAL::Tag_true}.}
\ccMethod{void erase_connected_component( Halfedge_handle h);}
{removes the vertices, halfedges, and faces that belong to the
connected component of $h$. \ccPrecond For all halfedges $g$ in the
{removes the vertices, halfedges, and faces that belong to the
connected component of $h$. \ccPrecond For all halfedges $g$ in the
connected component \ccc{g.next() != Halfedge_handle()}.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\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)}
@ -148,8 +154,8 @@ incidence relations except if mentioned otherwise.
\ccMethod{Halfedge_handle make_hole( Halfedge_handle h);}
{removes the face incident to \ccc{h} from \ccc{hds} and creates a hole.
\ccPrecond \ccc{h != Halfedge_handle()} and \ccc{!(h->is_border())}.
\ccCommentHeading{Requirement} If faces are supported,
\ccPrecond \ccc{h != Halfedge_handle()} and \ccc{!(h->is_border())}.
\ccCommentHeading{Requirement} If faces are supported,
\ccc{Supports_removal} $\equiv$ \ccc{CGAL::Tag_true}.}
\ccMethod{Halfedge_handle fill_hole( Halfedge_handle h);}
@ -162,27 +168,27 @@ incidence relations except if mentioned otherwise.
Returns \ccc{h}.
\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);}
{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
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
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
to $g$. Returns the new halfedge that is incident to the new face.
\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$.}
\ccMethod{Halfedge_handle add_face_to_border( Halfedge_handle h,
\ccMethod{Halfedge_handle add_face_to_border( Halfedge_handle h,
Halfedge_handle g,
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
$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.
\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$.}
% -----------------------------------------
@ -192,14 +198,14 @@ incidence relations except if mentioned otherwise.
The following Euler operations modify consistently the combinatorial
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
\ccc{join_vertex()} operation, or an edge removal to \ccc{join_face()}.
Given a halfedge data structure \ccc{hds} and a halfedge handle $h$
four special applications of the Euler operators are worth mentioning:
\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;
\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
@ -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
\ccc{g} respectively. The second (new) face obtained from
\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
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.}
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
to the distance from \ccc{h} to \ccc{g} around the face.}
\ccMethod{Halfedge_handle join_face( Halfedge_handle h);}
{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
obtained from \ccc{hds} is a copy of the first vertex. Returns
\ccc{h->next()->opposite()} after the operation, i.e., the new edge
in the orientation towards the new vertex. The time is proportional
to the distance from \ccc{h} to \ccc{g} around the vertex.}
in the orientation towards the new vertex. The time is proportional
to the distance from \ccc{h} to \ccc{g} around the vertex.}
\ccMethod{Halfedge_handle join_vertex( Halfedge_handle h);}
{joins the two vertices incident to $h$. The vertex denoted by
\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$
and keeps the polyhedron unchanged.
The time is proportional to the degree of the vertex removed and
and keeps the polyhedron unchanged.
The time is proportional to the degree of the vertex removed and
the time to compute \ccc{h->prev()} and \ccc{h->opposite()->prev()}.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\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);}
{barycentric triangulation of \ccc{h->face()}. Creates a new vertex,
a copy of \ccc{h->vertex()}, and connects it to each vertex incident
to \ccc{h->face()} splitting \ccc{h->face()} into triangles.
\ccc{h} remains incident to the original face, all other triangles
a copy of \ccc{h->vertex()}, and connects it to each vertex incident
to \ccc{h->face()} splitting \ccc{h->face()} into triangles.
\ccc{h} remains incident to the original face, all other triangles
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.
\ccPrecond \ccc{h} is not a border halfedge.}
\ccMethod{Halfedge_handle erase_center_vertex( Halfedge_handle g);}
{reverses \ccc{create_center_vertex}. Erases the
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,
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.
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
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
glued together with opposite orientations, such as would
happen with any vertex of a tetrahedron.)
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.}
\newpage
@ -324,14 +330,14 @@ the halfedge \ccc{h->next} with a new face in-between.
</CENTER>
\end{ccHtmlOnly}
\ccMethod{Halfedge_handle split_loop( Halfedge_handle h,
\ccMethod{Halfedge_handle split_loop( Halfedge_handle h,
Halfedge_handle i,
Halfedge_handle 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
new halfedges (one copy for each halfedge in the cycle), and two new
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
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()}.
\ccPrecond $h,i,j$ denote distinct, consecutive vertices of the
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()}.}
\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
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
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
data structure unchanged.
\ccPrecond The faces denoted by $h$ and $g$ are different and have
equal degree (i.e., number of edges).
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.}
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.}
% -----------------------------------------
\ccHeading{Validness Checks}
\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>}.
\begin{ccTexOnly}
See their documentation on page~\pageref{pageHalfedgeDSconstDecoratorRef}.

View File

@ -17,7 +17,7 @@
//
// $URL$
// $Id$
//
//
//
// Author(s) : Lutz Kettner <kettner@mpi-sb.mpg.de>
@ -26,9 +26,13 @@
#include <CGAL/HalfedgeDS_items_decorator.h>
#include <CGAL/HalfedgeDS_const_decorator.h>
#include <vector>
#include <CGAL/HalfedgeDS_iterator.h>
#include <CGAL/IO/Verbose_ostream.h>
#include <vector>
#include <map>
#include <list>
CGAL_BEGIN_NAMESPACE
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.
// ====================================================
// Creation of New Elements
@ -829,6 +880,123 @@ private:
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
// ----------------------------------
public:

View File

@ -3,7 +3,7 @@
% +------------------------------------------------------------------------+
% | 17.03.1999 Lutz Kettner
% | Package: Polyhedron
% |
% |
\RCSdef{\RCSPolyhedronRev}{$Id$}
\RCSdefDate{\RCSPolyhedronDate}{$Date$}
% +------------------------------------------------------------------------+
@ -17,7 +17,7 @@
\begin{ccRefClass}{Polyhedron_3<Traits>}
\ccDefinition
A polyhedral surface \ccClassTemplateName\ consists of vertices $V$,
edges $E$, facets $F$ and an incidence relation on them. Each edge is
represented by two halfedges with opposite orientations.
@ -105,7 +105,7 @@ template parameters:
\>\ccc{class Alloc = CGAL_ALLOCATOR(int)>}\\
\ccc{class Polyhedron_3;}
\end{tabbing}
The first parameter requires a model of the \ccc{PolyhedronTraits_3}
concept as argument, for example \ccc{CGAL::Polyhedron_traits_3}. The
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{CGAL::HalfedgeDS_default} is preselected, which is a list based
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}
will be used to create appropriate allocators internally. A default is
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 respective handle types. Wherever the handles appear
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
convenience, the \ccc{Point_iterator} enumerates all points in the polyhedral
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}
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}
adaptor. Similarly, a \ccc{Plane_iterator} is provided.
\ccNestedType{Vertex_handle}{handle to vertex.}
@ -249,12 +249,12 @@ supported or not.
\ccc{capacity} changes all iterators and circulators
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.}
\ccMethod{Halfedge_handle make_tetrahedron(const Point& p1,
\ccMethod{Halfedge_handle make_tetrahedron(const Point& p1,
const Point& p2,
const Point& p3,
const Point& p3,
const Point& p4);}{
a tetrahedron is added to the polyhedral surface with its
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.}
\vspace{-3mm}
\ccMethod{Halfedge_handle make_triangle(const Point& p1,
\ccMethod{Halfedge_handle make_triangle(const Point& p1,
const Point& p2,
const Point& p3);}{
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
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.}
@ -403,7 +403,7 @@ unchanged.
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
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
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.
@ -419,7 +419,7 @@ unchanged.
facet removed and the time to compute \ccc{h->prev()}.
\ccPrecond The degree of both vertices incident to $h$ is at least
three (no antennas).
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.}
\begin{ccHtmlOnly}
@ -432,35 +432,35 @@ unchanged.
Halfedge_handle g);}
{splits the vertex incident to \ccc{h} and \ccc{g} into two vertices,
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
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()},
\ldots, \ccc{h} remains around the old vertex, while the
halfedge sequence \ccc{hnew->opposite()}, \ccc{h->next()->opposite()}
\ldots, \ccc{h} remains around the old vertex, while the
halfedge sequence \ccc{hnew->opposite()}, \ccc{h->next()->opposite()}
(before the split), \ldots, \ccc{g} is regrouped around the new
vertex. The split returns \ccc{hnew}, i.e., the new halfedge incident
to the old vertex. The time is proportional to the distance from
vertex. The split returns \ccc{hnew}, i.e., the new halfedge incident
to the old vertex. The time is proportional to the distance from
\ccc{h} to \ccc{g} around the vertex.
\ccPrecond \ccc{h} and \ccc{g} are incident to the same vertex.
\ccc{h != g} (antennas are not allowed).
\ccCommentHeading{Note} A special application of the split is
\ccc{split_vertex(h,h->next()->opposite())} which is equivalent to an
edge split of the halfedge \ccc{h->next()} that creates a new
\ccCommentHeading{Note} A special application of the split is
\ccc{split_vertex(h,h->next()->opposite())} which is equivalent to an
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)}
below.}
\ccMethod{Halfedge_handle join_vertex( Halfedge_handle h);}
{joins the two vertices incident to $h$. The vertex denoted by
\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
$h$ and keeps the polyhedron unchanged.
The time is proportional to the degree of the vertex removed and
$h$ and keeps the polyhedron unchanged.
The time is proportional to the degree of the vertex removed and
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).
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.}
\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
\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()}
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()}
member function. Returns the new halfedge \ccc{hnew} pointing to the
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);}
{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
to $h$ are triangles.}
@ -496,9 +496,9 @@ unchanged.
\ccMethod{Halfedge_handle create_center_vertex( Halfedge_handle h);}
{barycentric triangulation of \ccc{h->facet()}. Creates a new vertex,
a copy of \ccc{h->vertex()}, and connects it to each vertex incident
to \ccc{h->facet()} splitting \ccc{h->facet()} into triangles.
\ccc{h} remains incident to the original facet, all other triangles
a copy of \ccc{h->vertex()}, and connects it to each vertex incident
to \ccc{h->facet()} splitting \ccc{h->facet()} into triangles.
\ccc{h} remains incident to the original facet, all other triangles
are copies of this facet. Returns the halfedge \ccc{h->next()}
after the operation, i.e., a halfedge pointing to the new vertex.
The time is proportional to the size of the facet.
@ -507,15 +507,15 @@ unchanged.
\ccMethod{Halfedge_handle erase_center_vertex( Halfedge_handle g);}
{reverses \ccc{create_center_vertex}. Erases the
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,
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.
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
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
glued together with opposite orientations, such as would
happen with any vertex of a tetrahedron.)
@ -546,10 +546,10 @@ unchanged.
Halfedge_handle 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).
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
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
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()}.
\ccPrecond $h,i,j$ denote distinct, consecutive vertices of the
polyhedron and form a cycle: i.e., \ccc{h->vertex() ==
@ -560,25 +560,25 @@ unchanged.
\ccMethod{Halfedge_handle join_loop( Halfedge_handle h,
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
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
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
polyhedron unchanged.
\ccPrecond The facets denoted by $h$ and $g$ are different and have
equal degree (i.e., number of edges).
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\ccc{CGAL::Tag_true}.}
% +-----------------------------------+
\ccHeading{Modifying Facets and Holes}
\ccMethod{Halfedge_handle make_hole( Halfedge_handle h);}
{removes the incident facet of $h$ and changes all halfedges incident
to the facet into border edges. Returns $h$.
See \ccc{erase_facet(h)} for a more generalized variant.
{removes the incident facet of $h$ and changes all halfedges incident
to the facet into border edges. Returns $h$.
See \ccc{erase_facet(h)} for a more generalized variant.
\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}.}
\ccMethod{Halfedge_handle fill_hole( Halfedge_handle h);}{
@ -596,26 +596,26 @@ unchanged.
\begin{ccHtmlOnly}
<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>
</CENTER>
\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);}
{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
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 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$.}
\begin{ccHtmlOnly}
<CENTER>
<img src="./fig/add_facet2.gif"
<img src="./fig/add_facet2.gif"
alt="Modifying Facets and Holes: add_facet_to_border()"><P>
</CENTER>
\end{ccHtmlOnly}
@ -625,9 +625,9 @@ unchanged.
{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$
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.
\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
starting with $h$.}
@ -636,20 +636,26 @@ unchanged.
\ccHeading{Erasing}
\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
polyhedral surface if they were already border edges.
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}
\ccc{Supports_removal} $\equiv$ \ccc{CGAL::Tag_true}.}
\ccMethod{void erase_connected_component( Halfedge_handle h);}
{removes the vertices, halfedges, and facets that belong to the
connected component of $h$.
{removes the vertices, halfedges, and facets that belong to the
connected component of $h$.
\ccCommentHeading{Requirement} \ccc{Supports_removal} $\equiv$
\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();}
{removes all vertices, halfedges, and facets.}
@ -658,7 +664,7 @@ unchanged.
\ccHeading{Operations with Border Halfedges}
\begin{ccAdvanced}
Halfedges incident to a hole are called {\em border halfedges}. An
halfedge is a {\em border edge\/} if itself or its opposite halfedge
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
border edges. For each border edge the halfedge iterator will
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;}
{number of border halfedges.
@ -721,7 +727,7 @@ automatically updated.
{reverses facet orientations (incl.\ plane equations if supported).}
\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
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
@ -731,7 +737,7 @@ automatically updated.
distinct.}
\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
iterator: The non-border edges precede the border edges and for
border edges, the second halfedge is the border halfedge. The halfedge

View File

@ -13,7 +13,7 @@
//
// $URL$
// $Id$
//
//
//
// Author(s) : Lutz Kettner <kettner@mpi-sb.mpg.de>)
@ -111,9 +111,9 @@ public:
return Halfedge_around_vertex_const_circulator( this->halfedge());
}
// the degree of the vertex, i.e., edges emanating from this vertex
std::size_t vertex_degree() const {
return this->halfedge()->vertex_degree();
// the degree of the vertex, i.e., edges emanating from this vertex
std::size_t vertex_degree() const {
return this->halfedge()->vertex_degree();
}
size_type degree() const { return vertex_degree(); } //backwards compatible
@ -286,20 +286,20 @@ public:
HDS::halfedge_handle(this));
}
// the degree of the incident vertex, i.e., edges emanating from this
// vertex
std::size_t vertex_degree() const {
return circulator_size( vertex_begin());
// the degree of the incident vertex, i.e., edges emanating from this
// vertex
std::size_t vertex_degree() const {
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
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
bool is_bivalent() const {
bool is_bivalent() const {
CGAL_precondition( this != &* (this->next()->opposite()));
return (this == &* (this->next()->opposite()->next()->opposite()));
}
@ -410,7 +410,7 @@ public:
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
std::size_t facet_degree() const {return this->halfedge()->facet_degree();}
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
template < class T, class I, class A>
#endif
class T_HDS = HalfedgeDS_default,
class T_HDS = HalfedgeDS_default,
class Alloc = CGAL_ALLOCATOR(int)>
class Polyhedron_3 {
//
@ -873,7 +873,7 @@ public:
// Combinatorial Predicates
bool is_closed() const {
bool is_closed() const {
for ( Halfedge_const_iterator i = halfedges_begin();
i != halfedges_end(); ++i) {
if ( i->is_border())
@ -883,14 +883,14 @@ public:
}
private:
bool is_pure_bivalent( Tag_true) const {
bool is_pure_bivalent( Tag_true) const {
for ( Vertex_const_iterator i = vertices_begin();
i != vertices_end(); ++i)
if ( ! i->is_bivalent())
return false;
return true;
}
bool is_pure_bivalent( Tag_false) const {
bool is_pure_bivalent( Tag_false) const {
for ( Halfedge_const_iterator i = halfedges_begin();
i != halfedges_end(); ++i)
if ( ! i->is_bivalent())
@ -900,19 +900,19 @@ private:
public:
// 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());
}
private:
bool is_pure_trivalent( Tag_true) const {
bool is_pure_trivalent( Tag_true) const {
for ( Vertex_const_iterator i = vertices_begin();
i != vertices_end(); ++i)
if ( ! i->is_trivalent())
return false;
return true;
}
bool is_pure_trivalent( Tag_false) const {
bool is_pure_trivalent( Tag_false) const {
for ( Halfedge_const_iterator i = halfedges_begin();
i != halfedges_end(); ++i)
if ( ! i->is_trivalent())
@ -922,19 +922,19 @@ private:
public:
// 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());
}
private:
bool is_pure_triangle( Tag_true) const {
bool is_pure_triangle( Tag_true) const {
for ( Facet_const_iterator i = facets_begin();
i != facets_end(); ++i)
if ( ! i->is_triangle())
return false;
return true;
}
bool is_pure_triangle( Tag_false) const {
bool is_pure_triangle( Tag_false) const {
for ( Halfedge_const_iterator i = halfedges_begin();
i != halfedges_end(); ++i)
if ( ! i->is_border() && ! i->is_triangle())
@ -944,19 +944,19 @@ private:
public:
// returns true if all facets are triangles
bool is_pure_triangle() const {
bool is_pure_triangle() const {
return is_pure_triangle( Supports_facet_halfedge());
}
private:
bool is_pure_quad( Tag_true) const {
bool is_pure_quad( Tag_true) const {
for ( Facet_const_iterator i = facets_begin();
i != facets_end(); ++i)
if ( ! i->is_quad())
return false;
return true;
}
bool is_pure_quad( Tag_false) const {
bool is_pure_quad( Tag_false) const {
for ( Halfedge_const_iterator i = halfedges_begin();
i != halfedges_end(); ++i)
if ( ! i->is_border() && ! i->is_quad())
@ -966,7 +966,7 @@ private:
public:
// returns true if all facets are quadrilaterals
bool is_pure_quad() const {
bool is_pure_quad() const {
return is_pure_quad( Supports_facet_halfedge());
}
@ -1376,6 +1376,21 @@ public:
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(); }
// 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);
g->next()->vertex()->point() = Point( 0, 1, 1);
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)
Halfedge_handle e = P.split_edge( f);
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()->facet_degree() == 3);
CGAL_assertion( P.is_pure_triangle());
CGAL_assertion( 2 == halfedgeds_connected_components(P,
CGAL_assertion( 2 == halfedgeds_connected_components(P,
CGAL::Emptyset_iterator()));
CGAL_assertion_code( const Polyhedron& Pq(P);)
CGAL_assertion( 2 == halfedgeds_connected_components(Pq,
CGAL_assertion( 2 == halfedgeds_connected_components(Pq,
CGAL::Emptyset_iterator()));
P.normalize_border();
CGAL_assertion( P.is_valid( false, 1));
@ -594,7 +594,7 @@ void test_Polyhedron() {
CGAL_assertion( P.is_valid());
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(
h->next()->opposite(),
h->opposite());)
@ -633,6 +633,14 @@ void test_Polyhedron() {
CGAL_assertion( P.size_of_vertices() == 4);
CGAL_assertion( P.size_of_halfedges() == 12);
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);
CGAL_assertion( P.is_valid());
CGAL_assertion( P.size_of_vertices() == 4);
@ -1165,7 +1173,7 @@ void test_min_Polyhedron() {
CGAL_assertion( P.is_valid());
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(
h->next()->opposite(),
h->opposite());)

View File

@ -26,6 +26,8 @@ endforeach()
# Require packages new or improved since CGAL 3.4
include_directories (BEFORE ../../../../AABB_tree/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 this package's headers first

View File

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

View File

@ -1,6 +1,6 @@
# 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)
@ -13,6 +13,8 @@ endif(COMMAND cmake_policy)
# Require packages new or improved since CGAL 3.4
include_directories (BEFORE ../../../../AABB_tree/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 this package's headers first
@ -25,11 +27,11 @@ if ( CGAL_FOUND )
include( CGAL_CreateSingleSourceCGALProgram )
endif()
# This demo requires MFC
# This demo requires MFC
if (MSVC)
message( STATUS "MFC library found" )
ADD_DEFINITIONS( "-D_AFXDLL" )
SET(CMAKE_MFC_FLAG 2)
SET(CMAKE_MFC_FLAG 2)
endif()
# This demo requires OpenGL
@ -45,7 +47,7 @@ if(OPENGL_FOUND)
link_libraries( ${OPENGL_LIBRARIES} )
endif()
# This demo requires TAUCS
# This demo requires TAUCS
find_package(TAUCS)
if(TAUCS_FOUND)
include( ${TAUCS_USE_FILE} )
@ -83,9 +85,9 @@ if(CGAL_FOUND AND MSVC AND OPENGL_FOUND AND TAUCS_FOUND)
# Creates Poisson executable
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
if ( CGAL_AUTO_LINK_ENABLED )
if ( CGAL_AUTO_LINK_ENABLED )
target_link_libraries(Poisson ${CGAL_3RD_PARTY_LIBRARIES} )
else()
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.
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)
@ -164,7 +164,6 @@ Returns a point located inside the inferred surface.
\ccSeeAlso
\ccRefIdfierPage{CGAL::Poisson_reconstruction_function<GeomTraits, ReconstructionTriangulation_3>} \\
\ccRefIdfierPage{CGAL::keep_largest_connected_components<Polyhedron>} \\
\ccExample

View File

@ -1,7 +1,7 @@
% +------------------------------------------------------------------------+
% | 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
% |
% |
@ -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::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/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}
%% EOF

View File

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

View File

@ -12,6 +12,8 @@ endif(COMMAND cmake_policy)
# Require packages new or improved since CGAL 3.4
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 this package's headers first

View File

@ -59,7 +59,7 @@ CGAL_BEGIN_NAMESPACE
///
/// APSS reconstruction may create small "ghost" connected components
/// 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:
/// 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/IO/read_xyz_points.h>
#include <CGAL/IO/output_surface_facets_to_polyhedron.h>
#include <CGAL/keep_largest_connected_components.h>
#include "compute_normal.h"
@ -285,12 +284,12 @@ int main(int argc, char * argv[])
std::cerr << "Erases small connected components...\n";
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
/*long*/ memory = CGAL::Memory_sizer().virtual_size();
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"
<< std::endl;
task_timer.reset();

View File

@ -12,6 +12,8 @@ endif(COMMAND cmake_policy)
# Require packages new or improved since CGAL 3.4
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 this package's headers first