diff --git a/HalfedgeDS/doc_tex/HalfedgeDS_ref/HalfedgeDS_decorator.tex b/HalfedgeDS/doc_tex/HalfedgeDS_ref/HalfedgeDS_decorator.tex index 0c35e248f42..a4d453fbaad 100644 --- a/HalfedgeDS/doc_tex/HalfedgeDS_ref/HalfedgeDS_decorator.tex +++ b/HalfedgeDS/doc_tex/HalfedgeDS_ref/HalfedgeDS_decorator.tex @@ -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} \ccDefinition - + The classes \ccc{CGAL::HalfedgeDS_items_decorator}, \ccc{CGAL::HalfedgeDS_decorator}, and \ccc{CGAL::HalfedgeDS_const_decorator} 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. \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}. \begin{ccTexOnly} See their documentation on page~\pageref{pageHalfedgeDSconstDecoratorRef}. diff --git a/HalfedgeDS/include/CGAL/HalfedgeDS_decorator.h b/HalfedgeDS/include/CGAL/HalfedgeDS_decorator.h index 1804703fb16..f3ec6091ff4 100644 --- a/HalfedgeDS/include/CGAL/HalfedgeDS_decorator.h +++ b/HalfedgeDS/include/CGAL/HalfedgeDS_decorator.h @@ -17,7 +17,7 @@ // // $URL$ // $Id$ -// +// // // Author(s) : Lutz Kettner @@ -26,9 +26,13 @@ #include #include -#include +#include #include +#include +#include +#include + 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 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& 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& tags) ///< container holding the tag of all vertices + { + // Circulator category. + typedef typename Halfedge::Supports_halfedge_prev Supports_prev; + typedef HalfedgeDS_circulator_traits 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 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 + 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 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 tags; + + // list of all connected components of a polyhedron, ordered by size. + std::multimap 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::iterator src; + for (src = components.begin(); src != components.end(); ++src) + *output++ = src->second; + } + // Others // ---------------------------------- public: diff --git a/Polyhedron/doc_tex/Polyhedron_ref/Polyhedron_3.tex b/Polyhedron/doc_tex/Polyhedron_ref/Polyhedron_3.tex index 11ea353d38f..25dd54a619c 100644 --- a/Polyhedron/doc_tex/Polyhedron_ref/Polyhedron_3.tex +++ b/Polyhedron/doc_tex/Polyhedron_ref/Polyhedron_3.tex @@ -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} \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}
- Modifying Facets and Holes: add_vertex_and_facet_to_border()

\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}
- Modifying Facets and Holes: add_facet_to_border()

