Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
321 views

A Tutorial On CGAL Polyhedron For Subdivision Algorithms

This document is a tutorial on how to get started with the polyhedron structure provided by CGAL, the Computational Geometry Algorithm Library. Assuming the reader to be familiar with the C++ template mechanisms and the key concepts of the STL (Standard Template Library), we first demonstrate two differ- ent approaches for implementing mesh subdivision schemes. Euler operators is applied for √3 subdivision and the modifier callback mechanism is applied for the Quad-Triangle subdivision. Both approaches are based on the build-in functionalities of the CGAL polyhedron. We then introduce a combinatory subdivi- sion library (CSL) with increasing level of sophistication and abstraction. CSL offers a convenient way to design user-customized subdivision schemes through the definition of rule templates. Catmull-Clark and Doo-Sabin schemes are used to demonstrate the design and implementation of CSL. Two companion appli- cations based on OpenGL, one developed with Windows MFC, and the other developed with Qt, showcase the subdivision schemes listed above, as well as several functionalities for interaction and visualization.

Uploaded by

zambom255602
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
321 views

A Tutorial On CGAL Polyhedron For Subdivision Algorithms

This document is a tutorial on how to get started with the polyhedron structure provided by CGAL, the Computational Geometry Algorithm Library. Assuming the reader to be familiar with the C++ template mechanisms and the key concepts of the STL (Standard Template Library), we first demonstrate two differ- ent approaches for implementing mesh subdivision schemes. Euler operators is applied for √3 subdivision and the modifier callback mechanism is applied for the Quad-Triangle subdivision. Both approaches are based on the build-in functionalities of the CGAL polyhedron. We then introduce a combinatory subdivi- sion library (CSL) with increasing level of sophistication and abstraction. CSL offers a convenient way to design user-customized subdivision schemes through the definition of rule templates. Catmull-Clark and Doo-Sabin schemes are used to demonstrate the design and implementation of CSL. Two companion appli- cations based on OpenGL, one developed with Windows MFC, and the other developed with Qt, showcase the subdivision schemes listed above, as well as several functionalities for interaction and visualization.

Uploaded by

zambom255602
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 25

A Tutorial on CGAL Polyhedron

for Subdivision Algorithms


Le-Jeng Shiue

Pierre Alliez

Radu Ursu

Lutz Kettner

Abstract
This document is a tutorial on how to get started with the polyhedron structure provided by CGAL, the
Computational Geometry Algorithm Library. Assuming the reader to be familiar with the C++ template
mechanisms and the key concepts of the STL (Standard Template Library), we first demonstrate
two different approaches for implementing mesh subdivision schemes. Euler operators is applied for 3 subdivision
and the modifier callback mechanism is applied for the Quad-Triangle subdivision. Both approaches are
based on the build-in functionalities of the CGAL polyhedron. We then introduce a combinatory subdivision library (CSL) with increasing level of sophistication and abstraction. CSL offers a convenient way to
design user-customized subdivision schemes through the definition of rule templates. Catmull-Clark and
Doo-Sabin schemes are used to demonstrate the design and implementation of CSL. Two companion applications based on OpenGL, one developed with Windows MFC, and the other developed with Qt, showcase
the subdivision schemes listed above, as well as several functionalities for interaction and visualization.
Keywords: CGAL
library, tutorial, halfedge data structure, polyhedron structure, subdivision surfaces,

quad-triangle, 3, Loop, Doo-Sabin, Catmull-Clark, OpenGL.

1 Introduction
Polyhedron data structures based on the concept of halfedges have been very successful for the design of
general algorithms on meshes. Common practice is to develop such data structure from scratch, since clearly
a first implementation is at the level of a students homework assignment. But then, these data structures
consist almost entirely of pointers for all sort of incidence informations. Maintaining them consistently
during mesh operations is not anymore a trivial linked-list update operation. So, moving from a students
exercise to a reliable research implementation, including maintaining and optimizing it, is a respectable
software task.
What is common practice for simple data structures, such as linked lists, should be common practice
even more so for mesh data structures, namely, to use a good, flexible, and efficient library implementation. In C++ the Standard Template Library, S TL, is an excellent address for our analog example of the
linked lists [Aus99], and we argue that the Polyhedron data structure in C GAL is such a flexible mesh data
structure [Ket99], and it comes with a rich and versatile infrastructure for mesh algorithms. C GAL, the Computational Geometry Algorithms Library, is a C++ library available from www.cgal.org [FGK+ 00].
We strongly believe that this tutorial with its wealth of information will give a head start to new researches and implementations of mesh algorithms. We also believe that it will raise the quality of implementations. Firstly, it encourages the use of well tested and over time matured implementations, e.g.,
SurfLab,

University of Florida
INRIA Sophia-Antipolis
Geometry Factory, Sophia-Antipolis
MPII, Saarbr
ucken
GEOMETRICA,

Figure 1 The polyhedron viewer running on Windows. A coarse polygon mesh is subdivided
using the Quad-Triangle subdivision scheme.

CGAL::Polyhedron 3 in its current design was publicly released in 1999 and used since then. Secondly, it documents good implementation choices, e.g., the example programs can be used as starting points
for evolutionary software development. Thirdly, it offers easy access to additional functionality, such as the
efficient self intersection test, that otherwise could be expandable in a research prototype.
The tutorial is organized around subdivision surfaces in a polyhedron viewer. The polyhedron viewer
(Figure 1) demonstrates the basic functionalities of the CGAL::Polyhedron 3 and some extended functionalities such as file I/O, mesh superimposition, and trackball manipulation. Several
subdivision surfaces
are supported in the polyhedron viewer, including Catmull-Clark, Loop, Doo-Sabin, 3 and Quad-Triangle
subdivisions. The tutorial shows how to implement subdivision surfaces in two different mechanisms
pro
vided by CGAL::Polyhedron 3: Euler operators and modifier callback mechanism. A 3 subdivision
implementation is designed based on the Euler operators and a Quad-Triangle subdivision implementation is designed based on overloading the modifier. Extended from the previous design, a combinatorial
subdivision library (CSL) is then proposed with increased sophistication and abstraction. CSL abstracts
the geometry operations from the refinements. Subdivisions in CSL are build from refinement host with
a template geometry policy. Several fundamental refinement schemes are provided within CSL. They are
instantiated with a geometry policy that can be user defined.
The goal of this tutorial is to show how to use CGAL::Polyhedron 3 on basic graphics functionalities, such as rendering and interactive trackball manipulation, and how to design and implement algorithms
around meshes. Since connectivity and geometry operations are the primal implementation components
in mesh algorithms, subdivisions are chosen to demonstrate both operations on CGAL::Polyhedron 3.

Hence, readers designing and implementing mesh algorithms other than subdivisions will also benefit from
the tutorial.

Intended Audience
The intended audience of the tutorial are researchers, developers or students developing algorithms around
polyhedron meshes. Knowledge of the halfedge data structure and subdivisions are prerequisites. Short
introductions of these two topics are given in the tutorial. The tutorial assumes familiarity with the C++
template mechanism and the key concepts of generic programming [Aus99].

2 Background and Prerequisite


2.1 CGAL Polyhedron
CGAL Polyhedron (CGAL::Polyhedron 3) is realized as a container class that manages geometry items
such as vertices, halfedges, and facets with their incidences. CGAL::Polyhedron 3 has chosen the
halfedge data structure as the underlying connectivity structure. In the halfedge data structure, a halfedge is
associated with a facet and stores the adjacency pointers to it previous, next and opposite halfedge (Figure
2). The details of the halfedge data structure and the CGAL::Polyhedron 3 based on it are described
in [Ket99].

Figure 2 One halfedge and its incident primitives. The next halfedge, the opposite halfedge,
and the incident vertex are mandatory, the remaining elements are optional.
What are the potential obstacles in using CGAL and CGAL::Polyhedron 3?
1. Is it fast enough? Yes. C GAL, coming from the field of Computational Geometry, might have a
reputation of using slow exact arithmetic to be on the safe side, but nonetheless, we know where
to apply the right techniques of exact arithmetic to gain robustness and yet not to loose efficiency.
In addition, C GAL uses generic programming and compile-time polymorphism to realize flexibility
without affecting optimal runtime.
2. Is it small enough? Yes. CGAL::Polyhedron 3 can be tailored to store exactly the required
incidences and other required data, not more and not less.
3. Is it flexible enough? Yes, certainly within its design space of oriented 2-manifold meshes with
boundary that was sufficient for the range of applications illustrated with our example programs.
4. Is it easy enough to use? Yes. The full tutorial with its example programs are exactly the starting
point for using CGAL::Polyhedron 3. The example programs are short and easy to understand.
There is certainly a learning curve for mastering C++ to the level of using templates, but it has to be
emphasized that using templates is far easier then developing templated code.

PSfrag replacements

PQQ

PTQ

DQQ

Figure 3 Examples of refinement schemes: primal quadrilateral quadrisection


(PQQ),
primal triangle quadrisection (PTQ), dual quadrilateral quadrisection (DQQ) and 3 triangulation. The control meshes are shown in the first row.
5. What is the license, can I use it? Yes, we hope so. C GAL since release 3.0 and our tutorial programs
have open source licenses. Other options are available.

2.2 Subdivision Surfaces


A subdivision algorithm recursively applies refinement and geometry smoothing on the control mesh (Figure
5, 7), and approximates the limit surface of the control mesh. Several refinement schemes in practice are
illustrated in Figure 3. The stencils of the geometry smoothing are depending on the refinement schemes,
i.e. the reparameterizations. A stencil defines a control submesh that is associated with normalized weights
of the nodes. Figure 4 demonstrates the stencils of the PQQ scheme in Catmull-Clark subdivision
[CC78]

