mirror of https://github.com/CGAL/cgal
282 lines
14 KiB
TeX
282 lines
14 KiB
TeX
% =============================================================================
|
|
% The CGAL Developers' Manual
|
|
% Chapter: Traits Classes
|
|
% -----------------------------------------------------------------------------
|
|
% file : traits_classes.tex
|
|
% authors: Bernd Gaertner <gaertner@inf.ethz.ch>
|
|
% -----------------------------------------------------------------------------
|
|
% $Id$
|
|
% $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{cgal:m-tnutt-95}; you may have heard about iterator traits which
|
|
follow this design pattern.
|
|
The traits class is used in template code to reflect properties (traits)
|
|
of the actual template argument.
|
|
On the lower levels, such as the number types,
|
|
the traits classes in \cgal\ indeed follow this pattern.
|
|
However, in higher level packages the term traits class is used in a slightly
|
|
different spirit. The most noticeable change is that the traits class becomes
|
|
the template argument. This allows to bundle several template
|
|
arguments and provides more flexibility as explained in the subsequent
|
|
sections.
|
|
|
|
\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\
|
|
(in the simplest case, the kernel models fit; 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 functor 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::Left_turn_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{Left_turn_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{Left_turn_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{Left_turn_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{Left_turn_2 left_turn_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{Left_turn_2} to be
|
|
simply member functions of the traits class.
|
|
\ccIndexMainItemBegin{functors} Instead, they are functor types, and
|
|
there are member functions generating instances of these types, \ie,
|
|
the actual functors. 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 via parameters which are functors. (The
|
|
only way to pass an actual function as a parameter would be via
|
|
function pointers.)
|
|
\item More flexibility. In contrast to member functions, functors can
|
|
carry data. For example, repeated calls to a function with only
|
|
slightly different parameters might be handled efficiently by
|
|
storing intermediate results. Functors are the natural framework
|
|
here. See~\cite{hhkps-aegk-01} for more exposition.
|
|
\end{itemize}
|
|
\ccIndexMainItemEnd{functors}
|
|
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{Kernel as traits\label{sec:kernel_traits}}
|
|
|
|
\ccIndexSubitemBegin{kernel}{as 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.
|
|
\ccIndexSubitemEnd{kernel}{as 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 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 functors 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 functor 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}
|
|
|