- Extended Polyhedron_incremental_builder with absolute indexing

functionality for David Bourguignon.
This commit is contained in:
Lutz Kettner 2002-04-05 21:19:03 +00:00
parent 9d2bd8fd82
commit 25f7cf46bc
7 changed files with 208 additions and 52 deletions

View File

@ -1,6 +1,11 @@
Polyhedron Package: Release changes: 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) 3.24 (21 Mar 2002)
- Moved member functions defined outside of the Polyhedron_3 class - Moved member functions defined outside of the Polyhedron_3 class

View File

@ -56,6 +56,15 @@ already known.
end\_facet\/$))\:*$ end\_surface 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} \ccInclude{CGAL/Polyhedron_incremental_builder_3.h}
@ -69,6 +78,11 @@ already known.
\ccGlue \ccGlue
\ccNestedType{size_type}{size type.} \ccNestedType{size_type}{size type.}
\ccConstants
\ccEnum{enum { RELATIVE, ABSOLUTE};}{two different indexing modes.}
\ccCreation \ccCreation
\ccThree{void}{B.remove_unconnected_vertices();;;}{} \ccThree{void}{B.remove_unconnected_vertices();;;}{}
\ccThreeToTwo \ccThreeToTwo
@ -82,19 +96,24 @@ already known.
diagnostic messages will be printed to \ccc{cerr} in case of diagnostic messages will be printed to \ccc{cerr} in case of
malformed input data.} malformed input data.}
\newpage
\ccOperations \ccOperations
\ccMethod{void begin_surface( size_type v, size_type f, size_type h = 0);} \ccMethod{void begin_surface( size_type v, size_type f, size_type h = 0,
{starts the construction. $v$ is the number of vertices int mode = RELATIVE);}
to expect, $f$ the number of facets, and $h$ the number of {starts the construction. $v$ is the number of new vertices
halfedges. If $h$ is unspecified (\ccc{== 0}) it is estimated using 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 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 the object). These values are used to reserve space in the
halfedge data structure \ccc{hds}. If the representation supports halfedge data structure \ccc{hds}. If the representation supports
insertion these values do not restrict the class of constructible insertion these values do not restrict the class of constructible
polyhedra. If the representation does not support insertion the 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);}{ \ccMethod{void add_vertex( const Point_3& p);}{
adds $p$ to the vertex list.} adds $p$ to the vertex list.}
@ -103,7 +122,8 @@ already known.
\ccGlue \ccGlue
\ccMethod{void add_vertex_to_facet( size_type i);}{adds a vertex with \ccMethod{void add_vertex_to_facet( size_type i);}{adds a vertex with
index $i$ to the current facet. The first point added 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 \ccGlue
\ccMethod{void end_facet();}{ends a facet.} \ccMethod{void end_facet();}{ends a facet.}
\ccGlue \ccGlue

View File

@ -56,6 +56,15 @@ already known.
end\_facet\/$))\:*$ end\_surface 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} \ccInclude{CGAL/Polyhedron_incremental_builder_3.h}
@ -69,6 +78,11 @@ already known.
\ccGlue \ccGlue
\ccNestedType{size_type}{size type.} \ccNestedType{size_type}{size type.}
\ccConstants
\ccEnum{enum { RELATIVE, ABSOLUTE};}{two different indexing modes.}
\ccCreation \ccCreation
\ccThree{void}{B.remove_unconnected_vertices();;;}{} \ccThree{void}{B.remove_unconnected_vertices();;;}{}
\ccThreeToTwo \ccThreeToTwo
@ -82,19 +96,24 @@ already known.
diagnostic messages will be printed to \ccc{cerr} in case of diagnostic messages will be printed to \ccc{cerr} in case of
malformed input data.} malformed input data.}
\newpage
\ccOperations \ccOperations
\ccMethod{void begin_surface( size_type v, size_type f, size_type h = 0);} \ccMethod{void begin_surface( size_type v, size_type f, size_type h = 0,
{starts the construction. $v$ is the number of vertices int mode = RELATIVE);}
to expect, $f$ the number of facets, and $h$ the number of {starts the construction. $v$ is the number of new vertices
halfedges. If $h$ is unspecified (\ccc{== 0}) it is estimated using 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 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 the object). These values are used to reserve space in the
halfedge data structure \ccc{hds}. If the representation supports halfedge data structure \ccc{hds}. If the representation supports
insertion these values do not restrict the class of constructible insertion these values do not restrict the class of constructible
polyhedra. If the representation does not support insertion the 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);}{ \ccMethod{void add_vertex( const Point_3& p);}{
adds $p$ to the vertex list.} adds $p$ to the vertex list.}
@ -103,7 +122,8 @@ already known.
\ccGlue \ccGlue
\ccMethod{void add_vertex_to_facet( size_type i);}{adds a vertex with \ccMethod{void add_vertex_to_facet( size_type i);}{adds a vertex with
index $i$ to the current facet. The first point added 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 \ccGlue
\ccMethod{void end_facet();}{ends a facet.} \ccMethod{void end_facet();}{ends a facet.}
\ccGlue \ccGlue

View File

@ -734,7 +734,7 @@ public:
size_type size_of_facets() const { return hds.size_of_faces();} size_type size_of_facets() const { return hds.size_of_faces();}
// number of facets. // number of facets.
bool empty() const { size_of_halfedges() == 0; } bool empty() const { return size_of_halfedges() == 0; }
size_type capacity_of_vertices() const { size_type capacity_of_vertices() const {
// space reserved for vertices. // space reserved for vertices.

View File

@ -43,6 +43,7 @@
#include <CGAL/Random_access_adaptor.h> #include <CGAL/Random_access_adaptor.h>
#include <CGAL/HalfedgeDS_decorator.h> #include <CGAL/HalfedgeDS_decorator.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/IO/Verbose_ostream.h> #include <CGAL/IO/Verbose_ostream.h>
#include <vector> #include <vector>
#include <cstddef> #include <cstddef>
@ -69,6 +70,7 @@ protected:
typedef typename HDS::Supports_vertex_halfedge Supports_vertex_halfedge; typedef typename HDS::Supports_vertex_halfedge Supports_vertex_halfedge;
typedef typename HDS::Supports_removal Supports_removal; typedef typename HDS::Supports_removal Supports_removal;
typedef typename HDS::Vertex_iterator Vertex_iterator; typedef typename HDS::Vertex_iterator Vertex_iterator;
typedef typename HDS::Halfedge_iterator Halfedge_iterator;
typedef Random_access_adaptor<Vertex_iterator> Random_access_index; typedef Random_access_adaptor<Vertex_iterator> Random_access_index;
bool m_error; bool m_error;
@ -99,13 +101,32 @@ protected:
// Implement the vertex_to_edge_map either with an array or // Implement the vertex_to_edge_map either with an array or
// the halfedge pointer in the vertices (if supported). // 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 , bool, Tag_true) {}
void initialize_vertex_to_edge_map( size_type n, Tag_false) { 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 = std::vector< Halfedge_handle>();
vertex_to_edge_map.reserve(n); 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;
} }
void initialize_vertex_to_edge_map( size_type n) { size_type i = 0;
initialize_vertex_to_edge_map( n, Supports_vertex_halfedge()); 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, 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 , Tag_true) {}
void push_back_vertex_to_edge_map( Halfedge_handle h, Tag_false) { void push_back_vertex_to_edge_map( Halfedge_handle h, Tag_false) {
@ -163,7 +184,8 @@ protected:
public: public:
bool error() const { return m_error; } 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 // stores a reference to the halfedge data structure `h' in the
// internal state. The previous polyhedral surface in `h' // internal state. The previous polyhedral surface in `h'
// remains unchanged. The incremental builder adds the new // remains unchanged. The incremental builder adds the new
@ -177,18 +199,25 @@ public:
} }
// OPERATIONS // 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 void begin_surface( size_type v, size_type f, size_type h = 0,
// vertices to expect, f the number of facets, and h the number of int mode = RELATIVE);
// halfedges. If h is unspecified (`== 0') it is estimated using // 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 // Euler equations (plus 5% for the so far unkown holes and genus
// of the object). These values are used to reserve space in the // of the object). These values are used to reserve space in the
// polyhedron representation `HDS'. If the representation // polyhedron representation `HDS'. If the representation
// supports insertion these // supports insertion these values do not restrict the class of
// values do not restrict the class of readable polyhedrons. // readable polyhedrons. If the representation does not support
// If the representation does not support insertion the object // insertion the object must fit in the reserved sizes.
// 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); void add_vertex( const Point_3& p);
// adds p to the vertex list. // adds p to the vertex list.
@ -267,7 +296,7 @@ find_vertex( Vertex_handle v) {
++n; ++n;
++it; ++it;
} }
n = n - ( hds.size_of_vertices() - new_vertices); n = n - rollback_v;
return n; return n;
} }
@ -284,7 +313,7 @@ find_facet( Face_handle f) {
++n; ++n;
++it; ++it;
} }
n = n - ( hds.size_of_faces() - new_faces); n = n - rollback_f;
return n; return n;
} }
@ -292,10 +321,8 @@ template < class HDS> CGAL_LARGE_INLINE
typename HDS::Halfedge_handle typename HDS::Halfedge_handle
Polyhedron_incremental_builder_3<HDS>:: Polyhedron_incremental_builder_3<HDS>::
lookup_halfedge( size_type w, size_type v) { lookup_halfedge( size_type w, size_type v) {
typedef typename HDS::Supports_halfedge_vertex typedef typename HDS::Supports_halfedge_vertex Supports_halfedge_vertex;
Supports_halfedge_vertex; Assert_compile_time_tag( Supports_halfedge_vertex(), Tag_true());
Assert_compile_time_tag( Supports_halfedge_vertex(),
Tag_true());
CGAL_assertion( w < new_vertices); CGAL_assertion( w < new_vertices);
CGAL_assertion( v < new_vertices); CGAL_assertion( v < new_vertices);
CGAL_assertion( ! last_vertex); CGAL_assertion( ! last_vertex);
@ -446,6 +473,9 @@ rollback() {
CGAL_assertion( rollback_v <= hds.size_of_vertices()); CGAL_assertion( rollback_v <= hds.size_of_vertices());
CGAL_assertion( rollback_h <= hds.size_of_halfedges()); CGAL_assertion( rollback_h <= hds.size_of_halfedges());
CGAL_assertion( rollback_f <= hds.size_of_faces()); CGAL_assertion( rollback_f <= hds.size_of_faces());
if ( rollback_v == 0 && rollback_h == 0 && rollback_f == 0) {
hds.clear();
} else {
while ( rollback_v != hds.size_of_vertices()) while ( rollback_v != hds.size_of_vertices())
hds.vertices_pop_back(); hds.vertices_pop_back();
CGAL_assertion((( hds.size_of_halfedges() - rollback_h) & 1) == 0); CGAL_assertion((( hds.size_of_halfedges() - rollback_h) & 1) == 0);
@ -453,6 +483,7 @@ rollback() {
hds.edges_pop_back(); hds.edges_pop_back();
while ( rollback_f != hds.size_of_faces()) while ( rollback_f != hds.size_of_faces())
hds.faces_pop_back(); hds.faces_pop_back();
}
m_error = false; m_error = false;
CGAL_assertion_code( check_protocoll = 0;) CGAL_assertion_code( check_protocoll = 0;)
} }
@ -460,16 +491,25 @@ rollback() {
template < class HDS> CGAL_MEDIUM_INLINE template < class HDS> CGAL_MEDIUM_INLINE
void void
Polyhedron_incremental_builder_3<HDS>:: Polyhedron_incremental_builder_3<HDS>::
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( check_protocoll == 0);
CGAL_assertion_code( check_protocoll = 1;) CGAL_assertion_code( check_protocoll = 1;)
CGAL_assertion( ! m_error); CGAL_assertion( ! m_error);
if ( mode == RELATIVE) {
new_vertices = 0; new_vertices = 0;
new_faces = 0; new_faces = 0;
new_halfedges = 0; new_halfedges = 0;
rollback_v = hds.size_of_vertices(); rollback_v = hds.size_of_vertices();
rollback_f = hds.size_of_faces(); rollback_f = hds.size_of_faces();
rollback_h = hds.size_of_halfedges(); 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) { if ( h == 0) {
// Use the Eulerian equation for connected planar graphs. We do // Use the Eulerian equation for connected planar graphs. We do
// not know the number of facets that are holes and we do not // 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.reserve( hds.size_of_vertices() + v,
hds.size_of_halfedges() + h, hds.size_of_halfedges() + h,
hds.size_of_faces() + f); hds.size_of_faces() + f);
if ( mode == RELATIVE) {
index_to_vertex_map = Random_access_index( hds.vertices_end()); index_to_vertex_map = Random_access_index( hds.vertices_end());
index_to_vertex_map.reserve(v); index_to_vertex_map.reserve(v);
initialize_vertex_to_edge_map( 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 template < class HDS> CGAL_MEDIUM_INLINE

View File

@ -89,6 +89,62 @@ Build_tetrahedron<HDS>:: 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<HDS> {
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<HDS>:: operator()( HDS& target) {
typedef CGAL::Polyhedron_incremental_builder_3<HDS> 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() { void test_Polyhedron() {
typedef CGAL::Cartesian<double> Kernel; typedef CGAL::Cartesian<double> Kernel;
typedef CGAL::Cartesian<int> KernelI; typedef CGAL::Cartesian<int> KernelI;
@ -285,6 +341,14 @@ void test_Polyhedron() {
P2.normalize_border(); P2.normalize_border();
CGAL_assertion( P2.is_valid( false, 1)); CGAL_assertion( P2.is_valid( false, 1));
P2.clear();
CGAL_assertion( P2.empty());
Build_tetrahedron_2<HDS> 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); Polyhedron P3(P2);
CGAL_assertion( P3.is_tetrahedron(P3.halfedges_begin())); CGAL_assertion( P3.is_tetrahedron(P3.halfedges_begin()));
P3.inside_out(); P3.inside_out();

View File

@ -1 +1 @@
3.24 (21 Mar 2002) 3.25 (05 Apr 2002)