From 25f7cf46bc66a76409d25b28c24f79ee3a5523f7 Mon Sep 17 00:00:00 2001 From: Lutz Kettner Date: Fri, 5 Apr 2002 21:19:03 +0000 Subject: [PATCH] - Extended Polyhedron_incremental_builder with absolute indexing functionality for David Bourguignon. --- Packages/Polyhedron/changes.txt | 5 + .../Polyhedron_incremental_builder_3.tex | 34 +++-- .../Polyhedron_incremental_builder_3.tex | 34 +++-- .../Polyhedron/include/CGAL/Polyhedron_3.h | 2 +- .../CGAL/Polyhedron_incremental_builder_3.h | 119 ++++++++++++------ .../test/Polyhedron/test_polyhedron.C | 64 ++++++++++ Packages/Polyhedron/version | 2 +- 7 files changed, 208 insertions(+), 52 deletions(-) diff --git a/Packages/Polyhedron/changes.txt b/Packages/Polyhedron/changes.txt index dd8003fd46d..faf0b651e53 100644 --- a/Packages/Polyhedron/changes.txt +++ b/Packages/Polyhedron/changes.txt @@ -1,6 +1,11 @@ Polyhedron Package: Release changes: --------------------------------------------------------------------- +3.25 (05 Apr 2002) + + - Extended Polyhedron_incremental_builder with absolute indexing + functionality for David Bourguignon. + 3.24 (21 Mar 2002) - Moved member functions defined outside of the Polyhedron_3 class diff --git a/Packages/Polyhedron/doc_tex/Polyhedron_ref/Polyhedron_incremental_builder_3.tex b/Packages/Polyhedron/doc_tex/Polyhedron_ref/Polyhedron_incremental_builder_3.tex index 77ce263d95e..7afbad14cd2 100644 --- a/Packages/Polyhedron/doc_tex/Polyhedron_ref/Polyhedron_incremental_builder_3.tex +++ b/Packages/Polyhedron/doc_tex/Polyhedron_ref/Polyhedron_incremental_builder_3.tex @@ -56,6 +56,15 @@ already known. end\_facet\/$))\:*$ end\_surface } +The incremental builder can work in two modes: \ccc{RELATIVE} (the +default), in which a polyhedral surface already contained in the +halfedge data structure is ignored and all indices are relative to the +newly added surface, or \ccc{ABSOLUTE}, in which all indices are +absolute indices including an already existing polyhedral surface. The +former mode allows to create easily independent connected components, +while the latter mode allows to to continue the construction of an +existing surface, the absolute indexing allows to address existing +vertices when creating new facets. \ccInclude{CGAL/Polyhedron_incremental_builder_3.h} @@ -69,6 +78,11 @@ already known. \ccGlue \ccNestedType{size_type}{size type.} +\ccConstants + +\ccEnum{enum { RELATIVE, ABSOLUTE};}{two different indexing modes.} + + \ccCreation \ccThree{void}{B.remove_unconnected_vertices();;;}{} \ccThreeToTwo @@ -82,19 +96,24 @@ already known. diagnostic messages will be printed to \ccc{cerr} in case of malformed input data.} -\newpage \ccOperations -\ccMethod{void begin_surface( size_type v, size_type f, size_type h = 0);} -{starts the construction. $v$ is the number of vertices - to expect, $f$ the number of facets, and $h$ the number of - halfedges. If $h$ is unspecified (\ccc{== 0}) it is estimated using +\ccMethod{void begin_surface( size_type v, size_type f, size_type h = 0, + int mode = RELATIVE);} +{starts the construction. $v$ is the number of new vertices + to expect, $f$ the number of new facets, and $h$ the number of + new halfedges. If $h$ is unspecified (\ccc{== 0}) it is estimated using Euler's equation (plus 5\% for the so far unknown holes and genus of the object). These values are used to reserve space in the halfedge data structure \ccc{hds}. If the representation supports insertion these values do not restrict the class of constructible polyhedra. If the representation does not support insertion the - object must fit into the reserved sizes.} + object must fit into the reserved sizes.\\ + If \ccc{mode} is set to \ccc{ABSOLUTE} the incremental builder + uses absolute indexing and the vertices of the old polyhedral surface + can be used in new facets (needs preprocessing time linear in the + size of the old surface). Otherwise relative indexing is used + starting with new indices for the new construction.} \ccMethod{void add_vertex( const Point_3& p);}{ adds $p$ to the vertex list.} @@ -103,7 +122,8 @@ already known. \ccGlue \ccMethod{void add_vertex_to_facet( size_type i);}{adds a vertex with index $i$ to the current facet. The first point added with - \ccc{add_vertex()} has the index 0.} + \ccc{add_vertex()} has the index 0 if \ccc{mode} was set to \ccc{RELATIVE}, + otherwise the first vertex in the referenced \ccc{hds} has the index 0.} \ccGlue \ccMethod{void end_facet();}{ends a facet.} \ccGlue diff --git a/Packages/Polyhedron/doc_tex/basic/Polyhedron_ref/Polyhedron_incremental_builder_3.tex b/Packages/Polyhedron/doc_tex/basic/Polyhedron_ref/Polyhedron_incremental_builder_3.tex index 77ce263d95e..7afbad14cd2 100644 --- a/Packages/Polyhedron/doc_tex/basic/Polyhedron_ref/Polyhedron_incremental_builder_3.tex +++ b/Packages/Polyhedron/doc_tex/basic/Polyhedron_ref/Polyhedron_incremental_builder_3.tex @@ -56,6 +56,15 @@ already known. end\_facet\/$))\:*$ end\_surface } +The incremental builder can work in two modes: \ccc{RELATIVE} (the +default), in which a polyhedral surface already contained in the +halfedge data structure is ignored and all indices are relative to the +newly added surface, or \ccc{ABSOLUTE}, in which all indices are +absolute indices including an already existing polyhedral surface. The +former mode allows to create easily independent connected components, +while the latter mode allows to to continue the construction of an +existing surface, the absolute indexing allows to address existing +vertices when creating new facets. \ccInclude{CGAL/Polyhedron_incremental_builder_3.h} @@ -69,6 +78,11 @@ already known. \ccGlue \ccNestedType{size_type}{size type.} +\ccConstants + +\ccEnum{enum { RELATIVE, ABSOLUTE};}{two different indexing modes.} + + \ccCreation \ccThree{void}{B.remove_unconnected_vertices();;;}{} \ccThreeToTwo @@ -82,19 +96,24 @@ already known. diagnostic messages will be printed to \ccc{cerr} in case of malformed input data.} -\newpage \ccOperations -\ccMethod{void begin_surface( size_type v, size_type f, size_type h = 0);} -{starts the construction. $v$ is the number of vertices - to expect, $f$ the number of facets, and $h$ the number of - halfedges. If $h$ is unspecified (\ccc{== 0}) it is estimated using +\ccMethod{void begin_surface( size_type v, size_type f, size_type h = 0, + int mode = RELATIVE);} +{starts the construction. $v$ is the number of new vertices + to expect, $f$ the number of new facets, and $h$ the number of + new halfedges. If $h$ is unspecified (\ccc{== 0}) it is estimated using Euler's equation (plus 5\% for the so far unknown holes and genus of the object). These values are used to reserve space in the halfedge data structure \ccc{hds}. If the representation supports insertion these values do not restrict the class of constructible polyhedra. If the representation does not support insertion the - object must fit into the reserved sizes.} + object must fit into the reserved sizes.\\ + If \ccc{mode} is set to \ccc{ABSOLUTE} the incremental builder + uses absolute indexing and the vertices of the old polyhedral surface + can be used in new facets (needs preprocessing time linear in the + size of the old surface). Otherwise relative indexing is used + starting with new indices for the new construction.} \ccMethod{void add_vertex( const Point_3& p);}{ adds $p$ to the vertex list.} @@ -103,7 +122,8 @@ already known. \ccGlue \ccMethod{void add_vertex_to_facet( size_type i);}{adds a vertex with index $i$ to the current facet. The first point added with - \ccc{add_vertex()} has the index 0.} + \ccc{add_vertex()} has the index 0 if \ccc{mode} was set to \ccc{RELATIVE}, + otherwise the first vertex in the referenced \ccc{hds} has the index 0.} \ccGlue \ccMethod{void end_facet();}{ends a facet.} \ccGlue diff --git a/Packages/Polyhedron/include/CGAL/Polyhedron_3.h b/Packages/Polyhedron/include/CGAL/Polyhedron_3.h index 51d5af8fd5d..54a60433dce 100644 --- a/Packages/Polyhedron/include/CGAL/Polyhedron_3.h +++ b/Packages/Polyhedron/include/CGAL/Polyhedron_3.h @@ -734,7 +734,7 @@ public: size_type size_of_facets() const { return hds.size_of_faces();} // number of facets. - bool empty() const { size_of_halfedges() == 0; } + bool empty() const { return size_of_halfedges() == 0; } size_type capacity_of_vertices() const { // space reserved for vertices. diff --git a/Packages/Polyhedron/include/CGAL/Polyhedron_incremental_builder_3.h b/Packages/Polyhedron/include/CGAL/Polyhedron_incremental_builder_3.h index 47c9e2b5912..4b617c41c68 100644 --- a/Packages/Polyhedron/include/CGAL/Polyhedron_incremental_builder_3.h +++ b/Packages/Polyhedron/include/CGAL/Polyhedron_incremental_builder_3.h @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -69,6 +70,7 @@ protected: typedef typename HDS::Supports_vertex_halfedge Supports_vertex_halfedge; typedef typename HDS::Supports_removal Supports_removal; typedef typename HDS::Vertex_iterator Vertex_iterator; + typedef typename HDS::Halfedge_iterator Halfedge_iterator; typedef Random_access_adaptor Random_access_index; bool m_error; @@ -99,13 +101,32 @@ protected: // Implement the vertex_to_edge_map either with an array or // the halfedge pointer in the vertices (if supported). // ---------------------------------------------------- - void initialize_vertex_to_edge_map( size_type , Tag_true) {} - void initialize_vertex_to_edge_map( size_type n, Tag_false) { + void initialize_vertex_to_edge_map( size_type , bool, Tag_true) {} + void initialize_vertex_to_edge_map( size_type n, bool mode, Tag_false){ vertex_to_edge_map = std::vector< Halfedge_handle>(); vertex_to_edge_map.reserve(n); + if ( mode) { + // go through all halfedges and keep a halfedge for each + // vertex found in a hashmap. + typedef Unique_hash_map< Vertex_iterator, Halfedge_handle> V_map; + Halfedge_handle hh; + V_map v_map( hh, hds.size_of_vertices()); + for ( Halfedge_iterator hi = hds.halfedges_begin(); + hi != hds.halfedges_end(); + ++hi) { + v_map[ hi->vertex()] = hi; + } + size_type i = 0; + for ( Vertex_iterator vi = hds.vertices_begin(); + vi != hds.vertices_end(); + ++vi) { + set_vertex_to_edge_map( i, v_map[ index_to_vertex_map[i]]); + ++i; + } + } } - void initialize_vertex_to_edge_map( size_type n) { - initialize_vertex_to_edge_map( n, Supports_vertex_halfedge()); + void initialize_vertex_to_edge_map( size_type n, bool mode) { + initialize_vertex_to_edge_map(n, mode, Supports_vertex_halfedge()); } void push_back_vertex_to_edge_map( Halfedge_handle , Tag_true) {} void push_back_vertex_to_edge_map( Halfedge_handle h, Tag_false) { @@ -163,7 +184,8 @@ protected: public: bool error() const { return m_error; } - Polyhedron_incremental_builder_3(HDS& h, bool verbose = false) + Polyhedron_incremental_builder_3(HDS& h, + bool verbose = false) // stores a reference to the halfedge data structure `h' in the // internal state. The previous polyhedral surface in `h' // remains unchanged. The incremental builder adds the new @@ -177,18 +199,25 @@ public: } // OPERATIONS + enum { RELATIVE = 0, ABSOLUTE = 1}; - void begin_surface( size_type v, size_type f, size_type h = 0); - // starts the construction. v is the number of - // vertices to expect, f the number of facets, and h the number of - // halfedges. If h is unspecified (`== 0') it is estimated using + + void begin_surface( size_type v, size_type f, size_type h = 0, + int mode = RELATIVE); + // starts the construction. v is the number of new + // vertices to expect, f the number of new facets, and h the number of + // new halfedges. If h is unspecified (`== 0') it is estimated using // Euler equations (plus 5% for the so far unkown holes and genus // of the object). These values are used to reserve space in the // polyhedron representation `HDS'. If the representation - // supports insertion these - // values do not restrict the class of readable polyhedrons. - // If the representation does not support insertion the object - // must fit in the reserved sizes. + // supports insertion these values do not restrict the class of + // readable polyhedrons. If the representation does not support + // insertion the object must fit in the reserved sizes. + // If `mode' is set to ABSOLUTE the incremental builder uses + // absolute indexing and the vertices of the old polyhedral surface + // can be used in new facets. Otherwise relative indexing is used + // starting with new indices for the new construction. + void add_vertex( const Point_3& p); // adds p to the vertex list. @@ -267,7 +296,7 @@ find_vertex( Vertex_handle v) { ++n; ++it; } - n = n - ( hds.size_of_vertices() - new_vertices); + n = n - rollback_v; return n; } @@ -284,7 +313,7 @@ find_facet( Face_handle f) { ++n; ++it; } - n = n - ( hds.size_of_faces() - new_faces); + n = n - rollback_f; return n; } @@ -292,10 +321,8 @@ template < class HDS> CGAL_LARGE_INLINE typename HDS::Halfedge_handle Polyhedron_incremental_builder_3:: lookup_halfedge( size_type w, size_type v) { - typedef typename HDS::Supports_halfedge_vertex - Supports_halfedge_vertex; - Assert_compile_time_tag( Supports_halfedge_vertex(), - Tag_true()); + typedef typename HDS::Supports_halfedge_vertex Supports_halfedge_vertex; + Assert_compile_time_tag( Supports_halfedge_vertex(), Tag_true()); CGAL_assertion( w < new_vertices); CGAL_assertion( v < new_vertices); CGAL_assertion( ! last_vertex); @@ -446,13 +473,17 @@ rollback() { CGAL_assertion( rollback_v <= hds.size_of_vertices()); CGAL_assertion( rollback_h <= hds.size_of_halfedges()); CGAL_assertion( rollback_f <= hds.size_of_faces()); - while ( rollback_v != hds.size_of_vertices()) - hds.vertices_pop_back(); - CGAL_assertion((( hds.size_of_halfedges() - rollback_h) & 1) == 0); - while ( rollback_h != hds.size_of_halfedges()) - hds.edges_pop_back(); - while ( rollback_f != hds.size_of_faces()) - hds.faces_pop_back(); + if ( rollback_v == 0 && rollback_h == 0 && rollback_f == 0) { + hds.clear(); + } else { + while ( rollback_v != hds.size_of_vertices()) + hds.vertices_pop_back(); + CGAL_assertion((( hds.size_of_halfedges() - rollback_h) & 1) == 0); + while ( rollback_h != hds.size_of_halfedges()) + hds.edges_pop_back(); + while ( rollback_f != hds.size_of_faces()) + hds.faces_pop_back(); + } m_error = false; CGAL_assertion_code( check_protocoll = 0;) } @@ -460,16 +491,25 @@ rollback() { template < class HDS> CGAL_MEDIUM_INLINE void Polyhedron_incremental_builder_3:: -begin_surface( size_type v, size_type f, size_type h) { +begin_surface( size_type v, size_type f, size_type h, int mode) { CGAL_assertion( check_protocoll == 0); CGAL_assertion_code( check_protocoll = 1;) CGAL_assertion( ! m_error); - new_vertices = 0; - new_faces = 0; - new_halfedges = 0; - rollback_v = hds.size_of_vertices(); - rollback_f = hds.size_of_faces(); - rollback_h = hds.size_of_halfedges(); + if ( mode == RELATIVE) { + new_vertices = 0; + new_faces = 0; + new_halfedges = 0; + rollback_v = hds.size_of_vertices(); + rollback_f = hds.size_of_faces(); + rollback_h = hds.size_of_halfedges(); + } else { + new_vertices = hds.size_of_vertices(); + new_faces = hds.size_of_faces(); + new_halfedges = hds.size_of_halfedges(); + rollback_v = 0; + rollback_f = 0; + rollback_h = 0; + } if ( h == 0) { // Use the Eulerian equation for connected planar graphs. We do // not know the number of facets that are holes and we do not @@ -480,9 +520,16 @@ begin_surface( size_type v, size_type f, size_type h) { hds.reserve( hds.size_of_vertices() + v, hds.size_of_halfedges() + h, hds.size_of_faces() + f); - index_to_vertex_map = Random_access_index( hds.vertices_end()); - index_to_vertex_map.reserve(v); - initialize_vertex_to_edge_map( v); + if ( mode == RELATIVE) { + index_to_vertex_map = Random_access_index( hds.vertices_end()); + index_to_vertex_map.reserve(v); + initialize_vertex_to_edge_map( v, false); + } else { + index_to_vertex_map = Random_access_index( hds.vertices_begin(), + hds.vertices_end()); + index_to_vertex_map.reserve( hds.size_of_vertices() + v); + initialize_vertex_to_edge_map( hds.size_of_vertices() + v, true); + } } template < class HDS> CGAL_MEDIUM_INLINE diff --git a/Packages/Polyhedron/test/Polyhedron/test_polyhedron.C b/Packages/Polyhedron/test/Polyhedron/test_polyhedron.C index 863de0fec4e..4e53279e434 100644 --- a/Packages/Polyhedron/test/Polyhedron/test_polyhedron.C +++ b/Packages/Polyhedron/test/Polyhedron/test_polyhedron.C @@ -89,6 +89,62 @@ Build_tetrahedron:: operator()( HDS& target) { } +// A polyhedron modifier that creates a tetrahedron using the +// incremental builder, but in two steps with a second incr. builder +// continueing what the first one started. +template < class HDS > +class Build_tetrahedron_2 : public CGAL::Modifier_base { +public: + Build_tetrahedron_2() {} + // creates the modifier. + void operator()( HDS& target); + // builds a tetrahedron. + // Postcondition: `target' is a valid polyhedral surface. +}; + +template < class HDS > +void +Build_tetrahedron_2:: operator()( HDS& target) { + typedef CGAL::Polyhedron_incremental_builder_3 Builder; + typedef typename HDS::Vertex Vertex; + typedef typename Vertex::Point Point; + { + Builder B( target, true); + B.begin_surface( 3, 1, 6); + // Point coordinates suitable for integer coordinates. + B.add_vertex( Point( 0, 0, 1)); + B.add_vertex( Point( 1, 1, 1)); + B.add_vertex( Point( 0, 1, 0)); + B.begin_facet(); + B.add_vertex_to_facet( 2); + B.add_vertex_to_facet( 1); + B.add_vertex_to_facet( 0); + B.end_facet(); + B.end_surface(); + }{ + Builder B( target, true); + B.begin_surface( 1, 3, 6, Builder::ABSOLUTE); + B.add_vertex( Point( 1, 0, 0)); + B.begin_facet(); + B.add_vertex_to_facet( 1); + B.add_vertex_to_facet( 3); + B.add_vertex_to_facet( 0); + B.end_facet(); + B.begin_facet(); + B.add_vertex_to_facet( 3); + B.add_vertex_to_facet( 2); + B.add_vertex_to_facet( 0); + B.end_facet(); + B.begin_facet(); + B.add_vertex_to_facet( 2); + B.add_vertex_to_facet( 3); + B.add_vertex_to_facet( 1); + B.end_facet(); + B.end_surface(); + } +} + + void test_Polyhedron() { typedef CGAL::Cartesian Kernel; typedef CGAL::Cartesian KernelI; @@ -285,6 +341,14 @@ void test_Polyhedron() { P2.normalize_border(); CGAL_assertion( P2.is_valid( false, 1)); + P2.clear(); + CGAL_assertion( P2.empty()); + Build_tetrahedron_2 modifier2; + P2.delegate( modifier2); + CGAL_assertion( P2.is_tetrahedron(P2.halfedges_begin())); + P2.normalize_border(); + CGAL_assertion( P2.is_valid( false, 1)); + Polyhedron P3(P2); CGAL_assertion( P3.is_tetrahedron(P3.halfedges_begin())); P3.inside_out(); diff --git a/Packages/Polyhedron/version b/Packages/Polyhedron/version index 9413d0b7622..ca50689d04b 100644 --- a/Packages/Polyhedron/version +++ b/Packages/Polyhedron/version @@ -1 +1 @@ -3.24 (21 Mar 2002) +3.25 (05 Apr 2002)