cgal/Packages/Distance_2/web/sqdistance_2.fw

2225 lines
64 KiB
Plaintext

@! $RCSfile$
@! $Revision$
@! $Date$
@! Author: Geert-Jan Giezeman (geert@cs.ruu.nl)
@i cgal_util.fwi
@A@<Squared distance computations@>
The routines in this chapter compute the square of the euclidean distance
between objects.
By computing the square of the distance between two objects instead of the
distance itself, often the computation of a square root is avoided.
This is not only important for efficiency reasons.
There may be number types (especially when an exact representation is used)
where taking the square root is not possible.
@B@<Utility routines@>
While computing square distances I need a number of routines that are not
supplied as basic facilities in CGAL, but that are pretty basic and not tied
to distance computations. Perhaps they should be added to more basic
components.
@C@<Low level routines that avoid divisions@>
In order to avoid division (which is important for homogeneous types), we
sometimes need to compute with different routines than the natural ones.
We prefix the natural name of such a routine with a @{w@} to indicate this.
For example, the dot product of two vectors @{u@} and @{v@} is computed as
@{dot(u,v) == (ux.vx+uy.vy)/(uw.vw)@}.
The routine @{wdot@} is computed as follows: @{wdot(u,v) == ux.vx+uy.vy@}.
We use a short notation here where @{ux@} stands for @{u.hx()@}, @{uw@} stands
for @{u.hw()@} and so on.
Often we only need the sign of a routine. Then multiplication by homogeneous
factors has no influence, as they are positive by definition.
Also, when we need to compare the dot product of two different vectors, we can
use multiplications instead of divisions. Instead of comparing @{dot(p,q)@}
with @{dot(u,v)@}, we can compare @{uw.vw.wdot(p,q)@} with
@{pw.qw.wdot(u,v)@}. The homogenising factors are brought to the other side of
the comparison operator which can be done, again, because they are positive.
The homogeneous factors that are multiplied differ from case to case. This
makes those routines pretty low level and care should be taken when they are
used.
In the case of cartesian coordinates, we know that the homogenising factors
are 1 by definition. This leads to ample possibilities for optimisation.
Therefore, most routines have a specialisation for the cartesian case that is
more efficient.
@D@<Multiplication with homogeneous factors (wmult)@>
As we have seen in the example where dot products are compared, we sometimes
need to multiply by homogenising factors. Of course, the multiplication
operator can be used for this. Still, we provide a special function, @{wmult@}
for this. The reason to do that is that now we can define a specialisation for
cartesian types. In that case, the multiplication is a noop and can be
optimised away.
There are versions of @{wmult@} taking a different number of parameters. This
depends on the number of factors that are to be multiplied.
Of the multiplying factors the first may an arbitrary number.
The other (1 or 2) factors must be homogenising factors.
This allows the optimisation in the cartesian case.
The routines take a, quite unnatural, first parameter.
This is the mechanism that allows to decide between the cartesian or general
case.
@O@<../include/CGAL/wmult.h@>==@{@-
@<cgal_heading@>@(@-
include/CGAL/wmult.h@,@-
sqdistance_2.fw@,@-
Geert-Jan Giezeman@,@-
Saarbruecken@)
#ifndef CGAL_WMULT_H
#define CGAL_WMULT_H
CGAL_BEGIN_NAMESPACE
#if defined CGAL_HOMOGENEOUS_H
template <class RT>
inline RT wmult(Homogeneous<RT>*, const RT &a, const RT & w)
{
return a*w;
}
template <class RT>
inline RT wmult(Homogeneous<RT>*,
const RT &a, const RT & w1, const RT & w2)
{
return a*w1*w2;
}
template <class RT>
inline RT wmult(Homogeneous<RT>*, const RT &a,
const RT & w1, const RT & w2, const RT & w3)
{
return a*w1*w2*w3;
}
template <class RT>
inline RT wmult(Homogeneous<RT>*, const RT &a,
const RT & w1, const RT & w2, const RT & w3, const RT & w4)
{
return a*w1*w2*w3*w4;
}
#endif // CGAL_HOMOGENEOUS_H
#if defined CGAL_SIMPLE_HOMOGENEOUS_H
template <class RT>
inline RT wmult(Simple_homogeneous<RT>*, const RT &a, const RT & w)
{
return a*w;
}
template <class RT>
inline RT wmult(Simple_homogeneous<RT>*,
const RT &a, const RT & w1, const RT & w2)
{
return a*w1*w2;
}
template <class RT>
inline RT wmult(Simple_homogeneous<RT>*, const RT &a,
const RT & w1, const RT & w2, const RT & w3)
{
return a*w1*w2*w3;
}
template <class RT>
inline RT wmult(Simple_homogeneous<RT>*, const RT &a,
const RT & w1, const RT & w2, const RT & w3, const RT & w4)
{
return a*w1*w2*w3*w4;
}
#endif // CGAL_SIMPLE_HOMOGENEOUS_H
#if defined CGAL_CARTESIAN_H
template <class RT>
inline RT wmult(Cartesian<RT> *, const RT &a, const RT & )
{
return a;
}
template <class RT>
inline RT wmult(Cartesian<RT> *,
const RT &a, const RT & , const RT & )
{
return a;
}
template <class RT>
inline RT wmult(Cartesian<RT> *, const RT &a,
const RT & , const RT & , const RT & )
{
return a;
}
template <class RT>
inline RT wmult(Cartesian<RT> *, const RT &a,
const RT & , const RT & , const RT & , const RT & )
{
return a;
}
#endif // CGAL_CARTESIAN_H
#if defined CGAL_SIMPLE_CARTESIAN_H
template <class RT>
inline RT wmult(Simple_cartesian<RT> *, const RT &a, const RT & )
{
return a;
}
template <class RT>
inline RT wmult(Simple_cartesian<RT> *,
const RT &a, const RT & , const RT & )
{
return a;
}
template <class RT>
inline RT wmult(Simple_cartesian<RT> *, const RT &a,
const RT & , const RT & , const RT & )
{
return a;
}
template <class RT>
inline RT wmult(Simple_cartesian<RT> *, const RT &a,
const RT & , const RT & , const RT & , const RT & )
{
return a;
}
#endif // CGAL_SIMPLE_CARTESIAN_H
CGAL_END_NAMESPACE
#endif // CGAL_WMULT_H
@}
@D@<Testing for null vector@>
A routine to test whether a vector is a null vector.
This code does not belong here.
@$@<2D squared distance general utilities@>+=@{
template <class R>
bool is_null(const Vector_2<R> &v)
{
typedef typename R::RT RT;
return v.hx()==RT(0) && v.hy()==RT(0);
}
@}
@D@<The dot product@>
The dot product is useful for projecting a point on a line, and for deciding
whether an angle is acute, straight or obtuse.
Apart from the @{wdot@} routine there are also routines that use @{wdot@} to
decide on the acuteness of an angle.
Of all the routines there are different flavours, taking points and
vectors as arguments respectively. The points @{p,q@} and @{r@} stand
for the vectors @{p-q@} and @{r-q@}. The homogenising factors that are used
for multiplication are different though.
For vectors @{u@} and @{v@} we have @{wdot(u,v) == wu.wv.dot(u,v)@}
For points @{p,q@} and @{r@} we have @{wdot(p,q,r) == wp.wq.wq.wr.dot(p-q,r-q)@}
Note the double occurrence of the factor@{wq@} in the latter definition.
@$@<2D squared distance general utilities@>+=@{
template <class R>
typename R::RT
wdot(const Vector_2<R> &u, const Vector_2<R> &v)
{
return (u.hx()*v.hx() + u.hy()*v.hy());
}
template <class R>
typename R::RT wdot(const Point_2< R > &p,
const Point_2< R > &q,
const Point_2< R > &r)
{
R* pR = 0;
return (wmult(pR, p.hx(),q.hw()) - wmult(pR, q.hx(),p.hw()))
* (wmult(pR, r.hx(),q.hw()) - wmult(pR, q.hx(),r.hw()))
+ (wmult(pR, p.hy(),q.hw()) - wmult(pR, q.hy(),p.hw()))
* (wmult(pR, r.hy(),q.hw()) - wmult(pR, q.hy(),r.hw()));
}
@}
@D@<The cross product@>
The cross product of two vectors can be used for various purposes.
The sign tells whether the two vectors make a left or right turn or are
collinear (have the same or opposite direction). The absolute value gives the
area of the parallelogram spanned by the two vectors. This can also be used to
compute the (signed) distance from a point to a line.
Like with the dot product, we have versions for two vectors and for three
points.
We define @{wcross(u,v) == wu.wv.cross(u,v)@} and
@{wcross(p,q,r) == @}@{wp.wq.wr.cross(q-p,r-q)@}.
Different from the dot case, the factor @{wq@} occurs only once in the
definition of the wcross product for points.
@$@<2D squared distance general utilities@>+=@{
template <class R>
typename R::RT
wcross(const Vector_2<R> &u,
const Vector_2<R> &v)
{
return (typename R::RT)(u.hx()*v.hy() - u.hy()*v.hx());
}
#if defined CGAL_HOMOGENEOUS_H
template <class RT>
inline
RT wcross_impl(const Homogeneous<RT>*,const Point_2< Homogeneous<RT> > &p,
const Point_2< Homogeneous<RT> > &q,
const Point_2< Homogeneous<RT> > &r)
{
return p.hx() * (q.hy()*r.hw() - q.hw()*r.hy() )
+ p.hy() * (q.hw()*r.hx() - q.hx()*r.hw() )
+ p.hw() * (q.hx()*r.hy() - q.hy()*r.hx() );
}
#endif // CGAL_HOMOGENEOUS_H
#if defined CGAL_SIMPLE_HOMOGENEOUS_H
template <class RT>
inline
RT wcross_impl(const Simple_homogeneous<RT>*,
const Point_2< Simple_homogeneous<RT> > &p,
const Point_2< Simple_homogeneous<RT> > &q,
const Point_2< Simple_homogeneous<RT> > &r)
{
return det3x3_by_formula(
p.hx(), q.hx(), r.hx(),
p.hy(), q.hy(), r.hy(),
p.hw(), q.hw(), r.hw());
}
#endif // CGAL_SIMPLE_HOMOGENEOUS_H
#if defined CGAL_CARTESIAN_H
template <class FT>
inline
FT wcross_impl(const Cartesian<FT> *, const Point_2< Cartesian<FT> > &p,
const Point_2< Cartesian<FT> > &q,
const Point_2< Cartesian<FT> > &r)
{
return (q.x()-p.x())*(r.y()-q.y()) - (q.y()-p.y())*(r.x()-q.x());
}
#endif // CGAL_CARTESIAN_H
#if defined CGAL_SIMPLE_CARTESIAN_H
template <class FT>
inline
FT wcross_impl(const Simple_cartesian<FT> *,
const Point_2< Simple_cartesian<FT> > &p,
const Point_2< Simple_cartesian<FT> > &q,
const Point_2< Simple_cartesian<FT> > &r)
{
return (q.x()-p.x())*(r.y()-q.y()) - (q.y()-p.y())*(r.x()-q.x());
}
#endif // CGAL_SIMPLE_CARTESIAN_H
template <class R>
typename R::RT wcross(const Point_2< R > &p,
const Point_2< R > &q,
const Point_2< R > &r)
{
return wcross_impl(static_cast<R*>(0), p, q, r);
}
@}
@C@<Routines that characterise angles@>
Often one needs to know whether an angle is sharp or obtuse or whether it is a
left turn or a right turn. An angle can be characterised by three points
@{p,q@} and @{r@} (the angle formed at @{q@} when going from @{p@} to @{r@}
via @{q@}), or by two vectors @{u@} and @{v@} (the angle formed when their
tails are placed in the origin).
Then we can use the routines @{wdot@} and @{wcross@} for this purpose.
@D@<Sharp or obtuse@>
Here are routines to decide whether an angle is sharp, straight or obtuse.
There should also be an enum with three values (@{ACUTE@},
@{STRAIGHT@},@{OBTUSE@}) and a routine that returns such a value.
@$@<2D squared distance general utilities@>+=@{
template <class R>
inline bool is_acute_angle(const Vector_2<R> &u,
const Vector_2<R> &v)
{
typedef typename R::RT RT;
return RT(wdot(u, v)) > RT(0) ;
}
template <class R>
inline bool is_straight_angle(const Vector_2<R> &u,
const Vector_2<R> &v)
{
typedef typename R::RT RT;
return RT(wdot(u, v)) == RT(0) ;
}
template <class R>
inline bool is_obtuse_angle(const Vector_2<R> &u,
const Vector_2<R> &v)
{
typedef typename R::RT RT;
return RT(wdot(u, v)) < RT(0) ;
}
template <class R>
inline bool is_acute_angle(const Point_2<R> &p,
const Point_2<R> &q, const Point_2<R> &r)
{
typedef typename R::RT RT;
return RT(wdot(p, q, r)) > RT(0) ;
}
template <class R>
inline bool is_straight_angle(const Point_2<R> &p,
const Point_2<R> &q, const Point_2<R> &r)
{
typedef typename R::RT RT;
return RT(wdot(p, q, r)) == RT(0) ;
}
template <class R>
inline bool is_obtuse_angle(const Point_2<R> &p,
const Point_2<R> &q, const Point_2<R> &r)
{
typedef typename R::RT RT;
return RT(wdot(p, q, r)) < RT(0) ;
}
@}
@D@<Clockwise or counterclockwise@>
The following routines decide whether the smallest angle between two vectors
(when their tails are in the same point) is clockwise or counterclockwise.
If both angles are equal (zero or pi), the vectors are collinear.
If the angle is characterised by three points @{p@}, @{q@} and @{r@}, it is
more natural to think of making a left or right turn at @{q@} when going from
@{p@} to @{r@}. Those routines are implemented elsewhere, though.
@$@<2D squared distance general utilities@>+=@{
template <class R>
Orientation orientation(const Vector_2<R> &u,
const Vector_2<R> &v)
{
typedef typename R::RT RT;
RT wcr = wcross(u,v);
return (wcr > RT(0)) ? COUNTERCLOCKWISE :
(wcr < RT(0)) ? CLOCKWISE
: COLLINEAR;
}
template <class R>
inline bool counterclockwise(const Vector_2<R> &u,
const Vector_2<R> &v)
{
typedef typename R::RT RT;
return RT(wcross(u,v)) > RT(0);
}
template <class R>
inline bool leftturn(const Vector_2<R> &u,
const Vector_2<R> &v)
{
typedef typename R::RT RT;
return RT(wcross(u,v)) > RT(0);
}
template <class R>
inline bool clockwise(const Vector_2<R> &u,
const Vector_2<R> &v)
{
typedef typename R::RT RT;
return RT(wcross(u,v)) < RT(0);
}
template <class R>
inline bool rightturn(const Vector_2<R> &u,
const Vector_2<R> &v)
{
typedef typename R::RT RT;
return RT(wcross(u,v)) < RT(0);
}
template <class R>
inline bool collinear(const Vector_2<R> &u,
const Vector_2<R> &v)
{
typedef typename R::RT RT;
return RT(wcross(u,v)) == RT(0);
}
/*
the ordertype, rightturn, leftturn and collinear routines for points are
defined elsewhere.
*/
@}
@B@<Point Point distance@>
The squared distance between two points is computed by taking the dot product
of the difference vector.
@$@<2D squared distance header declarations 1@>+=@{@-
template <class R>
inline typename R::FT
squared_distance(
const Point_2<R> & pt1,
const Point_2<R> & pt2)
{
Vector_2<R> vec(pt1-pt2);
return (typename R::FT)(vec*vec);
}
@}
@B@<Point Line distance@>
@C@<Declarations@>
@$@<2D squared distance header declarations 1@>+=@{@-
template <class R>
class Squared_distance_to_line {
typename R::RT a, b, c, sqnorm;
public:
Squared_distance_to_line(typename R::Line_2 const &line)
: a(line.a()), b(line.b()), c(line.c())
{
sqnorm = a*a+b*b;
}
typename R::FT operator()(typename R::Point_2 const &pt) const
{
typedef typename R::RT RT;
RT w = pt.hw();
RT n = a*pt.hx() + b*pt.hy() + wmult((R*)0, c, w);
RT d = wmult((R*)0, sqnorm, w, w);
return R::make_FT(n*n, d);
}
};
@<Point Line distance implementation@>
template <class R>
inline typename R::FT
squared_distance(
const Line_2<R> & line,
const Point_2<R> & pt)
{
return squared_distance(pt, line);
}
@}
@C@<Implementation@>
We compute a vector perpendicular to the line(@{normal@}).
The dot product of a vector from the point to an arbitrary point on the line
with the @{normal@} is the (signed) distance from the point to the line,
multiplied with the length of @{normal@}. Taking the square of this value and
dividing by the square of the length of the @{normal@} gives the square
distance between the line and the point.
@$@<Point Line distance implementation@>==@{
template <class R>
typename R::FT
squared_distance(
const Point_2<R> &pt,
const Line_2<R> &line)
{
typedef typename R::RT RT;
RT a = line.a();
RT b = line.b();
RT w = pt.hw();
RT n = a*pt.hx() + b*pt.hy() + wmult((R*)0, line.c(), w);
RT d = wmult((R*)0, a*a+b*b, w, w);
return R::make_FT(n*n, d);
}
@}
@B@<Point Ray distance@>
@C@<Declarations@>
@$@<2D squared distance header declarations 1@>+=@{@-
template <class R>
class Squared_distance_to_ray {
typename R::Vector_2 ray_dir;
typename R::Point_2 ray_source;
Squared_distance_to_line<R> supline_dist;
public:
Squared_distance_to_ray(typename R::Ray_2 const &ray)
: ray_dir(ray.direction().vector()),
ray_source(ray.source()),
supline_dist(ray.supporting_line())
{ }
typename R::FT operator()(typename R::Point_2 const &pt) const
{
Vector_2<R> diff = pt-ray_source;
if (!is_acute_angle(ray_dir,diff) )
return (typename R::FT)(diff*diff);
return supline_dist(pt);
}
};
@<Point Ray distance implementation@>
template <class R>
inline typename R::FT
squared_distance(
const Ray_2<R> & ray,
const Point_2<R> & pt)
{
return squared_distance(pt, ray);
}
@}
@C@<Implementation@>
We test the angle between the direction vector of the ray and the vector from
the start point of the ray to the point @{pt@}. If this angle is acute,
a line perpendicular to the ray through @{pt@} passes through the ray, so we
the distance from the point to the ray is the same as the distance from the
point to the supporting line of the ray. Otherwise we compute the squared
distance from @{pt@} to the start point of the ray, as this is the closest
point.
@$@<Point Ray distance implementation@>==@{
template <class R>
extern typename R::FT
squared_distance(
const Point_2<R> &pt,
const Ray_2<R> &ray)
{
Vector_2<R> diff = pt-ray.source();
const Vector_2<R> &dir = ray.direction().vector();
if (!is_acute_angle(dir,diff) )
return (typename R::FT)(diff*diff);
return squared_distance(pt, ray.supporting_line());
}
@}
@B@<Point Ray distance discerners@>
@$@<2D squared distance header declarations 1@>+=@{
@<Point Ray distance discerners implementation@>
@}
@C@<Implementation@>
@$@<Point Ray distance discerners implementation@>==@{
template <class R>
extern void
distance_index(
int &ind,
const Point_2<R> &pt,
const Ray_2<R> &ray)
{
if (!is_acute_angle(ray.direction().vector(),pt-ray.source())) {
ind = 0;
return;
}
ind = -1;
}
template <class R>
typename R::FT
squared_distance_indexed(const Point_2<R> &pt,
const Ray_2<R> &ray, int ind)
{
if (ind == 0)
return squared_distance(pt, ray.source());
return squared_distance(pt, ray.supporting_line());
}
@}
@B@<Point Segment distance@>
@$@<2D squared distance header declarations 1@>+=@{@-
template <class R>
class Squared_distance_to_segment {
typename R::Point_2 seg_source, seg_target;
Squared_distance_to_line<R> supline_dist;
typename R::Vector_2 segvec;
typename R::RT e;
public:
Squared_distance_to_segment(typename R::Segment_2 const &seg)
: seg_source(seg.source()), seg_target(seg.target()),
supline_dist(seg.supporting_line())
{
segvec = seg_target-seg_source;
e = wdot(segvec,segvec);
}
typename R::FT operator()(typename R::Point_2 const &pt) const
{
typedef typename R::RT RT;
// assert that the segment is valid (non zero length).
Vector_2<R> diff = pt-seg_source;
RT d = wdot(diff,segvec);
if (d <= (RT)0)
return (typename R::FT)(diff*diff);
if (wmult((R*)0 ,d, segvec.hw()) > wmult((R*)0, e, diff.hw()))
return squared_distance(pt, seg_target);
return supline_dist(pt);
}
};
@<Point Segment distance implementation@>
template <class R>
inline typename R::FT
squared_distance(
const Segment_2<R> & seg,
const Point_2<R> & pt)
{
return squared_distance(pt, seg);
}
@}
@C@<Implementation@>
To compute the distance of a point to a segment, first we divide the plane in
three parts. We draw two lines perpendicular to the segment, one through the
start point, the other through the end point of the segment. If the query
point lies between those two lines, we need to compute the distance of the
query point to the supporting line of the segment. Otherwise we need to
compute the distance from the point to either the endpoint or the startpoint.
To decide which case applies, we compute the dot poduct of the vector from
segment start to segment end and the vector from segment start to the point.
If this product is negative, the distance from the point to the start of the
segment is taken.
@$@<Point Segment distance implementation@>==@{
template <class R>
typename R::FT
squared_distance(
const Point_2<R> &pt,
const Segment_2<R> &seg)
{
typedef typename R::RT RT;
// assert that the segment is valid (non zero length).
Vector_2<R> diff = pt-seg.source();
Vector_2<R> segvec = seg.target()-seg.source();
RT d = wdot(diff,segvec);
if (d <= (RT)0)
return (typename R::FT)(diff*diff);
RT e = wdot(segvec,segvec);
if (wmult((R*)0 ,d, segvec.hw()) > wmult((R*)0, e, diff.hw()))
return squared_distance(pt, seg.target());
return squared_distance(pt, seg.supporting_line());
}
@}
@B@<Point Segment distance discerners@>
@$@<2D squared distance header declarations 1@>+=@{
@<Point Segment distance discerners implementation@>
@}
@C@<Implementation@>
@$@<Point Segment distance discerners implementation@>==@{
template <class R>
extern void
distance_index(
int &ind,
const Point_2<R> &pt,
const Segment_2<R> &seg)
{
if (!is_acute_angle(seg.target(),seg.source(),pt)) {
ind = 0;
return;
}
if (!is_acute_angle(seg.source(),seg.target(),pt)) {
ind = 1;
return;
}
ind = -1;
}
template <class R>
typename R::FT
squared_distance_indexed(const Point_2<R> &pt,
const Segment_2<R> &seg, int ind)
{
if (ind == 0)
return squared_distance(pt, seg.source());
if (ind == 1)
return squared_distance(pt, seg.target());
return squared_distance(pt, seg.supporting_line());
}
@}
@B@<Segment Segment distance@>
@C@<Declarations@>
@$@<2D squared distance header declarations 1@>+=@{@-
@<Segment Segment distance implementation@>
@}
@C@<Implementation@>
If two segments do not cross, the distance of the two segments can be found by
comparing the distance of the endpoints to the other segment. The minimum
of those four distances is the distance between the two segments. This is the
fact that is exploited in the implementation.
@D@<Distance computation@>
To compute the squared distance of two segments, the following steps are
taken.
First we check if one of the segments is degenerate (coinciding start and
end point). If so, we solve the problem for a point and a segment.
Then we decide if the one segment crosses the supporting line of the other
segment. The boolean @{crossing1@} tells whether @{seg1@} crosses the
supporting line of @{seg2@}, and vice versa for @{crossing2@}.
To decide whether they cross, we look at the sign of the cross product. If an
endpoint lies on the supporting line, we consider this as crossing. The value
of the cross product is stored in a variable because it is needed later on.
This is also the reason why we do not use the ordertype routine to decide on
which side the points lie. That would mean double work.
A special case arises if both segments lie on the same supporting line.
This is checked separately.
@$@<2D segment segment squared distance main routine@>+=@{
template <class R>
typename R::FT
squared_distance(
const Segment_2<R> &seg1,
const Segment_2<R> &seg2)
{
typedef typename R::RT RT;
typedef typename R::FT FT;
bool crossing1, crossing2;
RT c1s, c1e, c2s, c2e;
if (seg1.source() == seg1.target())
return squared_distance(seg1.source(), seg2);
if (seg2.source() == seg2.target())
return squared_distance(seg2.source(), seg1);
c1s = wcross(seg2.source(), seg2.target(), seg1.source());
c1e = wcross(seg2.source(), seg2.target(), seg1.target());
c2s = wcross(seg1.source(), seg1.target(), seg2.source());
c2e = wcross(seg1.source(), seg1.target(), seg2.target());
if (c1s < RT(0)) {
crossing1 = (c1e >= RT(0));
} else {
if (c1e <= RT(0)) {
if (c1s == RT(0) && c1e == RT(0))
return squared_distance_parallel(seg1, seg2);
crossing1 = true;
} else {
crossing1 = (c1s == RT(0));
}
}
if (c2s < RT(0)) {
crossing2 = (c2e >= RT(0));
} else {
if (c2e <= RT(0)) {
if (c2s == RT(0) && c2e == RT(0))
return squared_distance_parallel(seg1, seg2);
crossing2 = true;
} else {
crossing2 = (c2s == RT(0));
}
}
@}
Depending on the values of the crossing variables we now proceed. If both
segments cross the supporting line of the other segment, the segments
themselves must cross, so they have zero distance.
If exactly one of the segments does not cross, the distance is the
distance of one of the endpoints of this (non crossing) segment to the
other (crossing) segment. Which endpoint? The one that is closest to the
supporting lines of the other segment. This latter property can easily be
computed with the value of the cross product that was computed earlier.
The function @{_distance_measure_sub@} makes this comparison (it
subtracts the two absolute values of the cross product, first corrected by
homogenising factors).
Note that the computation of the endpoint closest to a line may be
susceptible to roundoff error. The result can be incorrect in that
case. This must still be solved, for instance by computing the squared
distance from both endpoints to the other segment and taking the minimum.
@$@<unused implementation@>@Z==@{
template <class R, class RT>
typename R::FT
_squared_distance_of_endpoint_exact(RT start_dm, RT end_dm,
const Point_2<R> &start, const Point_2<R> &end,
const Segment<R> &seg)
{
typedef typename R::RT RT;
RT dm;
dm = _distance_measure_sub(start_dm, end_dm, start, end);
if (dm < RT(0)) {
return squared_distance(start, seg);
} else {
return squared_distance(end, seg);
}
}
template <class R, class RT>
typename R::FT
_squared_distance_of_endpoint_inexact<R, RT>(
const Point_2<R> &start, const Point_2<R> &end,
const Segment<R> &seg)
{
typedef typename R::RT RT;
RT d1, d2;
d1 = squared_distance(start, seg);
d2 = squared_distance(end, seg);
return (d1 < d2) ? (typename R::FT)(d1) : (typename_R::FT)(d2);
}
template <class R, class RT>
inline typename R::FT
_squared_distance_of_endpoint<false, R, RT>(RT start_dm, RT end_dm,
const Point_2<R> &start, const Point_2<R> &end,
const Segment<R> &seg)
{
if (numeric_limits<R>::is_exact)
return _squared_distance_of_endpoint_exact(
start_dm, end_dm, start, end, seg);
else
return _squared_distance_of_endpoint_inexact(start, end, seg);
}
@}
@$@<2D segment segment squared distance main routine@>+=@{
if (crossing1) {
if (crossing2)
return (FT)0;
RT dm;
dm = _distance_measure_sub(c2s,c2e, seg2.source(), seg2.target());
if (dm < RT(0)) {
return squared_distance(seg2.source(), seg1);
} else {
if (dm > RT(0)) {
return squared_distance(seg2.target(), seg1);
} else {
// parallel, should not happen (no crossing)
return squared_distance_parallel(seg1, seg2);
}
}
} else {
if (crossing2) {
RT dm;
dm =
_distance_measure_sub(c1s, c1e,seg1.source(),seg1.target());
if (dm < RT(0)) {
return squared_distance(seg1.source(), seg2);
} else {
if (dm > RT(0)) {
return squared_distance(seg1.target(), seg2);
} else {
// parallel, should not happen (no crossing)
return squared_distance_parallel(seg1, seg2);
}
}
} else {
@}
Finally, neither of the segments may cross. This may be because the two
segments are parallel, which we deal with as a separate case.
Otherwise we have to compare the distance of two endpoints to the other
segment and take the minimum.
@$@<2D segment segment squared distance main routine@>+=@{
FT min1, min2;
RT dm = _distance_measure_sub(
c1s, c1e, seg1.source(), seg1.target());
if (dm == RT(0))
return squared_distance_parallel(seg1, seg2);
min1 = (dm < RT(0)) ?
squared_distance(seg1.source(), seg2):
squared_distance(seg1.target(), seg2);
dm = _distance_measure_sub(
c2s, c2e, seg2.source(), seg2.target());
if (dm == RT(0)) // should not happen.
return squared_distance_parallel(seg1, seg2);
min2 = (dm < RT(0)) ?
squared_distance(seg2.source(), seg1):
squared_distance(seg2.target(), seg1);
return (min1 < min2) ? min1 : min2;
}
}
}
@}
We need a small helper function to compare the distance from a point to the
intersection point of the supporting lines of the two segments. With the help
of the cross product (that is known), this can be computed cheaply.
@$@<2D segment segment squared distance helper routine@>==@{
template <class RT, class R>
RT _distance_measure_sub(RT startwcross, RT endwcross,
const Point_2<R> &start, const Point_2<R> &end
)
{
return CGAL_NTS abs(wmult((R*)0, startwcross, end.hw())) -
CGAL_NTS abs(wmult((R*)0, endwcross, start.hw()));
}
@}
We still need to deal with the case where both segments are parallel. The
segments may not be degenerate (this was tested before), but they may have
opposite directions. This is checked and stored in the boolean variable
@{same_direction@}.
The distance between two parallel segments is either the
distance between two endpoints or the distance between an arbitrary point on
one segment to the supporting line of the other segment. In order to decide
which case applies, we can project the second segment perpendicularly on the
supporting line of the first segment. If the resulting segments overlap, the
second case apllies, otherwise the former case. The projections are just a way
of explaining, they are not actually done. The sign of the dot product is used
to make the necessary decisions.
@$@<2D segment segment squared distance parallel case@>+=@{
template <class R>
typename R::FT
squared_distance_parallel(
const Segment_2<R> &seg1,
const Segment_2<R> &seg2)
{
bool same_direction;
const Vector_2<R> &dir1 = seg1.direction().vector();
const Vector_2<R> &dir2 = seg2.direction().vector();
if (CGAL_NTS abs(dir1.hx()) > CGAL_NTS abs(dir1.hy())) {
same_direction = (CGAL_NTS sign(dir1.hx()) == CGAL_NTS sign(dir2.hx()));
} else {
same_direction = (CGAL_NTS sign(dir1.hy()) == CGAL_NTS sign(dir2.hy()));
}
if (same_direction) {
if (!is_acute_angle(seg1.source(), seg1.target(), seg2.source()))
return squared_distance(seg1.target(), seg2.source());
if (!is_acute_angle(seg1.target(), seg1.source(), seg2.target()))
return squared_distance(seg1.source(), seg2.target());
} else {
if (!is_acute_angle(seg1.source(), seg1.target(), seg2.target()))
return squared_distance(seg1.target(), seg2.target());
if (!is_acute_angle(seg1.target(), seg1.source(), seg2.source()))
return squared_distance(seg1.source(), seg2.source());
}
return squared_distance(seg2.source(), seg1.supporting_line());
}
@}
@$@<Segment Segment distance implementation@>==@{
@<2D segment segment squared distance parallel case@>
@<2D segment segment squared distance helper routine@>
@<2D segment segment squared distance main routine@>
@}
@B@<Segment Ray distance@>
@C@<Declarations@>
@$@<2D squared distance header declarations 1@>+=@{@-
@<Segment Ray distance implementation@>
template <class R>
inline typename R::FT
squared_distance(
const Ray_2<R> & ray,
const Segment_2<R> & seg)
{
return squared_distance(seg, ray);
}
@}
@C@<Implementation@>
The computation of the squared distance between a segment and a ray goes along
the same lines as the computation of the square distance of two segments.
We give only short comments here.
First we check if the segment is degenerate (coinciding start and
end point). If so, we solve the problem for a point and a ray.
Then we decide if the one segment crosses the supporting line of the other
segment. The boolean @{crossing1@} tells whether the segment crosses the
supporting line of the ray, @{crossing2@} tells whether the ray crosses the
supporting line of the segment.
For the ray we look at the direction and on which side its starting point
lies.
@$@<2D ray segment squared distance computation@>+=@{
template <class R>
typename R::FT
squared_distance(
const Segment_2<R> &seg,
const Ray_2<R> &ray)
{
typedef typename R::RT RT;
typedef typename R::FT FT;
const Vector_2<R> &raydir = ray.direction().vector();
Vector_2<R> startvec(seg.source()-ray.source());
Vector_2<R> endvec(seg.target()-ray.source());
bool crossing1, crossing2;
RT c1s, c1e;
Orientation ray_s_side;
if (seg.source() == seg.target())
return squared_distance(seg.source(), ray);
c1s = wcross(raydir, startvec);
c1e = wcross(raydir, endvec);
if (c1s < RT(0)) {
crossing1 = (c1e >= RT(0));
} else {
if (c1e <= RT(0)) {
if (c1s == RT(0) && c1e == RT(0))
return squared_distance_parallel(seg, ray);
crossing1 = true;
} else {
crossing1 = (c1s == RT(0));
}
}
ray_s_side = orientation(seg.source(), seg.target(), ray.source());
switch (ray_s_side) {
case LEFTTURN:
crossing2 = rightturn(seg.target()-seg.source(), raydir);
break;
case RIGHTTURN:
crossing2 = leftturn(seg.target()-seg.source(), raydir);
break;
case COLLINEAR:
crossing2 = true;
break;
}
@}
Depending on the values of the crossing variables we now proceed. If both
segments cross the supporting line of the other segment, the segments
themselves must cross, so they have zero distance.
If exactly one of the segments does not cross, the distance is the
distance of one of the endpoints of this (non crossing) segment to the
other (crossing) segment. Which endpoint? The one that is closest to the
intersection point of the supporting lines of the two segments. This
latter property can easily be computed with the value of the cross product
that was computed earlier. The function @{_distance_measure_sub@}
makes this comparison (it subtracts the two absolute values of the cross
product, first corrected by homogenising factors).
@$@<2D ray segment squared distance computation@>+=@{
if (crossing1) {
if (crossing2)
return FT(0);
return squared_distance(ray.source(), seg);
} else {
if (crossing2) {
RT dm;
dm = _distance_measure_sub(c1s, c1e, startvec, endvec);
if (dm < RT(0)) {
return squared_distance(seg.source(), ray);
} else {
if (dm > RT(0)) {
return squared_distance(seg.target(), ray);
} else {
// parallel, should not happen (no crossing)
return squared_distance_parallel(seg, ray);
}
}
} else {
@}
Finally, neither of the segments may cross. This may be because the two
segments are parallel, which we deal with as a separate case.
Otherwise we have to compare the distance of two endpoints to the other
segment and take the minimum.
@$@<2D ray segment squared distance computation@>+=@{
FT min1, min2;
RT dm;
dm = _distance_measure_sub(c1s, c1e, startvec, endvec);
if (dm == RT(0))
return squared_distance_parallel(seg, ray);
min1 = (dm < RT(0))
? squared_distance(seg.source(), ray)
: squared_distance(seg.target(), ray);
min2 = squared_distance(ray.source(), seg);
return (min1 < min2) ? min1 : min2;
}
}
}
@}
@$@<2D ray segment squared distance parallel case@>==@{
template <class R>
typename R::FT
squared_distance_parallel(
const Segment_2<R> &seg,
const Ray_2<R> &ray)
{
bool same_direction;
const Vector_2<R> &dir1 = seg.direction().vector();
const Vector_2<R> &dir2 = ray.direction().vector();
if (CGAL_NTS abs(dir1.hx()) > CGAL_NTS abs(dir1.hy())) {
same_direction = (CGAL_NTS sign(dir1.hx()) == CGAL_NTS sign(dir2.hx()));
} else {
same_direction = (CGAL_NTS sign(dir1.hy()) == CGAL_NTS sign(dir2.hy()));
}
if (same_direction) {
if (!is_acute_angle(seg.source(), seg.target(), ray.source()))
return squared_distance(seg.target(), ray.source());
} else {
if (!is_acute_angle(seg.target(), seg.source(), ray.source()))
return squared_distance(seg.source(), ray.source());
}
return squared_distance(ray.source(), seg.supporting_line());
}
@}
@$@<2D ray segment squared distance helper routine@>==@{
template <class RT, class R>
RT _distance_measure_sub(RT startwcross, RT endwcross,
const Vector_2<R> &start, const Vector_2<R> &end
)
{
return CGAL_NTS abs(wmult((R*)0, startwcross, end.hw())) -
CGAL_NTS abs(wmult((R*)0, endwcross, start.hw()));
}
@}
@$@<Segment Ray distance implementation@>==@{
@<2D ray segment squared distance helper routine@>
@<2D ray segment squared distance parallel case@>
@<2D ray segment squared distance computation@>
@}
@B@<Segment Line distance@>
@C@<Declarations@>
@$@<2D squared distance header declarations 1@>+=@{@-
@<Segment Line distance implementation@>
template <class R>
inline typename R::FT
squared_distance(
const Line_2<R> & line,
const Segment_2<R> & seg)
{
return squared_distance(seg, line);
}
@}
@C@<Implementation@>
The computation of the squared distance between a segment and a line goes along
the same lines as the computation of the square distance of two segments.
First we check if the segment is degenerate (coinciding start and
end point). If so, we solve the problem for a point and a line.
Then we decide if the segment crosses the line.
The boolean @{crossing1@} tells whether the segment crosses the line.
@$@<2D line segment squared distance computation@>+=@{
template <class R>
typename R::FT
squared_distance(
const Segment_2<R> &seg,
const Line_2<R> &line)
{
typedef typename R::RT RT;
typedef typename R::FT FT;
const Vector_2<R> &linedir = line.direction().vector();
const Point_2<R> &linepoint = line.point();
Vector_2<R> startvec(seg.source()-linepoint);
Vector_2<R> endvec(seg.target()-linepoint);
bool crossing1;
RT c1s, c1e;
if (seg.source() == seg.target())
return squared_distance(seg.source(), line);
c1s = wcross(linedir, startvec);
c1e = wcross(linedir, endvec);
if (c1s < RT(0)) {
crossing1 = (c1e >= RT(0));
} else {
if (c1e <= RT(0)) {
crossing1 = true;
} else {
crossing1 = (c1s == RT(0));
}
}
@}
If the segment crosses the line, they have zero distance. Otherwise, the
distance is the distance of one of the endpoints of the segment to the
line. Which endpoint? The one that is closest to the supporting line of
the other segment. This latter property can easily be computed with the
value of the cross product that was computed earlier. The function
@{_distance_measure_sub@} makes this comparison (it subtracts the two
absolute values of the cross product, first corrected by homogenising
factors).
@$@<2D line segment squared distance computation@>+=@{
if (crossing1) {
return (FT)0;
} else {
RT dm;
dm = _distance_measure_sub(c1s, c1e, startvec, endvec);
if (dm <= RT(0)) {
return _sqd_to_line(startvec, c1s, linedir);
} else {
return _sqd_to_line(endvec, c1e, linedir);
}
}
}
@}
The following routine returns the square distance from a point to a line.
It is an optimised routine, that makes use of the intermediate results that
are available. It is based on the observation that given @{diff@}, the
difference vector between the point and a point on the line, and @{dir@}, the
(not necessarily normalized) direction vector of the line, the squared
distance can be computed as: @{cross(dir,diff)^2 / dot(dir,dir)@}.
We can write this in terms of wcross and wdot operations and multiplications
with hw factors. The hw factors of @{dir@} cancel.
@$@<2D line segment squared distance helper routine@>==@{
template <class RT, class R>
typename R::FT
_sqd_to_line(const Vector_2<R> &diff,
const RT & wcross, const Vector_2<R> &dir )
{
typedef typename R::FT FT;
RT numerator = wcross*wcross;
RT denominator = wmult((R*)0, RT(wdot(dir,dir)),
diff.hw(), diff.hw());
FT result = R::make_FT(numerator, denominator);
return result;
}
@}
@$@<Segment Line distance implementation@>==@{
@<2D line segment squared distance helper routine@>
@<2D line segment squared distance computation@>
@}
@B@<Ray Ray distance@>
@$@<2D squared distance header declarations 1@>+=@{@-
@<Ray Ray distance@>
@}
@C@<Implementation@>
The computation of the squared distance two rays goes along the same lines as
the computation of the square distance between a segment and a ray.
First we decide if the one ray crosses the supporting line of the other ray.
The boolean @{crossing1@} tells whether @{ray1@} crosses the supporting line
of the @{ray2@}, @{crossing2@} tells whether @{ray2@} crosses the
supporting line of @{ray1@}.
We look at the direction of the ray and on which side its starting point lies.
@$@<2D ray ray squared distance computation@>+=@{
template <class R>
typename R::FT
squared_distance(
const Ray_2<R> &ray1,
const Ray_2<R> &ray2)
{
typedef typename R::FT FT;
const Vector_2<R> &ray1dir = ray1.direction().vector();
const Vector_2<R> &ray2dir = ray2.direction().vector();
Vector_2<R> diffvec(ray2.source()-ray1.source());
bool crossing1, crossing2;
Orientation dirorder;
dirorder = orientation(ray1dir, ray2dir);
switch (dirorder) {
case COUNTERCLOCKWISE:
crossing1 = !clockwise(diffvec, ray2dir);
crossing2 = !counterclockwise(ray1dir, diffvec);
break;
case CLOCKWISE:
crossing1 = !counterclockwise(diffvec, ray2dir);
crossing2 = !clockwise(ray1dir, diffvec);
break;
case COLLINEAR:
return ray_ray_squared_distance_parallel(ray1dir,ray2dir,diffvec);
}
@}
Depending on the values of the crossing variables we now proceed. If both
rays cross the supporting line of the other ray, the rays
themselves must cross, so they have zero distance.
If exactly one of the rays does not cross, the distance is the distance of
the startpoint of this (non crossing) ray to the other (crossing)
ray.
@$@<2D ray ray squared distance computation@>+=@{
if (crossing1) {
if (crossing2)
return (FT)0;
return squared_distance(ray2.source(), ray1);
} else {
if (crossing2) {
return squared_distance(ray1.source(), ray2);
} else {
@}
Finally, neither of the rays may cross. This may be because the two
rays are parallel, which we deal with as a separate case.
Otherwise we have to compare the distance of two endpoints to the other
ray and take the minimum.
@$@<2D ray ray squared distance computation@>+=@{
FT min1, min2;
min1 = squared_distance(ray1.source(), ray2);
min2 = squared_distance(ray2.source(), ray1);
return (min1 < min2) ? min1 : min2;
}
}
}
@}
The following routine computes the squared distance between two rays if they
are parallel. The parameters are the directions of the rays and the vector
from the start point of the first ray to the start point of the second.
The distance is the distance between the two start points if there is no
line perpendicular to the rays that passes through both rays. Otherwise we can
take the distance between the starting point of the one ray to the supporting
line of the other.
@$@<2D ray ray squared distance parallel case@>==@{
template <class R>
typename R::FT
ray_ray_squared_distance_parallel(
const Vector_2<R> &ray1dir,
const Vector_2<R> &ray2dir,
const Vector_2<R> &from1to2)
{
typedef typename R::RT RT;
typedef typename R::FT FT;
if (!is_acute_angle(ray1dir, from1to2)) {
bool same_direction;
if (CGAL_NTS abs(ray1dir.hx()) > CGAL_NTS abs(ray1dir.hy())) {
same_direction =
(CGAL_NTS sign(ray1dir.hx()) == CGAL_NTS sign(ray2dir.hx()));
} else {
same_direction =
(CGAL_NTS sign(ray1dir.hy()) == CGAL_NTS sign(ray2dir.hy()));
}
if (!same_direction)
return (typename R::FT)(from1to2*from1to2);
}
RT wcr, w;
wcr = wcross(ray1dir, from1to2);
w = from1to2.hw();
return (typename R::FT)(FT(wcr*wcr)
/ FT(wmult((R*)0, RT(wdot(ray1dir, ray1dir)), w, w)));
}
@}
@$@<Ray Ray distance@>==@{
@<2D ray ray squared distance parallel case@>
@<2D ray ray squared distance computation@>
@}
@B@<Line Ray distance@>
@$@<2D squared distance header declarations 1@>+=@{@-
@<Line Ray distance implementation@>
template <class R>
inline typename R::FT
squared_distance(
const Ray_2<R> & ray,
const Line_2<R> & line)
{
return squared_distance(line, ray);
}
@}
@C@<Implementation@>
First we decide if the ray and the line intersect.
The normal to the line is taken.
If the start point of the ray lies on the normal side of the line and the
direction of the ray has a component in the opposite direction of the normal
(or the other way around), the line and ray intersect and 0 is returned.
Otherwise the squared distance from the start point to the line is reported.
Because we have intermediate results for this computation, we do not call
that routine but compute it using primitive operations.
It would be nice to have a routine to get the normal vector of a line (or of a
direction).
@$@<Line Ray distance implementation@>==@{
template <class R>
extern typename R::FT
squared_distance(
const Line_2<R> &line,
const Ray_2<R> &ray)
{
typedef typename R::FT FT;
Vector_2<R> normalvec(line.a(), line.b());
Vector_2<R> diff = ray.source()-line.point();
FT sign_dist = diff*normalvec;
if (sign_dist < FT(0)) {
if (is_acute_angle(normalvec, ray.direction().vector()) )
return (FT)0;
} else {
if (is_obtuse_angle(normalvec, ray.direction().vector()) )
return (FT)0;
}
return (typename R::FT)((sign_dist*sign_dist)/(normalvec*normalvec));
}
@}
@B@<Line Line distance@>
@$@<2D squared distance header declarations 1@>+=@{@-
@<Line Line distance@>
@}
@C@<Implementation@>
The distance between two lines is zero unless the two lines are paralel. In
that case we can take the distance of an arbitrary point on the one line to
the other line.
@$@<Line Line distance@>==@{
template <class R>
bool
_are_parallel(
const Line_2<R> &line1,
const Line_2<R> &line2)
{
return line1.a()*line2.b() == line2.a()*line1.b();
}
template <class R>
typename R::FT
squared_distance(
const Line_2<R> &line1,
const Line_2<R> &line2)
{
typedef typename R::FT FT;
if (_are_parallel(line1,line2))
return squared_distance(line1.point(), line2);
else
return (FT)0;
}
@}
@B@<Point Triangle distance helper function@>
The @{distance_index@} function computes to which feature of the
triangle the point is closest.
If the point lies inside the triangle, both indices are set to -1.
If the point is closest to the interior of a triangle edge, the indices
are set to the indices of the vertices of that edge, such that the point
lies to the right of the line through vertex(ind1) and vertex(ind2).
Otherwise, the point is closest to a vertex of the triangle. Then ind2 is
set to -1 and vertex(ind1) is the closest vertex.
@$@<2D squared distance header declarations 2@>+=@{
@<Point Triangle distance implementation 1@>
@}
@$@<2D squared distance header declarations 2@>+=@{
@<Point Triangle distance implementation 2@>
@}
@C@<Implementation@>
The implementation discerns between a whole lot of cases.
The outermost if then else clause discerns between a positive oriented
triangle (vertices in counterclockwise order) and a negative oriented.
The code in the else part is identical, except that the role of vertex 1 and 2
of the triangle are swapped.
A point can either lie inside the triangle, be closest to the interior of an
edge or closest to a vertex.
It lies inside the triangle iff it lies not to the right of any supporting
line of the triangle edges (for a positive oriented triangle).
It is closest to an edge if it lies to the right of the edge and if both the
angle edge.source, edge.target, point and edge.target, edge.source, point are
sharp.
Otherwise the point lies closest to a vertex.
@$@<Point Triangle distance implementation 1@>==@{
template <class R>
extern void
distance_index(
int &ind1,
int &ind2,
const Point_2<R> &pt,
const Triangle_2<R> &triangle)
{
const Point_2<R> &vt0 = triangle.vertex(0);
const Point_2<R> &vt1 = triangle.vertex(1);
const Point_2<R> &vt2 = triangle.vertex(2);
if (leftturn(vt0, vt1, vt2)) {
if (rightturn(vt0, vt1, pt)) {
if (!is_acute_angle(vt0, vt1, pt)) {
if (rightturn(vt1, vt2, pt)) {
if (!is_acute_angle(vt1, vt2, pt)) {
ind1 = 2; ind2 = -1;
return;
}
if (!is_acute_angle(vt2, vt1, pt)) {
ind1 = 1; ind2 = -1;
return;
}
ind1 = 1; ind2 = 2;
return;
}
ind1 = 1; ind2 = -1;
return;
}
if (!is_acute_angle(vt1, vt0, pt)) {
if (rightturn(vt2, vt0, pt)) {
if (!is_acute_angle(vt0, vt2, pt)) {
ind1 = 2; ind2 = -1;
return;
}
if (!is_acute_angle(vt2, vt0, pt)) {
ind1 = 0; ind2 = -1;
return;
}
ind1 = 2; ind2 = 0;
return;
}
ind1 = 0; ind2 = -1;
return;
}
ind1 = 0; ind2 = 1;
return;
} else {
if (rightturn(vt1, vt2, pt)) {
if (!is_acute_angle(vt1, vt2, pt)) {
if (rightturn(vt2, vt0, pt)) {
if (!is_acute_angle(vt0, vt2, pt)) {
ind1 = 2; ind2 = -1;
return;
}
if (!is_acute_angle(vt2, vt0, pt)) {
ind1 = 0; ind2 = -1;
return;
}
ind1 = 2; ind2 = 0;
return;
}
ind1 = 0; ind2 = -1;
return;
}
if (!is_acute_angle(vt2, vt1, pt)) {
ind1 = 1; ind2 = -1;
return;
}
ind1 = 1; ind2 = 2;
return;
} else {
if (rightturn(vt2, vt0, pt)) {
if (!is_acute_angle(vt2, vt0, pt)) {
ind1 = 0; ind2 = -1;
return;
}
if (!is_acute_angle(vt0, vt2, pt)) {
ind1 = 2; ind2 = -1;
return;
}
ind1 = 2; ind2 = 0;
return;
} else {
ind1 = -1; ind2 = -1; // point inside or on boundary.
return;
}
}
}
} else {
if (rightturn(vt0, vt2, pt)) {
if (!is_acute_angle(vt0, vt2, pt)) {
if (rightturn(vt2, vt1, pt)) {
if (!is_acute_angle(vt2, vt1, pt)) {
ind1 = 1; ind2 = -1;
return;
}
if (!is_acute_angle(vt1, vt2, pt)) {
ind1 = 2; ind2 = -1;
return;
}
ind1 = 2; ind2 = 1;
return;
}
ind1 = 2; ind2 = -1;
return;
}
if (!is_acute_angle(vt2, vt0, pt)) {
if (rightturn(vt1, vt0, pt)) {
if (!is_acute_angle(vt0, vt1, pt)) {
ind1 = 1; ind2 = -1;
return;
}
if (!is_acute_angle(vt1, vt0, pt)) {
ind1 = 0; ind2 = -1;
return;
}
ind1 = 1; ind2 = 0;
return;
}
ind1 = 0; ind2 = -1;
return;
}
ind1 = 0; ind2 = 2;
return;
} else {
if (rightturn(vt2, vt1, pt)) {
if (!is_acute_angle(vt2, vt1, pt)) {
if (rightturn(vt1, vt0, pt)) {
if (!is_acute_angle(vt0, vt1, pt)) {
ind1 = 1; ind2 = -1;
return;
}
if (!is_acute_angle(vt1, vt0, pt)) {
ind1 = 0; ind2 = -1;
return;
}
ind1 = 1; ind2 = 0;
return;
}
ind1 = 0; ind2 = -1;
return;
}
if (!is_acute_angle(vt1, vt2, pt)) {
ind1 = 2; ind2 = -1;
return;
}
ind1 = 2; ind2 = 1;
return;
} else {
if (rightturn(vt1, vt0, pt)) {
if (!is_acute_angle(vt1, vt0, pt)) {
ind1 = 0; ind2 = -1;
return;
}
if (!is_acute_angle(vt0, vt1, pt)) {
ind1 = 1; ind2 = -1;
return;
}
ind1 = 1; ind2 = 0;
return;
} else {
ind1 = -1; ind2 = -1; // point inside or on boundary.
return;
}
}
}
}
}
@}
@$@<Point Triangle distance implementation 2@>==@{
template <class R>
extern typename R::FT
squared_distance_indexed(const Point_2<R> &pt,
const Triangle_2<R> &triangle, int ind1, int ind2)
{
typedef typename R::FT FT;
if (ind1 == -1)
return FT(0);
if (ind2 == -1)
return squared_distance(pt, triangle.vertex(ind1));
return squared_distance(pt,
Line_2<R>(triangle.vertex(ind1), triangle.vertex(ind2)));
}
@}
@B@<Point Triangle distance@>
@$@<2D squared distance header declarations 2@>+=@{@-
@<Point Triangle distance implementation 3@>
template <class R>
inline typename R::FT
squared_distance(
const Triangle_2<R> & triangle,
const Point_2<R> & pt)
{
return squared_distance(pt, triangle);
}
@}
@C@<Implementation@>
@$@<Point Triangle distance implementation 3@>==@{
template <class R>
extern typename R::FT
squared_distance(
const Point_2<R> &pt,
const Triangle_2<R> &triangle)
{
int ind1,ind2;
distance_index(ind1, ind2, pt, triangle);
return squared_distance_indexed(pt, triangle, ind1, ind2);
}
@}
@B@<Line Triangle distance@>
@$@<2D squared distance header declarations 2@>+=@{@-
@<Line Triangle distance implementation@>
template <class R>
inline typename R::FT
squared_distance(
const Triangle_2<R> & triangle,
const Line_2<R> & line)
{
return squared_distance(line, triangle);
}
@}
@C@<Implementation@>
@$@<Line Triangle distance implementation@>==@{
template <class R>
extern typename R::FT
squared_distance(
const Line_2<R> &line,
const Triangle_2<R> &triangle)
{
typedef typename R::FT FT;
Oriented_side side0;
side0 = line.oriented_side(triangle.vertex(0));
if (line.oriented_side(triangle.vertex(1)) != side0)
return FT(0);
if (line.oriented_side(triangle.vertex(2)) != side0)
return FT(0);
FT mindist, dist;
int i;
mindist = squared_distance(triangle.vertex(0),line);
for (i=1; i<3; i++) {
dist = squared_distance(triangle.vertex(i),line);
if (dist < mindist)
mindist = dist;
}
return mindist;
}
@}
@B@<Ray Triangle distance@>
@$@<2D squared distance header declarations 2@>+=@{@-
@<Ray Triangle distance implementation@>
template <class R>
inline typename R::FT
squared_distance(
const Triangle_2<R> & triangle,
const Ray_2<R> & ray)
{
return squared_distance(ray, triangle);
}
@}
@C@<Implementation@>
@$@<Ray Triangle distance implementation@>==@{
template <class R>
extern typename R::FT
squared_distance(
const Ray_2<R> &ray,
const Triangle_2<R> &triangle)
{
typedef typename R::FT FT;
int i, ind_tr1, ind_tr2, ind_ray = 0, ind1;
FT mindist, dist;
distance_index(ind_tr1, ind_tr2, ray.source(), triangle);
mindist =
squared_distance_indexed(ray.source(), triangle, ind_tr1,ind_tr2);
for (i=0; i<3; i++) {
const Point_2<R>& pt = triangle.vertex(i);
distance_index(ind1, pt, ray);
dist = squared_distance_indexed(pt, ray, ind1);
if (dist < mindist) {
ind_ray = ind1;
ind_tr1 = i; ind_tr2 = -1;
mindist = dist;
}
}
// now check if all vertices are on the right side of the separating line.
// In case of vertex-vertex smallest distance this is the case.
if (ind_tr2 == -1 && ind_ray != -1)
return mindist;
if (ind_tr2 != -1) {
// Check if all the segment vertices lie at the same side of
// the triangle segment.
const Point_2<R> &vt1 = triangle.vertex(ind_tr1);
const Point_2<R> &vt2 = triangle.vertex(ind_tr2);
if (clockwise(ray.direction().vector(), vt2-vt1)) {
mindist = FT(0);
}
} else {
// Check if all the triangle vertices lie at the same side of the segment.
const Line_2<R> &sl = ray.supporting_line();
Oriented_side or_s = sl.oriented_side(triangle.vertex(0));
for (i=1; i<3; i++) {
if (sl.oriented_side(triangle.vertex(i)) != or_s) {
mindist = FT(0);
break;
}
}
}
return mindist;
}
@}
@B@<Segment Triangle distance@>
@$@<2D squared distance header declarations 2@>+=@{@-
@<Segment Triangle distance implementation@>
template <class R>
inline typename R::FT
squared_distance(
const Triangle_2<R> & triangle,
const Segment_2<R> & seg)
{
return squared_distance(seg, triangle);
}
@}
@C@<Implementation@>
@$@<Segment Triangle distance implementation@>==@{
template <class R>
extern typename R::FT
squared_distance(
const Segment_2<R> &seg,
const Triangle_2<R> &triangle)
{
typedef typename R::FT FT;
int i, ind_tr1 = 0, ind_tr2 = -1, ind_seg = 0, ind1, ind2;
FT mindist, dist;
mindist = squared_distance(seg.source(), triangle.vertex(0));
for (i=0; i<2; i++) {
const Point_2<R> &pt = seg.vertex(i);
distance_index(ind1, ind2, pt, triangle);
dist = squared_distance_indexed(pt, triangle, ind1, ind2);
if (dist < mindist) {
ind_seg = i;
ind_tr1 = ind1; ind_tr2 = ind2;
mindist = dist;
}
}
for (i=0; i<3; i++) {
const Point_2<R>& pt = triangle.vertex(i);
distance_index(ind1, pt, seg);
dist = squared_distance_indexed(pt, seg, ind1);
if (dist < mindist) {
ind_seg = ind1;
ind_tr1 = i; ind_tr2 = -1;
mindist = dist;
}
}
// now check if all vertices are on the right side of the separating line.
// In case of vertex-vertex smallest distance this is the case.
if (ind_tr2 == -1 && ind_seg != -1)
return mindist;
if (ind_tr2 != -1) {
// Check if all the segment vertices lie at the same side of
// the triangle segment.
const Point_2<R> &vt1 = triangle.vertex(ind_tr1);
const Point_2<R> &vt2 = triangle.vertex(ind_tr2);
Orientation or_s = orientation(vt1, vt2, seg.source());
if (orientation(vt1, vt2, seg.target()) != or_s) {
mindist = FT(0);
}
} else {
// Check if all the triangle vertices lie at the same side of the segment.
const Point_2<R> &vt1 = seg.source();
const Point_2<R> &vt2 = seg.target();
Orientation or_s = orientation(vt1, vt2, triangle.vertex(0));
for (i=1; i<3; i++) {
if (orientation(vt1, vt2, triangle.vertex(i)) != or_s) {
mindist = FT(0);
break;
}
}
}
return mindist;
}
@}
@B@<Triangle Triangle distance@>
@$@<2D squared distance header declarations 2@>+=@{@-
@<Triangle Triangle distance implementation@>
@}
@C@<Implementation@>
@$@<Triangle Triangle distance implementation@>==@{
template <class R>
extern typename R::FT
squared_distance(
const Triangle_2<R> &triangle1,
const Triangle_2<R> &triangle2)
{
typedef typename R::FT FT;
int i, ind1_1 = 0,ind1_2 = -1, ind2_1 = 0, ind2_2 = -1, ind1, ind2;
FT mindist, dist;
mindist =
squared_distance(triangle1.vertex(0), triangle2.vertex(0));
for (i=0; i<3; i++) {
const Point_2<R>& pt = triangle1.vertex(i);
distance_index(ind1, ind2, pt, triangle2);
dist = squared_distance_indexed(pt, triangle2, ind1, ind2);
if (dist < mindist) {
ind1_1 = i; ind1_2 = -1;
ind2_1 = ind1; ind2_2 = ind2;
mindist = dist;
}
}
for (i=0; i<3; i++) {
const Point_2<R>& pt = triangle2.vertex(i);
distance_index(ind1, ind2, pt, triangle1);
dist = squared_distance_indexed(pt, triangle1, ind1, ind2);
if (dist < mindist) {
ind1_1 = ind1; ind1_2 = ind2;
ind2_1 = i; ind2_2 = -1;
mindist = dist;
}
}
// now check if all vertices are on the right side of the separating line.
if (ind1_2 == -1 && ind2_2 == -1)
return mindist;
// In case of point-segment closest distance, there is still the possibility
// of overlapping triangles.
// Check if all the vertices lie at the same side of the segment.
if (ind1_2 != -1) {
const Point_2<R> &vt1 = triangle1.vertex(ind1_1);
const Point_2<R> &vt2 = triangle1.vertex(ind1_2);
Orientation or_s = orientation(vt1, vt2, triangle2.vertex(0));
for (i=1; i<3; i++) {
if (orientation(vt1, vt2, triangle2.vertex(i)) != or_s) {
mindist = FT(0);
break;
}
}
} else {
const Point_2<R> &vt1 = triangle2.vertex(ind2_1);
const Point_2<R> &vt2 = triangle2.vertex(ind2_2);
Orientation or_s = orientation(vt1, vt2, triangle1.vertex(0));
for (i=1; i<3; i++) {
if (orientation(vt1, vt2, triangle1.vertex(i)) != or_s) {
mindist = FT(0);
break;
}
}
}
return mindist;
}
@}
@B@<The header files@>
@O@<../include/CGAL/squared_distance_utils.h@>==@{@-
@<cgal_heading@>@(@-
include/CGAL/squared_distance_utils.h@,@-
sqdistance_2.fw@,@-
Geert-Jan Giezeman@,@-
Saarbruecken@)
#ifndef CGAL_SQUARED_DISTANCE_UTILS_H
#define CGAL_SQUARED_DISTANCE_UTILS_H
#include <CGAL/determinant.h>
#include <CGAL/wmult.h>
CGAL_BEGIN_NAMESPACE
@<2D squared distance general utilities@>
CGAL_END_NAMESPACE
#endif // CGAL_SQUARED_DISTANCE_UTILS_H
@}
@O@<../include/CGAL/squared_distance_2_1.h@>==@{@-
@<cgal_heading@>@(@-
include/CGAL/squared_distance_2_1.h@,@-
sqdistance_2.fw@,@-
Geert-Jan Giezeman@,@-
Saarbruecken@)
#ifndef CGAL_SQUARED_DISTANCE_2_1_H
#define CGAL_SQUARED_DISTANCE_2_1_H
#include <CGAL/user_classes.h>
#include <CGAL/utils.h>
#include <CGAL/Point_2.h>
#include <CGAL/Segment_2.h>
#include <CGAL/Line_2.h>
#include <CGAL/Ray_2.h>
#include <CGAL/enum.h>
#include <CGAL/wmult.h>
#include <CGAL/squared_distance_utils.h>
CGAL_BEGIN_NAMESPACE
@<2D squared distance header declarations 1@>
CGAL_END_NAMESPACE
#endif
@}
@O@<../include/CGAL/squared_distance_2_2.h@>==@{@-
@<cgal_heading@>@(@-
include/CGAL/squared_distance_2_2.h@,@-
sqdistance_2.fw@,@-
Geert-Jan Giezeman@,@-
Saarbruecken@)
#ifndef CGAL_SQUARED_DISTANCE_2_2_H
#define CGAL_SQUARED_DISTANCE_2_2_H
#include <CGAL/user_classes.h>
#include <CGAL/utils.h>
#include <CGAL/Point_2.h>
#include <CGAL/Segment_2.h>
#include <CGAL/Line_2.h>
#include <CGAL/Ray_2.h>
#include <CGAL/Triangle_2.h>
#include <CGAL/enum.h>
#include <CGAL/wmult.h>
#include <CGAL/squared_distance_utils.h>
#include <CGAL/squared_distance_2_1.h>
CGAL_BEGIN_NAMESPACE
@<2D squared distance header declarations 2@>
CGAL_END_NAMESPACE
#endif
@}
@O@<../include/CGAL/squared_distance_2.h@>==@{@-
@<cgal_heading@>@(@-
include/CGAL/squared_distance_2.h@,@-
sqdistance_2.fw@,@-
Geert-Jan Giezeman@,@-
Saarbruecken@)
#ifndef CGAL_SQUARED_DISTANCE_2_H
#define CGAL_SQUARED_DISTANCE_2_H
#include <CGAL/squared_distance_2_1.h>
#include <CGAL/squared_distance_2_2.h>
#endif
@}