mirror of https://github.com/CGAL/cgal
1773 lines
64 KiB
Plaintext
1773 lines
64 KiB
Plaintext
%------------------------------------------------------------------------------
|
|
%KILLSTART DISS REP
|
|
%LDEL TRACE.*?\)\;
|
|
%LDEL CGAL_NTS\
|
|
\documentclass[a4paper]{article}
|
|
\usepackage{MyLweb}
|
|
\input{defs}
|
|
|
|
\excludeversion{ignoreindiss}
|
|
\excludeversion{ignore}
|
|
|
|
\begin{document}
|
|
|
|
\title{Simple Extended Kernel}
|
|
\author{Michael Seel}
|
|
|
|
\maketitle
|
|
\tableofcontents
|
|
|
|
%KILLEND REP
|
|
\section{Introduction}\label{Extended geometry}
|
|
|
|
It is convenient to extend the vision of standard rational points by
|
|
so-called {\em non-standard} points. We have one non-standard point
|
|
for each equivalence class of rays. Two rays are called equivalent if
|
|
one is contained in the other. The geometric properties of
|
|
non-standard points are derived by giving them a geometric
|
|
interpretation by means of an infinimaximal $R$. $R$ is a real
|
|
variable. The value of $R$ is finite but larger than the value of any
|
|
concrete real number. Let $F$ be the square box with corners
|
|
|NW(-R,R)|, |NE(R,R)|, |SE(R,-R)|, and |SW(-R,-R)|. Let $p$ be a
|
|
non-standard point and let $r$ be a ray defining it. If the frame $F$
|
|
contains the source point of $r$ then let $p(R)$ be the intersection
|
|
of $r$ with the frame $F$, if $F$ does not contain the source of $r$
|
|
then $p(R)$ is undefined. For a standard point let $p(R)$ be equal to
|
|
$p$ if $p$ is contained in the frame $F$ and let $p(R)$ be undefined
|
|
otherwise. Clearly, for any standard or non-standard point $p(R)$ is
|
|
defined for any sufficiently large $R$.
|
|
|
|
Let $f$ be any function on standard points, say with $k$ arguments. We
|
|
call $f$ {\em extensible} if for any $k$ points $p_1$, \ldots, $p_k$
|
|
the function value $f(p_1(R),\ldots,p_k(R))$ is constant for all
|
|
sufficiently large $R$ and has the same value as the function
|
|
evaluated at a fixed large enough value $R_0$. We also consider
|
|
geometric constructions. Let $g$ be a construction on standard points
|
|
constructing a tuple of $l$ points from a tuple of $k$ points. We call
|
|
$g$ {\em extensible} if for any $k$ points $p_1$, \ldots, $p_k$ the
|
|
construction is closed in our set of extended points: if it constructs
|
|
a point tuple $q_1$, \ldots, $q_l$ of extended points for all
|
|
sufficiently large $R$ with the property that by fixing a large enough
|
|
$R_0$ the tuple is the result of the standard construction. As we
|
|
will see in a moment the predicates |lexicographic order| of points,
|
|
|orientation|, and |side_of_circle| are extensible. Also the
|
|
calculation of the point in the |intersection| of line segments
|
|
defined on two pairs of points is extensible.
|
|
|
|
For a formal definition of extended points, extended segments and the
|
|
corresponding predicates see the technical
|
|
report~\cite{TR:infimaximalframes}.
|
|
|
|
\section{Homogeneous Representation}
|
|
%KILLEND DISS
|
|
|
|
We implement planar extended points by a homogeneous component
|
|
representation in a polynomial ring type which provides standard ring
|
|
operations like $+,-,*$. The definition of extended points puts
|
|
constraints on the kind of polynomials representing the
|
|
coordinates. We have seen that our extensible predicates are defined
|
|
via polynomials in the coordinate polynomials and as such are
|
|
extensible via the limit process on polynomials. Going to infinity the
|
|
value of a polynomial is determined by the highest-order nonzero
|
|
coefficient.
|
|
|
|
Using extensible predicates on an input set of extended points in the
|
|
execution of an algorithm we can determine a concrete value $R_0$
|
|
which ensures their extendibility for all $R \geq R_0$ (for each
|
|
evaluation determine one $R_i$ and take the maximum of all). Plugging
|
|
$R_0$ into all coordinate polynomials leads back to standard affine
|
|
geometry and standard predicates. This gives us the possibility to
|
|
argue also about the correctness of our algorithms. If the algorithm
|
|
is proven to be correct for standard geometry and it computes a
|
|
certain output then it will also calculate some extended geometric
|
|
result when plugging in extended points and when all geometric
|
|
predicates are extensible.
|
|
|
|
Note that in this way we can design algorithms that use ray like
|
|
structures much simpler by enclosing finite structures into the box
|
|
$F$ and pruning the rays by means of the frame in a ray tip. The
|
|
calculation with the extended points makes algorithmic decisions
|
|
trivial if the predicates we use are extensible in the above sense.
|
|
|
|
In this section we will describe how extended points are stored: they
|
|
are composed from the 2D CGAL kernel point type
|
|
|Homogeneous<...>::Point_2| and the polynomial ring number type
|
|
|Polynomial<...>|. We also describe how the affine world of standard
|
|
points and rays interacts with the unifying concept extended
|
|
point. This interaction has two directions: the construction of an
|
|
extended point from a standard object (point or ray) and the reversal
|
|
extraction depending on the character of the extended
|
|
point. Afterwards, we show how simple it is to implement predicates
|
|
and the intersection construction on top of the genericity of CGAL's
|
|
standard kernel. We will encounter the problem of simplification of
|
|
polynomials there. And finally, we give some details about
|
|
visualization issues of extended objects.
|
|
|
|
We often use the short term \emph{epoint} to denote extended points.
|
|
Each epoint is either a standard point, one of the corner ray points
|
|
or lies in the relative interior of one of the frame segments.
|
|
|
|
|
|
\subsubsection*{Extended Points}
|
|
|
|
The tip of a ray $l$ can be described in two ways. First in form of
|
|
its underlying oriented line equation $a x + b y + c = 0$. But also by
|
|
its point-vector form $p = p_0 + \lambda d$. The former is the
|
|
standard representation of lines. The latter is more suitable to
|
|
explore the character of the corresponding extended point.
|
|
|
|
Starting from the second representation we have two points $p_0$ and
|
|
$p_0 + d$ on the line. Now all points on the line can also be
|
|
described by the determinant equation:
|
|
\begin{eqnarray*}
|
|
\begin{vmatrix}
|
|
1 & 1 & 1 \\
|
|
x_0 & x_0 + d_x & x \\
|
|
y_0 & y_0 + d_y & y
|
|
\end{vmatrix}
|
|
& = & 0
|
|
\end{eqnarray*}
|
|
and developing this by the last column leads us to
|
|
$-d_y x + d_x y + (x_0 d_y - y_0 d_x) = 0$.
|
|
Thus the direction vector is:
|
|
\[ d = \binom{d_x}{d_y} = \binom{b}{-a} \]
|
|
A point on the line specified by the line equation is:
|
|
\[ p_0 = \begin{cases} (0,-c/b) & b \neq 0 \\
|
|
(-c/a,0) & a \neq 0 \end{cases} \] Both $a$ and
|
|
$b$ cannot be zero. In the following assume |Line_2| to be a model for
|
|
the CGAL standard geometric kernel.
|
|
<<line conversion methods>>=
|
|
static RT dx(const Line_2& l) { return l.b(); }
|
|
static RT dy(const Line_2& l) { return -l.a(); }
|
|
|
|
@ Depending on the slope $m = d_y/d_x (d_x \neq 0)$ of a line $l$ we
|
|
can define its vertical distance to the origin. If $d_x \neq 0$
|
|
$(\Labs{m} \neq \infty)$ then the ordinate intersection $d_o$
|
|
determines that distance $d_o = -c / b$.
|
|
<<line conversion methods>>=
|
|
static FT ordinate_distance(const Line_2& l)
|
|
{ return Kernel::make_FT(-l.c(),l.b()); }
|
|
|
|
@ We introduce enumeration specifiers that describe extended points.
|
|
<<enumerate extended point character>>=
|
|
enum Point_type { SWCORNER=1, LEFTFRAME, NWCORNER,
|
|
BOTTOMFRAME, STANDARD, TOPFRAME,
|
|
SECORNER, RIGHTFRAME, NECORNER };
|
|
|
|
|
|
@ Now if we look at a non-standard point $p$ with underlying line
|
|
equation $ax + by + c = 0$ the frame segment which is hit by the ray
|
|
tip is determined by the slope and in case $\Labs{m}=1$ by the
|
|
distance $d_o$ defined above. Look for example at a non-standard point
|
|
hitting the left frame segment. This is generally the case if $d_x <
|
|
0$ and $\Labs{m}<1$. The latter is equivalent to the condition
|
|
$\Labs{d_x} > \Labs{d_y}$. A special case is $\Labs{m} = 1$. Then, we
|
|
only hit the left segment if either $m=-1 \AND d_o < 0$ or $m=1 \AND
|
|
d_o > 0$. The latter can be checked by $|sign|(d_y) == - |sign|(d_o)$.
|
|
Note that because $\Labs{m} \leq 1$ the line indeed intersects the
|
|
$y$-axis. The other cases follow by symmetric reasoning.
|
|
<<line conversion methods>>=
|
|
static Point_type determine_type(const Line_2& l)
|
|
{
|
|
RT adx = CGAL_NTS abs(dx(l)), ady = CGAL_NTS abs(dy(l));
|
|
int sdx = CGAL_NTS sign(dx(l)), sdy = CGAL_NTS sign(dy(l));
|
|
int cmp_dx_dy = CGAL_NTS compare(adx,ady), s(1);
|
|
if (sdx < 0 && ( cmp_dx_dy > 0 || cmp_dx_dy == 0 &&
|
|
sdy != (s = CGAL_NTS sign(ordinate_distance(l))))) {
|
|
if (0 == s) return ( sdy < 0 ? SWCORNER : NWCORNER );
|
|
else return LEFTFRAME;
|
|
} else if (sdx > 0 && ( cmp_dx_dy > 0 || cmp_dx_dy == 0 &&
|
|
sdy != (s = CGAL_NTS sign(ordinate_distance(l))))) {
|
|
if (0 == s) return ( sdy < 0 ? SECORNER : NECORNER );
|
|
else return RIGHTFRAME;
|
|
} else if (sdy < 0 && ( cmp_dx_dy < 0 || cmp_dx_dy == 0 &&
|
|
ordinate_distance(l) < FT(0))) {
|
|
return BOTTOMFRAME;
|
|
} else if (sdy > 0 && ( cmp_dx_dy < 0 || cmp_dx_dy == 0 &&
|
|
ordinate_distance(l) > FT(0))) {
|
|
return TOPFRAME;
|
|
}
|
|
CGAL_assertion_msg(false," determine_type: degenerate line.");
|
|
return (Point_type)-1; // never come here
|
|
}
|
|
|
|
|
|
@ All the operations above are packaged into the class
|
|
|Line_to_epoint<R>|, where |R| is a model of the CGAL standard 2d
|
|
geometric kernel. From |R| we derive the types |RT|, |FT|, and
|
|
|Line_2| as used in the code.
|
|
\begin{ignoreindiss}
|
|
<<Line_to_epoint.h>>=
|
|
<<CGAL L2E Header>>
|
|
#ifndef CGAL_LINE_TO_EPOINT_H
|
|
#define CGAL_LINE_TO_EPOINT_H
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
template <class Kernel_>
|
|
struct Line_to_epoint {
|
|
typedef Kernel_ Kernel;
|
|
typedef typename Kernel::RT RT;
|
|
typedef typename Kernel::FT FT;
|
|
typedef typename Kernel::Line_2 Line_2;
|
|
<<enumerate extended point character>>
|
|
<<line conversion methods>>
|
|
};
|
|
|
|
CGAL_END_NAMESPACE
|
|
#endif //CGAL_LINE_TO_EPOINT_H
|
|
|
|
@ \end{ignoreindiss}
|
|
|
|
Any non-standard point can be expressed as a pair of two polynomials
|
|
in a variable $R$ --- our infimaximal symbolic number. Let's look at
|
|
our example again. Our point $p$ on the left frame segment supported
|
|
by the line $ax + by + c = 0$ can be described by the tuple $(-R, a/b
|
|
R -c/b)$. Accordingly, a ray tip on the upper frame segment can be
|
|
described by $(-b/a R - c/a, R)$. Note that the denominators are
|
|
nonzero in both cases due to their frame position. Thus we can store
|
|
epoints in terms of linear polynomials $m R + n$. For standard points
|
|
the polynomials are just constant with $m=0$. We give the
|
|
representation of all points in homogeneous representation, such that
|
|
all coefficients can be represented by a ring type.
|
|
\begin{equation}\label{pointsfromline}
|
|
\begin{array}{ll}
|
|
\text{STANDARD} & p = (x,y,w) \\
|
|
\text{CORNER} & p = (\pm R, \pm R, 1) \\
|
|
\text{LEFTFRAME} & p = (-bR, a R - c, b) \\
|
|
\text{RIGHTFRAME} & p = ( bR, -a R - c, b) \\
|
|
\text{BOTTOMFRAME} & p = ( bR - c, -aR, a) \\
|
|
\text{TOPFRAME} & p = (-b R -c, aR, a)
|
|
\end{array}
|
|
\end{equation}
|
|
The general representation can be taken to be $p = (m_x R + n_x, m_y R
|
|
+ n_y, w)$ where $m_{x,y}, n_{x,y}, w$ are objects of a ring number
|
|
type. We provide the functionality of extended points bundled into an
|
|
extended geometry kernel. This kernel carries the types, predicates,
|
|
and constructions that we need in our algorithms. The kernel concept
|
|
is specified in the manual page |ExtendedKernelTraits_2| of the
|
|
appendix.
|
|
|
|
|
|
\subsubsection*{A decorator wraps functionality}
|
|
|
|
We obtain the extended point class by plugging our polynomial
|
|
arithmetic type into the standard homogeneous point type from the CGAL
|
|
kernel. We create a traits class |Extended_homogeneous<RT>| that
|
|
carries all types and methods that are used in our algorithmic
|
|
framework.
|
|
|
|
To ensure the special character of homogeneous points concerning their
|
|
coordinates and to offer a comfortable construction of such points we
|
|
make |Extended_homogeneous<RT>| a decorator/factory data type
|
|
\cite{designpatterns95} for the geometric objects. Construction and
|
|
conversion routines can be accessed as methods of the factory.
|
|
<<extended homogeneous>>=
|
|
/*{\Moptions outfile=ExtendedKernelTraits_2.man}*/
|
|
/*{\Moptions print_title=yes }*/
|
|
/*{\Msubst Extended_homogeneous ExtendedKernelTraits_2}*/
|
|
/*{\Manpage {ExtendedKernelTraits_2}{}{Extended Kernel Traits}{K}}*/
|
|
|
|
template <class RT_>
|
|
class Extended_homogeneous : public
|
|
CGAL::Homogeneous< CGAL::Polynomial<RT_> > { public:
|
|
|
|
/*{\Mdefinition |\Mname| is a kernel concept providing extended
|
|
geometry\footnote{It is called extended geometry for simplicity,
|
|
though it is not a real geometry in the classical sense.}. Let |\Mvar|
|
|
be an instance of the data type |\Mname|. The central notion of
|
|
extended geomtry are extended points. An extended point represents
|
|
either a standard affine point of the Cartesian plane or a
|
|
non-standard point representing the equivalence class of rays where
|
|
two rays are equivalent if one is contained in the other.
|
|
|
|
Let $R$ be an infinimaximal number\footnote{A finite but very large
|
|
number.}, $F$ be the square box with corners $NW(-R,R)$, $NE(R,R)$,
|
|
$SE(R,-R)$, and $SW(-R,-R)$. Let $p$ be a non-standard point and let
|
|
$r$ be a ray defining it. If the frame $F$ contains the source point
|
|
of $r$ then let $p(R)$ be the intersection of $r$ with the frame $F$,
|
|
if $F$ does not contain the source of $r$ then $p(R)$ is undefined.
|
|
For a standard point let $p(R)$ be equal to $p$ if $p$ is contained in
|
|
the frame $F$ and let $p(R)$ be undefined otherwise. Clearly, for any
|
|
standard or non-standard point $p$, $p(R)$ is defined for any
|
|
sufficiently large $R$. Let $f$ be any function on standard points,
|
|
say with $k$ arguments. We call $f$ {\em extensible} if for any $k$
|
|
points $p_1$, \ldots, $p_k$ the function value
|
|
$f(p_1(R),\ldots,p_k(R))$ is constant for all sufficiently large
|
|
$R$. We define this value as $f(p_1,\ldots,p_k)$. Predicates like
|
|
lexicographic order of points, orientation, and incircle tests are
|
|
extensible.
|
|
|
|
An extended segment is defined by two extended points such that it
|
|
is either an affine segment, an affine ray, an affine line, or a
|
|
segment that is part of the square box. Extended directions extend
|
|
the affine notion of direction to extended objects.
|
|
|
|
This extended geometry concept serves two purposes. It offers
|
|
functionality for changing between standard affine and extended
|
|
geometry. At the same time it provides extensible geometric primitives
|
|
on the extended geometric objects.}*/
|
|
|
|
<<extended homogeneous kernel interface types>>
|
|
<<extended homogeneous kernel members>>
|
|
|
|
};
|
|
|
|
@ We introduce the standard affine types into our kernel by prefixing
|
|
them accordingly. The extended types carry the typenames without the
|
|
prefix. Note that this decorator serves as a traits class to be used
|
|
in algorithms that are based on our infimaximal frame. It is also the
|
|
glue between the CGAL standard kernel and the extended geometric
|
|
objects.
|
|
<<extended homogeneous kernel interface types>>=
|
|
typedef CGAL::Homogeneous< CGAL::Polynomial<RT_> > Base;
|
|
typedef Extended_homogeneous<RT_> Self;
|
|
|
|
/*{\Mtypes 8.5}*/
|
|
/*{\Mtext \headerline{Affine kernel types}}*/
|
|
|
|
typedef CGAL::Homogeneous<RT_> Standard_kernel;
|
|
/*{\Mtypemember the standard affine kernel.}*/
|
|
|
|
typedef RT_ Standard_RT;
|
|
/*{\Mtypemember the standard ring type.}*/
|
|
|
|
typedef typename Standard_kernel::FT Standard_FT;
|
|
/*{\Xtypemember the field type.}*/
|
|
|
|
typedef typename Standard_kernel::Point_2 Standard_point_2;
|
|
/*{\Mtypemember standard points.}*/
|
|
|
|
typedef typename Standard_kernel::Segment_2 Standard_segment_2;
|
|
/*{\Mtypemember standard segments.}*/
|
|
|
|
typedef typename Standard_kernel::Line_2 Standard_line_2;
|
|
/*{\Mtypemember standard oriented lines.}*/
|
|
|
|
typedef typename Standard_kernel::Direction_2 Standard_direction_2;
|
|
/*{\Mtypemember standard directions.}*/
|
|
|
|
typedef typename Standard_kernel::Ray_2 Standard_ray_2;
|
|
/*{\Mtypemember standard rays.}*/
|
|
|
|
typedef typename Standard_kernel::Aff_transformation_2
|
|
Standard_aff_transformation_2;
|
|
/*{\Mtypemember standard affine transformations.}*/
|
|
|
|
/*{\Mtext \headerline{Extended kernel types}}*/
|
|
|
|
typedef typename Base::RT RT;
|
|
/*{\Mtypemember the ring type of our extended kernel.}*/
|
|
|
|
typedef typename Base::Point_2 Point_2;
|
|
/*{\Mtypemember extended points.}*/
|
|
|
|
typedef typename Base::Segment_2 Segment_2;
|
|
/*{\Mtypemember extended segments.}*/
|
|
|
|
typedef typename Base::Direction_2 Direction_2;
|
|
/*{\Mtypemember extended directions.}*/
|
|
|
|
typedef typename Base::Line_2 Line_2;
|
|
// used only internally
|
|
|
|
enum Point_type { SWCORNER=1, LEFTFRAME, NWCORNER,
|
|
BOTTOMFRAME, STANDARD, TOPFRAME,
|
|
SECORNER, RIGHTFRAME, NECORNER };
|
|
/*{\Menum a type descriptor for extended points.}*/
|
|
|
|
|
|
@ We now implement the construction deduced above. For a non-standard
|
|
point on the upper frame segment supported by a line $l \equiv ax + by
|
|
+c = 0$ the polynomial coefficients are $m = -b/a, n = -c/a$.
|
|
Accordingly on the left frame segment $m = -a/b, n = -c/b$.
|
|
<<non-standard point construction>>=
|
|
Point_2 epoint(const Standard_RT& m1, const Standard_RT& n1,
|
|
const Standard_RT& m2, const Standard_RT& n2,
|
|
const Standard_RT& n3) const
|
|
{ return Point_2(RT(n1,m1),RT(n2,m2),RT(n3)); }
|
|
|
|
Point_2 construct_point(const Standard_line_2& l, Point_type& t) const
|
|
{
|
|
t = (Point_type)Line_to_epoint<Standard_kernel>::determine_type(l);
|
|
Point_2 res;
|
|
switch (t) {
|
|
case SWCORNER: res = epoint(-1, 0, -1, 0, 1); break;
|
|
case NWCORNER: res = epoint(-1, 0, 1, 0, 1); break;
|
|
case SECORNER: res = epoint( 1, 0, -1, 0, 1); break;
|
|
case NECORNER: res = epoint( 1, 0, 1, 0, 1); break;
|
|
case LEFTFRAME:
|
|
res = epoint(-l.b(), 0, l.a(), -l.c(), l.b()); break;
|
|
case RIGHTFRAME:
|
|
res = epoint( l.b(), 0, -l.a(), -l.c(), l.b()); break;
|
|
case BOTTOMFRAME:
|
|
res = epoint( l.b(), -l.c(), -l.a(), 0, l.a()); break;
|
|
case TOPFRAME:
|
|
res = epoint(-l.b(), -l.c(), l.a(), 0, l.a()); break;
|
|
default: CGAL_assertion_msg(0,"EPoint type not correct!");
|
|
}
|
|
return res;
|
|
}
|
|
|
|
@ \subsubsection*{Type determination}
|
|
|
|
To evaluate the results of an algorithm one also needs an operation
|
|
that deduces the type from an epoint $p$. From the polynomial
|
|
representation we can easily defer this type by checking the
|
|
homogeneous components |p.hx()| and |p.hy()|. Of course standard
|
|
points have zero degree in both x- and y-components. For any
|
|
non-standard $p$ on the frame we know that the relative interior of
|
|
the frame box segments is specified by the condition that
|
|
$\Labs{|p.hx()|} \gtrless \Labs{|p.hy()|}$. The sign of the larger
|
|
component (larger with respect to its absolute value) determines the
|
|
box segment. Equality $\Labs{|p.hx()|} = \Labs{|p.hy()|}$ specifies
|
|
the corners of the box.
|
|
@c
|
|
Point_type type(const Point_2& p)
|
|
{
|
|
CGAL_assertion(p.hx().degree()>=0 && p.hy().degree()>=0 );
|
|
CGAL_assertion(p.hw().degree()==0);
|
|
if (p.hx().degree() == 0 && p.hy().degree() == 0)
|
|
return STANDARD;
|
|
// now we are on the square frame box
|
|
RT rx = p.hx(), ry = p.hy();
|
|
int sx = sign(rx), sy = sign(ry);
|
|
if ( sx < 0 ) rx = -rx;
|
|
if ( sy < 0 ) ry = -ry;
|
|
if ( rx > ry )
|
|
if (sx > 0) return RIGHTFRAME; else return LEFTFRAME;
|
|
if ( rx < ry )
|
|
if (sy > 0) return TOPFRAME; else return BOTTOMFRAME;
|
|
|
|
// now (rx == ry)
|
|
if ( sx == sy ) {
|
|
if (sx < 0) return SWCORNER; else return NECORNER;
|
|
} else { CGAL_assertion(sx==-sy);
|
|
if (sx < 0) return NWCORNER; else return SECORNER;
|
|
}
|
|
}
|
|
|
|
@ \subsubsection*{Visualization}
|
|
|
|
We finally treat the problem of how to visualize extended objects.
|
|
Given a set $S$ of extended points let us determine a concrete frame
|
|
radius $R_0$ such that all standard points in $S$ are contained inside
|
|
our frame but also all non-standard points in $S$ can be drawn on the
|
|
correct frame box segments. Note that the latter is not trivially true
|
|
for arbitrary small values of $R_0$.
|
|
|
|
Consider a line $l$ with slope $m$. If $\Labs{m} \neq 1$ the line $l$
|
|
intersects both angular bisectors of our coordinate frame. The
|
|
intersection point of the larger absolute coordinates determines a
|
|
lower bound for $R_0$. If $\Labs{m} = 1$ a natural lower bound for
|
|
$R_0$ is half the length of the ordinate segment on the y-axis between
|
|
$l$ and the origin. See Figure \figref{infiframevis}.
|
|
|
|
\displaylps{infiframevis} {The point $P_1$ determines a lower bound
|
|
for the frame radius $R_0$ to display the non-standard points at the
|
|
tips of line $l$. In case (A) we take the absolute value of its
|
|
coordinates, in case (B) we take half of its distance to the origin.}
|
|
|
|
For our polynomial representation $(m_x R + n_x, m_y R + n_y,w)$ we
|
|
know that for points in the interior of the frame box segments it
|
|
holds that $\Labs{(m_x R + n_x)} \gtrless \Labs{(m_y R + n_y)}$. In
|
|
either case we can set both polynomials equal and resolve for $R$ if
|
|
$\Labs{m_x} \neq \Labs{m_y}$. $R = \Labs{(n_x - n_y)}/\Labs{(m_y -
|
|
m_x)}$ presumed the line is not parallel to any of the angular
|
|
bisectors of the coordinate frame. If $\Labs{m_x} = \Labs{m_y}$ then
|
|
the constant parts $n_x/w$ or $n_y/w$ determine the abscissa or
|
|
ordinate distances between the underlying line and the origin
|
|
(depending on the frame segment that contains the extended point). At
|
|
least one of $n_x/w$ or $n_y/w$ is actually zero (by definition of our
|
|
extended points). In this case the minimum frame radius $R_0$ is half
|
|
the absolute value of the abscissa or ordinate distance of the line to
|
|
the origin.
|
|
|
|
We now code this determination of $R_0$ for an iterator range of
|
|
extended points. Note that the common denominator of the homogenous
|
|
representation is always a constant and positive. Note that we round
|
|
the integral division operations on the ring type up.
|
|
<<determining a lower bound for R>>=
|
|
template <class Forward_iterator>
|
|
void determine_frame_radius(Forward_iterator start, Forward_iterator end,
|
|
Standard_RT& R0) const
|
|
{ Standard_RT R, mx, nx, my, ny;
|
|
while ( start != end ) {
|
|
Point_2 p = *start++;
|
|
if ( is_standard(p) ) {
|
|
R = CGAL_NTS max(CGAL_NTS abs(p.hx()[0])/p.hw()[0],
|
|
CGAL_NTS abs(p.hy()[0])/p.hw()[0]);
|
|
} else {
|
|
RT rx = CGAL_NTS abs(p.hx()), ry = CGAL_NTS abs(p.hy());
|
|
mx = ( rx.degree()>0 ? rx[1] : 0 ); nx = rx[0];
|
|
my = ( ry.degree()>0 ? ry[1] : 0 ); ny = ry[0];
|
|
if ( mx > my ) R = CGAL_NTS abs((ny-nx)/(mx-my));
|
|
else if ( mx < my ) R = CGAL_NTS abs((nx-ny)/(my-mx));
|
|
else /* mx == my */ R = CGAL_NTS abs(nx-ny)/(2*p.hw()[0]);
|
|
}
|
|
R0 = CGAL_NTS max(R+1,R0);
|
|
}
|
|
}
|
|
|
|
@ \subsubsection*{Extended predicates}
|
|
|
|
Remember why the predicates |compare_xy|, |orientation|,
|
|
|side_of_circle| are extensible. The first is just a cascaded
|
|
comparison of coordinates (sign of their difference), the latter are
|
|
sign-of-determinant calculations. The orientation predicate on three
|
|
points is defined by the homogeneous expression:
|
|
\begin{displaymath}
|
|
\mathrm{orientation}(p1,p2,p3) = \mathrm{sign}
|
|
\begin{vmatrix}
|
|
x_1 & x_2 & x_3 \\
|
|
y_1 & y_2 & y_3 \\
|
|
w_1 & w_2 & w_3
|
|
\end{vmatrix}
|
|
\end{displaymath}
|
|
Thus, evaluation of the sign means looking at the sign of the
|
|
coefficient of $R$ if it is nonzero, or at the sign of the constant
|
|
term if it is zero. The corresponding functionality is programmed into
|
|
the sign function of our polynomial ring number type
|
|
|Polynomial<NT>|. Thus adding the following methods to the extended
|
|
geometry traits class implements the functionality via the kernel base
|
|
class.
|
|
@c
|
|
int compare_xy(const Point_2& p1, const Point_2& p2) const
|
|
{ typename Base::Compare_xy_2 _compare_xy = compare_xy_2_object();
|
|
return _compare_xy(p1,p2);
|
|
}
|
|
|
|
int orientation(const Point_2& p1, const Point_2& p2, const Point_2& p3)
|
|
{ typename Base::Orientation_2 _orientation = orientation_2_object();
|
|
return _orientation(p1,p2,p3);
|
|
}
|
|
|
|
@ \subsubsection*{Extended constructions}
|
|
|
|
Algorithms in computational geometry can be grouped into three
|
|
categories: \emph{subset selection}, \emph{computation}, and
|
|
\emph{decision} \cite[1.4]{prep-sham:CG}. Algorithms of the first type
|
|
resort to predicates, algorithms of the second type construct
|
|
geometric objects. To cover this necessity software libraries like
|
|
LEDA or CGAL offer a set of so called constructions in their geometric
|
|
kernels. We have already shown that the intersection construction is
|
|
extendible to be used with extended segments.
|
|
|
|
First we want to present three examples how the standard algebraic
|
|
calculation of intersection points is blown up by common polynomial
|
|
factors.
|
|
|
|
The coefficients of a line $l$ through two points $p_1 = (x_1,y_1)$,
|
|
$p_2 = (x_2,y_2)$ are
|
|
\begin{equation} \label{linefrompoints}
|
|
a = y_1 - y_2 , b = x_2 - x_1, c = x_1 y_2 - x_2 y_1.
|
|
\end{equation}
|
|
The intersection point is defined by the common point of the two
|
|
underlying lines $l_i \equiv (a_i x + b_i y + c_i = 0), i=1,2$. Their
|
|
common point is then obtained by solving the linear system which has a
|
|
solution if the lines are not parallel. We obtain
|
|
\begin{equation}\label{intersectionoflines}
|
|
p_i = (b_1 c_2 - b_2 c_1, a_2 c_1 - a_1 c_2, a_1 b_2 - a_2 b_1 )
|
|
\end{equation}
|
|
in homogeneous representation. Apart from the formal argument why
|
|
these quotients contain common factors and how they can be simplified
|
|
to a minimal representation we give three examples.
|
|
\begin{description}
|
|
\item[two non-standard points on one frame segment] --- Look at the
|
|
case where the frame segment is the upper one. Thus $p_i = (m_i R +
|
|
n_i, R), i=1,2$. According to equation (\ref{linefrompoints}) we
|
|
obtain
|
|
\begin{eqnarray*}
|
|
a & = & R-R = 0 \\
|
|
b & = & (m_2 - m_1) R + (n_2 - n_1) \\
|
|
c & = & (m_1 - m_2) R^2 + (n_1-n_2) R = bR
|
|
\end{eqnarray*}
|
|
The common factor is $b$, the underlying line is $l \equiv by + c = 0
|
|
\gdw y - R = 0$. We obtain a simple parameterized version of a
|
|
horizontal line supporting the upper frame segment. The three other
|
|
cases are symmetric.
|
|
|
|
\item[two non-standard points spanning a standard line] --- Look at
|
|
the case of one point $p_1$ on the lower frame segment, $p_2$ on the
|
|
upper frame segment, both on a line $l \equiv ax + by + c = 0$ where
|
|
we assume orientation from $p_1$ to $p_2$. We get according to
|
|
Construction (\ref{pointsfromline}) $p_1 = (b/a\; R - c/a , -R)$, $p_2 =
|
|
(-b/a\; R -c/a , R)$. According to equation (\ref{linefrompoints}) we
|
|
obtain
|
|
\begin{eqnarray*}
|
|
a' & = & -2R \\
|
|
b' & = & -2R \; b/a \\
|
|
c' & = & (b/a - b/a) \; R^2 - 2R \; c/a = - 2R \; c/a
|
|
\end{eqnarray*}
|
|
The common factor is $-2R$. The underlying line is $l' \equiv a'x +
|
|
b'y + c' = 0 \gdw ax + by + c = 0$ as multiplying by $a$ and dividing
|
|
by $-2R$ does not change the line.
|
|
|
|
\item[one non-standard point and one standard point spanning a
|
|
standard ray] --- We look again at a line $l \equiv ax + by + c = 0$
|
|
supporting $p_2$ on the upper frame segment and a standard point $p_1$
|
|
on this line. We have $p_1 = (b/a\;y_0 - c/a , -y_0)$, $p_2 = (-b/a\;R
|
|
-c/a , R)$. According to equation (\ref{linefrompoints}) we obtain
|
|
\begin{eqnarray*}
|
|
a' & = & (y_0 - R) \\
|
|
b' & = & -b/a \; R - c/a + b/a \; y_0 + c/a = b/a \; (y_0 - R) \\
|
|
c' & = & -b/a \; y_0 R - c/a \; R + b/a \; y_0 R + c/a \;
|
|
y_0 = c/a \; (y_0 - R)
|
|
\end{eqnarray*}
|
|
The common factor is $(y_0 - R)$.
|
|
\end{description}
|
|
Note that the polynomial factors are very simple. The greatest common
|
|
divisor operation and the polynomial division scheme of the
|
|
|Polynomial| data type can be used to do the simplificication.
|
|
@c
|
|
void simplify(Point_2& p)
|
|
{ RT x=p.hx(), y=p.hy(), w=p.hw();
|
|
RT common = x.is_zero() ? y : gcd(x,y);
|
|
common = gcd(common,w);
|
|
p = Point_2(x/common,y/common,w/common);
|
|
}
|
|
|
|
@ Now the intersection uses the kernel operation and simplifies
|
|
the resulting point afterwards.
|
|
@c
|
|
Point_2 intersection(
|
|
const Segment_2& s1, const Segment_2& s2)
|
|
{ typename Base::Intersect_2 _intersect = intersect_2_object();
|
|
typename Base::Construct_line_2 _line = construct_line_2_object();
|
|
Point_2 p;
|
|
CGAL::Object result = _intersect(_line(s1),_line(s2));
|
|
if ( !CGAL::assign(p, result) )
|
|
CGAL_assertion_msg(false,"intersection: no intersection.");
|
|
simplify(p);
|
|
return p;
|
|
}
|
|
|
|
@ \begin{ignoreindiss}
|
|
We offer construction from standard affine kernel objects.
|
|
<<extended homogeneous kernel members>>=
|
|
public:
|
|
<<non-standard point construction>>
|
|
<<determining a lower bound for R>>
|
|
|
|
/*{\Moperations 2}*/
|
|
/*{\Mtext \headerline{Interfacing the affine kernel types}}*/
|
|
|
|
Point_2 construct_point(const Standard_point_2& p) const
|
|
/*{\Mop creates an extended point and initializes it to the
|
|
standard point |p|.}*/
|
|
{ return Point_2(p.hx(), p.hy(), p.hw()); }
|
|
|
|
Point_2 construct_point(const Standard_point_2& p1,
|
|
const Standard_point_2& p2,
|
|
Point_type& t) const
|
|
/*{\Xop creates an extended point and initializes it to the equivalence
|
|
class of all the rays underlying the oriented line |l(p1,p2)|.
|
|
|t| returns the type of the new extended point.}*/
|
|
{ return construct_point(Standard_line_2(p1,p2),t); }
|
|
|
|
Point_2 construct_point(const Standard_line_2& l) const
|
|
/*{\Mop creates an extended point and initializes it to the equivalence
|
|
class of all the rays underlying the oriented line |l|. }*/
|
|
{ Point_type dummy; return construct_point(l,dummy); }
|
|
|
|
Point_2 construct_point(const Standard_point_2& p1,
|
|
const Standard_point_2& p2) const
|
|
/*{\Mop creates an extended point and initializes it to the equivalence
|
|
class of all the rays underlying the oriented line |l(p1,p2)|.}*/
|
|
{ return construct_point(Standard_line_2(p1,p2)); }
|
|
|
|
Point_2 construct_point(const Standard_point_2& p,
|
|
const Standard_direction_2& d) const
|
|
/*{\Mop creates an extended point and initializes it to the equivalence
|
|
class of all the rays underlying the ray starting in |p| in direction |d|.}*/
|
|
{ return construct_point(Standard_line_2(p,d)); }
|
|
|
|
Point_2 construct_opposite_point(const Standard_line_2& l) const
|
|
/*{\Mop creates an extended point and initializes it to the equivalence
|
|
class of all the rays underlying the oriented line opposite to |l|. }*/
|
|
{ Point_type dummy; return construct_point(l.opposite(),dummy); }
|
|
|
|
|
|
Point_type type(const Point_2& p) const
|
|
/*{\Mop determines the type of |p| and returns it.}*/
|
|
{
|
|
CGAL_assertion(p.hx().degree()>=0 && p.hy().degree()>=0 );
|
|
CGAL_assertion(p.hw().degree()==0);
|
|
if (p.hx().degree() == 0 && p.hy().degree() == 0)
|
|
return STANDARD;
|
|
// now we are on the square frame
|
|
RT rx = p.hx();
|
|
RT ry = p.hy();
|
|
int sx = sign(rx);
|
|
int sy = sign(ry);
|
|
if (sx < 0) rx = -rx;
|
|
if (sy < 0) ry = -ry;
|
|
if (rx>ry) {
|
|
if (sx > 0) return RIGHTFRAME;
|
|
else return LEFTFRAME;
|
|
}
|
|
if (rx<ry) {
|
|
if (sy > 0) return TOPFRAME;
|
|
else return BOTTOMFRAME;
|
|
}
|
|
// now (rx == ry)
|
|
if (sx==sy) {
|
|
if (sx < 0) return SWCORNER;
|
|
else return NECORNER;
|
|
} else { CGAL_assertion(sx==-sy);
|
|
if (sx < 0) return NWCORNER;
|
|
else return SECORNER;
|
|
}
|
|
}
|
|
|
|
|
|
bool is_standard(const Point_2& p) const
|
|
/*{\Mop returns |true| iff |p| is a standard point.}*/
|
|
{ return (type(p)==STANDARD); }
|
|
|
|
Standard_point_2 standard_point(const Point_2& p) const
|
|
/*{\Mop returns the standard point represented by |p|.
|
|
\precond |\Mvar.is_standard(p)|.}*/
|
|
{ CGAL_assertion(type(p)==STANDARD);
|
|
CGAL_assertion(p.hw() > RT(0));
|
|
return Standard_point_2(p.hx()[0],p.hy()[0],p.hw()[0]);
|
|
}
|
|
|
|
Standard_line_2 standard_line(const Point_2& p) const
|
|
/*{\Mop returns the oriented line representing the
|
|
bundle of rays defining |p|.
|
|
\precond |!\Mvar.is_standard(p)|.}*/
|
|
{ CGAL_assertion(type(p)!=STANDARD);
|
|
RT hx = p.hx(), hy = p.hy(), hw = p.hw();
|
|
Standard_RT dx,dy;
|
|
if (hx.degree()>0) dx=hx[1]; else dx=0;
|
|
if (hy.degree()>0) dy=hy[1]; else dy=0;
|
|
Standard_point_2 p0(hx[0],hy[0],hw[0]);
|
|
Standard_point_2 p1(hx[0]+dx,hy[0]+dy,hw[0]);
|
|
return Standard_line_2(p0,p1);
|
|
}
|
|
|
|
Standard_ray_2 standard_ray(const Point_2& p) const
|
|
/*{\Mop a ray defining |p|. \precond |!\Mvar.is_standard(p)|.}*/
|
|
{ CGAL_assertion(type(p)!=STANDARD);
|
|
Standard_line_2 l = standard_line(p);
|
|
Standard_direction_2 d = l.direction();
|
|
Standard_point_2 q = l.point(0);
|
|
return Standard_ray_2(q,d);
|
|
}
|
|
|
|
Point_2 NE() const { return construct_point(Standard_line_2(-1, 1,0)); }
|
|
/*{\Mop returns the point on the northeast frame corner.}*/
|
|
|
|
Point_2 SE() const { return construct_point(Standard_line_2( 1, 1,0)); }
|
|
/*{\Mop returns the point on the southeast frame corner.}*/
|
|
|
|
Point_2 NW() const { return construct_point(Standard_line_2(-1,-1,0)); }
|
|
/*{\Mop returns the point on the northwest frame corner.}*/
|
|
|
|
Point_2 SW() const { return construct_point(Standard_line_2( 1,-1,0)); }
|
|
/*{\Mop returns the point on the southwest frame corner.}*/
|
|
|
|
|
|
Line_2 upper() const { return construct_line(NW(),NE()); }
|
|
/*{\Xop returns the line underlying the upper frame segment.}*/
|
|
|
|
Line_2 lower() const { return construct_line(SW(),SE()); }
|
|
/*{\Xop returns the line underlying the lower frame segment.}*/
|
|
|
|
Line_2 left() const { return construct_line(SW(),NW()); }
|
|
/*{\Xop returns the line underlying the left frame segment.}*/
|
|
|
|
Line_2 right() const { return construct_line(SE(),NE()); }
|
|
/*{\Xop returns the line underlying the right frame segment.}*/
|
|
|
|
|
|
/*{\Mtext \headerline{Geometric kernel calls}}*/
|
|
|
|
Point_2 source(const Segment_2& s) const
|
|
/*{\Mop returns the source point of |s|.}*/
|
|
{ typename Base::Construct_source_point_2 _source =
|
|
construct_source_point_2_object();
|
|
return _source(s); }
|
|
|
|
Point_2 target(const Segment_2& s) const
|
|
/*{\Mop returns the target point of |s|.}*/
|
|
{ typename Base::Construct_target_point_2 _target =
|
|
construct_target_point_2_object();
|
|
return _target(s); }
|
|
|
|
Segment_2 construct_segment(const Point_2& p, const Point_2& q) const
|
|
/*{\Mop constructs a segment |pq|.}*/
|
|
{ typename Base::Construct_segment_2 _segment =
|
|
construct_segment_2_object();
|
|
return _segment(p,q); }
|
|
|
|
void simplify(Point_2& p) const
|
|
/*{\Xop only used internally.}*/
|
|
{ TRACEN("simplify("<<p<<")");
|
|
RT x=p.hx(), y=p.hy(), w=p.hw();
|
|
RT common = x.is_zero() ? y : RT::gcd(x,y);
|
|
common = RT::gcd(common,w);
|
|
p = Point_2(x/common,y/common,w/common);
|
|
TRACEN("canceled="<<p);
|
|
}
|
|
|
|
Line_2 construct_line(const Standard_line_2& l) const
|
|
/*{\Xop only used internally.}*/
|
|
{ return Line_2(l.a(),l.b(),l.c()); }
|
|
|
|
Line_2 construct_line(const Point_2& p1, const Point_2& p2) const
|
|
/*{\Xop only used internally.}*/
|
|
{ Line_2 l(p1,p2);
|
|
TRACEN("eline("<<p1<<p2<<")="<<l);
|
|
RT a=l.a(), b=l.b(), c=l.c();
|
|
RT common = a.is_zero() ? b : RT::gcd(a,b);
|
|
common = RT::gcd(common,c);
|
|
l = Line_2(a/common,b/common,c/common);
|
|
TRACEN("canceled="<<l);
|
|
return l;
|
|
}
|
|
|
|
int orientation(const Segment_2& s, const Point_2& p) const
|
|
/*{\Mop returns the orientation of |p| with respect to the line
|
|
through |s|.}*/
|
|
{ typename Base::Orientation_2 _orientation =
|
|
orientation_2_object();
|
|
return static_cast<int> ( _orientation(source(s),target(s),p) );
|
|
}
|
|
|
|
int orientation(const Point_2& p1, const Point_2& p2, const Point_2& p3)
|
|
const
|
|
/*{\Mop returns the orientation of |p3| with respect to the line
|
|
through |p1p2|.}*/
|
|
{ typename Base::Orientation_2 _orientation =
|
|
orientation_2_object();
|
|
return static_cast<int> ( _orientation(p1,p2,p3) );
|
|
}
|
|
|
|
bool left_turn(const Point_2& p1, const Point_2& p2, const Point_2& p3)
|
|
const
|
|
/*{\Mop return true iff the |p3| is left of the line through |p1p2|.}*/
|
|
{ return orientation(p1,p2,p3) > 0; }
|
|
|
|
bool is_degenerate(const Segment_2& s) const
|
|
/*{\Mop return true iff |s| is degenerate.}*/
|
|
{ typename Base::Is_degenerate_2 _is_degenerate =
|
|
is_degenerate_2_object();
|
|
return _is_degenerate(s); }
|
|
|
|
int compare_xy(const Point_2& p1, const Point_2& p2) const
|
|
/*{\Mop returns the lexicographic order of |p1| and |p2|.}*/
|
|
{ typename Base::Compare_xy_2 _compare_xy =
|
|
compare_xy_2_object();
|
|
return static_cast<int>( _compare_xy(p1,p2) );
|
|
}
|
|
|
|
int compare_x(const Point_2& p1, const Point_2& p2) const
|
|
/*{\Mop returns the order on the $x$-coordinates of |p1| and |p2|.}*/
|
|
{ typename Base::Compare_x_2 _compare_x =
|
|
compare_x_2_object();
|
|
return static_cast<int>( _compare_x(p1,p2) );
|
|
}
|
|
|
|
int compare_y(const Point_2& p1, const Point_2& p2) const
|
|
/*{\Mop returns the order on the $y$-coordinates of |p1| and |p2|.}*/
|
|
{ typename Base::Compare_y_2 _compare_y =
|
|
compare_y_2_object();
|
|
return static_cast<int>( _compare_y(p1,p2) );
|
|
}
|
|
|
|
Point_2 intersection(
|
|
const Segment_2& s1, const Segment_2& s2) const
|
|
/*{\Mop returns the point of intersection of the lines supported by
|
|
|s1| and |s2|. \precond the intersection point exists.}*/
|
|
{ typename Base::Intersect_2 _intersect =
|
|
intersect_2_object();
|
|
typename Base::Construct_line_2 _line =
|
|
construct_line_2_object();
|
|
Point_2 p;
|
|
CGAL::Object result =
|
|
_intersect(_line(s1),_line(s2));
|
|
if ( !CGAL::assign(p, result) )
|
|
CGAL_assertion_msg(false,"intersection: no intersection.");
|
|
simplify(p);
|
|
return p;
|
|
}
|
|
|
|
Direction_2 construct_direction(
|
|
const Point_2& p1, const Point_2& p2) const
|
|
/*{\Mop returns the direction of the vector |p2| - |p1|.}*/
|
|
{ typename Base::Construct_direction_of_line_2 _direction =
|
|
construct_direction_of_line_2_object();
|
|
return _direction(construct_line(p1,p2)); }
|
|
|
|
bool strictly_ordered_ccw(const Direction_2& d1,
|
|
const Direction_2& d2, const Direction_2& d3) const
|
|
/*{\Mop returns |true| iff |d2| is in the interior of the
|
|
counterclockwise angular sector between |d1| and |d3|.}*/
|
|
{
|
|
if ( d1 < d2 ) return ( d2 < d3 )||( d3 <= d1 );
|
|
if ( d1 > d2 ) return ( d2 < d3 )&&( d3 <= d1 );
|
|
return false;
|
|
}
|
|
|
|
bool strictly_ordered_along_line(
|
|
const Point_2& p1, const Point_2& p2, const Point_2& p3) const
|
|
/*{\Mop returns |true| iff |p2| is in the relative interior of the
|
|
segment |p1p3|.}*/
|
|
{ typename Base::Are_strictly_ordered_along_line_2 _ordered =
|
|
are_strictly_ordered_along_line_2_object();
|
|
return _ordered(p1,p2,p3);
|
|
}
|
|
|
|
bool contains(const Segment_2& s, const Point_2& p) const
|
|
/*{\Mop returns true iff |s| contains |p|.}*/
|
|
{ typename Base::Has_on_2 _contains = has_on_2_object();
|
|
return _contains(s,p);
|
|
}
|
|
|
|
bool first_pair_closer_than_second(
|
|
const Point_2& p1, const Point_2& p2,
|
|
const Point_2& p3, const Point_2& p4) const
|
|
/*{\Mop returns true iff $\Labs{p1-p2} < \Labs{p3-p4}$.}*/
|
|
{ return ( squared_distance(p1,p2) < squared_distance(p3,p4) ); }
|
|
|
|
@ We can transform points, but have to be careful about their
|
|
representation. The method |transform| just applies the standard
|
|
matrix multiplication of planar affine transformations to our extended
|
|
points. Afterwards we scale the represenstation back to our square
|
|
box by the method |scale_first_by_second|.
|
|
|
|
Note that the correctness of the following piece of code is due to two
|
|
facts:
|
|
\begin{itemize}
|
|
\item the larger absolute values of the two tranformed components
|
|
determines the coordinate that can be scaled to the square frame.
|
|
\item any coordinate transformation $R \leftarrow mR+n$ is a legal
|
|
transformation of our point representation $(m_x R + n_x, m_y R +
|
|
n_y)$. One can easily show that both lie on the same line equation.
|
|
\end{itemize}
|
|
<<extended homogeneous kernel members>>=
|
|
void scale_first_by_second(RT& r1, RT& r2, RT& w) const
|
|
{ CGAL_assertion(w.degree()==0&&w!=RT(0)&& r2[1]!=Standard_RT(0));
|
|
Standard_RT w_res = w[0]*r2[1];
|
|
int sm2 = CGAL_NTS sign(r2[1]);
|
|
RT r2_res = RT(Standard_RT(0),sm2 * w_res);
|
|
RT r1_res = RT(r2[1]*r1[0]-r1[1]*r2[0], w[0]*r1[1]*sm2);
|
|
r1 = r1_res; r2 = r2_res; w = w_res;
|
|
}
|
|
|
|
Point_2 transform(const Point_2& p,
|
|
const Standard_aff_transformation_2& t) const
|
|
{
|
|
RT tpx = t.homogeneous(0,0)*p.hx() + t.homogeneous(0,1)*p.hy() +
|
|
t.homogeneous(0,2)*p.hw();
|
|
RT tpy = t.homogeneous(1,0)*p.hx() + t.homogeneous(1,1)*p.hy() +
|
|
t.homogeneous(1,2)*p.hw();
|
|
RT tpw = t.homogeneous(2,2)*p.hw();
|
|
if ( is_standard(p) ) {
|
|
Point_2 res(tpx,tpy,tpw); simplify(res);
|
|
return res;
|
|
}
|
|
RT tpxa = CGAL_NTS abs(tpx);
|
|
RT tpya = CGAL_NTS abs(tpy);
|
|
if ( tpxa > tpya ) {
|
|
scale_first_by_second(tpy,tpx,tpw);
|
|
} else { // tpxa <= tpya
|
|
scale_first_by_second(tpx,tpy,tpw);
|
|
}
|
|
Point_2 res(tpx,tpy,tpw); simplify(res);
|
|
return res;
|
|
}
|
|
|
|
const char* output_identifier() const { return "Extended_homogeneous"; }
|
|
/*{\Mop returns a unique identifier for kernel object input/output.}*/
|
|
|
|
|
|
@ The file wrapper is here.
|
|
<<Extended_homogeneous.h>>=
|
|
<<CGAL EH Header>>
|
|
#ifndef CGAL_EXTENDED_HOMOGENEOUS_H
|
|
#define CGAL_EXTENDED_HOMOGENEOUS_H
|
|
|
|
#include <CGAL/basic.h>
|
|
#include <CGAL/Homogeneous.h>
|
|
#include <CGAL/Point_2.h>
|
|
#include <CGAL/Line_2_Line_2_intersection.h>
|
|
#include <CGAL/squared_distance_2.h>
|
|
#ifndef _MSC_VER
|
|
#include <CGAL/Nef_2/Polynomial.h>
|
|
#else
|
|
#include <CGAL/Nef_2/Polynomial_MSC.h>
|
|
#define Polynomial Polynomial_MSC
|
|
#endif
|
|
#undef _DEBUG
|
|
#define _DEBUG 5
|
|
#include <CGAL/Nef_2/debug.h>
|
|
#include <CGAL/Nef_2/Line_to_epoint.h>
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
template <class T> class Extended_homogeneous;
|
|
|
|
<<extended homogeneous>>
|
|
|
|
#undef Polynomial
|
|
CGAL_END_NAMESPACE
|
|
#endif // CGAL_EXTENDED_HOMOGENEOUS_H
|
|
|
|
|
|
@ \end{ignoreindiss}%
|
|
|
|
We provide a similar kernel based on a \emph{cartesian representation}
|
|
of points. In this case we use |Polynomial<NT>| fed with a field type
|
|
and use standard polynomial division for simplification in the
|
|
intersection construction. The latter replaces the |gcd| operation of
|
|
the ring type in the homogeneous case.
|
|
|
|
\begin{ignoreindiss}
|
|
\section{Cartesian Representation}
|
|
|
|
We obtain our epoint class by plugging our polynomial arithmetic type
|
|
into the standard Cartesian point type from CGAL.
|
|
<<extended cartesian>>=
|
|
/*{\Xanpage {Extended_cartesian}{}{An extended geometric kernel model}{K}}*/
|
|
|
|
template <class pFT>
|
|
class Extended_cartesian : public
|
|
CGAL::Cartesian< CGAL::Polynomial<pFT> > { public:
|
|
typedef CGAL::Cartesian< CGAL::Polynomial<pFT> > Base;
|
|
typedef Extended_cartesian<pFT> Self;
|
|
|
|
/*{\Xdefinition |\Mname| is a kernel model realizing the concept
|
|
extended geometry. }*/
|
|
|
|
/*{\Xtypes 6.5}*/
|
|
/*{\Xtext \headerline{Affine kernel and types}}*/
|
|
|
|
typedef CGAL::Cartesian<pFT> Standard_kernel;
|
|
/*{\Xtypemember the standard affine kernel.}*/
|
|
|
|
typedef typename Standard_kernel::RT Standard_RT;
|
|
/*{\Xtypemember the standard ring type.}*/
|
|
|
|
typedef typename Standard_kernel::FT Standard_FT;
|
|
/*{\Xtypemember the field type.}*/
|
|
|
|
typedef typename Standard_kernel::Point_2 Standard_point_2;
|
|
/*{\Xtypemember standard points.}*/
|
|
|
|
typedef typename Standard_kernel::Segment_2 Standard_segment_2;
|
|
/*{\Xtypemember standard segments.}*/
|
|
|
|
typedef typename Standard_kernel::Line_2 Standard_line_2;
|
|
/*{\Xtypemember standard oriented lines.}*/
|
|
|
|
typedef typename Standard_kernel::Direction_2 Standard_direction_2;
|
|
/*{\Xtypemember standard directions.}*/
|
|
|
|
typedef typename Standard_kernel::Ray_2 Standard_ray_2;
|
|
/*{\Xtypemember standard rays.}*/
|
|
|
|
typedef typename Standard_kernel::Aff_transformation_2
|
|
Standard_aff_transformation_2;
|
|
/*{\Xtypemember standard affine transformations.}*/
|
|
|
|
/*{\Xtext \headerline{Extended kernel types}}*/
|
|
|
|
typedef typename Base::RT RT;
|
|
/*{\Xtypemember the ring type of our extended kernel.}*/
|
|
|
|
typedef typename Base::FT FT;
|
|
/*{\Xtypemember the ring type of our extended kernel.}*/
|
|
|
|
typedef typename Base::Point_2 Point_2;
|
|
/*{\Xtypemember extended points.}*/
|
|
|
|
typedef typename Base::Segment_2 Segment_2;
|
|
/*{\Xtypemember extended segments.}*/
|
|
|
|
typedef typename Base::Line_2 Line_2;
|
|
/*{\Xtypemember extended lines.}*/
|
|
|
|
typedef typename Base::Direction_2 Direction_2;
|
|
/*{\Xtypemember extended directions.}*/
|
|
|
|
enum Point_type { SWCORNER=1, LEFTFRAME, NWCORNER,
|
|
BOTTOMFRAME, STANDARD, TOPFRAME,
|
|
SECORNER, RIGHTFRAME, NECORNER };
|
|
/*{\Xenum a type descriptor for extended points.}*/
|
|
|
|
<<extended cartesian kernel members>>
|
|
|
|
const char* output_identifier() const { return "Extended_cartesian"; }
|
|
|
|
};
|
|
|
|
|
|
@ We offer construction from a standard affine kernel objects.
|
|
|
|
<<extended cartesian kernel members>>=
|
|
Point_2 epoint(const Standard_FT& m1, const Standard_FT& n1,
|
|
const Standard_FT& m2, const Standard_FT& n2) const
|
|
{ return Point_2(FT(n1,m1),FT(n2,m2)); }
|
|
|
|
public:
|
|
/*{\Xoperations 2}*/
|
|
/*{\Xtext \headerline{Interfacing the affine kernel types}}*/
|
|
|
|
Point_2 construct_point(const Standard_point_2& p) const
|
|
/*{\Xop creates an extended point |Point_2| and initializes it to the
|
|
standard point |p|.}*/
|
|
{ return Point_2(p.x(), p.y()); }
|
|
|
|
Point_2 construct_point(const Standard_line_2& l, Point_type& t) const
|
|
/*{\Xop creates an extended point initialized to the equivalence
|
|
class of all the rays underlying the oriented line |l|.
|
|
|t| returns the type of the new extended point.}*/
|
|
{
|
|
t = (Point_type)Line_to_epoint<Standard_kernel>::determine_type(l);
|
|
Point_2 res;
|
|
switch (t) {
|
|
case SWCORNER: res = epoint(-1, 0, -1, 0); break;
|
|
case NWCORNER: res = epoint(-1, 0, 1, 0); break;
|
|
case SECORNER: res = epoint( 1, 0, -1, 0); break;
|
|
case NECORNER: res = epoint( 1, 0, 1, 0); break;
|
|
case LEFTFRAME:
|
|
res = epoint(-1, 0, l.a()/l.b(), -l.c()/l.b()); break;
|
|
case RIGHTFRAME:
|
|
res = epoint( 1, 0, -l.a()/l.b(), -l.c()/l.b()); break;
|
|
case BOTTOMFRAME:
|
|
res = epoint( l.b()/l.a(), -l.c()/l.a(), -1, 0); break;
|
|
case TOPFRAME:
|
|
res = epoint(-l.b()/l.a(), -l.c()/l.a(), 1, 0); break;
|
|
default: CGAL_assertion_msg(0,"EPoint type not correct!");
|
|
}
|
|
return res;
|
|
}
|
|
|
|
Point_2 construct_point(const Standard_point_2& p1,
|
|
const Standard_point_2& p2,
|
|
Point_type& t) const
|
|
/*{\Xop creates an extended point and initializes it to the equivalence
|
|
class of all the rays underlying the oriented line |l(p1,p2)|.
|
|
|t| returns the type of the new extended point.}*/
|
|
{ return construct_point(Standard_line_2(p1,p2),t); }
|
|
|
|
Point_2 construct_point(const Standard_line_2& l) const
|
|
/*{\Xop creates an extended point and initializes it to the equivalence
|
|
class of all the rays underlying the oriented line |l|. }*/
|
|
{ Point_type dummy; return construct_point(l,dummy); }
|
|
|
|
Point_2 construct_point(const Standard_point_2& p1,
|
|
const Standard_point_2& p2) const
|
|
/*{\Xop creates an extended point and initializes it to the equivalence
|
|
class of all the rays underlying the oriented line |l(p1,p2)|.}*/
|
|
{ return construct_point(Standard_line_2(p1,p2)); }
|
|
|
|
Point_2 construct_point(const Standard_point_2& p,
|
|
const Standard_direction_2& d) const
|
|
/*{\Xop creates an extended point and initializes it to the equivalence
|
|
class of all the rays underlying the ray starting in |p| in direction |d|.}*/
|
|
{ return construct_point(Standard_line_2(p,d)); }
|
|
|
|
Point_2 construct_opposite_point(const Standard_line_2& l) const
|
|
/*{\Xop creates an extended point and initializes it to the equivalence
|
|
class of all the rays underlying the oriented line opposite to |l|. }*/
|
|
{ Point_type dummy; return construct_point(l.opposite(),dummy); }
|
|
|
|
Point_type type(const Point_2& p) const
|
|
/*{\Xop determines the type of |p| and returns it.}*/
|
|
{
|
|
CGAL_assertion(p.x().degree()>=0 && p.y().degree()>=0 );
|
|
if ( p.x().degree() == 0 && p.y().degree() == 0)
|
|
return STANDARD;
|
|
// now we are on the square frame
|
|
FT rx = p.x();
|
|
FT ry = p.y();
|
|
int sx = sign(rx);
|
|
int sy = sign(ry);
|
|
if (sx < 0) rx = -rx;
|
|
if (sy < 0) ry = -ry;
|
|
if (rx>ry) {
|
|
if (sx > 0) return RIGHTFRAME;
|
|
else return LEFTFRAME;
|
|
}
|
|
if (rx<ry) {
|
|
if (sy > 0) return TOPFRAME;
|
|
else return BOTTOMFRAME;
|
|
}
|
|
// now (rx == ry)
|
|
if (sx==sy) {
|
|
if (sx < 0) return SWCORNER;
|
|
else return NECORNER;
|
|
} else { CGAL_assertion(sx==-sy);
|
|
if (sx < 0) return NWCORNER;
|
|
else return SECORNER;
|
|
}
|
|
}
|
|
|
|
|
|
bool is_standard(const Point_2& p) const
|
|
/*{\Xop returns |true| iff |p| is a standard point.}*/
|
|
{ return (type(p)==STANDARD); }
|
|
|
|
Standard_point_2 standard_point(const Point_2& p) const
|
|
/*{\Xop returns the standard point represented by |p|.
|
|
\precond |\Mvar.is_standard(p)|.}*/
|
|
{ CGAL_assertion( type(p)==STANDARD );
|
|
return Standard_point_2(p.x()[0],p.y()[0]);
|
|
}
|
|
|
|
Standard_line_2 standard_line(const Point_2& p) const
|
|
/*{\Xop returns the oriented line representing the
|
|
bundle of rays defining |p|.
|
|
\precond |!\Mvar.is_standard(p)|.}*/
|
|
{ CGAL_assertion( type(p)!=STANDARD );
|
|
FT x = p.x(), y = p.y();
|
|
Standard_FT dx = x.degree()>0 ? x[1] : Standard_FT(0);
|
|
Standard_FT dy = y.degree()>0 ? y[1] : Standard_FT(0);
|
|
Standard_point_2 p0(x[0],y[0]);
|
|
Standard_point_2 p1(x[0]+dx,y[0]+dy);
|
|
return Standard_line_2(p0,p1);
|
|
}
|
|
|
|
Standard_ray_2 standard_ray(const Point_2& p) const
|
|
/*{\Xop a ray defining |p|. \precond |!\Mvar.is_standard(p)|.}*/
|
|
{ Standard_line_2 l = standard_line(p);
|
|
Standard_direction_2 d = l.direction();
|
|
Standard_point_2 q = l.point(0);
|
|
return Standard_ray_2(q,d);
|
|
}
|
|
|
|
Point_2 NE() const { return construct_point(Standard_line_2(-1, 1,0)); }
|
|
/*{\Xop returns the point on the north east frame corner.}*/
|
|
|
|
Point_2 SE() const { return construct_point(Standard_line_2( 1, 1,0)); }
|
|
/*{\Xop returns the point on the south east frame corner.}*/
|
|
|
|
Point_2 NW() const { return construct_point(Standard_line_2(-1,-1,0)); }
|
|
/*{\Xop returns the point on the north west frame corner.}*/
|
|
|
|
Point_2 SW() const { return construct_point(Standard_line_2( 1,-1,0)); }
|
|
/*{\Xop returns the point on the south west frame corner.}*/
|
|
|
|
|
|
Line_2 upper() const { return construct_line(NW(),NE()); }
|
|
/*{\Xop returns the line underlying the upper frame segment.}*/
|
|
|
|
Line_2 lower() const { return construct_line(SW(),SE()); }
|
|
/*{\Xop returns the line underlying the lower frame segment.}*/
|
|
|
|
Line_2 left() const { return construct_line(SW(),NW()); }
|
|
/*{\Xop returns the line underlying the left frame segment.}*/
|
|
|
|
Line_2 right() const { return construct_line(SE(),NE()); }
|
|
/*{\Xop returns the line underlying the right frame segment.}*/
|
|
|
|
|
|
/*{\Xtext \headerline{Geometric kernel calls}}*/
|
|
|
|
Point_2 source(const Segment_2& s) const
|
|
/*{\Xop returns the source point of |s|.}*/
|
|
{ typename Base::Construct_source_point_2 _source =
|
|
construct_source_point_2_object();
|
|
return _source(s); }
|
|
|
|
Point_2 target(const Segment_2& s) const
|
|
/*{\Xop returns the target point of |s|.}*/
|
|
{ typename Base::Construct_target_point_2 _target =
|
|
construct_target_point_2_object();
|
|
return _target(s); }
|
|
|
|
Segment_2 construct_segment(const Point_2& p, const Point_2& q) const
|
|
/*{\Xop constructs a segment |pq|.}*/
|
|
{ typename Base::Construct_segment_2 _segment =
|
|
construct_segment_2_object();
|
|
return _segment(p,q); }
|
|
|
|
Line_2 construct_line(const Standard_line_2& l) const
|
|
/*{\Xop returns an extended line.}*/
|
|
{ return Line_2(l.a(),l.b(),l.c()); }
|
|
|
|
Line_2 construct_line(const Point_2& p1, const Point_2& p2) const
|
|
/*{\Xop returns a line through the two extended points |p1| and |p2|.}*/
|
|
{ Line_2 l(p1,p2);
|
|
TRACEN("eline("<<p1<<p2<<")="<<l);
|
|
RT a=l.a(), b=l.b(), c=l.c();
|
|
l = Line_2(a,b,c);
|
|
return l;
|
|
}
|
|
|
|
|
|
int orientation(const Segment_2& s, const Point_2& p) const
|
|
/*{\Xop returns the orientation of |p| with respect to the line
|
|
through |s|.}*/
|
|
{ typename Base::Orientation_2 _orientation =
|
|
orientation_2_object();
|
|
return static_cast<int> ( _orientation(source(s),target(s),p) );
|
|
}
|
|
|
|
int orientation(const Point_2& p1, const Point_2& p2, const Point_2& p3)
|
|
const
|
|
/*{\Xop returns the orientation of |p2| with respect to the line
|
|
through |p1p2|.}*/
|
|
{ typename Base::Orientation_2 _orientation =
|
|
orientation_2_object();
|
|
return static_cast<int> ( _orientation(p1,p2,p3) );
|
|
}
|
|
|
|
bool left_turn(const Point_2& p1, const Point_2& p2, const Point_2& p3)
|
|
const
|
|
/*{\Xop return true iff the |p3| is left of the line through |p1p2|.}*/
|
|
{ return orientation(p1,p2,p3) > 0; }
|
|
|
|
bool is_degenerate(const Segment_2& s) const
|
|
/*{\Xop return true iff |s| is degenerate.}*/
|
|
{ typename Base::Is_degenerate_2 _is_degenerate =
|
|
is_degenerate_2_object();
|
|
return _is_degenerate(s); }
|
|
|
|
int compare_xy(const Point_2& p1, const Point_2& p2) const
|
|
/*{\Xop returns the lexicographic order of |p1| and |p2|.}*/
|
|
{ typename Base::Compare_xy_2 _compare_xy =
|
|
compare_xy_2_object();
|
|
return static_cast<int>( _compare_xy(p1,p2) );
|
|
}
|
|
|
|
int compare_x(const Point_2& p1, const Point_2& p2) const
|
|
/*{\Xop returns the order on the $x$-coordinates of |p1| and |p2|.}*/
|
|
{ typename Base::Compare_x_2 _compare_x =
|
|
compare_x_2_object();
|
|
return static_cast<int>( _compare_x(p1,p2) );
|
|
}
|
|
|
|
int compare_y(const Point_2& p1, const Point_2& p2) const
|
|
/*{\Xop returns the order on the $y$-coordinates of |p1| and |p2|.}*/
|
|
{ typename Base::Compare_y_2 _compare_y =
|
|
compare_y_2_object();
|
|
return static_cast<int>( _compare_y(p1,p2) );
|
|
}
|
|
|
|
|
|
Point_2 intersection(
|
|
const Segment_2& s1, const Segment_2& s2) const
|
|
/*{\Xop returns the point of intersection of the lines supported by |s1|
|
|
and |s2|.}*/
|
|
{ typename Base::Intersect_2 _intersect =
|
|
intersect_2_object();
|
|
typename Base::Construct_line_2 _line =
|
|
construct_line_2_object();
|
|
Point_2 p;
|
|
CGAL::Object result =
|
|
_intersect(_line(s1),_line(s2));
|
|
if ( !CGAL::assign(p, result) )
|
|
CGAL_assertion_msg(false,"intersection: no intersection.");
|
|
return p;
|
|
}
|
|
|
|
Direction_2 construct_direction(
|
|
const Point_2& p1, const Point_2& p2) const
|
|
/*{\Xop returns the direction of the vector |p2| - |p1|.}*/
|
|
{ typename Base::Construct_direction_of_line_2 _direction =
|
|
construct_direction_of_line_2_object();
|
|
return _direction(construct_line(p1,p2)); }
|
|
|
|
bool strictly_ordered_ccw(const Direction_2& d1,
|
|
const Direction_2& d2, const Direction_2& d3) const
|
|
/*{\Xop returns |true| iff |d2| is in the interior of the
|
|
counterclockwise angular sector between |d1| and |d3|.}*/
|
|
{
|
|
if ( d1 < d2 ) return ( d2 < d3 )||( d3 <= d1 );
|
|
if ( d1 > d2 ) return ( d2 < d3 )&&( d3 <= d1 );
|
|
return false;
|
|
}
|
|
|
|
bool contains(const Segment_2& s, const Point_2& p) const
|
|
/*{\Xop returns true iff |s| contains |p|.}*/
|
|
{ typename Base::Has_on_2 _contains = has_on_2_object();
|
|
return _contains(s,p);
|
|
}
|
|
|
|
bool strictly_ordered_along_line(
|
|
const Point_2& p1, const Point_2& p2, const Point_2& p3) const
|
|
/*{\Xop returns |true| iff |p2| is in the relative interior of the
|
|
segment |p1p3|.}*/
|
|
{ typename Base::Are_strictly_ordered_along_line_2 _ordered =
|
|
are_strictly_ordered_along_line_2_object();
|
|
return _ordered(p1,p2,p3);
|
|
}
|
|
|
|
bool first_pair_closer_than_second(
|
|
const Point_2& p1, const Point_2& p2,
|
|
const Point_2& p3, const Point_2& p4) const
|
|
{ return ( squared_distance(p1,p2) < squared_distance(p3,p4) ); }
|
|
|
|
template <class Forward_iterator>
|
|
void determine_frame_radius(Forward_iterator start, Forward_iterator end,
|
|
Standard_RT& R0) const
|
|
{ Standard_RT R;
|
|
while ( start != end ) {
|
|
Point_2 p = *start++;
|
|
if ( is_standard(p) ) {
|
|
R = CGAL_NTS max(CGAL_NTS abs(p.x()[0]), CGAL_NTS abs(p.y()[0]));
|
|
} else {
|
|
RT rx = CGAL_NTS abs(p.x()), ry = CGAL_NTS abs(p.y());
|
|
if ( rx[1] > ry[1] ) R = CGAL_NTS abs(ry[0]-rx[0])/(rx[1]-ry[1]);
|
|
else if ( rx[1] < ry[1] ) R = CGAL_NTS abs(rx[0]-ry[0])/(ry[1]-rx[1]);
|
|
else /* rx[1] == ry[1] */ R = CGAL_NTS abs(rx[0]-ry[0])/2;
|
|
}
|
|
R0 = CGAL_NTS max(R+1,R0);
|
|
}
|
|
}
|
|
|
|
|
|
@ The file wrapper is here.
|
|
<<Extended_cartesian.h>>=
|
|
<<CGAL EC Header>>
|
|
#ifndef CGAL_EXTENDED_CARTESIAN_H
|
|
#define CGAL_EXTENDED_CARTESIAN_H
|
|
|
|
#include <CGAL/Cartesian.h>
|
|
#include <CGAL/Point_2.h>
|
|
#include <CGAL/Line_2_Line_2_intersection.h>
|
|
#ifndef _MSC_VER
|
|
#include <CGAL/Nef_2/Polynomial.h>
|
|
#else
|
|
#include <CGAL/Nef_2/Polynomial_MSC.h>
|
|
#define Polynomial Polynomial_MSC
|
|
#endif
|
|
#undef _DEBUG
|
|
#define _DEBUG 51
|
|
#include <CGAL/Nef_2/debug.h>
|
|
#include <CGAL/Nef_2/Line_to_epoint.h>
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
template <class T> class Extended_cartesian;
|
|
|
|
<<extended cartesian>>
|
|
|
|
#undef Polynomial
|
|
CGAL_END_NAMESPACE
|
|
#endif // CGAL_EXTENDED_CARTESIAN_H
|
|
|
|
|
|
@ \section{A Test of Extended Points}
|
|
|
|
<<EPoint-test.C>>=
|
|
#define POLYNOMIAL_EXPLICIT_OUTPUT
|
|
#include <CGAL/Cartesian.h>
|
|
#include <CGAL/Extended_homogeneous.h>
|
|
#include <CGAL/Extended_cartesian.h>
|
|
#include <CGAL/Filtered_extended_homogeneous.h>
|
|
#include <CGAL/test_macros.h>
|
|
|
|
#ifdef CGAL_USE_LEDA
|
|
#include <CGAL/leda_integer.h>
|
|
typedef leda_integer Integer;
|
|
template <>
|
|
struct ring_or_field<leda_integer> {
|
|
typedef ring_with_gcd kind;
|
|
typedef leda_integer RT;
|
|
static RT gcd(const RT& r1, const RT& r2)
|
|
{ return ::gcd(r1,r2); }
|
|
};
|
|
#include <CGAL/leda_real.h>
|
|
typedef leda_real Real;
|
|
template <>
|
|
struct ring_or_field<leda_real> {
|
|
typedef field_with_div kind;
|
|
};
|
|
#else
|
|
#ifdef CGAL_USE_GMP
|
|
#include <CGAL/Gmpz.h>
|
|
#include <CGAL/Quotient.h>
|
|
typedef CGAL::Gmpz Integer;
|
|
template <>
|
|
struct ring_or_field<CGAL::Gmpz> {
|
|
typedef ring_with_gcd kind;
|
|
typedef CGAL::Gmpz RT;
|
|
static RT gcd(const RT& r1, const RT& r2)
|
|
{ return CGAL::gcd(r1,r2); }
|
|
};
|
|
typedef CGAL::Quotient<Integer> Real;
|
|
template <>
|
|
struct ring_or_field<Real> {
|
|
typedef field_with_div kind;
|
|
};
|
|
#else
|
|
typedef long Integer;
|
|
typedef double Real;
|
|
#endif
|
|
#endif
|
|
|
|
#include <CGAL/intersection_2.h>
|
|
using namespace CGAL;
|
|
|
|
int main()
|
|
{
|
|
SETDTHREAD(41);
|
|
CGAL_TEST_START;
|
|
{
|
|
typedef CGAL::Extended_homogeneous<Integer> EDec;
|
|
<<EDec test body>>
|
|
<<IO test>>
|
|
}
|
|
{
|
|
typedef CGAL::Extended_cartesian<Real> EDec;
|
|
<<EDec test body>>
|
|
//IO does not work for LEDA reals
|
|
}
|
|
{
|
|
typedef CGAL::Filtered_extended_homogeneous<Integer> EDec;
|
|
<<EDec test body>>
|
|
<<IO test>>
|
|
D.print_statistics();
|
|
}
|
|
CGAL_TEST_END;
|
|
}
|
|
|
|
|
|
<<EDec test body>>=
|
|
typedef EDec::Point_2 EP;
|
|
typedef EDec::Segment_2 ES;
|
|
typedef EDec::Direction_2 ED;
|
|
typedef EDec::Standard_kernel::Point_2 Point;
|
|
typedef EDec::Standard_kernel::Line_2 Line;
|
|
typedef EDec::Standard_RT RT;
|
|
|
|
EDec D;
|
|
CGAL::set_pretty_mode ( std::cerr );
|
|
Point ps1(0,0), ps2(1,1), ps3(1,0), ps4(0,1), ps5(1,1,2);
|
|
EDec::Point_type t1,t2,t3;
|
|
EP eps1 = D.construct_point(ps1);
|
|
EP eps2 = D.construct_point(ps2);
|
|
EP eps3 = D.construct_point(ps3);
|
|
EP eps4 = D.construct_point(ps4);
|
|
EP eps5 = D.construct_point(ps5);
|
|
EP epn1 = D.construct_point(ps4,ps1,t1); // vertical down ray
|
|
EP epn2 = D.construct_point(ps1,ps4,t2); // vertical up ray
|
|
EP epn3 = D.construct_point(ps1,ps3,t3); // horizontal right ray
|
|
EP epn4 = D.construct_point(Line(2,3,4));
|
|
ES el1 = D.construct_segment(D.construct_point(Line(ps1,ps4)),
|
|
D.construct_point(Line(ps4,ps1)));
|
|
ES el2 = D.construct_segment(D.NW(),D.NE());
|
|
|
|
CGAL_TEST(D.type(D.SW())==EDec::SWCORNER);
|
|
CGAL_TEST(D.type(D.NW())==EDec::NWCORNER);
|
|
CGAL_TEST(D.type(D.SE())==EDec::SECORNER);
|
|
CGAL_TEST(D.type(D.NE())==EDec::NECORNER);
|
|
CGAL_TEST(D.type(epn1)==EDec::BOTTOMFRAME);
|
|
CGAL_TEST(D.type(epn2)==EDec::TOPFRAME);
|
|
CGAL_TEST(D.type(epn3)==EDec::RIGHTFRAME);
|
|
CGAL_TEST(D.type(eps1)==EDec::STANDARD);
|
|
|
|
CGAL_TEST(D.standard_line(epn1) == Line(ps4,ps1));
|
|
CGAL_TEST(D.standard_point(eps1) == ps1);
|
|
|
|
ES es1 = D.construct_segment(epn1,epn2);
|
|
ES es2 = D.construct_segment(eps1,eps5);
|
|
CGAL_TEST(D.source(es1) == epn1);
|
|
CGAL_TEST(D.target(es1) == epn2);
|
|
CGAL_TEST(D.orientation(es1,D.construct_point(Point(-1,-2))) > 0 );
|
|
CGAL_TEST(D.is_degenerate(D.construct_segment(epn1,epn1)));
|
|
CGAL_TEST(D.compare_xy(eps1,eps5)<0);
|
|
CGAL_TEST(D.compare_xy(eps1,epn2)<0);
|
|
CGAL_TEST(D.compare_xy(epn1,eps1)<0);
|
|
CGAL_TEST(D.intersection(es1,es2) == eps1);
|
|
|
|
CGAL_TEST(D.compare_xy(eps1,eps2)<0);
|
|
CGAL_TEST(D.compare_xy(eps4,eps1)>0);
|
|
CGAL_TEST(D.compare_xy(eps1,eps1)==0);
|
|
|
|
CGAL_TEST(D.compare_xy(D.NW(),eps2)<0);
|
|
CGAL_TEST(D.compare_xy(eps1,D.NE())<0);
|
|
CGAL_TEST(D.compare_xy(D.SW(),D.SE())<0);
|
|
CGAL_TEST(D.compare_xy(epn1,eps1)<0);
|
|
CGAL_TEST(D.compare_xy(eps1,epn2)<0);
|
|
|
|
CGAL_TEST(D.orientation(eps1,eps2,eps3)<0);
|
|
CGAL_TEST(D.orientation(eps1,eps3,eps2)>0);
|
|
CGAL_TEST(D.orientation(eps1,eps2,D.construct_point(Point(2,2)))==0);
|
|
|
|
CGAL_TEST(D.orientation(eps1,eps2,D.construct_point(ps1,ps2))==0);
|
|
CGAL_TEST(D.orientation(eps1,eps2,epn3)<0);
|
|
CGAL_TEST(D.orientation(eps1,eps2,epn2)>0);
|
|
|
|
CGAL_TEST(D.orientation(D.NW(),D.NE(),eps1)<0);
|
|
CGAL_TEST(D.orientation(D.NE(),D.NW(),eps1)>0);
|
|
CGAL_TEST(D.orientation(D.SW(),D.NE(),eps1)==0);
|
|
CGAL_TEST(D.orientation(epn1,epn2,eps1)==0);
|
|
CGAL_TEST(D.orientation(epn1,epn2,eps4)==0);
|
|
CGAL_TEST(D.orientation(epn1,epn2,eps3)<0);
|
|
CGAL_TEST(D.orientation(epn2,epn1,eps3)>0);
|
|
|
|
CGAL_TEST(D.first_pair_closer_than_second(eps1,eps5,eps1,eps2));
|
|
CGAL_TEST(!D.first_pair_closer_than_second(eps1,eps3,eps1,eps4));
|
|
CGAL_TEST(D.first_pair_closer_than_second(eps1,eps3,eps2,
|
|
D.construct_point(Point(2,2,1))));
|
|
CGAL_TEST(D.first_pair_closer_than_second(eps1,eps3,eps2,D.NW()));
|
|
CGAL_TEST(D.first_pair_closer_than_second(eps1,D.SE(),D.SW(),D.NE()));
|
|
CGAL_TEST(!D.first_pair_closer_than_second(eps1,D.SE(),eps5,D.NE()));
|
|
CGAL_TEST(D.first_pair_closer_than_second(eps5,D.NE(),eps1,D.SE()));
|
|
CGAL_TEST(!D.first_pair_closer_than_second(eps1,D.SE(),eps1,D.NE()));
|
|
CGAL_TEST(D.first_pair_closer_than_second(D.SE(),D.NE(),D.NE(),D.SW()));
|
|
CGAL_TEST(!D.first_pair_closer_than_second(D.SE(),D.NE(),D.NW(),D.SW()));
|
|
|
|
CGAL_TEST(D.construct_direction(D.NW(),D.NE())==ED(RT(1),RT(0)));
|
|
CGAL_TEST(D.construct_direction(D.NE(),D.NW())==ED(RT(-1),RT(0)));
|
|
CGAL_TEST(D.construct_direction(D.SW(),D.NE())==ED(RT(1),RT(1)));
|
|
CGAL_TEST(D.construct_direction(D.NW(),D.SE())==ED(RT(1),RT(-1)));
|
|
CGAL_TEST(D.construct_direction(D.NW(),D.SW())==ED(RT(0),RT(-1)));
|
|
CGAL_TEST(D.construct_direction(D.SW(),D.NW())==ED(RT(0),RT(1)));
|
|
|
|
CGAL_TEST(D.construct_direction(eps5,D.NE())==ED(RT(1),RT(1)));
|
|
CGAL_TEST(D.construct_direction(eps5,D.SW())==ED(RT(-1),RT(-1)));
|
|
|
|
ES upper = D.construct_segment(D.NW(),D.NE());
|
|
ES left = D.construct_segment(D.SW(),D.NW());
|
|
EP ep_res = D.intersection(el1,upper);
|
|
CGAL_TEST(ep_res==epn2);
|
|
ep_res = D.intersection(left, upper);
|
|
CGAL_TEST(ep_res == D.NW());
|
|
|
|
<<IO test>>=
|
|
CGAL_IO_TEST(eps3,eps1);
|
|
CGAL_IO_TEST(epn2,epn1);
|
|
|
|
|
|
@ \section{A Demo of the EPoint concept}
|
|
|
|
<<EPoint-demo.C>>=
|
|
#define RPOLYNOMIAL_EXPLICIT_OUTPUT
|
|
#include <CGAL/Extended_homogeneous.h>
|
|
#include <CGAL/leda_integer.h>
|
|
#include <CGAL/test_macros.h>
|
|
|
|
template <>
|
|
struct ring_or_field<leda_integer> {
|
|
typedef ring_with_gcd kind;
|
|
};
|
|
|
|
typedef CGAL::Extended_homogeneous<leda_integer> EDec;
|
|
typedef EDec::Standard_point_2 Standard_point;
|
|
typedef EDec::Standard_line_2 Standard_line;
|
|
typedef EDec::Point_2 Point;
|
|
typedef EDec::Standard_aff_transformation_2 Atra;
|
|
|
|
EDec D;
|
|
|
|
int main() {
|
|
CGAL::set_pretty_mode ( std::cout );
|
|
CGAL::set_pretty_mode ( std::cerr );
|
|
Standard_point p1(0,0),p2(2,1),p3(1,4);
|
|
Standard_line l(p1,p2);
|
|
Point ep1 = D.construct_point(l);
|
|
Point ep2 = D.construct_point(p2,p3);
|
|
Point ep3 = D.construct_point(p2);
|
|
TRACEV(ep1); TRACEV(ep2); TRACEV(ep3);
|
|
Atra T(CGAL::ROTATION,1,0);
|
|
Point ep10 = D.transform(ep1,T);
|
|
Point ep20 = D.transform(ep2,T);
|
|
Point ep30 = D.transform(ep3,T);
|
|
TRACEV(ep10); TRACEV(ep20); TRACEV(ep30);
|
|
}
|
|
|
|
@ \begin{ignore}
|
|
<<CGAL EH Header>>=
|
|
// ============================================================================
|
|
//
|
|
// Copyright (c) 1997-2000 The CGAL Consortium
|
|
//
|
|
// This software and related documentation is part of an INTERNAL release
|
|
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
|
// intended for general use.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// release : $CGAL_Revision$
|
|
// release_date : $CGAL_Date$
|
|
//
|
|
// file : include/CGAL/Extended_homogeneous.h
|
|
// package : Nef_2
|
|
// chapter : Nef Polyhedra
|
|
//
|
|
// source : nef_2d/Simple_extended_kernel.lw
|
|
// revision : $Id$
|
|
// revision_date : $Date$
|
|
//
|
|
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
|
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
|
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
|
//
|
|
// implementation: Extended homogeneous kernel
|
|
// ============================================================================
|
|
@
|
|
<<CGAL EC Header>>=
|
|
// ============================================================================
|
|
//
|
|
// Copyright (c) 1997-2000 The CGAL Consortium
|
|
//
|
|
// This software and related documentation is part of an INTERNAL release
|
|
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
|
// intended for general use.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// release : $CGAL_Revision$
|
|
// release_date : $CGAL_Date$
|
|
//
|
|
// file : include/CGAL/Extended_cartesian.h
|
|
// package : Nef_2
|
|
// chapter : Nef Polyhedra
|
|
//
|
|
// source : nef_2d/Simple_extended_kernel.lw
|
|
// revision : $Id$
|
|
// revision_date : $Date$
|
|
//
|
|
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
|
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
|
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
|
//
|
|
// implementation: Extended cartesian kernel
|
|
// ============================================================================
|
|
<<CGAL L2E Header>>=
|
|
// ============================================================================
|
|
//
|
|
// Copyright (c) 1997-2000 The CGAL Consortium
|
|
//
|
|
// This software and related documentation is part of an INTERNAL release
|
|
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
|
// intended for general use.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// release : $CGAL_Revision$
|
|
// release_date : $CGAL_Date$
|
|
//
|
|
// file : include/CGAL/Nef_2/Line_to_epoint.h
|
|
// package : Nef_2
|
|
// chapter : Nef Polyhedra
|
|
//
|
|
// source : nef_2d/Simple_extended_kernel.lw
|
|
// revision : $Id$
|
|
// revision_date : $Date$
|
|
//
|
|
// author(s) : Michael Seel <seel@mpi-sb.mpg.de>
|
|
// maintainer : Michael Seel <seel@mpi-sb.mpg.de>
|
|
// coordinator : Michael Seel <seel@mpi-sb.mpg.de>
|
|
//
|
|
// implementation: Simple converter
|
|
// ============================================================================
|
|
@ \end{ignore}
|
|
\end{ignoreindiss}
|
|
%KILLSTART DISS REP
|
|
\bibliographystyle{alpha}
|
|
\bibliography{comp_geo,general,diss}
|
|
\newpage
|
|
\section{Appendix}
|
|
\input manpages/ExtendedKernelTraits_2.man
|
|
\end{document}
|
|
%KILLEND DISS REP
|