revise the section 5 and 6 in the manual.

This commit is contained in:
Le-Jeng Shiue 2006-02-20 05:43:36 +00:00
parent 7383a82726
commit 477dc132ec
1 changed files with 170 additions and 146 deletions

View File

@ -354,11 +354,11 @@ void PQQ(Polyhedron& p, Mask<Polyhedron> mask, int depth)
\end{ccExampleCode} \end{ccExampleCode}
\ccc{Polyhedron} is a model of \ccc{CGAL::Polyhedron_3}, which \ccc{Polyhedron} is a model of \ccc{CGAL::Polyhedron_3}, which
is a mesh data structure that can represent arbitrary is a generic mesh data structure of arbitrary
2-manifolds. \ccc{PQQ(...)} provides the process refining 2-manifolds. \ccc{PQQ()} provides the process refining
the control polyhedron \ccc{p}. During the refinement, the control polyhedron \ccc{p}. During the refinement,
\ccc{PQQ(...)}, the \emph{refinement host}, computes and assigns the \ccc{PQQ()}, the \emph{refinement host}, computes and assigns the
new points by communicating with the \ccc{mask}. new points by coorperating with the \ccc{mask}.
To implement Catmull-Clark subdivision, To implement Catmull-Clark subdivision,
\ccc{Mask}, the \emph{geometry policy}, has to realize the geometry \ccc{Mask}, the \emph{geometry policy}, has to realize the geometry
masks of Catmull-Clark subdivision. masks of Catmull-Clark subdivision.
@ -372,7 +372,7 @@ To implement the geometry masks, we need to know how
a mask communicates with the refinement host. The PQQ refinement a mask communicates with the refinement host. The PQQ refinement
defines three stencils, and therefor three geometry masks defines three stencils, and therefor three geometry masks
are required for Catmull-Clark subdivision. are required for Catmull-Clark subdivision.
The interfaces of the stencils are specified like The interfaces of the stencils are specified as
the policy class \ccc{PQQ_stencil_3}. the policy class \ccc{PQQ_stencil_3}.
\begin{ccExampleCode} \begin{ccExampleCode}
@ -384,11 +384,11 @@ class PQQ_stencil_3 {
}; };
\end{ccExampleCode} \end{ccExampleCode}
Now we can compute the new points using the primitive handle A mask computes the new point with the primitive handle
passed into the policy functions, and assign the result to passed into the policy function, and assigns the new point to
\ccc{Point& pt}. Since our goal is to implement Catmull-Clark \ccc{Point& pt}. Since our goal is to implement Catmull-Clark
subdivision, we need to implement the policy functions by its subdivision, we need to implement the policy functions realizing
geometry masks. its geometry masks.
%For clarity, we rename the policy class %For clarity, we rename the policy class
%to indicate geometry masks are in place. %to indicate geometry masks are in place.
@ -444,16 +444,19 @@ class CatmullClark_mask_3 {
}; };
\end{ccExampleCode} \end{ccExampleCode}
Note types used in this example (such as \ccc{Point} and The listed codes show the default implementation of Catmull-Clark
\ccc{Facet_handle}) are assumed to be type-defined within the masks (and hence the Catmull-Clark subdivision function)
\ccc{Polyhedron}. This \ccc{CatmullClark_mask_3} is designed in \ccc{Subdivision_method_3}.
This default implementation assumes the \emph{types}
(such as \ccc{Point} and \ccc{Facet_handle}) are defined
within the \ccc{Polyhedron}. It is designed
to work on a \ccc{CGAL::Polyhedron_3} with the default CGAL to work on a \ccc{CGAL::Polyhedron_3} with the default CGAL
kernel geometry. You may need to rewrite the geometry computation kernel geometry. You may need to rewrite the geometry computation
in the code to match the kernel geometry of your application. to match the kernel geometry of your application.
To excute the subdivision, you can To invoke the subdivision method, you can
simply call the \ccc{PQQ(...)} with the Catmull-Clark mask simply call the \ccc{PQQ(...)} with the Catmull-Clark mask
we just designed. we just defined.
\begin{ccExampleCode} \begin{ccExampleCode}
PQQ(p, CatmullClark_mask_3<Polyhedron>(), depth); PQQ(p, CatmullClark_mask_3<Polyhedron>(), depth);
@ -467,21 +470,24 @@ PQQ(p, CatmullClark_mask_3<Polyhedron>(), depth);
%\end{ccExampleCode} %\end{ccExampleCode}
Loop, Doo-Sabin and $\sqrt{3}$ subdivisions are implemented Loop, Doo-Sabin and $\sqrt{3}$ subdivisions are implemented
with a similar process: pick a refinement host and implement in a similar process: pick a refinement host and implement
the geometry policy. To develop your own subdivision with the geometry policy. The key of developing your own
\ccc{Subdivision_method_3}, the key is subdivision method is implementing the right combination of
to find the right combination of the host and the policy, the refinement host and the geometry policy. It is
which are explained in the following sections. explained in the next two sections.
% +-------------------------------------------------------------+ % +-------------------------------------------------------------+
\section{Refinement Host} \section{Refinement Host}
\label{secRefHost} \label{secRefHost}
\ccc{Subdivision_method_3} provides four refinement hosts of primal A refinement host is a function with template parameters of
quadrilateral quadrisection (PQQ), primal triangle a polyhedron class and a geometry mask class. It refines
quadrisection (PTQ), dual quadrilateral the input polyhedron, and assigns new points by the geometry masks.
quadrisection (DQQ) and $\sqrt{3}$ triangulation, which \ccc{Subdivision_method_3} supports four refinement hosts:
are used by Catmull-Clark, Loop, \DS\ and $\sqrt{3}$ subdivision, primal quadrilateral quadrisection (PQQ),
respectively. primal triangle quadrisection (PTQ), dual quadrilateral
quadrisection (DQQ) and $\sqrt{3}$ triangulation.
They are respectively used by Catmull-Clark, Loop, \DS\ and $\sqrt{3}$
subdivision.
\begin{ccTexOnly} \begin{ccTexOnly}
\begin{center} \begin{center}
@ -502,20 +508,18 @@ respectively.
\begin{ccExampleCode} \begin{ccExampleCode}
template <class Polyhedron> namespace Subdivision_method_3 {
class Subdivision_method_3 { template <class Polyhedron, template <typename> class Mask>
// S is the geometry policy realizing the geometry masks void PQQ(Polyhedron& p, Mask<Polyhedron> mask, int step);
template <template <typename> class S>
static void PQQ(Polyhedron& p, S<Polyhedron> rule, int step);
template <template <typename> class S> template <class Polyhedron, template <typename> class Mask>
static void PTQ(Polyhedron& p, S<Polyhedron> rule, int step); void PTQ(Polyhedron& p, Mask<Polyhedron> mask, int step);
template <template <typename> class S> template <class Polyhedron, template <typename> class Mask>
static void DQQ(Polyhedron& p, S<Polyhedron> rule, int step); void DQQ(Polyhedron& p, Mask<Polyhedron> mask, int step)
template <template <typename> class S> template <class Polyhedron, template <typename> class Mask>
static void Sqrt3(Polyhedron& p, S<Polyhedron> rule, int step); void Sqrt3(Polyhedron& p, Mask<Polyhedron> mask, int step)
} }
\end{ccExampleCode} \end{ccExampleCode}
@ -528,59 +532,59 @@ class Subdivision_method_3 {
%% order is implicitly used to determine the stencil of %% order is implicitly used to determine the stencil of
%% the visited node. %% the visited node.
Each refinement host is a template function of The polyhedron class is a specialization of the
a polyhedron type and a policy type. The polyhedron type is \ccc{CGAL::Polyhedron_3}, and the mask is a policy
a model of the \ccc{CGAL::Polyhedron_3} concept, and the class realizing the geometry masks of the subdivision
policy type is a class with functions realizing the method.
geometry masks of a specific subdivision scheme.
Refinement hosts refine the polyhedron, maintain the stencils A refinement host refines the input polyhedron, maintains
(i.e.~the mapping between the control mesh and the refined mesh), the stencils (i.e.~the mapping between the control mesh
and call policy functions to compute and assign the new points. and the refined mesh), and calls the geometry mask
In our implementation, refinements are done by applying a to compute the new points.
sequence of connectivity operations (mostly Euler operations). In \ccc{Subdivision_method_3}, refinements are implemented
The stencils are maintained by ordering nodes on the refined as a sequence of connectivity operations (mostly Euler operations).
polyhedron to match the sequence of the connectivity operations. The order of the connectivity operations plays the key of the mapping
By matching the order, no flag to classify the stencils of the stencils. By matching the order, no flag in the primitives
is required to maintain and access the stencils. is required to register the stencils, and it avoids the data
But to make the ordering trick work, the polyhedron type need dependency of the refinement host on the polyhedron class.
to use an internal storage with sequential ordering, such as To make the ordering trick work, the polyhedron class must
a vector or a linked-list. A sequential ordered container inserts have a sequential container, such as a vector or a linked-list, as
new entries at the end, and its iterator visits the entries in the the internal storage.
order of their insertion. Non-sequential structures such as %The polyhedron class always inserts
%new primitives at the end, and
A sequential container guarantees that the iterators of the
polyhedron always traverse the primitives in the order of their
insertions. Non-sequential structures such as
tree or map do not provide the required ordering, and hence tree or map do not provide the required ordering, and hence
can not be used with \ccc{Subdivision_method_3}. can not be used with \ccc{Subdivision_method_3}.
Although \ccc{Subdivision_method_3} does not require flags or Although \ccc{Subdivision_method_3} does not require flags
tags to support the refinements and the stencil accesses, it to support the refinements and the stencils, it
still need to know how to compute and where to store the geometry still needs to know how to compute and where to store the geometry
data (in most cases, the points). \ccc{Subdivision_method_3} data (i.e.~the points). \ccc{Subdivision_method_3}
expects that the typename \ccc{Point_3} is expects that the typename \ccc{Point_3} is
defined in the scope of \ccc{Polyhedron} and \ccc{Polyhedron::Vertex}. defined in the geometry kernel of the polyhedron
The refinement hosts use (i.e.~the \ccc{Polyhedron::Traits::Kernel}).
this point type as the geometry holder and delegate the geometry A point of the type \ccc{Point_3} is returned by the geometry
computation to the geometry policies. The geometry policy is policy and is then assgined to the new vertex.
explained in next section. The geometry policy is explained in next section.
For details of the refinement algorithm and implementation, For details of the refinement implementation,
interested users can refer to \cite{cgal:sp-mrbee-05}. interested users should refer to \cite{cgal:sp-mrbee-05}.
% +-------------------------------------------------------------+ % +-------------------------------------------------------------+
\section{Geometry Policy} \section{Geometry Policy}
A geometry policy defines a set of geometry masks. A geometry policy defines a set of geometry masks.
Each geometry mask is realized as a member function (i.e.~the Each geometry mask is realized as a member function
policy function) computing and assigning new points according computing the new point of the subdivision surface.
to a particular subdivision scheme.
%The policy interface is defined with the refinement host. %The policy interface is defined with the refinement host.
Each policy function receives a primitive handle Each geometry mask receives a primitive handle
(e.g.~\ccc{Halfedge_handle}) of the control polyhedron, (e.g.~\ccc{Halfedge_handle}) of the control polyhedron,
and the reference of the \ccc{Point} to the refined vertex. and returns a \ccc{Point_3} to the subdivided vertex.
In general, the implementation of the policy function The function collects the neighbors of the primitive handle
collects the neighbors of the primitive handle (i.e.~nodes (i.e.~nodes on the stencil), and computes the new point
on the stencil), and (ideally) computes the new point based on the neighbors and the mask (i.e.~the stencil weights).
by a linear combination of the stencil
nodes and the mask (i.e.~the stencil weights).
\begin{ccTexOnly} \begin{ccTexOnly}
\begin{center} \begin{center}
@ -595,20 +599,18 @@ nodes and the mask (i.e.~the stencil weights).
</CENTER> </CENTER>
\end{ccHtmlOnly} \end{ccHtmlOnly}
This picture shows the stencils and the geometry masks for This figure shows the geometry masks for
Catmull-Clark subdivision. The weights shown here are unnormalized, Catmull-Clark subdivision. The weights shown here are unnormalized,
and $n$ is the valence of the vertex. The new points are and $n$ is the valence of the vertex. The new points are
computed by the summation of the weighted points on their stencils. computed by the summation of the weighted points on their stencils.
Following codes show an implementation of the geometry policy of Following codes show an implementation of the geometry mask of
the facet-node. \ccc{Point} is a typedef to the \ccc{Point_3} the facet-node. The complete listing
in \ccc{Polyhedron}. Note when \ccc{n} is $4$, this policy computes of the Catmull-Clark geometry policy is in the Section~\ref{secCC}.
the facet-node shown in the above picture. The complete listing
of the Catmull-Clark policy class is in the Section~\ref{secCC}.
\begin{ccExampleCode} \begin{ccExampleCode}
template <class Polyhedron> template <class Polyhedron>
class CatmullClark_mask_3 { class CatmullClark_mask_3 {
void facet_node(Facet_handle facet, Point& pt) { void facet_node(Facet_handle facet, Point_3& pt) {
Halfedge_around_facet_circulator hcir = facet->facet_begin(); Halfedge_around_facet_circulator hcir = facet->facet_begin();
int n = 0; int n = 0;
FT p[] = {0,0,0}; FT p[] = {0,0,0};
@ -622,22 +624,27 @@ class CatmullClark_mask_3 {
} }
\end{ccExampleCode} \end{ccExampleCode}
In this example, \ccc{Point} is assumed to be a \ccc{CGAL::Point_3}. In this example, the computation is based on the assumption that
But you are allowed to use any point \emph{type} as long as it is type the \ccc{Point_3} is the \ccc{CGAL::Point_3}. It is an assumption,
defined as \ccc{Point_3} in your polyhedron class and vertex class. but not a restriction.
You are allowed to use any point class as long as it is
defined as the \ccc{Point_3} in your polyhedron.
You may need to modify the geometry policy to support the computation You may need to modify the geometry policy to support the computation
and assignment of your specialized point. This extension is not unusual and assignment of the specialized point. This extension is not unusual
in graphics applications. For example, you might want to subdivide the in graphics applications. For example, you might want to subdivide the
texture coordinates when you subdivide the polyhedron. The typename texture coordinates when you subdivide the polyhedron.
\ccc{Point_3} is actually the attribute holder, including the %The typename
point of course, for the vertices. %\ccc{Point_3} is actually the attribute holder, including the
%point of course, for the vertices.
The PQQ refinement host requires three policy functions for The PQQ refinement host requires three geometry masks for
polyhedrons without open boundaries: a vertex-node polyhedrons without open boundaries: a vertex-node
stencil, an edge-node stencil, and a facet-node stencil. mask, an edge-node mask, and a facet-node mask.
To support polyhedrons with boundaries, a policy function To support polyhedrons with boundaries, a border-node mask is
for border vertices is also required. The border policy for also required. The border-node mask for Catmull-Clark subdivision
Catmull-Clark is given below. is listed below, where \ccc{ept} returns the new point splitting the
edge and \ccc{vpt} returns the new point on the vertex pointed by
the edge.
%% \begin{ccTexOnly} %% \begin{ccTexOnly}
%% \begin{center} %% \begin{center}
@ -648,72 +655,81 @@ Catmull-Clark is given below.
%% \end{ccTexOnly} %% \end{ccTexOnly}
\begin{ccExampleCode} \begin{ccExampleCode}
void border_node(Halfedge_handle edge, Point& ept, Point& vpt) { void border_node(Halfedge_handle edge, Point_3& ept, Point_3& vpt) {
Point& ep1 = edge->vertex()->point(); Point_3& ep1 = edge->vertex()->point();
Point& ep2 = edge->opposite()->vertex()->point(); Point_3& ep2 = edge->opposite()->vertex()->point();
ept = Point((ep1[0]+ep2[0])/2, (ep1[1]+ep2[1])/2, (ep1[2]+ep2[2])/2); ept = Point_3((ep1[0]+ep2[0])/2, (ep1[1]+ep2[1])/2, (ep1[2]+ep2[2])/2);
Halfedge_around_vertex_circulator vcir = edge->vertex_begin(); Halfedge_around_vertex_circulator vcir = edge->vertex_begin();
Point& vp1 = vcir->opposite()->vertex()->point(); Point_3& vp1 = vcir->opposite()->vertex()->point();
Point& vp0 = vcir->vertex()->point(); Point_3& vp0 = vcir->vertex()->point();
Point& vp_1 = (--vcir)->opposite()->vertex()->point(); Point_3& vp_1 = (--vcir)->opposite()->vertex()->point();
vpt = Point((vp_1[0] + 6*vp0[0] + vp1[0])/8, vpt = Point_3((vp_1[0] + 6*vp0[0] + vp1[0])/8,
(vp_1[1] + 6*vp0[1] + vp1[1])/8, (vp_1[1] + 6*vp0[1] + vp1[1])/8,
(vp_1[2] + 6*vp0[2] + vp1[2])/8 ); (vp_1[2] + 6*vp0[2] + vp1[2])/8 );
} }
\end{ccExampleCode} \end{ccExampleCode}
The interfaces of a geometry policy need to match the stencils of The mask interfaces of all four refinement hosts are listed below.
the refinement host. We have already seen the geometry masks for Please note that \ccc{DQQ_stencil_3} and \ccc{Sqrt3_stencil_3}
a PQQ-base subdivision, Catmull-Clark subdivision, which gives do not have the border-node stencil because the refinement hosts of
four stencil interfaces. The stencil interface the other three DQQ and $\sqrt{3}$ refinements do not support global boundaries in the
refinement host, PTQ, DQQ and $\sqrt{3}$, are defined below current release of \ccc{Subdivision_method_3}. Though this might be
(PQQ as well). changed in the future releases.
%The interface of a geometry policy need to match the stencils of
%the refinement host. We have already seen the geometry masks for
%a PQQ-base subdivision, Catmull-Clark subdivision.
%The mask interface the other three refinement hosts, PTQ, DQQ and
%$\sqrt{3}$, are defined below
%(PQQ as well).
\begin{ccExampleCode} \begin{ccExampleCode}
template <class Poly> template <class Poly>
class PQQ_stencil_3 { class PQQ_stencil_3 {
void facet_node(Facet_handle, Point&) {}; void facet_node(Facet_handle, Point_3&);
void edge_node(Halfedge_handle, Point&) {}; void edge_node(Halfedge_handle, Point_3&);
void vertex_node(Vertex_handle, Point&) {}; void vertex_node(Vertex_handle, Point_3&);
void border_node(Halfedge_handle, Point&, Point&) {}; void border_node(Halfedge_handle, Point&, Point_3&);
}; };
template <class Poly> template <class Poly>
class PTQ_stencil_3 { class PTQ_stencil_3 {
void edge_node(Halfedge_handle, Point&) {}; void edge_node(Halfedge_handle, Point_3&);
void vertex_node(Vertex_handle, Point&) {}; void vertex_node(Vertex_handle, Point_3&);
void border_node(Halfedge_handle, Point&, Point&) {}; void border_node(Halfedge_handle, Point&, Point_&);
}; };
template <class Poly> template <class Poly>
class DQQ_stencil_3 { class DQQ_stencil_3 {
public: public:
void corner_node(Halfedge_handle edge, Point& pt) {}; void corner_node(Halfedge_handle edge, Point_3& pt);
}; };
template <class Poly> template <class Poly>
class Sqrt3_stencil_3 { class Sqrt3_stencil_3 {
public: public:
void vertex_node(Vertex_handle vertex, Point& pt) {} void vertex_node(Vertex_handle vertex, Point_3& pt);
}; };
\end{ccExampleCode} \end{ccExampleCode}
Note, only the \ccc{PQQ_stencil_3} and the \ccc{DQQ_stencil_3} The source codes of \ccc{CatmullClark_mask_3}, \ccc{Loop_mask_3},
are provided in \ccc{Subdivision_method_3}. \ccc{DooSabin_mask_3}, and \ccc{Sqrt3_mask_3} are
The \ccc{PTQ_stencil_3} and the \ccc{Sqrt3_stencil_3} are given the best source of learning the these stencil
here for reference only. Both stencils are a subset of the interfaces.
\ccc{PQQ_stencil_3}, and you can just use the
\ccc{PQQ_stencil_3} to develop masks for PTQ or $\sqrt{3}$
schemes. Our DQQ and $\sqrt{3}$ refinement hosts do %Note, only the \ccc{PQQ_stencil_3} and the \ccc{DQQ_stencil_3}
not support global boundaries yet, hence the %are provided in \ccc{Subdivision_method_3}.
\ccc{DQQ_stencil_3} and the \ccc{Sqrt3_stencil_3} do not %The \ccc{PTQ_stencil_3} and the \ccc{Sqrt3_stencil_3} are given
have the border-node policy (this might be changed in the %here for reference only. Both stencils are a subset of the
future release). %\ccc{PQQ_stencil_3}, and you can just use the
%\ccc{PQQ_stencil_3} to develop masks for PTQ or $\sqrt{3}$
%schemes.
%% \begin{ccExampleCode} %% \begin{ccExampleCode}
@ -751,34 +767,42 @@ future release).
% +------------------------------------------------------------------------+ % +------------------------------------------------------------------------+
\section{Built-in subdivision schemes} \section{Subdivision methods}
% +------------------------------------------------------------------------+ % +------------------------------------------------------------------------+
Considering their popularity in graphics modeling, \ccc{Subdivision_method_3} directly supports
Catmull-Clark, Loop, \DS\ and $\sqrt{3}$ subdivisions are directly Catmull-Clark, Loop, \DS\ and $\sqrt{3}$ subdivisions by specializing
supported in \ccc{Subdivision_method_3}. their respective refinemnt hosts.
%Each of these subdivision schemes is realized by parameterizing
%the corresponding geometry policy to the .
\begin{ccExampleCode} \begin{ccExampleCode}
static void CatmullClark_subdivision(Polyhedron& p, int step) { namespace Subdivision_method_3 {
PQQ(p, CatmullClark_stencil_3<Polyhedron>(), step); template <class Polyhedron>
void CatmullClark_subdivision(Polyhedron& p, int step = 1) {
PQQ(p, CatmullClark_mask_3<Polyhedron>(), step);
} }
static void Loop_subdivision(Polyhedron& p, int step) {
PTQ(p, Loop_stencil_3<Polyhedron>() , step); template <class Polyhedron>
void Loop_subdivision(Polyhedron& p, int step = 1) {
PTQ(p, Loop_mask_3<Polyhedron>() , step);
} }
static void DooSabin_subdivision(Polyhedron& p, int step) {
DQQ(p, DooSabin_stencil_3<Polyhedron>(), step); template <class Polyhedron>
void DooSabin_subdivision(Polyhedron& p, int step = 1) {
DQQ(p, DooSabin_mask_3<Polyhedron>(), step);
} }
static void Sqrt3_subdivision(Polyhedron& p, int step) {
Sqrt3(p, Sqrt3_stencil_3<Polyhedron>(), step); template <class Polyhedron>
void Sqrt3_subdivision(Polyhedron& p, int step = 1) {
Sqrt3(p, Sqrt3_mask_3<Polyhedron>(), step);
} }
}
\end{ccExampleCode} \end{ccExampleCode}
The following shows an example of \DS\ subdivision on a polyhedral mesh. The following example demonstrates the use of the \DS\ subdivision
on a polyhedral mesh.
\ccIncludeExampleCode{Subdivision_method_3/DooSabin_subdivision.C} \ccIncludeExampleCode{Subdivision_method_3/DooSabin_subdivision.C}
% +------------------------------------------------------------------------+ % +------------------------------------------------------------------------+
\section{Customize subdivision schemes} \section{Subdivision customization}
% +------------------------------------------------------------------------+ % +------------------------------------------------------------------------+
One of the goals of \ccc{Subdivision_method_3} is One of the goals of \ccc{Subdivision_method_3} is
to provide a flexible platform to provide a flexible platform