- 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:
---------------------------------------------------------------------
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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -43,6 +43,7 @@
#include <CGAL/Random_access_adaptor.h>
#include <CGAL/HalfedgeDS_decorator.h>
#include <CGAL/Unique_hash_map.h>
#include <CGAL/IO/Verbose_ostream.h>
#include <vector>
#include <cstddef>
@ -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<Vertex_iterator> 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<HDS>::
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<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_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

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() {
typedef CGAL::Cartesian<double> Kernel;
typedef CGAL::Cartesian<int> 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<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);
CGAL_assertion( P3.is_tetrahedron(P3.halfedges_begin()));
P3.inside_out();

View File

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