\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 diff --git a/Polyhedron/include/CGAL/Polyhedron_3.h b/Polyhedron/include/CGAL/Polyhedron_3.h index a8d32bddd5b..876b29ff37e 100644 --- a/Polyhedron/include/CGAL/Polyhedron_3.h +++ b/Polyhedron/include/CGAL/Polyhedron_3.h @@ -13,7 +13,7 @@ // // $URL$ // $Id$ -// +// // // Author(s) : Lutz Kettner ) @@ -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 D(hds); + return D.keep_largest_connected_components(nb_components_to_keep); + } + void clear() { hds.clear(); } // removes all vertices, halfedges, and facets. diff --git a/Polyhedron/test/Polyhedron/test_polyhedron.cpp b/Polyhedron/test/Polyhedron/test_polyhedron.cpp index a75c6a7527b..32b40d4d961 100644 --- a/Polyhedron/test/Polyhedron/test_polyhedron.cpp +++ b/Polyhedron/test/Polyhedron/test_polyhedron.cpp @@ -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());) diff --git a/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/Point_set_demo/CMakeLists.txt b/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/Point_set_demo/CMakeLists.txt index 4fe2408d829..39a1f85fd30 100644 --- a/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/Point_set_demo/CMakeLists.txt +++ b/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/Point_set_demo/CMakeLists.txt @@ -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 diff --git a/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/Point_set_demo/Point_set_demo_APSS_reconstruction_plugin_cgal_code.cpp b/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/Point_set_demo/Point_set_demo_APSS_reconstruction_plugin_cgal_code.cpp index e0ab0de1d12..dc245317e12 100644 --- a/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/Point_set_demo/Point_set_demo_APSS_reconstruction_plugin_cgal_code.cpp +++ b/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/Point_set_demo/Point_set_demo_APSS_reconstruction_plugin_cgal_code.cpp @@ -16,7 +16,6 @@ // This package #include #include -#include // 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(); diff --git a/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/poisson/CMakeLists.txt b/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/poisson/CMakeLists.txt index c8fcdd0ca1a..578d395cc93 100644 --- a/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/poisson/CMakeLists.txt +++ b/Surface_reconstruction_points_3/demo/Surface_reconstruction_points_3/poisson/CMakeLists.txt @@ -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} ) diff --git a/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/APSS_reconstruction_function.tex b/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/APSS_reconstruction_function.tex index 81de5d61d73..34aeae01b55 100644 --- a/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/APSS_reconstruction_function.tex +++ b/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/APSS_reconstruction_function.tex @@ -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} \\ -\ccRefIdfierPage{CGAL::keep_largest_connected_components} \\ \ccExample diff --git a/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/intro.tex b/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/intro.tex index 95a1cab216d..83ad4d74ef3 100644 --- a/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/intro.tex +++ b/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/intro.tex @@ -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} \\ \ccRefIdfierPage{CGAL::APSS_reconstruction_function} \\ - -\subsection{Functions} - -\ccRefIdfierPage{CGAL::output_surface_facets_to_polyhedron} \\ -\ccRefIdfierPage{CGAL::keep_largest_connected_components} \\ - diff --git a/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/keep_largest_connected_components.tex b/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/keep_largest_connected_components.tex deleted file mode 100644 index 92a99055890..00000000000 --- a/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/keep_largest_connected_components.tex +++ /dev/null @@ -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} - -%% \ccHtmlCrossLink{} %% add further rules for cross referencing links -%% \ccHtmlIndexC[function]{} %% add further index entries - -\ccDefinition - -\ccc{keep_largest_connected_components} 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 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} 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} \\ - -\ccExample - -See \ccc{APSS_reconstruction.cpp} example. - -\end{ccRefFunction} - -% +------------------------------------------------------------------------+ -%%RefPage: end of main body, begin of footer -\ccRefPageEnd -% EOF -% +------------------------------------------------------------------------+ - diff --git a/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/main.tex b/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/main.tex index 6fffb94f6c4..beca1229f35 100644 --- a/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/main.tex +++ b/Surface_reconstruction_points_3/doc_tex/Surface_reconstruction_points_3_ref/main.tex @@ -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 diff --git a/Surface_reconstruction_points_3/examples/Surface_reconstruction_points_3/APSS_reconstruction.cpp b/Surface_reconstruction_points_3/examples/Surface_reconstruction_points_3/APSS_reconstruction.cpp index e0b8ca611da..9ddd9128d75 100644 --- a/Surface_reconstruction_points_3/examples/Surface_reconstruction_points_3/APSS_reconstruction.cpp +++ b/Surface_reconstruction_points_3/examples/Surface_reconstruction_points_3/APSS_reconstruction.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #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(); diff --git a/Surface_reconstruction_points_3/examples/Surface_reconstruction_points_3/CMakeLists.txt b/Surface_reconstruction_points_3/examples/Surface_reconstruction_points_3/CMakeLists.txt index 63e689ff2f3..97801ef1b86 100644 --- a/Surface_reconstruction_points_3/examples/Surface_reconstruction_points_3/CMakeLists.txt +++ b/Surface_reconstruction_points_3/examples/Surface_reconstruction_points_3/CMakeLists.txt @@ -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 diff --git a/Surface_reconstruction_points_3/include/CGAL/APSS_reconstruction_function.h b/Surface_reconstruction_points_3/include/CGAL/APSS_reconstruction_function.h index adb4c92d62c..aca667cbd9b 100644 --- a/Surface_reconstruction_points_3/include/CGAL/APSS_reconstruction_function.h +++ b/Surface_reconstruction_points_3/include/CGAL/APSS_reconstruction_function.h @@ -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. diff --git a/Surface_reconstruction_points_3/include/CGAL/keep_largest_connected_components.h b/Surface_reconstruction_points_3/include/CGAL/keep_largest_connected_components.h deleted file mode 100644 index 1166d69bcd3..00000000000 --- a/Surface_reconstruction_points_3/include/CGAL/keep_largest_connected_components.h +++ /dev/null @@ -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 -#include - -#include -#include - -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. -/// -/// @return a list of pairs (component's size (number of vertices), a vertex of the component), -/// ordered by size. - -template -typename Polyhedron::Vertex_handle -get_any_free_vertex(Polyhedron& polyhedron, - std::map& 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. -/// -/// @return the size (number of vertices) of the component. -template -unsigned int tag_component(Polyhedron& polyhedron, - typename Polyhedron::Vertex_handle pSeedVertex, - std::map& 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 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 that supports vertices. -/// @param OutputIterator value_type must be Polyhedron::Vertex_handle. -template -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 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 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 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::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 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 -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 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 diff --git a/Surface_reconstruction_points_3/test/Surface_reconstruction_points_3/APSS_reconstruction_test.cpp b/Surface_reconstruction_points_3/test/Surface_reconstruction_points_3/APSS_reconstruction_test.cpp index 586db18616c..1cd609dfc72 100644 --- a/Surface_reconstruction_points_3/test/Surface_reconstruction_points_3/APSS_reconstruction_test.cpp +++ b/Surface_reconstruction_points_3/test/Surface_reconstruction_points_3/APSS_reconstruction_test.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #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(); diff --git a/Surface_reconstruction_points_3/test/Surface_reconstruction_points_3/CMakeLists.txt b/Surface_reconstruction_points_3/test/Surface_reconstruction_points_3/CMakeLists.txt index ceac0b6c5da..5548331a82b 100644 --- a/Surface_reconstruction_points_3/test/Surface_reconstruction_points_3/CMakeLists.txt +++ b/Surface_reconstruction_points_3/test/Surface_reconstruction_points_3/CMakeLists.txt @@ -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