cgal/Kernel_d/doc_tex/Kernel_d/predicates_constructions_d.tex

122 lines
5.8 KiB
TeX

\section{Predicates and Constructions}
\subsection{Predicates}
Predicates are at the heart of a geometry kernel. They are basic units
for the composition of geometric algorithms and encapsulate
decisions. Hence their correctness is crucial for the control flow
and hence for the correctness of an implementation of a geometric
algorithm. \cgal\ uses the term predicate in a generalized sense. Not
only components returning a Boolean value are called predicates but
also components returning an enumeration type like a
\ccc{Comparison_result} or an \ccc{Orientation}. We say components,
because predicates are implemented both as functions and function
objects (also called functors and provided by a kernel class).
\cgal\ provides predicates for the \ccHtmlNoLinksFrom{orientation} of
point sets (\ccc{orientation}), for comparing points according to some
given order, especially for comparing Cartesian coordinates
(e.g.~\ccc{lexicographically_xy_smaller}), in-sphere tests, and
predicates to compare distances.
\subsection{Constructions}
Functions and function objects that generate objects that are neither
of type \ccc{bool} nor enum types are called constructions.
Constructions involve computation of new numerical values and may be
imprecise due to rounding errors unless a kernel with an exact number
type is used.
Affine transformations (\ccc{Aff_transformation_d<R>}) allow to
generate new object instances under arbitrary affine transformations.
These transformations include translations, rotations (within planes)
and scaling. Most of the geometric objects in a kernel have a member
function \ccc{transform(Aff_transformation t)} which applies the
transformation to the object instance.
{\cgal} also provides a set of functions that detect or compute the
\ccHtmlNoLinksFrom{intersection}\index{intersection} between objects
and functions to calculate their squared
distance\index{distance}\index{distance!squared}. Moreover, some
member functions of kernel objects are constructions.
So there are routines that compute the square of the Euclidean
distance, but no routines that compute the distance itself. Why?
First of all, the two values can be derived from each other quite
easily (by taking the square root or taking the square). So, supplying
only the one and not the other is only a minor inconvenience for the
user. Second, often either value can be used. This is for example the
case when (squared) distances are compared. Third, the library wants
to stimulate the use of the squared distance instead of the distance.
The squared distance can be computed in more cases and the computation
is cheaper. We do this by not providing the perhaps more natural
routine, The problem of a distance routine is that it needs the
\ccStyle{sqrt} operation. This has two drawbacks:
\begin{itemize}
\item The \ccStyle{sqrt} operation can be costly. Even if it is not
very costly for a specific number type and platform, avoiding it is
always cheaper.
\item There are number types on which no \ccStyle{sqrt} operation is
defined, especially integer types and rationals.
\end{itemize}
\subsection{Intersection and Polymorphic Return Values}
Intersections on kernel objects currently cover only those objects
that are part of flats (\ccc{Segment_d<R>}, \ccc{Ray_d<R>},
\ccc{Line_c<R>}, and \ccc{Hyperplane_d<R>}). For any pair of objects
$o1$, $o2$ of these types the operation \ccc{intersection(o1,o2)}
returns a polymorphic object that wraps the result of the intersection
operation.
The class \ccc{Object} provides the polymorphic abstraction. An
object \ccStyle{obj} of type \ccc{Object} can represent an arbitrary
class. The only operations it provides is to make copies and
assignments, so that you can put them in lists or arrays. Note that
\ccc{Object} is NOT a common base class for the elementary classes.
Therefore, there is no automatic conversion from these classes to
\ccc{Object} Rather this is done with the global function
\ccc{make_object()}. This encapsulation mechanism requires the use of
\ccc{object_cast} to unwrap the encapsulated class.
\ccExample
In the following example, the object type is used as a return value for
the \ccHtmlNoLinksFrom{intersection} computation, as there are
possibly different return values.
\ccHtmlLinksOff%
\begin{cprog}
typedef Point_d< Cartesian_d<double> > Point;
typedef Segment_d< Cartesian_d<double> > Segment;
Segment s1, s2;
std::cin >> s1 >> s2;
Object obj = intersection(s1, s2);
if (const Point *p = object_cast<Point>(&obj) ) {
/* do something with *p */
} else if (const Segment *s = object_cast<Segment>(&obj) ) {
/* do something with *s */
}
/* there was no intersection */
\end{cprog}
\ccHtmlLinksOn%
\subsection{Constructive Predicates}
For testing where a point $p$ lies with respect to a hyperplane
defined by an array $P$ of points $p_1$, ... , $p_d$, one may be
tempted to construct the hyperplane \ccc{Hyperplane_d<R>(d,P,P+d)} and
use the method \ccc{oriented_side(p)}. This may pay off if many tests
with respect to the plane are made. Nevertheless, unless the number
type is exact, the constructed plane is only approximated, and
round-off errors may lead \ccc{oriented_side(p)} to return an
\ccHtmlNoLinksFrom{orientation} which is different from the
\ccHtmlNoLinksFrom{orientation} of $p_1$, ... , $p_d$, $p$.
In {\cgal}, we provide predicates in which such geometric decisions
are made directly with a reference to the input points in $P$ without
an intermediary object like a plane. For the above test, the
recommended way to get the result is to use
\ccc{orientation(P',P'+d)}, where $P'$ is an array containing the
points $p_1$, ... , $p_d$, $p$.
For exact number types like \ccc{leda_real}, the situation is
different. If several tests are to be made with the same plane, it
pays off to construct the plane and to use \ccc{oriented_side(p)}.