% ============================================================================= % The CGAL Developers' Manual % Chapter: Traits Classes % ----------------------------------------------------------------------------- % file : traits_classes.tex % authors: Bernd Gaertner % ----------------------------------------------------------------------------- % $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{} \ccFunction{template 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{} \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}