and DQQ scheme in Doo-Sabin subdivision [DS78]. We also demonstrate Loop [Loo94], 3 [Kob00] and
Quad-Triangle [SL03] subdivisions in this tutorial. For further details about subdivisions, readers should
refer to [WW02] and [ZS00].

3 Polyhedron Viewer
This tutorial implements an interactive basic polyhedron viewer based on the CGAL::Polyhedron 3
with the default configuration.
This viewer demonstrates basic functionalities of a
CGAL::Polyhedron 3. We show the mesh traversal based on the iterators and the circulators
during the assembly of facet polygons for basic OpenGL rendering. The viewer is then extended by
customizing the Polyhedron 3 with extra attributes and functionalities. This enriched polyhedron
supports facet and vertex normals for rendering, an axis-aligned bounding box of the polyhedron, and
provides geometry items specialized with algorithmic flags. A number of rendering modes are available to
the user depending on the choices of lighting, shading and edge superimposing. The superimposition of the
control mesh on the subdivision surfaces is implemented for the quad-triangle scheme with a boolean flag
of the halfedge item, this flag being automatically propagated to the subdivided edges during subdivision
(Figure 7).
The tutorial demonstrates basic combinatorial algorithms on the connectivity of the polyhedron by
counting the number of connected components and boundaries, and deducing the combinatorial genus of
the active polyhedron.

PSfrag replacements

(a)

(b)

(c)

(d)

Figure 4 The stencil (top blue) and its vertex (bottom red) in Catmull-Clark subdivision (ac) and Doo-Sabin subdivision (d). Catmull-Clark subdivision has three stencils: facet-stencil
(a), edge-stencil (b) and vertex-stencil (c). Doo-Sabin subdivision has only corner-stencil
(d). The stencil weights are not shown.

In addition to the build-in features of OFF file I/O in C GAL, we show how to import a polyhedron file
in the OBJ format based on the modifier callback mechanism and the incremental builder. The OBJ file
exporting is simply based on mesh traversal.
The camera and transformation states are automatically adjusted when a new polyhedron is loaded so as
to originally view the model in all. A function snapshots the camera and transformation states for the sake
of comparing two models with the same viewpoint.
The viewer also features a raster output of the current client image to the clipboard, as well as a vectorial
output to a postscript file. Note however that the latter functionality is not based on the painter algorithm
and performs instead a simple z-sorting of the polygons based on each facet barycenter and the current
viewpoint.

4 Subdivision Surfaces

The second part of the tutorial focuses on the design and the implementation of 3 (Figure 5), QuadTriangle subdivision (Figure 7) and our combinatory subdivision library (CSL).
In addition to its importance in the surface modeling, we choose subdivision algorithms to demonstrate both the connectivity operation (refinement) and the geometry operation (smoothing) of a
CGAL::Polyhedron 3. These two operations are the primary implementation components required
by algorithms on polyhedron meshes. Readers intended to design and implement mesh algorithms other
than subdivisions will also be benefited from the techniques we proposed here.
The key to implement a subdivision algorithm is to efficiently support the refinement, i.e. the connectivity modifications. Two approaches are introduced to support the refinement: the Euler operators (operator
scheme) and the modifier callback mechanism (modifier
scheme). The operator scheme reconfigures the
connectivity with a combination of Euler operators.
3 subdivision [Kob00] is used to demonstrate this
scheme. We also compare our implementation with the 3 subdivision provided in OpenMesh library.

Though simple and efficient in some refinements, e.g. 3 subdivision, the correct combination of the
operators is hard to find for some refinements, e.g. Doo-Sabin subdivision [DS78]. The modifier scheme
solves the problem by letting the programmers create their own combinatorial operators using the polyhedron incremental builder. Quad-Triangle subdivision [SL03, Lev03] is used to demonstrate this scheme.

4.1

3 Subdivision

This scheme was introduced as an adaptive scheme [Kob00], but we restrict our example program to a single
uniform subdivision step, see Fig. 5 for an example of a subdivision sequence and Fig. 6 for a closeup on
the refinement.
The subdivision step takes a triangle mesh as input and splits each facet at its centroid into three triangles.
We write a function that creates the centroid for one triangle. The topology refinement part exists already as
an Euler operator in CGAL::Polyhedron 3, we only have to compute the coordinates of the new vertex.
Since the facet is a triangle, we access the 1-ring of the centroid directly without any loops or branching
decisions (in general, we could use the circulator loop shown in the render function).

Figure 5

3 subdivision of the mannequin mesh.

void c r e a t e c e n t r o i d ( Polyhedron & P , F a c e t i t e r a t o r f ) {


H a l f e d g e h a n d l e h = f>h a l f e d g e ( ) ;
V e c t o r v e c = h>v e r t e x ()> p o i n t ( ) ORIGIN ;
v e c = v e c + ( h>n e x t ()> v e r t e x ()> p o i n t ( ) ORIGIN ) ;
v e c = v e c + ( h>n e x t ()> n e x t ()> v e r t e x ()> p o i n t ( ) ORIGIN ) ;
Halfedge handle new center = P . c r e a t e c e n t e r v e r t e x ( h ) ;
n e w c e n t e r >v e r t e x ()> p o i n t ( ) = ORIGIN + ( v e c / 3 . 0 ) ;
}

Next, all edges of the initial mesh are flipped to join two adjacent centroids. It is part of the
CGAL::Polyhedron 3 interface.
Finally, each initial vertex is replaced by a barycentric combination of its neighbors. However, the mesh
has already been subdivided, so the original neighbors of a vertex are actually every other vertex in the
1-ring. We write a function object for the smoothing step that can be used with the std::transform
function.

Figure 6 The
and edge flips.

3-subdivision scheme is decomposed into Euler operators: center vertex

struct Smooth old vertex {


Point operator ( ) ( const Vertex & v ) const {
std : : s i z e t degree = v . vertex degree ( ) / 2 ;
d o u b l e a l p h a = ( 4 . 0 2 . 0 c o s ( 2 . 0 CGAL PI / d e g r e e ) ) / 9 . 0 ;
V e c t o r v e c = ( v . p o i n t ( ) ORIGIN ) ( 1 . 0 a l p h a ) ;
Halfedge around vertex const circulator h = v . vertex begin ( ) ;
do {
v e c = v e c + ( h>o p p o s i t e ()> v e r t e x ()> p o i n t ( ) ORIGIN )
alpha / degree ;
++ h ; + + h ;
} while ( h ! = v . v e r t e x b e g i n ( ) ) ;
r e t u r n ( ORIGIN + v e c ) ;
}};

In the final subdivision program we exploit that newly created items are appended at the end of the sequences, so that we can keep valid iterators telling us where the old items end and where the new items
start. We are as economical as possible with the extra storage needed in this method, which is an extra array
for the smoothed coordinates of original vertices. We start by creating the centroids, then smooth the old
vertices, and conclude with flipping the old edges.

void subdiv ( Polyhedron & P ) {


s t d : : s i z e t nv = P . s i z e o f v e r t i c e s ( ) ;
Vertex iterator last v = P. vertices end ();
l a s t v ;
/ / the l a s t of the old v e r t i c e s
E d g e i t e r a t o r l a s t e = P . edges end ( ) ;
l a s t e ;
/ / the l a s t of the old edges
Facet iterator last f = P. facets end ();
/ / the l a s t of the old f a c e t s
l a s t f ;
Facet iterator f = P. facets begin ( ) ;
// centroids
do {
create centroid ( P , f );
} while ( f ++ != l a s t f ) ;
s t d : : v e c t o r <P o i n t > p t s ;
/ / smooth o l d v e r t i c e s
p t s . r e s e r v e ( nv ) ;
/ / s p a c e f o r t h e new p o i n t s
++ l a s t v ;
/ / move t o p a s t t h eend a g a i n
std : : transform ( P. vertices begin ( ) , last v ,
std : : back inserter ( pts ) , Smooth old vertex ( ) ) ;
s t d : : copy ( p t s . b e g i n ( ) , p t s . end ( ) , P . p o i n t s b e g i n ( ) ) ;
/ / move t o p a s t t h eend a g a i n
++ l a s t e ;
for ( E d g e i t e r a t o r e = P . edges begin ( ) ; e ! = l a s t e ; ++ e )
P. flip edge (e ) ;
/ / f l i p the old edges
}

The O PEN M ESH library Release 1.0.0-beta4 comes with a demo application
for the subdivision algorithms
that are available in O PEN M ESH. Since L. Kobbelt, the author of the 3-subdivision, is the head of the
group developing O PEN M ESH, it is natural to find his algorithm in the library. We compared it with our
example implementation on a laptop with an Intel Mobile Pentium4 running at 1.80GHz with 512KB cache

and 254MB main memory under Linux.


We selected an instance of CGAL::Polyhedron 3 that was closely matching the implementation
used in O PEN M ESH, i.e., array-storage, no plane equation in facets, and float coordinates in points.
O PEN M ESH uses the specialized triangle-mesh data structure where our structure remains the general
polygonal mesh. We only exploited the triangle nature of our mesh in the centroid computation, and as
it turned out, this was not crucial. What is crucial is the size of the structure. For example, the same experiment with an unused plane equations in the facets increases the running time by 25%. Similarly the choice
of the coordinate type matters. We used the lion vase, see Fig. 12 with 400k triangles as benchmark in two
successive subdivision steps. The other models had boundary edges so that we could not use them in our
currently limited example program. Time in seconds:

3-subdivision
Lion vase: step 1
Lion vase: step 2

