mirror of https://github.com/CGAL/cgal
281 lines
13 KiB
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}
|
|
|