mirror of https://github.com/CGAL/cgal
295 lines
7.3 KiB
TeX
295 lines
7.3 KiB
TeX
\chapter{Extensible Kernel}
|
|
|
|
\section{Introduction}
|
|
|
|
The following manual sections describe how users can plug user defined
|
|
geometric classes in existing \cgal\ kernels.
|
|
|
|
\section{The Anatomy of a Kernel}
|
|
|
|
\subsection{Introduction}
|
|
|
|
\cgal\ defines the concept of a geometry kernel. Such a kernel provides types,
|
|
construction objects and generalized predicates. Most implementations
|
|
of Computational Geometry algorithms and data structures in the basic
|
|
library of \cgal\ were done in a way that classes or functions can be
|
|
parametrized with a geometric traits class.
|
|
|
|
In most cases this geometric traits class must be a model of the \cgal\ geometry
|
|
kernel concept (but there are some exceptions).
|
|
|
|
|
|
|
|
\subsection{An Example}
|
|
|
|
Assume you have the following point class, where the coordinates are
|
|
stored in an array of \ccc{doubles}, where we have another data member
|
|
\ccc{color}, which shows up in the constructor.
|
|
|
|
\ccHtmlLinksOff
|
|
\begin{ccExampleCode}
|
|
class MyPointC2 {
|
|
|
|
private:
|
|
double vec[2];
|
|
int col;
|
|
|
|
public:
|
|
|
|
MyPointC2()
|
|
: col(0)
|
|
{
|
|
*vec = 0;
|
|
*(vec+1) = 0;
|
|
}
|
|
|
|
|
|
MyPointC2(const double x, const double y, int c)
|
|
: col(c)
|
|
{
|
|
*vec = x;
|
|
*(vec+1) = y;
|
|
}
|
|
|
|
const double& x() const { return *vec; }
|
|
|
|
const double& y() const { return *(vec+1); }
|
|
|
|
double & x() { return *vec; }
|
|
|
|
double& y() { return *(vec+1); }
|
|
|
|
int color() const { return col; }
|
|
|
|
int& color() { return col; }
|
|
|
|
|
|
bool operator==(const MyPointC2 &p) const
|
|
{
|
|
return ( *vec == *(p.vec) ) && ( *(vec+1) == *(p.vec + 1) && ( col == p.col) );
|
|
}
|
|
|
|
bool operator!=(const MyPointC2 &p) const
|
|
{
|
|
return !(*this == p);
|
|
}
|
|
|
|
};
|
|
\end{ccExampleCode}
|
|
\ccHtmlLinksOn
|
|
|
|
|
|
As said earlier the class is pretty minimalistic, for
|
|
example it has no \ccc{bbox()} method. One
|
|
might assume that a basic library algorithm which computes
|
|
a bounding box (e.g, to compute the bounding box of a polygon),
|
|
will not compile. Luckily it will, because it does not
|
|
use of member functions of geometric objects, but it makes
|
|
use of the functor \ccc{Kernel::Construct_bbox_2}.
|
|
|
|
To make the right thing happen with \ccc{MyPointC2} we
|
|
have to provide the following functor.
|
|
|
|
\ccHtmlLinksOff
|
|
\begin{ccExampleCode}
|
|
template <class ConstructBbox_2>
|
|
class MyConstruct_bbox_2 : public ConstructBbox_2 {
|
|
public:
|
|
CGAL::Bbox_2 operator()(const typename MyPointC2& p) const {
|
|
return CGAL::Bbox_2(p.x(), p.y(), p.x(), p.y());
|
|
}
|
|
};
|
|
\end{ccExampleCode}
|
|
\ccHtmlLinksOn
|
|
|
|
|
|
Things are similar for random access to the \ccHtmlNoLinksFrom{Cartesian}
|
|
coordinates of a point. As the coordinates are stored
|
|
in an array of \ccc{doubles} we can use \ccc{double*} as
|
|
random access iterator.
|
|
|
|
\ccHtmlLinksOff
|
|
\begin{ccExampleCode}
|
|
class MyConstruct_coord_iterator {
|
|
public:
|
|
const double* operator()(const MyPointC2& p)
|
|
{
|
|
return &p.x();
|
|
}
|
|
|
|
const double* operator()(const MyPointC2& p, int)
|
|
{
|
|
const double* pyptr = &p.y();
|
|
pyptr++;
|
|
return pyptr;
|
|
}
|
|
};
|
|
\end{ccExampleCode}
|
|
\ccHtmlLinksOn
|
|
|
|
The last functor we have to provide is the one which constructs
|
|
points. That is you are not forced to add the constructor
|
|
with the \ccc{Origin} as parameter to your class, nor the constructor with
|
|
homogeneous coordinates, and at the same time you can
|
|
pass the additional color argument to your point constructor.
|
|
The functor is a kind of glue layer between the \cgal\ algorithms
|
|
and your class.
|
|
|
|
\ccHtmlLinksOff
|
|
\begin{ccExampleCode}
|
|
template <typename K>
|
|
class MyConstruct_point_2
|
|
{
|
|
typedef typename K::RT RT;
|
|
typedef typename K::Point_2 Point_2;
|
|
public:
|
|
typedef Point_2 result_type;
|
|
typedef CGAL::Arity_tag< 1 > Arity;
|
|
|
|
Point_2
|
|
operator()() const
|
|
{ return Point_2(); }
|
|
|
|
Point_2
|
|
operator()(CGAL::Origin o) const
|
|
{ return Point_2(0,0, 0); }
|
|
|
|
Point_2
|
|
operator()(const RT& x, const RT& y) const
|
|
{ return Point_2(x, y, 0); }
|
|
|
|
|
|
// We need this one, as such a functor is in the Filtered_kernel
|
|
Point_2
|
|
operator()(const RT& x, const RT& y, const RT& w) const
|
|
{
|
|
if(w != 1){
|
|
return Point_2(x/w, y/w, 0);
|
|
} else {
|
|
return Point_2(x,y, 0);
|
|
}
|
|
}
|
|
};
|
|
|
|
\end{ccExampleCode}
|
|
\ccHtmlLinksOn
|
|
|
|
|
|
Now we are ready to put the puzzle together. To do so we
|
|
scavenge code. We won't explain it in detail, but you see
|
|
that there are \ccc{typedefs} to the new point class and
|
|
the functors. All the other types are inherited.
|
|
|
|
\ccHtmlLinksOff
|
|
\begin{ccExampleCode}
|
|
#ifndef MYKERNEL_H
|
|
#define MYKERNEL_H
|
|
|
|
#include <CGAL/Cartesian/Cartesian_base.h>
|
|
#include <CGAL/Simple_Handle_for.h>
|
|
|
|
|
|
#include "MyPointC2.h"
|
|
|
|
// Taken from include/CGAL/Cartesian/Cartesian_base.h
|
|
|
|
template < typename K_ >
|
|
struct MyCartesian_base : public CGAL::Cartesian_base< K_ >
|
|
{
|
|
typedef K_ Kernel;
|
|
typedef CGAL::Cartesian_base< K_ > Base;
|
|
typedef MyPointC2 Point_2;
|
|
typedef MyConstruct_point_2<Kernel> Construct_point_2;
|
|
typedef const double* Cartesian_const_iterator_2;
|
|
typedef MyConstruct_coord_iterator Construct_cartesian_const_iterator_2;
|
|
typedef MyConstruct_bbox_2<typename Base::Construct_bbox_2>
|
|
Construct_bbox_2;
|
|
};
|
|
|
|
|
|
// Taken from include/CGAL/Cartesian.h
|
|
|
|
template < typename FT_, typename Kernel >
|
|
struct MyCartesian_base_no_ref_count
|
|
: public MyCartesian_base< Kernel >
|
|
{
|
|
typedef FT_ RT;
|
|
typedef FT_ FT;
|
|
|
|
// The mecanism that allows to specify reference-counting or not.
|
|
template < typename T >
|
|
struct Handle { typedef CGAL::Simple_Handle_for<T> type; };
|
|
|
|
template < typename Kernel2 >
|
|
struct Base { typedef MyCartesian_base_no_ref_count<FT_, Kernel2> Type; };
|
|
|
|
static FT make_FT(const RT & num, const RT& denom) { return num/denom;}
|
|
static FT make_FT(const RT & num) { return num;}
|
|
static RT FT_numerator(const FT &r) { return r;}
|
|
static RT FT_denominator(const FT &) { return RT(1);}
|
|
};
|
|
|
|
template < typename FT_ >
|
|
struct MyKernel
|
|
: public MyCartesian_base_no_ref_count<FT_, MyKernel<FT_> >
|
|
{
|
|
public:
|
|
typedef MyCartesian_base_no_ref_count<FT_, MyKernel<FT_> > Kernel_base;
|
|
};
|
|
|
|
CGAL_ITERATOR_TRAITS_POINTER_SPEC_TEMPLATE(MyKernel)
|
|
|
|
#endif // MYKERNEL_H
|
|
|
|
\end{ccExampleCode}
|
|
\ccHtmlLinksOn
|
|
|
|
|
|
|
|
Finally, we give an example how this new kernel can be used.
|
|
|
|
|
|
\ccHtmlLinksOff
|
|
\begin{ccExampleCode}
|
|
#include <CGAL/basic.h>
|
|
#include <CGAL/convex_hull_2.h>
|
|
#include ``./MyKernel.h''
|
|
#include <list>
|
|
|
|
typedef MyKernel<double> MyK;
|
|
typedef CGAL::Filtered_kernel<MyK> K;
|
|
typedef K::Point_2 Point_2;
|
|
|
|
int main()
|
|
{
|
|
std::list<Point_2> input;
|
|
|
|
Point_2 act;
|
|
input.push_back(act);
|
|
|
|
std::list<Point_2> output;
|
|
|
|
K traits;
|
|
|
|
CGAL::convex_hull_2(input.begin(), input.end(),
|
|
std::back_inserter(output), traits);
|
|
return 0;
|
|
}
|
|
\end{ccExampleCode}
|
|
|
|
\ccHtmlLinksOn
|
|
|
|
|
|
\subsection{Limitations}
|
|
|
|
The point class must have member functions \ccc{x()} and \ccc{y()}
|
|
(and \ccc{z()} for the 3d point). We work on that.
|
|
|
|
Global functions operating on, for example
|
|
\ccc{CGAL::Orientation(CGAL::Point_2<K>, CGAL::Point_2<K>,
|
|
CGAL::Point_2<K>)} will not work. Instead you have to
|
|
use the functor \ccc{MyKernel<double>::Orientation_2}.
|
|
|
|
Rewriting the code is however pretty easy, as you can give
|
|
the functor object the same name as the global function.
|