C GAL
float double
0.95
1.22
3.90
23.73

O PEN M ESH
float
1.27
128.00

The result is clearly encouraging for the C GAL implementation, but it should be interpreted cautiously.
For example, the O PEN M ESH implementation was obviously running into swap problems in the second
refinement step, which is not expected when studying the example program and reading the manual about
the default space requirements of this implementation. Nonetheless, the simple and easy customization
possible with the CGAL::Polyhedron 3 resulted in a short, readable, and competitive implementation
for this algorithm without great efforts. It is also the first result showing that the abstraction of Euler
operations does not necessarily harm your performance, and they clearly simplify things.

4.2 Quad-triangle Subdivision


The quad-triangle subdivision scheme was introduced by Levin [Lev03], then Stam and Loop [SL03]. It
applies to polygon meshes and basically features Loop subdivision on triangles and Catmull-Clark subdivision on polygons of the control mesh (see Fig.7). After one iteration of subdivision the subdivided model
is only composed of triangles and quads.

Figure 7 Quad-triangle subdivision of the rhombicuboctahedron mesh.


A simple solution for implementing such a scheme is to use the incremental builder offered for the
CGAL Polyhedron. The polyhedron provides a backdoor access to the underlying halfedge data structure
with the CGAL::Modifier class and checks the integrity of the data structure when this access finishes.

The prime example for this backdoor use is an alternative way of describing meshes in the indexed-facet-set
format that is common in file formats: Points are defined with coordinates, then facets are defined by the
points on their boundary, but the points are given as indices to the already given list of points.
In the example below we make use of the incremental builder to assemble a subdivided polyhedron from
an input polyhedron. Our implementation requires enriched halfedge, vertex and facet primitives with an
integer tag that recovers the vertex indices of the subdivided model.

# include enriched polyhedron . h


