cgal/Kernel_d/doc/Kernel_d/Kernel_d.txt

555 lines
26 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

namespace CGAL {
/*!
\mainpage User Manual
\anchor Chapter_dD_Geometry_Kernel
\cgalAutoToc
\author Michael Seel
\section Kernel_dIntroduction Introduction
This part of the reference manual covers the higher-dimensional
kernel. The kernel contains objects of constant size, such as point,
vector, direction, line, ray, segment, circle. With each type comes a
set of functions which can be applied to an object of this type. You
will typically find access functions (e.g. to the coordinates of a
point), tests of the position of a point relative to the object, a
function returning the bounding box, the length, or the area of an
object, and so on. The \cgal kernel further contains basic
operations such as affine transformations, detection and computation
of intersections, and distance computations. Note that this section
partly recapitulates facts already mentioned for the lower-dimensional
kernel.
\subsection Kernel_dRobustness Robustness
The correctness proof of nearly all geometric algorithms presented in
theory papers assumes exact computation with real numbers. This leads
to a fundamental problem with the implementation of geometric
algorithms. Naively, often the exact real arithmetic is replaced by
inexact floating-point arithmetic in the implementation. This often
leads to acceptable results for many input data. However, even for
the implementation of the simplest geometric algorithms this
simplification occasionally does not work. Rounding errors introduced
by inaccurate arithmetic may lead to inconsistent decisions, causing
unexpected failures for some correct input data. There are many
approaches to this problem, one of them is to compute exactly (compute
so accurate that all decisions made by the algorithm are exact) which
is possible in many cases but more expensive than standard
floating-point arithmetic. C. M. Hoffmann \cgalCite{h-gsm-89}, \cgalCite{h-pargc-89}
illustrates some of the problems arising in the implementation of
geometric algorithms and discusses some approaches to solve them. A
more recent overview is given in \cgalCite{s-rpigc-00}. The exact
computation paradigm is discussed by Yap and Dubé \cgalCite{yd-ecp-95}
and Yap \cgalCite{y-tegc-97}.
In \cgal you can choose the underlying number types and arithmetic.
You can use different types of arithmetic simultaneously and the
choice can be easily changed, e.g. for testing. So you can choose
between implementations with fast but occasionally inexact arithmetic
and implementations guaranteeing exact computation and exact results.
Of course you have to pay for the exactness in terms of execution time
and storage space. See the dedicated chapter for more details
on number types and their capabilities and performance.
\subsection Kernel_dGenericity Genericity
To increase generic usage of objects and predicates the
higher-dimensional kernel makes heavy use of iterator ranges as
defined in the STL for modeling tuples. Iterators conceptualize C++
pointers.
For an iterator range `[first,last)` we define `T = tuple [first,last)` as the ordered tuple \f$ (T[0],T[1], \ldots T[d-1])\f$
where \f$ S[i] = *++^{(i)}\mathit{first}\f$ (the element obtained by \f$ i\f$
times forwarding the iterator by operator `++` and then
dereferencing it to get the value to which it points). We write `d = size [first,last)` and `S = set [first,last)` to denote the
unordered set of elements of the corresponding tuple.
This extends the syntax of random access iterators to input iterators.
If we index the tuple as above then we require that
\f$ ++^{(d)}\mathit{first} = \mathit{last}\f$.
\section Kernel_dKernel Kernel Representations
Our object of study is the \f$ d\f$-dimensional affine Euclidean space,
where \f$ d\f$ is a parameter of our geometry. Objects in that space are
sets of points. A common way to represent the points is the use of
%Cartesian coordinates, which assumes a reference
frame (an origin and \f$ d\f$ orthogonal axes). In that framework, a point
is represented by a \f$ d\f$-tuple \f$ (c_0,c_1,\ldots,c_{d-1})\f$,
and so are vectors in the underlying linear space. Each point is
represented uniquely by such %Cartesian
coordinates.
Another way to represent points is by homogeneous coordinates. In that
framework, a point is represented by a \f$ (d+1)\f$-tuple \f$ (h_0,h_1,\ldots,h_d)\f$.
Via the formulae \f$ c_i = h_i/h_d\f$,
the corresponding point with %Cartesian coordinates
\f$ (c_0,c_1,\ldots,c_{d-1})\f$
can be computed. Note that homogeneous coordinates are not unique.
For \f$ \lambda\ne 0\f$, the tuples \f$ (h_0,h_1,\ldots,h_d)\f$ and
\f$ (\lambda\cdot h_0,\lambda\cdot h_1,\ldots,\lambda\cdot h_d)\f$
represent the same point.
For a point with %Cartesian coordinates
\f$ (c_0,c_1,\ldots,c_{d-1})\f$ a
possible homogeneous representation is
\f$ (c_0,c_1,\ldots,c_{d-1},1)\f$.
%Homogeneous coordinates in fact allow to represent
objects in a more general space, the projective space \f$ \mathbb{P}^d\f$.
In \cgal, we do not compute in projective geometry. Rather, we use
homogeneous coordinates to avoid division operations,
since the additional coordinate can serve as a common denominator.
\subsection Kernel_dGenericitythroughParameterization Genericity through Parameterization
Almost all the kernel objects (and the corresponding functions) are
templates with a parameter that allows the user to choose the
representation of the kernel objects. A type that is used as an
argument for this parameter must fulfill certain requirements on
syntax and semantics. The list of requirements defines an abstract
kernel concept. In \cgal such a kernel concept is often also called a
<I>representation class</I> and denoted by `R`. A representation
class provides the actual implementations of the kernel objects.
For all kernel objects `Kernel_object` of a representation class `R` based
on `Cartesian_d` or `Homogeneous_d`, the types `CGAL::Kernel_object<R>` and
`R::Kernel_object` are identical.
\cgal offers three families of concrete models for the concept
representation class, two based on the %Cartesian
representation of points and one based on the homogeneous
representation of points. The interface of the kernel objects is
designed such that it works well with both
%Cartesian and homogeneous representation, for
example, points have a constructor with a range of coordinates plus a
common denominator (the \f$ d+1\f$ homogeneous coordinates of the point).
The common interfaces parameterized with a representation class allow
one to develop code independent of the chosen representation. We said
"families" of models, because both families are parameterized too.
A user can choose the number type used to represent the coordinates
and the linear algebra module used to calculate the result of
predicates and constructions.
For reasons that will become evident later, a representation class
provides two typenames for number types,
namely `R::FT` and `R::RT`.
The type `R::FT` must fulfill the
requirements on what is called a <I>field type</I> in \cgal. This
roughly means that `R::FT` is a type for which operations \f$ +\f$,
\f$ -\f$, \f$ *\f$ and \f$ /\f$ are defined with semantics (approximately)
corresponding to those of a field in a mathematical sense. Note that,
strictly speaking, the built-in type `int` does not fulfill the
requirements on a field type, since `int`s correspond to elements
of a ring rather than a field, especially operation \f$ /\f$ is not the
inverse of \f$ *\f$. The requirements on the type `R::RT` are
weaker. This type must fulfill the requirements on what is called a
<I>Euclidean ring type</I> in \cgal. This roughly means that
`R::RT` is a type for which operations \f$ +\f$, \f$ -\f$, \f$ *\f$ are
defined with semantics (approximately) corresponding to those of a
ring in a mathematical sense. A very limited division operation \f$ /\f$
must be available as well. It must work for exact (i.e., no
remainder) integer divisions only. Furthermore, both number types
should fulfill \cgal's requirements on a number type.
\subsection Kernel_dCartesianKernel Cartesian Kernel
With `Cartesian_d<FieldNumberType,LinearAlgebra>` you can choose
%Cartesian representation of coordinates. The type
`LinearAlgebra` must me a linear algebra module working on numbers
of type `FieldNumberType`. The second parameter defaults to module
delivered with the kernel so for short a user can just write
`Cartesian_d<FieldNumberType>` when not providing her own linear
algebra.
When you choose %Cartesian representation you have
to declare at least the type of the coordinates. A number type used
with the `Cartesian_d` representation class should be a <I>field
type</I> as described above. Both `Cartesian_d<FieldNumberType>::%FT`
and `Cartesian_d<FieldNumberType>::%RT` are mapped to number type
`FieldNumberType`.
`Cartesian_d<FieldNumberType,LinearAlgebra>::%LA` is mapped to the
type `LinearAlgebra`. `Cartesian_d<FieldNumberType>` uses
reference counting internally to save copying costs.
\subsection Kernel_dHomogeneousKernel Homogeneous Kernel
As we mentioned before, homogeneous coordinates permit to avoid
division operations in numerical computations, since the additional
coordinate can serve as a common denominator. Avoiding divisions can
be useful for exact geometric computation. With
`Homogeneous_d<RingNumberType,LinearAlgebra>` you can choose
homogeneous representation of coordinates with the kernel objects.
As for %Cartesian representation you have to declare
at the same time the type used to store the homogeneous coordinates.
Since the homogeneous representation allows one to avoid the
divisions, the number type associated with a homogeneous
representation class must be a model for the weaker concept Euclidean
ring type only.
The type `LinearAlgebra` must me a linear algebra module working
on numbers of type `RingNumberType`. Again the second parameter
defaults to module delivered with the kernel so for short one can just
write `Homogeneous_d<RingNumberType>` when replacing the default
is no issue.
However, some operations provided by this kernel involve division
operations, for example computing squared distances or returning a
%Cartesian coordinate. To keep the requirements on
the number type parameter of `Homogeneous` low, the number type
`Quotient<RingNumberType>` is used instead. This number type
turns a ring type into a field type. It maintains numbers as
quotients, i.e.\ a numerator and a denominator. Thereby, divisions are
circumvented. With `Homogeneous_d<RingNumberType>`,
`Homogeneous_d<RingNumberType>::%FT` is equal to
`Quotient<RingNumberType>` while
`Homogeneous_d<RingNumberType>::%RT` is equal to
`RingNumberType`.
`Homogeneous_d<RingNumberType,LinearAlgebra>::%LA` is mapped to the
type `LinearAlgebra`.
\subsection Kernel_dEpickKernel Epick_d Kernel
The kernel `Epick_d<DimensionTag>`, short for <em>Exact Predicates Inexact
Constructions Kernel</em> is a kernel particularly useful when the dimension of
the space is known at compile-time; The template parameter `DimensionTag` is then
`Dimension_tag<d>` where `d` is an integer representing the dimension. It
may also be used with parameter `Dynamic_dimension_tag`, in which case the
dimension does not need to be known at compile-time.
It uses a %Cartesian representation and
supports construction of points from `double` coordinates. It provides exact
geometric predicates, but the geometric constructions are not guaranteed to
be exact.
Note that it provides few interfaces in addition to those documented in the
`Kernel_d` concept. In particular, the type of a point is only available as
`Epick_d<DimensionTag>::%Point_d`, <B>not</B> `Point_d<Epick_d<DimensionTag>>`.
\subsection Kernel_dNamingconventions Naming Conventions
The use of representation classes does not only avoid problems, it also
makes all \cgal classes very uniform. Like `Cartesian_d<double>::%Point_d`,
they <B>always</B> consist of:
<OL>
<LI>The <I>capitalized base name</I> of the geometric object, such as
`Point`, `Segment`, `Triangle`.
<LI>Followed by `_d`.
<LI>A <I>representation class</I>, which itself may be parameterized with a
number type, such as `Cartesian_d<double>` or `Homogeneous_d<leda_integer>`,
where the type can be found, except for `Epick_d<DimensionTag>` where the
number type is implicitly `double`.
</OL>
\subsection Kernel_dKernelasaTraitsClass Kernel as a Traits Class
Algorithms and data structures in the basic library of \cgal are
parameterized by a traits class that subsumes the objects on which the
algorithm or data structure operates as well as the operations to do
so. For most of the algorithms and data structures in the basic
library you can use a kernel as a traits class. For some algorithms
you even do not have to specify the kernel; it is detected
automatically using the types of the geometric objects passed to the
algorithm. In some other cases, the algorithms or data structures
need more than is provided by a kernel. In these cases, a kernel can
not be used as a traits class.
\subsection Kernel_dChoosingaKernel Choosing a Kernel
If you start with integral %Cartesian coordinates,
many geometric computations will involve integral numerical values
only. Especially, this is true for geometric computations that
evaluate only predicates, which are tantamount to determinant
computations. Examples are triangulation of point sets and convex hull
computation.
The dimension \f$ d\f$ of our affine space determines the dimension of the
matrix computations in the mathematical evaluation of predicates. As
rounding errors accumulate fast the homogeneous representation used
with multi-precision integers is the kernel of choice for well-behaved
algorithms. Note, that unless you use an arbitrary precision integer
type, incorrect results might arise due to overflow.
If new points are to be constructed, for example the
intersection point of two lines, computation of
%Cartesian coordinates usually involves divisions,
so you need to use a field type with %Cartesian
representation or have to switch to homogeneous representation.
`double` is a possible, but imprecise field type. You can also
put any ring type into `Quotient` to get a field type and put it
into `Cartesian_d`, but you better put the ring type into
`Homogeneous`. `leda_rational` and `leda_real` are valid
field types, too.
Still other people will prefer the built-in type <TT>double</TT>, because
they need speed and can live with approximate results, or even
algorithms that, from time to time, crash or compute incorrect results
due to accumulated rounding errors.
The `Epick_d` kernel provides a compromise using `double` coordinates. It
evaluates predicates exactly, which is slower than plain `double`
computations, but still faster than using an exact number type thanks to
filtering techniques. Constructions are inexact, computed with `double`.
\subsection Kernel_dInclusionofHeaderFiles Inclusion of Header Files
You need just to include a representation class to obtain the
geometric objects of the kernel that you would like to use with the
representation class, i.e., `CGAL/Cartesian_d.h` or
`CGAL/Homogeneous_d.h`
\section Kernel_dKernel_1 Kernel Geometry
\subsection Kernel_dPointsandVectors Points and Vectors
In \cgal, we strictly distinguish between points, vectors and
directions. A <I>point</I> is a point in the Euclidean space \f$ \E^d\f$, a
<I>vector</I> is the difference of two points \f$ p_2\f$, \f$ p_1\f$ and denotes
the direction and the distance from \f$ p_1\f$ to \f$ p_2\f$ in the vector space
\f$ \mathbb{R}^d\f$, and a <I>direction</I> is a vector where we forget about its
length. They are different mathematical concepts. For example, they
behave different under affine transformations and an addition of two
points is meaningless in affine geometry. By putting them in
different classes we not only get cleaner code, but also type checking
by the compiler which avoids ambiguous expressions. Hence, it pays
twice to make this distinction.
\cgal defines a symbolic constant `ORIGIN` of type
`Origin` which denotes the point at the origin. This constant is
used in the conversion between points and vectors. Subtracting it from
a point \f$ p\f$ results in the locus vector of \f$ p\f$.
\code{.cpp}
double coord[] = {1.0, 1.0, 1.0, 1.0};
Cartesian_d<double>::Point_d p(4,coord,coord+4), q(4);
Cartesian_d<double>::Vector_d v(4);
v = p - ORIGIN;
q = ORIGIN + v;
assert( p == q );
\endcode
In order to obtain the point corresponding to a vector \f$ v\f$ you simply
have to add \f$ v\f$ to `ORIGIN`. If you want to determine
the point \f$ q\f$ in the middle between two points \f$ p_1\f$ and \f$ p_2\f$, you can
write\cgalFootnote{you might call `midpoint(p_1,p_2)` instead}
\code{.cpp}
q = p_1 + (p_2 - p_1) / 2.0;
\endcode
Note that these constructions do not involve any performance overhead
for the conversion with the currently available representation
classes.
\subsection Kernel_dKernelObjects Kernel Objects
Besides points (`R::Point_d`), vectors (`R::Vector_d`), and
directions (`R::Direction_d`), \cgal provides lines, rays,
segments, hyperplanes, and spheres.
Lines (`R::Line_d`) in \cgal are oriented. A ray
(`R::Ray_d`) is a semi-infinite interval on a line, and this line
is oriented from the finite endpoint of this interval towards any
other point in this interval. A segment (`R::Segment_d`) is a
bounded interval on a directed line, and the endpoints are ordered so
that they induce the same direction as that of the line.
Hyperplanes are affine subspaces of dimension \f$ d-1\f$ in \f$ \E^d\f$, passing
through \f$ d\f$ points. Hyperplanes are oriented and partition space into
a positive side and a negative side. In \cgal, there are no special
classes for halfspaces. Halfspaces are supposed to be represented by
oriented hyperplanes. All kernel objects are equality comparable via
`operator==` and `operator!=`. For those oriented objects
whose orientation can be reversed (segments, lines, hyperplanes,
spheres) there is also a global function `weak_equality()` that
allows to test for point set equality disregarding the orientation.
\subsection Kernel_dOrientationandRelativePosition Orientation and Relative Position
Geometric objects in \cgal have member functions that test the
position of a point relative to the object. Full dimensional objects
and their boundaries are represented by the same type, e.g.
halfspaces and hyperplanes are not distinguished, neither are balls
and spheres. Such objects split the ambient space into two
full-dimensional parts, a bounded part and an unbounded part (e.g.
spheres), or two unbounded parts (e.g. hyperplanes). By default these
objects are oriented, i.e., one of the resulting parts is called the
positive side, the other one is called the negative side. Both of
these may be unbounded.
For these objects there is a function `oriented_side()` that
determines whether a test point is on the positive side, the negative
side, or on the oriented boundary. These function returns a value of
type `Oriented_side`.
Those objects that split the space in a bounded and an unbounded part,
have a member function `bounded_side()` with return type
`Bounded_side`.
If an object is lower dimensional, e.g. a segment in \f$ d\f$-dimensional
space, there is only a test whether a point belongs to the object or
not. This member function, which takes a point as an argument and
returns a Boolean value, is called `has_on()`
\section Kernel_dPredicates Predicates and Constructions
\subsection Kernel_dPredicates_1 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
`Comparison_result` or an `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 orientation of
point sets (`orientation`), for comparing points according to some
given order, especially for comparing %Cartesian coordinates
(e.g. `lexicographically_xy_smaller`), in-sphere tests, and
predicates to compare distances.
\subsection Kernel_dConstructions Constructions
Functions and function objects that generate objects that are neither
of type `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 (`R::Aff_transformation_d`) 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 `transform(Aff_transformation_d t)` which applies the
transformation to the object instance.
\cgal also provides a set of functions that detect or compute the
intersection between objects
and functions to calculate their squared
distance. 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
`sqrt` operation. This has two drawbacks:
<UL>
<LI>The `sqrt` operation can be costly. Even if it is not
very costly for a specific number type and platform, avoiding it is
always cheaper.
<LI>There are number types on which no `sqrt` operation is
defined, especially integer types and rationals.
</UL>
\subsection Kernel_dIntersections Intersections
Intersections on kernel objects currently cover only those objects
that are part of flats (`R::Segment_d`, `R::Ray_d`,
`R::Line_d`, and `R::Hyperplane_d`). For any pair of objects
\f$ o1\f$, \f$ o2\f$ of these types the operation `intersection(o1,o2)`
returns a `boost::optional< boost::variant< T... > >`
where `T...` is a list of all possible resulting geometric objects.
The exact result type of an intersection can be determined by using
`cpp11::result_of<Kernel::Intersect_d(Type1, Type2)>::%type`
where `Type1` and `Type2` are the types of the objects
used in the intersection computation.
\subsubsection Kernel_dExample Example
In the following example, the object type is used as a return value for
the intersection computation, as there are
possibly different return values.
\code{.cpp}
typedef Cartesian_d<double> K;
typedef Point_d<K> Point;
typedef Segment_d<K> Segment;
Segment s1, s2;
std::cin >> s1 >> s2;
cpp11::result_of<K::Intersect_d(Segment, Segment)>::type
v = intersection(s1, s2);
if(v) {
// not empty
if (const Point *p = boost::get<Point>(&*v) ) {
// do something with *p
} else {
const Segment *s = boost::get<Segment>(&*v) ) {
// do something with *s
}
} else {
// empty intersection
}
\endcode
\subsection Kernel_dConstructivePredicates Constructive Predicates
For testing where a point \f$ p\f$ lies with respect to a hyperplane
defined by an array \f$ P\f$ of points \f$ p_1\f$, ... , \f$ p_d\f$, one may be
tempted to construct the hyperplane `R::Hyperplane_d(d,P,P+d)` and
use the method `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 `oriented_side(p)` to return an
orientation which is different from the
orientation of \f$ p_1\f$, ... , \f$ p_d\f$, \f$ p\f$.
In \cgal, we provide predicates in which such geometric decisions
are made directly with a reference to the input points in \f$ P\f$ without
an intermediary object like a plane. For the above test, the
recommended way to get the result is to use
\f$\mathrm{orientation}(P',P'+d)\f$, where \f$ P'\f$ is an array containing the
points \f$ p_1\f$, ... , \f$ p_d\f$, \f$ p\f$.
For exact number types like `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 `oriented_side(p)`.
\section Kernel_dDesign Design and Implementation History
This higher-dimensional kernel is the result of a long evolving
development. A first version of the kernel was offered as a LEDA
extension package ddgeo by Kurt Mehlhorn and Michael Seel. The
original design was driven by the realization of a d-dimensional
convex hull data type developed at the
Max-Planck Institut f&uuml;r Informatik.
The code base was discussed and reviewed within the \cgal kernel group
(of the low-dimensional kernel). This led to the identification of
the concept interfaces and in parallel to adaptations according to the
evolution of the low-dimensional kernel. The kernel was revised
based on suggestions by Herv&eacute; Br&ouml;nnimann, Michael Hoffmann, and
Stefan Schirra.
Epick_d was added by Marc Glisse in 2014.
\subsection Kernel_dAcknowledgments Acknowledgments
This work was supported by ESPRIT IV Long Term Research Projects
No. 21957 (CGAL) and No. 28155 (GALIA).
The Epick_d kernel was partially supported by the IST Programme of the EU
(FET Open) Project under Contract No IST-25582 (CGL - Computational
Geometric Learning).
*/
} /* namespace CGAL */