cgal/Packages/Developers_manual/traits_classes.tex

281 lines
13 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 whose name contains
the word \ccc{Traits}. 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 full with the concept ConvexHullTraits\_2.
\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. These
requirements should be documented as a concept. For the
example above, if you look in the manual at the description of the concept
\ccAnchor{http://www.cgal.org/Manual/doc_html/basic_lib/Convex_hull_2_ref/Concept_ConvexHullTraits_2.html}{ConvexHullTraits\_2}, you will find that the
traits class itself and the identifiers that are mentioned have to meet the
following specifications:
\begin{ccRefConcept}{ConvexHullTraits_2}
\ccTypes
\ccAutoIndexingOff
\ccSetTwoColumns{ConvexHullTraits_2::Left_of_line_2}{}
\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$,
respectively.
}
\ccNestedType{Leftturn_2}%
{Predicate object type that 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{traits} %% choose variable name
Only a copy constructor is required.
\ccConstructor{ConvexHullTraits_2(ConvexHullTraits_2& t);}{}
\ccOperations
The following member functions to create instances of the above predicate
object types must exist.
\setlength\parskip{0mm}
\ccMemberFunction{Less_xy_2 less_xy_2_object(); }{}
\ccGlue
\ccMemberFunction{Leftturn_2 leftturn_2_object(); }{}
\end{ccRefConcept}
\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, \ie, 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.
See~\cite{hhkps-aegk-01} for more exposition.
\end{itemize}
\ccIndexMainItemEnd{function objects}
If you really look up the documentation of the
\ccAnchor{http://www.cgal.org/Manual/doc_html/basic_lib/Convex_hull_2_ref/Concept_ConvexHullTraits_2.html}{concept} 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 in the \ccAnchor{http://www.cgal.org/Manual/doc_html/basic_lib/Convex_hull_2_ref/Function_ch_graham_andrew.html}{description of the function}.
\ccIndexSubitem{documentation}{of default traits class}
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\
2D and 3D kernel.
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. However,
some algorithms and data structures require specialized predicates that would
not be appropriate to add to a general-purpose kernel. The traits classes
for these algorithms and data structures should use kernel primitives
wherever possible, and for those primitives not provided by the kernel
the fixed naming scheme for predicates and constructions
(Section~\ref{sec:naming_scheme}) should be used to make the library more
consistent and thus easier to use.
\InternalOnly{
\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 class 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}