# include b u i l d e r . h
t e m p l a t e < c l a s s HDS, c l a s s P o l y h e d r o n , c l a s s k e r n e l >
c l a s s C M o d i f i e r Q u a d T r i a n g l e : p u b l i c CGAL : : M o d i f i e r b a s e <HDS>
{
private :
typedef . . .
P o l y h e d r o n m pMesh ;
public :
/ / l i f e cycle
C M o d i f i e r Q u a d T r i a n g l e ( P o l y h e d r o n pMesh )
{
C G A L a s s e r t i o n ( pMesh ! = NULL ) ;
m pMesh = pMesh ;
}
CModifierQuadTriangle () {}
/ / subdivision
v o i d o p e r a t o r ( ) ( HDS& h d s )
{
b u i l d e r B ( hds , t r u e ) ;
B. begin surface (3 ,1 ,6);
a d d v e r t i c e s (B ) ;
a d d f a c e t s (B ) ;
B. end surface ( ) ;
}
private :
// ...
/ / for the complete implementation of the subdivision ,
/ / r e a d e r s should r e f e r to t h e accompanied source codes of
// this tutorial .
};
template < c l a s s Polyhedron , c l a s s kernel>
class CSubdivider quad triangle
{
public :
t y p e d e f typename P o l y h e d r o n : : HalfedgeDS HalfedgeDS ;
public :
/ / l i f e cycle
CSubdivider quad triangle () {}
CSubdivider quad triangle () {}
public :
void s u b d i v i d e ( Polyhedron & OriginalMesh ,
P o l y h e d r o n &NewMesh ,
bool smooth boundary = true )
{
C M o d i f i e r Q u a d T r i a n g l e <HalfedgeDS , P o l y h e d r o n , k e r n e l >
b u i l d e r (& O r i g i n a l M e s h ) ;
/ / delegate construction

NewMesh . d e l e g a t e ( b u i l d e r ) ;
/ / smooth
b u i l d e r . smooth (&NewMesh , s m o o t h b o u n d a r y ) ;
};

4.3 Combinatorial Subdivision Library


Based on the techniques and functionalities described in the previous sections, we now show how to design
and implement a subdivision library for a generic CGAL polyhedron. This library is named Combinatorial
Subdivision Library, short CSL. CSL contains a set of refinement functions and geometry smoothing rules
that are user-customizable. Subdivisions in CSL are specialized as a proper combination of the refinement
functions and the geometry smoothing rules.
CSL follows in its desing the ideas of policy-based design [Ale01]. The policy-based design assembles
a class (called host) with complex behavior out of many small and generic behaviors (called policies). Each
policy defines an interface for a specific behavior and is customizable by the user. Policies are usually
implemented as functions or functors. One gentle example is the for each algorithm in STL 1 .

t e m p l a t e < c l a s s I n p u t I t e r a t o r , c l a s s U n a r y F u n c t i o n>
UnaryFunction for each ( I n p u t I t e r a t o r f i r s t , I n p u t I t e r a t o r l a s t , UnaryFunction f ) ;

The for each is the algorithm host and the UnaryFunction f is the generic behavior customizable
by the user. To use it, one has to provide a policy functor or function that meets the interface requirement
of an unary function.
Based on the policy-based design, CSL is designed to support both generic types, i.e. the polyhedron,
and generic behaviors, i.e. the subdivisions. The generic type is specified to follow the interface of the
CGAL::Polyhedron 3 that specifies both the connectivity and the geometry interface. The connectivity
interface has to support the circulators over primitives, or the adjacency pointers of an halfedge. The
geometry interface has to provide the Point type of a vertex item. The operational interface of the Point
is not specified by CSL and can be non-CGAL style. For a non-CGAL Point type, users should provide
user-defined policies that perform the point operations.
A subdivision algorithm has three key behaviors: refinement, smoothing, and stencil correspondence.
The refinement is acted as a for each algorithm on the source and the refined polyhedron while applying
the smoothing behaviors. CSL implement the refinements as the host functions with the smoothing rules as
the policies. Some major refinement schemes are shown in Figure 3. The tutorial accompanying CSL only
provides PQQ, PTQ and DQQ schemes. The refinement configurations also define the stencil correspondences; stencils of PQQ and DQQ schemes are shown in Figure 4. These stencil correspondences specified
the functional interface between the refinement hosts and the geometry smoothing policies.

Primal Quad Quadralization


A subdivision algorithm in CSL is constructed as a refinement function parameterized with a set of the
geometry smoothing rules. The rule set is specified as a template policy class. For example, Catmull-Clark
subdivision in CSL is instantiated as the PQQ scheme parameterized with a Catmull-Clark geometry policy
class.

void C a t m u l l C l a r k s u b d i v i s i o n ( Polyhedron & p , i n t s t e p = 1 ) {


q u a d q u a d r a l i z e p o l y h e d r o n ( p , C a t m u l l C l a r k r u l e <P o l y h e d r o n > ( ) , s t e p ) ;
1 http://www.sgi.com/tech/stl/for_each.html

Figure 8 Catmull-Clark subdivision of the box polyhedron.


}

The quad quadralize polyhedron is the refinement host that refines the control polyhedron using
PQQ scheme and the CatmullClark rule is the template geometry policy class.
Geometry policies are represented as the policy functions of the policy class. Each policy function receive
a primitive handle of the represented 1-ring submesh of the control polyhedron; and a reference of the
smoothing point on the refined polyhedron. The interface of a policy class for a PQQ refinement host is
shown below.

t e m p l a t e < c l a s s P o l y>
class quadralize rule {
public :
void f a c e p o i n t r u l e ( Facet handle , P o i n t &) {};
void e d g e p o i n t r u l e ( Halfedge handle , P o i n t &) {};
void v e r t e x p o i n t r u l e ( Vertex handle , P o i n t &) {};
};

The interface is defined according to the stencil correspondence of the refinement scheme. A PQQ scheme
contains three stencils that are shown in Figure 4 (ac). Each of them defines a policy function, which of the
quadralize rule is the facet rule(), the edge rule(), and the vertex rule() respectively.
Any customized policy class of the geometry smoothing rules are required to provide the proper functions.
To assure the interface consistence, CSL provides a geometry rule class for each refinement scheme. To
create a new geometry policy class, the class inheritance is used.

/ / S p e c i a l i z e d a C a t m u l lC l a r k r u l e by i n h e r i t i n g t h e q u a d r a l i z e r u l e .
t e m p l a t e < c l a s s P o l y>
c l a s s C a t m u l l C l a r k r u l e : public q u a d r a l i z e r u l e < Poly > {...}

The smoothing points of a refined polyhedron is generated by calling the corresponding geometry policies. Inside each policy, applying the stencil is simplified into the mesh traversal of a 1-ring neighborhood.
It can be done with a primitive circulator or a simple sequence of the adjacency pointers of the halfedges.
The face point rule for Catmull-Clark subdivision demonstrates the usage of a facet circulator for
stenciling.

void f a c e p o i n t r u l e ( F a c e t h a n d l e f a c e t , P o i n t & pt ) {
/ / F a c e t c i r c u l a t o r i s u s e d t o t r a v e r s e t h e 1 r i n g o f a f a c e t .
H a l f e d g e a r o u n d f a c e t c i r c u l a t o r h c i r = f a c e t >f a c e t b e g i n ( ) ;
int n = 0;
K e r n e l : : FT p [ ] = { 0 , 0 , 0 } ;
/ / Apply t h e s t e n c i l w h i l e c i r c u l a t i n g a r o u n d t h e f a c e t .
do {
P o i n t t = h c i r >v e r t e x ()> p o i n t ( ) ;
p[0] += t [0] , p[1] += t [1] , p[2] += t [2];
++n ;
} w h i l e ( + + h c i r ! = f a c e t >f a c e t b e g i n ( ) ) ;
/ / Assign the smoothing p o i n t .
pt = Point ( p [ 0 ] / n , p [ 1 ] / n , p [ 2 ] / n ) ;
}

The facet circulator provides a convenient way to traverse and collect the points. The point calculation use
the conventional interface [i] of the point type. For Point not equipped with the index access [i], a
user-implemented policy class need to be provided. The CGAL Point 3/Vector 3 computation can be
used if the Point is the equivalent type of Point 3 which is shown below.

void f a c e p o i n t r u l e ( F a c e t h a n d l e f a c e t , P o i n t & pt ) {
H a l f e d g e a r o u n d f a c e t c i r c u l a t o r h c i r = f a c e t >f a c e t b e g i n ( ) ;
/ / Use CGAL : : ORIGIN t o t r a n s f o r m P o i n t i n t o V e c t o r .
V e c t o r v e c = h c i r >v e r t e x ()> p o i n t ( ) CGAL : : ORIGIN ;
++ h c i r ;
do {
/ / Vector i s a computational c l a s s
v e c = v e c + h c i r >v e r t e x ()> p o i n t ( ) ;
} w h i l e ( + + h c i r ! = f a c e t >f a c e t b e g i n ( ) ) ;
/ / Use CGAL : : ORIGIN t o t r a n s f o r m V e c t o r b a c k t o P o i n t .
p t = CGAL : : ORIGIN + v e c / c i r c u l a t o r s i z e ( h c i r ) ;
}

The edge point rule() of Catmull-Clark subdivision requires the low lever halfedge traversal that
is the next(), the prev(), and the opposite() of the halfedge item.

v o i d e d g e p o i n t r u l e ( H a l f e d g e h a n d l e edge , P o i n t & p t ) {
P o i n t p1 = edge>v e r t e x ()> p o i n t ( ) ;
P o i n t p2 = edge>o p p o s i t e ()> v e r t e x ()> p o i n t ( ) ;
P o i n t f1 , f 2 ;
f a c e p o i n t r u l e ( edge>f a c e t ( ) , f 1 ) ;
f a c e p o i n t r u l e ( edge>o p p o s i t e ()> f a c e t ( ) , f 2 ) ;
p t = P o i n t ( ( p1 [ 0 ] + p2 [ 0 ] + f 1 [ 0 ] + f 2 [ 0 ] ) / 4 ,
( p1 [ 1 ] + p2 [ 1 ] + f 1 [ 1 ] + f 2 [ 1 ] ) / 4 ,
( p1 [ 2 ] + p2 [ 2 ] + f 1 [ 2 ] + f 2 [ 2 ] ) / 4 ) ;
}

The edge->opposite() is used to locate the opposite point and the opposite facet. Instead of using the
facet circulator for each facet after obtaining the facet handle, the face point rule is called to calculate
the facet centroids. The smoothing point is then assigned as the centroid of the two opposite points and the
two facet centroids.

The vertex point rule for Catmull-Clark subdivision is more complicated than the other two
policy functions. Unlike the facet and edge rules, vertex rule is not static in the scenes of the stencil
weights. The weights are functions of the vertex valence and it introduces more geometry computations.
Nonetheless, the connectivity traversal is still homomorphic to a vertex circulation.

void v e r t e x p o i n t r u l e ( Vertex handle vertex , P o i n t & pt ) {


/ / Only a v e r t e x c i r c u l a t o r i s n e e d e d t o c o l l e c t t h e submesh .
H a l f e d g e a r o u n d v e r t e x c i r c u l a t o r v c i r = v e r t e x >v e r t e x b e g i n ( ) ;
/ / The v e r t e x v a l e n c e i s u s e d t o c a l c u l a t e t h e s t e n c i l w e i g h t s .
int n = circulator size ( vcir );
f l o a t Q[ ] = { 0 . 0 , 0 . 0 , 0 . 0 } , R[ ] = { 0 . 0 , 0 . 0 , 0 . 0 } ;
P o i n t & S = v e r t e x >p o i n t ( ) ; / / The c e n t e r v e r t e x
Point q ;
for ( i n t i = 0 ; i < n ; i ++ , ++ v c i r ) {
P o i n t & p2 = v c i r >o p p o s i t e ()> v e r t e x ()> p o i n t ( ) ;
R [ 0 ] + = ( S [ 0 ] + p2 [ 0 ] ) / 2 ; R [ 1 ] + = ( S [ 1 ] + p2 [ 1 ] ) / 2 ; R [ 2 ] + = ( S [ 2 ] + p2 [ 2 ] ) / 2 ;
f a c e p o i n t r u l e ( v c i r >f a c e t ( ) , q ) ;
Q[ 0 ] + = q [ 0 ] ; Q[ 1 ] + = q [ 1 ] ; Q[ 2 ] + = q [ 2 ] ;
}
R[0] /= n ;
R[1] /= n ;
R[2] /= n;
Q[ 0 ] / = n ;
Q[ 1 ] / = n ;
Q[ 2 ] / = n ;

/ / Assign the smoothing p o i n t .


p t = P o i n t ( (Q[ 0 ] + 2 R [ 0 ] + S [ 0 ] ( n 3))/ n ,
(Q [ 1 ] + 2 R [ 1 ] + S [ 1 ] ( n 3 ) ) / n ,
(Q [ 2 ] + 2 R [ 2 ] + S [ 2 ] ( n 3 ) ) / n ) ;

Connectivity refinement in CSL is design as a host function. A refinement host refines the input control polyhedron, maintains the stencil correspondence and assign the smoothed points. The
quad quadralize polyhedron is the refinement host for a PQQ scheme. It redirects the refinement
by repeating the quad quadralize 1step() that does one-step polyhedron refinement.

/ / RULE i s a t e m p l a t e p a r a m e t e r s p e c i f y i n g t h e g e o m e t r y s t e n c i l s .
t e m p l a t e < t e m p l a t e <typename > c l a s s RULE>
v o i d q u a d q u a d r a l i z e p o l y h e d r o n ( P o l y h e d r o n & p , RULE<P o l y h e d r o n > r u l e , i n t d ) {
/ / Do d t i m e s r e f i n e m e n t .
for ( int i = 0 ; i < d ; i ++) quad quadralize 1step (p , ru le ) ;
}

The quad quadralize 1step() is implemented based on a sequence of the Euler operations which
incrementally modify the connectivity. Figure 9 illustrates the incremental modifications for a PQQ scheme.

/ / B u i l d t h e c o n n e c t i v i t y u s i n g i n s e r t v e r t e x ( ) and i n s e r t e d g e ( )
/ / S t e p 1 . I n s e r t edgev e r t i c e s on a l l e d g e s and s e t them t o new p o s i t i o n s .
f o r ( i n t i = 0 ; i < num edge ; i + + , + + e i t r ) {
V e r t e x h a n d l e vh = i n s e r t v e r t e x ( p , e i t r ) ;
vh>p o i n t ( ) = e d g e p o i n t b u f f e r [ i ] ; / / P o i n t s a r e o b t a i n e d w i t h t h e e d g e r u l e .
}
f i t r = p. facets begin ();
for ( i n t i = 0 ; i < num facet ; i ++ , ++ f i t r ) {
H a l f e d g e a r o u n d f a c e t c i r c u l a t o r h c i r b e g i n = f i t r >f a c e t b e g i n ( ) ;
Halfedge around facet circulator hcir = hcir begin ;
/ / S t e p 2 . I n s e r t a c u te d g e b e t w e e n 2 r a n d o m l y s e l e c t e d i n c i d e n t edgev e r t i c e s .
H a l f e d g e h a n d l e e1 = + + h c i r ;

++ h c i r ;
H a l f e d g e h a n d l e e2 = + + h c i r ;
++ h c i r ; / / Must move t h e c i r b e f o r e i n s e r t s t h e new e d g e ! !
H a l f e d g e h a n d l e newe = i n s e r t e d g e ( p , e1 , e2 ) ;
/ / S t e p 3 . I n s e r t a f a c e t v e r t e x on t h e c u te d g e and s e t i t t o
H a l f e d g e h a n d l e newv = i n s e r t v e r t e x r e t u r n e d g e ( p , newe ) ;
newv = newv>o p p o s i t e ()> p r e v ( ) ; / / c h a n g e newv t o t h e l a r g e r
/ / s t i l l p o i n t s t o t h e newly
/ / vertex
/ / U p d a t e t h e g e o m e t r y d a t a o f t h e f a c ev e r t e x
newv>v e r t e x ()> p o i n t ( ) = f a c e p o i n t b u f f e r [ i ] ; / / P o i n t s a r e

t h e new p o s i t i o n
f a c e and
inserted

obtained with the f a c e t r u l e .

/ / S t e p 4 . I n s e r t t h e f a c e t e d g e s b e t w e e n t h e edgev e r t i c e s and t h e f a c e t v e r t e x .
while ( h c i r ! = h c i r b e g i n ) {
e1 = + + h c i r ;
++ h c i r ; / / Must move t h e c i r b e f o r e i n s e r t s t h e new e d g e ! !
i n s e r t e d g e ( p , e1 , newv ) ;
}

}
/ / U p d a t e t h e g e o m e t r y d a t a o f t h e v e r t e x v e r t i c e s
vitr = p. vertices begin ();
for ( i n t i = 0 ; i < num vertex ; i ++ , ++ v i t r )
v i t r >p o i n t ( ) = v e r t e x p o i n t b u f f e r [ i ] ; / / P o i n t s a r e o b t a i n e d w i t h t h e v e r t e x r u l e .

The details of the Step2 and Step3 are shown in Figure 10. Note that the insert vertex() and
insert edge() are simple connectivity functions composed of the Euler operators provided by
CGAL::Polyhedron 3. Details about these two functions, readers should refer to the lib/SurfLab/Polyhedron decorator.h.

PSfrag replacements

Step1

Step2

Step3

Step4

Figure 9 A PQQ refinement of a facet is encoded into a sequence of vertex insertions and
edge insertions. Red indicates the inserted vertices and edges in each step.
PSfrag replacements
Step1
Step2
Step3
Step4

e2
hcir

e1

newe
newv

Figure 10 The Euler operations for the Step2 and Step3 of the PQQ refinement.
Stencil correspondence is another key behavior for a subdivision algorithm. CSL refinement hosts employ the geometry policies to generate the smoothing points. Three temporary point buffers, vertex point buffer, edge point buffer and face point buffer, are used in the refinement
host to store the points generated by the geometry policies. These points are then assigned to the corresponding refined vertices. In the Quad-Triangle implementation, the customized item flags are used to
register the stencil correspondence. Since CSL is designed to accept a generic CGAL::Polyhedron 3,
customized item flags (witch results a specific CGAL::Polyhedron 3) is not a feasible option for CSL.
To maintain the stencil correspondence, CSL implicitly matches the storage order and operation order. The
operation order is the order of creating the vertices through the connectivity operation in the refinement host.
This order is demonstrated in the Figure 9 and the related source code. Note CGAL::Polyhedron 3 al-

locates new geometry items by appending them at the end of the underlying containers, in most cases the
linked-list or the vector. So the operation order is equivalent to the storage of the vertex items, hence the
storage order of the points. CSL arranges the calling order of the geometry policies to meet the operation
order, which ensures the correspondence between the stencils and the points.

/ / B u i l d a new v e r t i c e s b u f f e r h a s t h e f o l l o w i n g s t r u c t u r e :
/ / 0 1 . . . e begin . . . f begin . . . ( end of buffer )
: s t o r e t h e p o i n t s o f t h e v e r t e x v e r t i c e s
/ / 0 . . . e b e g i n 1
/ / e b e g i n . . . f b e g i n 1 : s t o r e t h e p o i n t s o f t h e edgev e r t i c e s
/ / f b e g i n . . . ( end )
: s t o r e t h e p o i n t s o f t h e f a c ev e r t i c e s
int num vertex = p . s i z e o f v e r t i c e s ( ) ;
i n t num edge = p . s i z e o f h a l f e d g e s ( ) / 2 ;
int num facet = p . s i z e o f f a c e t s ( ) ;
//
//
//
p.

I f P o l y h e d r o n i s u s i n g v e c t o r , we n e e d t o r e s e r v e t h e memory t o p r e v e n t
t h e C G A L a s s e r t i o n . We assume p i s a quadp o l y h e d r o n .
T h i s f u n c t i o n f o r p o l y h e d r o n u s i n g l i s t i s VOID .
r e s e r v e ( n u m v e r t e x + num edge + n u m f a c e t , 4 2 num edge , 4 num edge / 2 ) ;

/ / Allocate the temporary point b u f f e r s .


P o i n t v e r t e x p o i n t b u f f e r = new P o i n t [ n u m v e r t e x + num edge + n u m f a c e t ] ;
Point e d g e p o i n t b u f f e r = v e r t e x p o i n t b u f f e r + num vertex ;
P o i n t f a c e p o i n t b u f f e r = e d g e p o i n t b u f f e r + num edge ;
s t d : : v e c t o r <bool > v o n b o r d e r ( n u m v e r t e x ) ;
/ / Generate the f a c e t points in the operation order .
Facet iterator f i t r = p. facets begin ();
for ( i n t i = 0 ; i < num facet ; i ++ , ++ f i t r )
rule . face point rule ( fitr , face point buffer [ i ]);
i n t sb = p . s i z e o f b o r d e r e d g e s ( ) ;
/ / G e n e r a t e t h e edge p o i n t s i n t h e o p e r a t i o n o r d e r .
Edge iterator e i t r = p . edges begin ( ) ;
f o r ( i n t i = 0 ; i < num edges b ; i + + , + + e i t r )
rule . edge point rule ( eitr , edge point buffer [ i ]);
/ / Take c a r e b o r d e r p o i n t a s a n o t h e r g e o m e t r y p o l i c y .
f o r ( i n t i = num edges b ; i < num edge ; i + + , + + e i t r ) {
i n t v = s t d : : d i s t a n c e ( p . v e r t i c e s b e g i n ( ) , e i t r >v e r t e x ( ) ) ;
v onborder [ v ] = true ;
rule . border point rule ( eitr , edge point buffer [ i ] , vertex point buffer [v ]);
}
/ / Generate the vertex points in the operation order .
Vertex iterator vitr = p. vertices begin ();
for ( i n t i = 0 ; i < num vertex ; i ++ , ++ v i t r )
i f ( ! v onborder [ i ] ) rule . v e r t e x p o i n t r u l e ( vitr , v e r t e x p o i n t b u f f e r [ i ] ) ;

A border point policy is introduced to support the boundary case. Border points usually have special stencil
that in general degenerated from 2-variable surface to 1-variable curve. The full list of the refinement host
and the geometry policies (including border point rule()) can be found in the accompanying source
code.

Dual Quad Quadralization

Primal schemes, such as PQQ, PTQ and 3 refinement, reserve the control vertices or even the control polyhedron. We can devise a sequence of Euler operations to incrementally manipulate the connectivity while
maintaining the stencil correspondence for these schemes. Dual schemes, such as DQQ refinement, exchange the vertex and facet in the process. These schemes lost the control vertices and hence are hard to devise incremental manipulations. The modifier callback mechanism supported by CGAL::Polyhedron 3
is then used to implement such refinement schemes.

Figure 11 Doo-Sabin subdivision of the box polyhedron.


CSL represents Doo-Sabin subdivision as a DQQ refinement parameterized with Doo-Sabin smoothing
rules.

void DooSabin subdivision ( Polyhedron & p , i n t s t e p = 1 ) {


d u a l i z e p o l y h e d r o n ( p , D o o S a b i n r u l e <P o l y h e d r o n > ( ) , s t e p ) ;
}

The dualize polyhedron() is the refinement host and the DooSabin rule is a policy class
supporting Doo-Sabin stencils.
The geometry policy of a DQQ scheme is shown in Figure 4 (d) where the stencil centers around a corner
(as a facet-vertex pair). Only one geometry policy, i.e. the corner point, is needed for a DQQ scheme.

t e m p l a t e < c l a s s P o l y>
class dualize rule {
public :
/ / The c o r n e r i s p o i n t e d by a h a l f e d g e h a n d l e .
v o i d p o i n t r u l e ( H a l f e d g e h a n d l e edge , P o i n t & p t ) { } ;
};

The Halfedge handle edge points to the corner centered in the stencil submesh; and the Point&
pt refers to the smoothing point of the refined polyhedron. The implementation of the Doo-Sabin stencil is
shown below.

t e m p l a t e < c l a s s P o l y>
c l a s s DooSabin rule : public d u a l i z e r u l e < Poly > {
public :
v o i d p o i n t r u l e ( H a l f e d g e h a n d l e he , P o i n t & p t ) {

/ / The DooS a b i n r u l e i s a f u n c t i o n o f t h e f a c e t d e g r e e .
i n t n = CGAL : : c i r c u l a t o r s i z e ( he>f a c e t ()> f a c e t b e g i n ( ) ) ;
/ / CGAL V e c t o r c o m p u t a t i o n i s u s e d f o r s i m p l e c o d i n g .
V e c t o r cv ( 0 , 0 , 0 ) , t ;
i f ( n = = 4 ) { / / Regular f a c e t .
cv = cv + ( he>v e r t e x ()> p o i n t ()CGAL : : ORIGIN ) 9 ;
cv = cv + ( he>n e x t ()> v e r t e x ()> p o i n t ()CGAL : : ORIGIN ) 3 ;
cv = cv + ( he>n e x t ()> n e x t ()> v e r t e x ()> p o i n t ()CGAL : : ORIGIN ) ;
cv = cv + ( he>p r e v ()> v e r t e x ()> p o i n t ()CGAL : : ORIGIN ) 3 ;
cv = cv / 1 6 ;
} else { / / Extraordinary facet .
double a ;
f o r ( i n t k = 0 ; k < n ; + + k , he = he>n e x t ( ) ) {
i f ( k = = 0 ) a = ( ( double ) 5 / n ) + 1 ;
e l s e a = ( 3 + 2 s t d : : c o s (2 k 3 . 1 4 1 5 9 3 / n ) ) / n ;
cv = cv + ( he>v e r t e x ()> p o i n t ()CGAL : : ORIGIN ) a ;
}
cv = cv / 4 ;
}
/ / Assign the smoothing p o i n t .
p t = CGAL : : ORIGIN + cv ;
};

The next() of the halfedges around the facet is the only connectivity functionality needed to support
Doo-Sabin stencil. Instead of using the conventional interface [i] of the point type, we demonstrate the
CGAL Point 3/Vector 3 computation that gives more succinct codes.
Connectivity refinement is implemented based on the modifier callback mechanism (MCM). In the demonstration of Quad-Triangle subdivision, MCM is used to devise customized Euler-like atomic operators. In
CSL, MCM is used to rebuild the refinement polyhedron based on a complete facet-vertex index list. This
method is called wholesale scheme in contrast to the incremental scheme of Euler operations. The refinement host of a DQQ scheme is represented as the dualize polyhedron() and it redirects the
refinement by repeating a one-step refinement function dualize 1step().

t e m p l a t e < t e m p l a t e <typename > c l a s s RULE>


v o i d d u a l i z e p o l y h e d r o n ( P o l y h e d r o n & p , RULE<P o l y h e d r o n > r u l e , i n t d = 1 ) {
for ( int i = 0 ; i < d ; ++ i ) d u a l i z e 1 s t e p (p , rule ) ;
}

The dualize 1step() first constructs a facet-vertex list that is similar to the format of a OFF file or the
OpenGL vertex array. A facet-vertex list contains two buffers: a point buffer and a facet index buffer. The
point buffer stores the smoothing points generated by the geometry policy, i.e. the point rule(). The
points are generated in the order of the halfedge iterator. Note that each halfedge points to a corner that is
a vertex on the refined polyhedron. The facet index buffer contains a list of the vertex indices which depict
facet polygons of the refined polyhedron. The vertex indices point to the storage position in the point buffer.
Since each facet of the refined polyhedron is mapped into a geometry primitive, i.e. vertex, edge, and facet,
of the source polyhedron, the facet order is defined by (and equal to) the iterator order of the primitives in a
CGAL::Polyhedron 3.

t e m p l a t e < c l a s s P > t e m p l a t e < t e m p l a t e <typename > c l a s s RULE>


v o i d P o l y h e d r o n s u b d i v i s i o n < P >:: d u a l i z e 1 s t e p ( P & p , RULE< P > r u l e ) {
i n t num v = p . s i z e o f v e r t i c e s ( ) ;
i n t num e = p . s i z e o f h a l f e d g e s ( ) / 2 ; / / Number o f e d g e s .
i n t num f = p . s i z e o f f a c e t s ( ) ;
i n t n u m f a c e t = num v + num e + num f ;
//

I n i t t h e f a c e t v e r t e x l i s t f o r t h e r e f i n e d p o l y h e d r o n .

P o i n t p o i n t b u f f e r = new P o i n t [ num e 2 ] ;
i n t f a c e t b u f f e r = new i n t [ n u m f a c e t ] ;
f o r ( i n t i = 0 ; i < n u m f a c e t ; + + i ) f a c e t b u f f e r [ i ] = NULL ;
/ / Build the point b u f f e r in the order of the halfedge i t e r a t o r .
Halfedge iterator he itr = p . halfedges begin ( ) ;
f o r ( i n t i = 0 ; i < num e 2 ; + + i , + + h e i t r ) {
H a l f e d g e a r o u n d f a c e t c i r c u l a t o r c i r = h e i t r >f a c e t b e g i n ( ) ;
/ / Generate the p o i n t with the geometry p o l i c y .
rule . point rule ( cir , point buffer [ i ] ) ;
}
h e i t r = p . h a l f e d g e s b e g i n ( ) ; / / Used t o c a l c u l a t e t h e v e r t e x i n d e x .
/ / The v e r t e x i n d e x i s t h e d i s t a n c e o f t h e h a l f e d g e i t e r a t o r t o i t s b e g i n i t e r a t o r .
/ / B u i l d t h e f a c e t b u f f e r . Each r e f i n e d f a c e t c o r r e s p o n d s t o a c o n t r o l p r i m i t i v e .
/ / C o n s t r u c t t h e f a c e t f a c e t .
Facet iterator f i t r = p. facets begin ();
f o r ( i n t i = 0 ; i < num f ; + + i , + + f i t r ) {
Halfedge around facet circulator
c i r = f i t r >f a c e t b e g i n ( ) ;
i n t n = CGAL : : c i r c u l a t o r s i z e ( c i r ) ; / / Can be an e x t r a o r d i n a r y f a c e t .
f a c e t b u f f e r [ i ] = new i n t [ n + 1 ] ;
facet buffer [ i ][0] = n;
for ( int j = 1 ; j < n +1; ++ j , ++ c i r )
facet buffer [ i ][ j ] =
s t d : : d i s t a n c e ( h e i t r , H a l f e d g e h a n d l e ( c i r . o p e r a t o r >()));
}
/ / C o n s t r u c t t h e edgef a c e t .
Halfedge iterator e i t r = p . halfedges begin ( ) ;
f o r ( i n t i = num f ; i < num f +num e ; + + i , + + e i t r ) {
f a c e t b u f f e r [ i ] = new i n t [ 4 + 1 ] ;
facet buffer [ i ][0] = 4;
f a c e t b u f f e r [ i ] [ 1 ] = ( inum f ) 2 ;
f a c e t b u f f e r [ i ] [ 2 ] = s t d : : d i s t a n c e ( h e i t r , e i t r >p r e v ( ) ) ;
++ e i t r ;
f a c e t b u f f e r [ i ] [ 3 ] = ( inum f ) 2 + 1 ;
f a c e t b u f f e r [ i ] [ 4 ] = s t d : : d i s t a n c e ( h e i t r , e i t r >p r e v ( ) ) ;
}
/ / C o n s t r u c t t h e v e r t e x f a c e t .
Vertex iterator vitr = p. vertices begin ();
f o r ( i n t i = num f +num e ; i < num f +num e+num v ; + + i , + + v i t r ) {
Halfedge around vertex circulator
c i r = v i t r >v e r t e x b e g i n ( ) ;
i n t n = CGAL : : c i r c u l a t o r s i z e ( c i r ) ; / / Can be an e x t r a o r d i n a r y v e r t e x .
f a c e t b u f f e r [ i ] = new i n t [ n + 1 ] ;
facet buffer [ i ][0] = n;

f o r ( i n t j = 1 ; j < n + 1 ; + + j , c i r )
facet buffer [ i ][ j ] =
s t d : : d i s t a n c e ( h e i t r , H a l f e d g e h a n d l e ( c i r . o p e r a t o r >()));

/ / Rebuild the r e f i n e d polyhedron .


p. clear ();
P o l y h e d r o n m e m o r y b u i l d e r <P o l y h e d r o n > pb ( num e 2 , p o i n t b u f f e r ,
num f +num e+num v , f a c e t b u f f e r ) ;
p . d e l e g a t e ( pb ) ;
/ / r e l e a s e t h e b u f f e r o f t h e new l e v e l
for ( int i = 0 ; i < num facet ; ++ i ) delete [ ] f a c e t b u f f e r [ i ] ;
delete [ ] facet buffer ;
delete [ ] point buffer ;
}

After the facet-vertex list is build, the refined polyhedron is rebuild from the list with the modifier and the
incremental builder.

Point p = ( Point ) point buffer ;


pb . b e g i n s u r f a c e ( n u m p o i n t , n u m f a c e t ) ; {

f o r ( i n t i = 0 ; i < n u m p o i n t ; + + i ) pb . a d d v e r t e x ( p [ i ] ) ;
for ( int i = 0 ; i < num facet ; ++ i ) {
pb . b e g i n f a c e t ( ) ; {
for ( int n = 0 ; n < f a c e t b u f f e r [ i ] [ 0 ] ; + + n )
pb . a d d v e r t e x t o f a c e t ( f a c e t b u f f e r [ i ] [ n + 1 ] ) ;
}
pb . e n d f a c e t ( ) ;
}

}
pb . e n d s u r f a c e ( ) ;

The pb is an object of the CGAL::Polyhedron incremental builder 3.

CSL
CSLs policy-based approach offers a convenient way to specialize a subdivision with a template geometry
policy class. The accompanying source code of CSL supports Catmull-Clark, Loop, and Doo-Sabin geometry policies and hence the subdivisions. Each of the subdivision is constructed by a proper combination
of the refinement host and the subdivision rules. A customized subdivision can be easily created with a
user-customized policy class. For example, a linear subdivision with PQQ configuration is parameterized
with average geometry rules.

t e m p l a t e < c l a s s P o l y>
c l a s s a v e r a g e r u l e : public q u a d r a l i z e r u l e < Poly > {
public :
/ / Generate the f a c e t centroid .
void f a c e p o i n t r u l e ( F a c e t h a n d l e f a c e t , P o i n t & pt ) {
H a l f e d g e a r o u n d f a c e t c i r c u l a t o r h c i r = f a c e t >f a c e t b e g i n ( ) ;
int n = 0;
FT p [ ] = { 0 , 0 , 0 } ;
do {
P o i n t t = h c i r >v e r t e x ()> p o i n t ( ) ;
p[0] += t [0] , p[1] += t [1] , p[2] += t [2];
++n ;
} w h i l e ( + + h c i r ! = f a c e t >f a c e t b e g i n ( ) ) ;
pt = Point ( p [ 0 ] / n , p [ 1 ] / n , p [ 2 ] / n ) ;
}
/ / G e n e r a t e t h e edge midpoint .
v o i d e d g e p o i n t r u l e ( H a l f e d g e h a n d l e edge , P o i n t & p t ) {
P o i n t p1 = edge>v e r t e x ()> p o i n t ( ) ;
P o i n t p2 = edge>o p p o s i t e ()> v e r t e x ()> p o i n t ( ) ;
p t = P o i n t ( ( p1 [ 0 ] + p2 [ 0 ] ) / 2 , ( p1 [ 1 ] + p2 [ 1 ] ) / 2 , ( p1 [ 2 ] + p2 [ 2 ] ) / 2 ) ;
}
/ / Return the vertex i t s e l f .
void v e r t e x p o i n t r u l e ( Vertex handle vertex , P o i n t & pt ) {
p t = v e r t e x >p o i n t ( ) ;
}
};

Following function call invokes this simple linear PQQ subdivision.

q u a d q u a d r a l i z e p o l y h e d r o n ( p o l y , a v e r a g e r u l e <P o l y h e d r o n > ( ) , s t e p ) ;

Though demonstrated with a specific enriched Polyhedron 3 in our polyhedron viewer, CSL accepts
any polyhedron mesh specialized from the Polyhedron 3 . The only geometry requirement is the Point
type defined in the vertex item. Subdivisions in CSL are build as proper combinations of the refinement
functions and the geometry policy classes (hence the name Combinatory SL). The proper combination is
constrained by the stencil correspondence and checked in the compiler time.

Figure 12 Models used for benchmarking. Complexity (in triangles): Bunny: 69,451, Lion
vase: 400k, David (simplified version): 700k, Raptor: 2M.
The tutorial version of CSL only supports the geometry modification of the vertex (hence only the
isotrophic subdivision). Boundary can be easily supported by introducing the boundary policy. But for
anisotropic subdivisions (e.g. Pixars crease rules), data modifications of the halfedge are required. It can
be done by introducing halfedge policy, though a much complex structure is needed in the refinement host.

5 Auxiliary Geometric Algorithms


There are geometric algorithms available in C GAL, not directly processing a mesh, but that can be helpful
in the mesh processing context, for example, a fast self intersection test, the smallest enclosing sphere, or
the minimum width of a point set. We use a few large meshes (see Fig. 12) to evaluate performance on a
laptop with an Intel Mobile Pentium4 running at 1.80GHz with 512KB cache and 256MB main memory
under Linux. For our largest mesh, the Raptor, the algorithms started swapping. Nevertheless, the runtimes
are quite acceptable.
(These programs were written with features only available with the next C GAL release 3.1., in particular
the box intersection and an improved convex hull function are not yet available.)
time in
min. sphere
convex
min.
self interseconds
double gmpq
hull
width
section
Bunny
0.02
14
3.5
111
3.2
Lion vase 0.19
396
13.1
276
22.9
David
0.12
215
20.3
112
41.6
Raptor
0.35
589
45.5
123
92.3

5.1 Self Intersection Test


The self intersection test is based on the general algorithm for fast box intersections [ZE02], applied to the
bounding boxes of individual facets, i.e. triangles, as a filtering step. The triangles of intersecting boxes are
then checked in detail, i.e., if they share a common edge they do not intersect, if they share a common vertex
they may intersect or not depending on the opposite edge, and otherwise the intersection test for triangles
in the C GAL geometric kernel is used to decide the intersection. A geometric kernel with exact predicates
is sufficient for this algorithm. Interestingly, only the lion vase is free of self intersections. The algorithm

is fast, see the table below, though not sufficient for interactive use. Nevertheless, a final quality check is
possible for quite large meshes.
See the full program in examples/intersection.C, we discuss a shortened version here that
detects self intersections among a triangle soup, i.e., we ignore the extra handling for the mesh and the
incidences that are no intersections.

// file :
# include
# include
# include
# include
# include
# include
# include
# include
# include
typedef
typedef
typedef
typedef
typedef
typedef

examples / B o x i n t e r s e c t i o n d / t r i a n g l e s e l f i n t e r s e c t .C
<CGAL/ E x a c t p r e d i c a t e s i n e x a c t c o n s t r u c t i o n s k e r n e l . h>
<CGAL/ i n t e r s e c t i o n s . h>
<CGAL/ p o i n t g e n e r a t o r s 3 . h>
<CGAL/ Bbox 3 . h>
<CGAL/ b o x i n t e r s e c t i o n d . h>
<CGAL/ f u n c t i o n o b j e c t s . h>
<CGAL/ J o i n i n p u t i t e r a t o r . h>
<CGAL/ c o p y n . h>
<vector>
CGAL : : E x a c t p r e d i c a t e s i n e x a c t c o n s t r u c t i o n s k e r n e l
Kernel : : Point 3
Kernel : : Triangle 3
s t d : : v e c t o r <T r i a n g l e 3 >
Triangles : : i t e r a t o r
CGAL : : B o x i n t e r s e c t i o n d : : B o x w i t h h a n d l e d <double , 3 ,

Kernel ;
Point 3 ;
Triangle 3 ;
Triangles ;
Iterator ;
I t e r a t o r > Box ;

T r i a n g l e s t r i a n g l e s ; / / global vector of a l l t r i a n g l e s

Up to here we have included all necessary include files, defined our triangle type and a std::vector
storing all triangles, and the Box type. As a specialty, the chosen box type with the double type for its
coordinates and in dimension three has special support for accepting CGAL::Bbox 3 in a constructor. The
box type additionally stores an iterator to the triangle that it encloses.
Next, we define a callback function for the box intersection. It accepts two boxes as arguments and
will be called when the algorithm detects that these two boxes are intersecting. The algorithm uses an idfunction of the boxes, here mapped to the address of the triangles, to avoid reporting pairs of boxes twice.
The trivial intersection of a box with itself is not reported. Now, the boxes are placeholders for triangles;
we access the triangles and test whether the triangles intersect as well.

/ / callback function that reports all truly intersecting triangles


v o i d r e p o r t i n t e r s ( c o n s t Box& a , c o n s t Box& b ) {
s t d : : c o u t << Box << ( a . h a n d l e ( ) t r i a n g l e s . b e g i n ()) < < and
<< (b . h a n d l e ( ) t r i a n g l e s . b e g i n ()) < < i n t e r s e c t ;
i f ( ! a . h a n d l e ()> i s d e g e n e r a t e ( ) & & ! b . h a n d l e ()> i s d e g e n e r a t e ( )
&& CGAL : : d o i n t e r s e c t ( ( a . h a n d l e ( ) ) , ( b . h a n d l e ( ) ) ) ) {
s t d : : c o u t << , and t h e t r i a n g l e s i n t e r s e c t a l s o ;
}
s t d : : c o u t << . << s t d : : e n d l ;
}

The main function creates some random triangles, fills a std::vector of boxes with the corresponding C GAL bounding boxes of all triangles, and calls the box self intersection d function of C GAL.

i n t main ( ) {
/ / C r e a t e 1 0 random t r i a n g l e s
t y p e d e f CGAL : : R a n d o m p o i n t s i n c u b e 3 <P o i n t 3 >
Pts ;
t y p e d e f CGAL : : C r e a t o r u n i f o r m 3 < P o i n t 3 , T r i a n g l e 3 >
Creator ;
t y p e d e f CGAL : : J o i n i n p u t i t e r a t o r 3 <P t s , P t s , P t s , C r e a t o r > T r i a n g l e g e n ;
Pts
p o i n t s ( 1 ) ; / / i n c e n t e r e d cube [ 1 ,1)3
Triangle gen triangle gen ( points , points , points ) ;
CGAL : : c o p y n ( t r i a n g l e g e n , 1 0 , s t d : : b a c k i n s e r t e r ( t r i a n g l e s ) ) ;

/ / Create t h e c o r r e s p o n d i n g v e c t o r of bounding boxes


s t d : : v e c t o r <Box> b o x e s ;
f o r ( I t e r a t o r i = t r i a n g l e s . b e g i n ( ) ; i ! = t r i a n g l e s . end ( ) ; + + i )
b o x e s . p u s h b a c k ( Box ( i>bbox ( ) , i ) ) ;
/ / Run t h e s e l f i n t e r s e c t i o n a l g o r i t h m w i t h a l l d e f a u l t s
CGAL : : b o x s e l f i n t e r s e c t i o n d ( b o x e s . b e g i n ( ) , b o x e s . end ( ) , r e p o r t i n t e r s ) ;
return 0 ;
}

For the full program example using triangulated meshes, the callback is more involved checking for
triangles that intersect geometrically but that should not be reportted as intersecting since they intersect only
at the common endpoint or common edge with some proper neighbor. Since the callback is more costly, the
tradeoff between calling the box intersection algorithm with the boxes themselfes or with pointers to boxes
(bot variants are supported by default) shift in faviour for the pointer version. So we create an additional
std::vector with pointers to the boxes and run the algorithm on those. For better practical performance,
one also has to consider a cutoff parameter of the algorithm. A higher value than the currently chosen
default turns out to be quite a bit faster for our meshes.

5.2 Smallest Enclosing Sphere


Smallest enclosing spheres, min. sphere for short, are commonly used as bounding volumes in bounding
volume hierarchies, for example, to speed up intersection tests. The algorithm in [FG03] needs a geometric
kernel with an exact number type for correctness, but specializations for the number types double and
float have been written to be quite robust as well. For the exact version, we use here gmpq from the
GMP number type package [Gra96]. The runtimes are slow, but still feasible for huge meshes. In contrast,
when we run the algorithm with the double number type, it becomes fast enough to be considered for
interactive purposes, for example, selecting a good view frustum in a viewer. We compared the resulting
spheres of the algorithm running with the exact and with the floating-point number type. In all cases the
sphere center coordinates and the radius where exactly the same up to the seven digits after the decimal.
We want to point out the running time anomaly in above tablethe smaller lion vase needs longer than the
larger David sculpturewhich is o.k. for this data sensitive algorithm. It is worst-case linear time (expected
time over the randomized order of the input points), but depends on a heuristic to be really fast.
See the full program in examples/mini_ball.C, we discuss some aspects of it here. When running
the program with the double number type, we choose the kernel:

t y p e d e f CGAL : : S i m p l e c a r t e s i a n <double >

Kernel ;

Instead, when picking the exact number type, we use the kernel:

t y p e d e f CGAL : : C a r t e s i a n < CGAL : : Gmpq>

Kernel ;

Since we are only interested in the points in the vertices of the polyhedron, we choose a version of the
polyhedron with small memory footprint:

t y p e d e f CGAL : : P o l y h e d r o n 3 <K e r n e l , CGAL : : P o l y h e d r o n m i n i t e m s 3 ,


CGAL : : H a l f e d g e D S v e c t o r >
Polyhedron ;

The chosen version of the algorithm, CGAL::Min sphere of spheres d, is actually designed to
compute the smallest enclosing sphere of spheres, so it could be used to construct hierarchical schemes

of bounding spheres, but we use it here just for points, i.e., spheres with a degenerate zero radius. The
necessary conversion from points to spheres requires an explicit step.

void m i n s p h e r e o f s p h e r e s ( const Polyhedron & P ) {


Min sphere of spheres min sphere ;
min sphere . prepare ( P . s i z e o f v e r t i c e s ( ) ) ;
for ( P o i n t i t e r a t o r i = P . points begin ( ) ; i != P . points end ( ) ; + + i ) {
m i n s p h e r e . i n s e r t ( S p h e r e ( i , 0 . 0 ) ) ;
}
// ...

The algorithm is working in arbitrary dimension, and in the exact case with roots in the coordinates.
This makes the access to the resulting sphere less intuitive, e.g., the center point is accessed with an iterator
over the coordinates, and the following code works only for the double version of the program.

// ...
c o u t << C e n t e r p o i n t
: ;
s t d : : copy ( m i n s p h e r e . c e n t e r c a r t e s i a n b e g i n ( ) ,
min sphere . c e n t e r c a r t e s i a n e n d ( ) ,
s t d : : o s t r e a m i t e r a t o r <double >( c o u t , ) ) ;
c o u t << e n d l ;
c o u t << Double r a d i u s : << m i n s p h e r e . r a d i u s () < < e n d l ;
}

5.3 Convex Hull and the Width of a Point Set


Convex hulls are, similar to the smallest enclosing sphere, sometimes useful as bounding volumes, for
example, as a placeholder for faster interaction. For the quickhull algorithm [BDH96] used in C GAL a
geometric kernel with exact predicates suffices, and the convex hull can be computed significantly faster
than the exact smallest enclosing sphere, however, far slower than the double version of the smallest
enclosing sphere.

typedef
typedef
typedef
typedef
typedef

CGAL : : E x a c t p r e d i c a t e s i n e x a c t c o n s t r u c t i o n s k e r n e l
Kernel : : Vector 3
Kernel : : Point 3
CGAL : : P o l y h e d r o n 3 <K e r n e l >
Polyhedron : : P o i n t c o n s t i t e r a t o r

void c o n v e x h u l l ( const
CGAL : : c o n v e x h u l l 3
c e r r << # v e r t i c e s
c e r r << # f a c e t s
c e r r << # e d g e s
}

Kernel ;
Vector ;
Point ;
Polyhedron ;
Point iterator ;

P o l y h e d r o n & P , P o l y h e d r o n & Q) {
( P . points begin ( ) , P . points end ( ) , Q) ;
: << Q . s i z e o f v e r t i c e s () < < e n d l ;
: << Q . s i z e o f f a c e t s () < < e n d l ;
: << (Q . s i z e o f h a l f e d g e s ( ) / 2 ) < < e n d l ;

In fact we are more interested in the convex hull as a preprocessing to another optimization algorithm,
the width of a point set. The minimum width is obtained by two parallel planes of smallest possible distance
that enclose all points between them. The printing time for three-dimensional stereo-lithographic printer
is proportional to the height of the object printed. Minimizing this height can be done by computing the
normal direction that minimizes the width between the two planes, and then align this normal direction with
the printer height direction.
The width algorithm requires an exact number type, so we use the result of the convex hull computation,
convert all vertices to exact points, recompute the convex hull, and run the width algorithm. The runtimes in
the table above are for the conversion, recomputing of the convex hull and the width computation together,

but excluding the first convex hull computation that runs on the full data set.

typedef
typedef
typedef
typedef
typedef

CGAL : : E x a c t p r e d i c a t e s e x a c t c o n s t r u c t i o n s k e r n e l
CGAL : : P o l y h e d r o n 3 <EKernel >
EKernel : : P o i n t 3
CGAL : : W i d t h d e f a u l t t r a i t s 3 <EKernel >
CGAL : : Width 3<W i d t h t r a i t s >

EKernel ;
EPolyhedron ;
EPoint ;
Width traits ;
Width ;

void width ( const Polyhedron & P ) {


s t d : : vector < EPoint > e p o i n t s ;
for ( P o i n t i t e r a t o r i = P . points begin ( ) ; i ! = P . points end ( ) ; + + i )
e p o i n t s . p u s h b a c k ( E P o i n t ( CGAL : : t o d o u b l e ( i>x ( ) ) ,
CGAL : : t o d o u b l e ( i>y ( ) ) ,
CGAL : : t o d o u b l e ( i>z ( ) ) ) ) ;
Width w i d t h ( e p o i n t s . b e g i n ( ) , e p o i n t s . end ( ) ) ;
Width : : RT num , denum ;
w i d t h . g e t s q u a r e d w i d t h ( num , denum ) ;
c e r r << w i d t h
: < < ( s q r t ( CGAL : : t o d o u b l e ( num ) /
CGAL : : t o d o u b l e ( denum ))) < < e n d l ;
: << w i d t h . g e t b u i l d d i r e c t i o n () < < e n d l ;
c e r r << d i r e c t i o n
}

See the full program in examples/convex_hull.C .

6 Application demo
The application demo runs on windows and features a standard MFC multi document-view architecture. It
features a trackball to interactively manipulate the polyhedron. Accepted mesh file formats are ASCII OFF
and OBJ (1-based vertex indices for the latter).
Mouse interaction
Left: rotation
Right: translation
Both: zoom.
Main keys
Press s to subdivide the mesh using the quad-triangle scheme.
Press r to choose a rendering mode. Note that superimposing the control edges during subdivision is only
available for the quad-triangle subdivision scheme.
Press ctrl+c to generate a 24-bits raster image output to the clipboard.
Compiling on Windows
The application has been compiled on MS .NET 2003 using CGAL. Apply the following steps to compile
the demo:
Install the last release of CGAL.
Define an environment variable CGALROOT with the path to the CGAL folder. If you installed
CGAL with the standard wizard installation, the CGALROOT variable was defined at that time.
Compile the CGAL library in multithread mode. Go in CGALROOT/src directory and open
the cgallib project. Open from the main menu, Project Properties. Go to C/C++, Code Generation, Runtime Library and choose Multi-threaded Debug (/MTd). Go to Librarian, General,
Output File and modify to ../lib/msvc7/CGAL MT DEBUG.LIB. If you want to build in release
mode, choose at the Project Properties Configuration Release, and do the same steps as before
but at the Runtime Library you choose Multi-threaded (/MT) and in the output of Librarian put
../lib/msvc7/CGAL MT RELEASE.LIB.

To build debug and release mode, you need to choose the mode in the main menu Build at the Configuration manager.
Open the Mesh project in the tutorial/Polyhedron/MFC/Subdivision/ directory. Choose from the Configuration manager the mode (release or debug) you want to build your application and then go to the
next step.
Rebuild all.

References
[Ale01]

Andrei Alexandrescu. Modern C++ Design: Generic Programming and Design Patterns Applied. Addison-Wesley, 2001.

[Aus99]

Matthew H. Austern. Generic programming and the STL: using and extending the C++ Standard Template Library. Addison-Wessley, 1999.

[BDH96]

C. Bradford Barber, David P. Dobkin, and Hannu Huhdanpaa. The Quickhull algorithm for
convex hulls. ACM Trans. Math. Softw., 22(4):469483, December 1996.

[CC78]

E. Catmull and J. Clark. Recursively generated B-spline surfaces on arbitrary topological


meshes. Computer-Aided Design, 10:350355, September 1978.

[DS78]

D. Doo and M. Sabin. Behaviour of recursive division surfaces near extraordinary points.
Computer-Aided Design, 10:356360, September 1978.

[FG03]

K. Fischer and B. Gartner. The smallest enclosing ball of balls: Combinatorial structure and
algorithms. In Proc. of ACM Sympos. Comput. Geom., pages 292301, 2003.

[FGK+ 00] A. Fabri, G.-J. Giezeman, L. Kettner, S. Schirra, and S. Scho nherr. On the Design of CGAL, a
Computational Geometry Algorithms Library. Softw. Pract. Exp., 30(11):11671202, 2000.
[Gra96]

T. Granlund. GNU MP, The GNU Multiple Precision Arithmetic Library, version 2.0.2, June
1996.

[Ket99]

L. Kettner. Using generic programming for designing a data structure for polyhedral surfaces.
Comput. Geom. Theory Appl., 13:6590, 1999.

L. Kobbelt. 3-Subdivision. In Proceedings of SIGGRAPH, pages 103112, 2000.

[Kob00]
[Lev03]

A. Levin. Polynomial generation and quasi-interpolation in stationary non-uniform subdivision.


Compu. Aided Geom. Des., 20(1):4160, 2003.

[Loo94]

C. Loop. Smooth spline surfaces over irregular meshes. In Proceedings of SIGGRAPH, pages
303310, 1994.

[SL03]

J. Stam and C. Loop. Quad/triangle subdivision. Computer Graphics Forum, 22(1):7985,


March 2003.

[WW02]

J. Warren and H. Weimer. Subdivision Methods for Geometric Design. Morgan Kaufmann,
2002.

[ZE02]

Afra Zomorodian and Herbert Edelsbrunner. Fast software for box intersection. Int. J. Comput.
Geom. Appl., 12:143172, 2002.

[ZS00]

D. Zorin and P. Schroder, editors. Subdivision for Modeling and Animation, Course Notes.
ACM SIGGRAPH, 2000.

You might also like