mirror of https://github.com/CGAL/cgal
295 lines
14 KiB
TeX
295 lines
14 KiB
TeX
% =============================================================================
|
|
% The CGAL Developers' Manual
|
|
% Chapter: Traits Classes
|
|
% -----------------------------------------------------------------------------
|
|
% file : traits_classes.tex
|
|
% authors: Bernd Gaertner <gaertner@inf.ethz.ch>
|
|
% -----------------------------------------------------------------------------
|
|
% $Revision$
|
|
% $Date$
|
|
% =============================================================================
|
|
|
|
\chapter{Traits Classes}
|
|
\label{chap:traits_classes}
|
|
\ccChapterRelease{Chapter Version: 1.0} \\
|
|
\ccChapterAuthor{Bernd G\"artner ({\tt gaertner@inf.ethz.ch})}
|
|
\ccIndexMainItemBegin{traits class}
|
|
|
|
The concept of a traits class is central to \cgal. The name ``traits class''
|
|
comes from a standard \CC\ design pattern \cite{Myers95}; you may have heard
|
|
about iterator traits which follow this design pattern. In \cgal, traits
|
|
classes are something different, although the philosophy is similar in
|
|
a certain sense.
|
|
|
|
\section{What are traits classes in \cgal?}
|
|
\label{sec:what_is_a_traits_class}
|
|
\ccIndexMainItemDef{traits class}
|
|
|
|
The algorithms in \cgal's basic library are implemented as function templates
|
|
or class templates, usually having a template parameter called \ccc{Traits}
|
|
(but notation is not completely uniform here). This template parameter
|
|
represents a concept and so has a corresponding set of requirements that
|
|
define the interface between the algorithm and the geometric (or numeric)
|
|
primitives it uses. Any concrete class that serves as a model for this
|
|
concept is a traits class for the given algorithm or data structure.
|
|
|
|
\section{Why are traits classes in \cgal?}
|
|
\label{sec:why_traits_classes}
|
|
|
|
Using traits concepts as template parameters allows for customization of
|
|
the behavior of algorithms without changing implementations.
|
|
At least one model for each traits concept should be provided in
|
|
\cgal (and usually this should be the kernel traits class; see
|
|
Section~\ref{sec:kernel_traits}), but often more than one are provided
|
|
in order to supply certain customizations that users may want. The user
|
|
is also free to supply his or her own class as a model of the traits
|
|
concept when the desired tailoring is not present in the library.
|
|
|
|
Traits classes allow for tailoring of algorithms not only at compile time
|
|
but also at run time. Some primitive operations that appear in the traits
|
|
class (in the form of function object types) may need additional data that
|
|
are not known at compile time. A standard example is the following: we have
|
|
three-dimensional points, but we want the convex hull of the two-dimensional
|
|
points that arise after projecting along some direction in space, which is
|
|
computed as the program runs. How does the algorithm get to know about this
|
|
direction? If there is a traits class object as a parameter, the
|
|
information can be provided to the proper primitives through a proper
|
|
initialization of the traits class object.
|
|
For this reason, traits class objects are passed
|
|
as parameters to functions.\ccIndexSubitem{traits class}{as parameter}
|
|
|
|
\section{An example -- planar convex hulls}
|
|
\label{sec:traits_class_example}
|
|
\ccIndexSubitemBegin{traits class}{example}
|
|
|
|
Consider convex hulls in the plane. What are the geometric primitives a
|
|
typical
|
|
convex hull algorithm uses? Of course, this depends on the algorithm, so
|
|
let us consider what is probably the simplest efficient algorithm, the
|
|
so-called Graham Scan. This algorithm first sorts the points from left to right,
|
|
and then builds the convex hull incrementally by adding one point after
|
|
another from the sorted list. To do this, it must at least know about
|
|
some point type, it should have some idea how to sort those points, and
|
|
it must be able to evaluate the orientation of a triple of points. The
|
|
signature of the Graham Scan algorithm in \cgal\ (actually a variation
|
|
due to Andrews) is as follows:
|
|
|
|
\ccAutoIndexingOff
|
|
\lcRawHtml{<A NAME="ch_graham_andrew">}
|
|
\ccFunction{template <class InputIterator, class OutputIterator, class Traits>
|
|
OutputIterator
|
|
ch_graham_andrew( InputIterator first,
|
|
InputIterator beyond,
|
|
OutputIterator result,
|
|
const Traits & ch_traits);}
|
|
{{\sc traits}: operates on \ccc{Traits::Point_2} using
|
|
\ccc{Traits::Leftturn_2} and \ccc{Traits::Less_xy_2}.
|
|
}
|
|
\lcRawHtml{</A>}
|
|
\ccAutoIndexingOn
|
|
|
|
You notice that there is a template parameter named \ccc{Traits}, and you
|
|
also see a comment that mentions three identifiers (\ccc{Point_2},
|
|
\ccc{Leftturn_2} and \ccc{Less_xy_2}) that have to be defined in the
|
|
scope of the traits class in order for the algorithm to work.
|
|
As you can guess, \ccc{Leftturn_2} is responsible for the orientation
|
|
test, while \ccc{Less_xy_2} does the sorting. So, obviously, the traits class
|
|
must provide these three identifiers. The requirements it has to satisfy
|
|
beyond that are documented, in this case (and many others), in a section
|
|
labeled ``traits class requirements''.
|
|
|
|
\subsection{Traits class requirements}
|
|
\label{subsec:traits_class_requirements}
|
|
\ccIndexSubitemBegin{traits class}{requirements}
|
|
|
|
Whenever you write a function or class that is parameterized with a traits
|
|
class, you must provide the requirements that class has to fulfill. For the
|
|
example above, if you look in the \ccAnchor{http://www.mpi-sb.mpg.de/GALIA/Members/Manual/doc_html/ref-manual2/contents.html}{manual} at the section describing
|
|
the traits class requirements for convex hull algorithms, you find that the
|
|
traits class itself and the identifiers that are mentioned have to meet the
|
|
following specifications (copied from the manual).
|
|
|
|
\ccHtmlNoClassLinks%
|
|
\ccAutoIndexingOff
|
|
\begin{ccClass}{Traits}
|
|
\ccCreationVariable{ch_traits}
|
|
|
|
\ccTypes
|
|
|
|
\ccNestedType{Point_2}%
|
|
{The point type on which the convex hull functions operate.}
|
|
|
|
\ccNestedType{Less_xy_2}%
|
|
{Binary predicate object type comparing \ccc{Point_2}s
|
|
lexicographically.
|
|
Must provide \ccc{bool operator()(Point_2 p, Point_2 q)} where
|
|
\ccc{true}
|
|
is returned iff $p <_{xy} q$.
|
|
We have $p<_{xy}q$, iff $p_x < q_x$ or $p_x = q_x$ and $p_y < q_y$,
|
|
where $p_x$ and $p_y$ denote $x$ and $y$ coordinate of point $p$ resp.
|
|
}
|
|
|
|
\ccNestedType{Leftturn_2}%
|
|
{Predicate object type. Must provide
|
|
\ccc{bool operator()(Point_2 p,Point_2 q,Point_2 r)}, which
|
|
returns \ccc{true} iff \ccc{r} lies to the left of the
|
|
oriented line through \ccc{p} and \ccc{q}.}
|
|
|
|
\ccCreation
|
|
\ccCreationVariable{ch_traits}
|
|
|
|
Only default and copy constructor are required.
|
|
|
|
\ccConstructor{ Traits( );}{A default constructor.}
|
|
|
|
\ccConstructor{ Traits( Traits const& tbc);}{A copy constructor.}
|
|
|
|
\ccOperations
|
|
|
|
The following member functions to create instances of the above predicate
|
|
object types must exist. These member functions forward their
|
|
arguments to the constructors of the corresponding predicate classes.
|
|
|
|
\ccMemberFunction{Less_xy less_xy_2_object(); }{}
|
|
\ccMemberFunction{Leftturn leftturn_2_object(); }{}
|
|
|
|
\end{ccClass}
|
|
\ccAutoIndexingOn
|
|
|
|
This ends the copied manual text.
|
|
Some comments are in order here. You might have expected \ccc{Less_xy_2}
|
|
and \ccc{Leftturn_2} to be simply member functions of the traits class.
|
|
\ccIndexMainItemBegin{function objects}
|
|
Instead, they are function object types, and there are member
|
|
functions generating instances of these types, i.e. the actual function
|
|
objects. This might appear pretty complicated, but it is the way it should
|
|
be done in \cgal. Reasons for this are the following.
|
|
\begin{itemize}
|
|
\item \cgal\ is designed to have an \stl-like look-and-feel.
|
|
All algorithms in the \stl that depend on computational
|
|
primitives (like a sorting algorithm depending on a comparison operator),
|
|
receive those primitives as function object parameters. (The only way to
|
|
pass an actual function as a parameter would be via function pointers.)
|
|
\item More flexibility. In contrast to member functions, function objects
|
|
can carry data. For example, repeated calls to a function with only
|
|
slightly different parameters might be handled efficiently by storing
|
|
intermediate results. Function objects are the natural framework here.
|
|
\end{itemize}
|
|
\ccIndexMainItemEnd{function objects}
|
|
|
|
If you really look up the documentation of the
|
|
\ccAnchor{http://www.mpi-sb.mpg.de/GALIA/Members/Manual/doc_html/ref-manual2/ConvexHull/Traits.html}{requirements} in the manual, you will find a larger
|
|
list of requirements.
|
|
A traits class fulfilling this complete list of requirements can be used
|
|
for all of the 2-dimensional convex hull algorithms provided in \cgal.
|
|
For example, there are also
|
|
algorithms that require a sorting of points by angle, and a traits class for
|
|
that algorithm has to supply appropriate predicates for that. Still, to use
|
|
the Graham Scan, a traits class meeting only the specifications listed above
|
|
is sufficient.
|
|
\ccIndexSubitemEnd{traits class}{requirements}
|
|
|
|
\subsection{\cgal-provided traits classes}
|
|
\label{subsec:cgal_traits_classes}
|
|
\ccIndexSubitemBegin{traits class}{providing}
|
|
|
|
As mentioned in Section~\ref{sec:what_is_a_traits_class},
|
|
the traits class requirements define a concept. An
|
|
actual traits class that complies with these requirements is a model for
|
|
that concept. At least one such model must be provided for all \cgal\
|
|
algorithms.\ccIndexSubitem{traits class}{model}
|
|
Often this is called the default traits class.%
|
|
\ccIndexSubitem{traits class}{default}
|
|
Default traits classes are very
|
|
easy to use, especially when they are invoked via default arguments.
|
|
Look at the function \ccAnchor{#ch_graham_andrews}{\ccc{ch_graham_andrews}}
|
|
again. The signature does not
|
|
tell the whole story. In reality, the third template parameter defaults
|
|
to the default traits class, and the last function parameter defaults to
|
|
a default instance of the default traits class. Of course, such behavior
|
|
must be specified somewhere.
|
|
\ccIndexSubitem{documentation}{of default traits class}
|
|
In case of convex hulls, it is mentioned in
|
|
the \ccAnchor{http://www.mpi-sb.mpg.de/GALIA/Members/Manual/doc_html/ref-manual2/ConvexHull/Chapter_main.html#Section_1}{introductory section}.
|
|
|
|
The implication is that a user can call \ccc{ch_graham_andrews} with
|
|
just three parameters, which delimit the iterator range to be handled and
|
|
supply the iterator for the result. The types
|
|
and primitives used by the algorithm in this case are the ones from the \cgal\
|
|
kernel, and this connection is established via the default traits class
|
|
\ccc{convex_hull_traits_2<R>}.
|
|
|
|
In many cases, there are more than one traits classes provided by \cgal. In the
|
|
case of convex hulls, for example, there are traits classes that interface
|
|
the algorithms with the geometry kernel of \leda. Though the user who has
|
|
a third-party geometric kernel will not be able to profit from the \cgal\
|
|
or \leda\ traits, he or she can still provide own traits classes, which meet
|
|
the specified requirements.
|
|
\ccIndexSubitemEnd{traits class}{providing}
|
|
\ccIndexSubitemEnd{traits class}{example}
|
|
|
|
|
|
\section{The kernel traits}
|
|
\label{sec:kernel_traits}
|
|
\ccIndexMainItemBegin{kernel traits}
|
|
|
|
Most default traits classes in \cgal\ are written in terms of the
|
|
types and classes provided in the \cgal\ kernel. So one may wonder why
|
|
it is not possible to plug the kernel in as a traits class directly.
|
|
Ideally, it provides all the primitives an algorithm needs. So far,
|
|
the situation has not been so ideal. Different designers of traits classes
|
|
have invented different names for the same required functionality. As a
|
|
hypothetical example, the type \ccc{Less_xy_2} required in the convex hull
|
|
traits might somewhere else be called \ccc{Lexicographic_comparison}.
|
|
When developers are free to choose the names for these types to suit their
|
|
fancy, the kernel cannot serve as a traits class everywhere unless it offers
|
|
all functionality under all conceivable names.
|
|
|
|
This issue has meanwhile been addressed; the agreement is that there is
|
|
a fixed naming scheme for predicates and constructions
|
|
(Section~\ref{sec:naming_scheme}), so they are named the same way everywhere.
|
|
Implementing this naming scheme in the kernel
|
|
then allows the kernel to be used as a traits class in algorithms whose traits
|
|
class requirements follow the naming scheme. Convex hull traits classes,
|
|
for example, already comply with this naming scheme.
|
|
\ccIndexMainItemEnd{kernel traits}
|
|
|
|
\section{Requirements and recommendations}
|
|
\label{sec:traits_class_req_and_rec}
|
|
\ccIndexSubitemBegin{traits class}{design}
|
|
|
|
This section condenses the previous material into a few guidelines you
|
|
have to observe when you design a traits yourself.
|
|
\begin{itemize}
|
|
\item Keep it small and simple. In particular, avoid redundant functionality
|
|
in the traits class requirements. For example, if you require
|
|
\ccc{Less_xy_2}, there is no reason to require \ccc{Greater_xy_2},
|
|
because the latter can be constructed from the former. In general,
|
|
designing a good traits class requires a deep understanding of the
|
|
algorithm it is made for. Finding the ``right'' set of geometric
|
|
primitives required by the algorithm can be a nontrivial task.
|
|
However, spending effort on that task decreases the effort needed
|
|
later to implement traits classes and increases the ease of use of
|
|
the algorithm.
|
|
|
|
\item Obey the naming conventions (Section~\ref{sec:naming_scheme}).
|
|
|
|
\item Use function objects instead of member functions for the predicates
|
|
required. This is not only necessary for the kernel traits, it also
|
|
gives the benefit of more flexibility. For each type you must provide
|
|
a member function to get the actual function object and thus this seems
|
|
to increase the size of the traits class.
|
|
However, if you follow the naming scheme, the
|
|
signatures of these functions are obvious and obtainable mechanically.
|
|
|
|
\item Provide at least one model (which should normally be the kernel
|
|
traits class) for every traits concept.
|
|
|
|
\item Define and document a default traits class so the user need not provide
|
|
a traits class argument if customization of the algorithm is not needed.
|
|
|
|
\end{itemize}
|
|
\ccIndexSubitemEnd{traits class}{design}
|
|
\ccIndexMainItemEnd{traits class}
|
|
|