mirror of https://github.com/CGAL/cgal
3177 lines
96 KiB
PHP
3177 lines
96 KiB
PHP
@! ============================================================================
|
|
@! The CGAL Library
|
|
@! Implementation: 2D Smallest Enclosing Circle
|
|
@! ----------------------------------------------------------------------------
|
|
@! file : web/Min_circle_2.aw
|
|
@! author: Bernd Gärtner, Sven Schönherr <sven@inf.ethz.ch>
|
|
@! ----------------------------------------------------------------------------
|
|
@! $CGAL_Chapter: Geometric Optimisation $
|
|
@! $CGAL_Package: Min_circle_2 WIP $
|
|
@! $Id$
|
|
@! $Date$
|
|
@! ============================================================================
|
|
|
|
@documentclass[twoside]{article}
|
|
@usepackage[latin1]{inputenc}
|
|
@usepackage{a4wide2}
|
|
@usepackage{amssymb}
|
|
@usepackage{path}
|
|
@usepackage{cc_manual,cc_manual_index}
|
|
@article
|
|
|
|
\input{cprog.sty}
|
|
\setlength{\parskip}{1ex}
|
|
|
|
@! LaTeX macros
|
|
\newenvironment{pseudocode}[1]%
|
|
{\vspace*{-0.5\baselineskip} \upshape \begin{tabbing}
|
|
99 \= bla \= bla \= bla \= bla \= bla \= bla \= bla \= bla \kill
|
|
#1 \+ \\}%
|
|
{\end{tabbing}}
|
|
\newcommand{\keyword}[1]{\texttt{#1}}
|
|
\newcommand{\IF}{\keyword{IF} }
|
|
\newcommand{\THEN}{\keyword{THEN} \+ \\}
|
|
\newcommand{\ELSE}{\< \keyword{ELSE} \\}
|
|
\newcommand{\END}{\< \keyword{END} \- \\ }
|
|
\newcommand{\OR}{\keyword{OR} }
|
|
\newcommand{\FOR}{\keyword{FOR} }
|
|
\newcommand{\TO}{\keyword{TO} }
|
|
\newcommand{\DO}{\keyword{DO} \+ \\}
|
|
\newcommand{\RETURN}{\keyword{RETURN} }
|
|
|
|
\newcommand{\mc}{\texttt{mc}}
|
|
|
|
\newcommand{\linebreakByHand}{\ccTexHtml{\linebreak[4]}{}}
|
|
\newcommand{ \newlineByHand}{\ccTexHtml{\\}{}}
|
|
\newcommand{\SaveSpaceByHand}{} %%%%% [2]{\ccTexHtml{#1}{#2}}
|
|
|
|
@! ============================================================================
|
|
@! Title
|
|
@! ============================================================================
|
|
|
|
\RCSdef{\rcsRevision}{$Id$}
|
|
\RCSdefDate{\rcsDate}{$Date$}
|
|
\newcommand{\cgalWIP}{{\footnotesize{} (\rcsRevision{} , \rcsDate) }}
|
|
|
|
@t vskip 5 mm
|
|
@t title titlefont centre "2D Smallest Enclosing Circle*"
|
|
@t vskip 1 mm
|
|
@t title smalltitlefont centre "Bernd Gärtner and Sven Schönherr"
|
|
\smallskip
|
|
\begin{center}
|
|
\begin{tabular}{l}
|
|
\verb+$CGAL_Chapter: Geometric Optimisation $+ \\
|
|
\verb+$CGAL_Package: Min_circle_2 WIP+\cgalWIP\verb+$+ \\
|
|
\end{tabular}
|
|
\end{center}
|
|
@t vskip 1 mm
|
|
|
|
\renewcommand{\thefootnote}{\fnsymbol{footnote}}
|
|
\footnotetext[1]{This work was supported by the ESPRIT IV LTR Project
|
|
No.~21957 (CGAL).}
|
|
|
|
@! ============================================================================
|
|
@! Introduction and Contents
|
|
@! ============================================================================
|
|
|
|
\section*{Introduction}
|
|
|
|
We provide an implementation of an optimisation algorithm for computing
|
|
the smallest (w.r.t.\ area) enclosing circle of a finite point set $P$
|
|
in the plane. The class template \ccc{Min_circle_2} is implemented
|
|
as a semi-dynamic data structure, thus allowing to insert points while
|
|
maintaining the smallest enclosing circle. It is parameterized with a
|
|
traits class, that defines the abstract interface between the
|
|
optimisation algorithm and the primitives it uses. For ease of use, we
|
|
provide traits class adapters that interface the optimisation algorithm
|
|
with user supplied point classes.
|
|
|
|
This document is organized as follows. The algorithm is described in
|
|
Section~1. Section~2 contains the specifications as they appear in the
|
|
CGAL Reference Manual. Section~3 gives the implementations. In
|
|
Section~4 we provide a test program which performs some correctness
|
|
checks. Finally the product files are created in Section~5.
|
|
|
|
\tableofcontents
|
|
|
|
@! ============================================================================
|
|
@! The Algorithm
|
|
@! ============================================================================
|
|
|
|
\clearpage
|
|
\section{The Algorithm} \label{sec:algo}
|
|
|
|
The implementation is based on an algorithm by Welzl~\cite{w-sedbe-91a},
|
|
which we shortly describe now. The smallest (w.r.t.\ area) enclosing
|
|
circle of a finite point set $P$ in the plane, denoted by $mc(P)$, is
|
|
built up incrementally, adding one point after another. Assume $mc(P)$
|
|
has been constructed, and we would like to obtain $mc(P \cup \{p\})$, $p$
|
|
some new point. There are two cases: if $p$ already lies inside $mc(P)$,
|
|
then $mc(P \cup \{p\}) = mc(P)$. Otherwise $p$ must lie on the boundary
|
|
of $mc(P \cup \{p\})$ (this is proved in~\cite{w-sedbe-91a} and not hard
|
|
to see), so we need to compute $mc(P,\{p\})$, the smallest circle
|
|
enclosing $P$ with $p$ on the boundary. This is recursively done in the
|
|
same manner. In general, for point sets $P$,$B$, define $mc(P,B)$ as the
|
|
smallest circle enclosing $P$ that has the points of $B$ on the boundary
|
|
(if defined). Although the algorithm finally delivers a circle
|
|
$mc(P,\emptyset)$, it internally deals with circles that have a possibly
|
|
nonempty set $B$. Here is the pseudo-code of Welzl's method. To compute
|
|
$mc(P)$, it is called with the pair $(P,\emptyset)$, assuming that
|
|
$P=\{p_1,\ldots,p_n\}$ is stored in a linked list.
|
|
|
|
\begin{pseudocode}{$\mc(P,B)$:}
|
|
$mc := \mc(\emptyset,B)$ \\
|
|
\IF $|B| = 3$ \keyword{THEN} \RETURN $mc$ \\
|
|
\FOR $i := 1$ \TO $n$ \DO
|
|
\IF $p_i \not\in mc$ \THEN
|
|
$mc := \mc(\{p_1,\ldots,p_{i-1}\}, B \cup \{p_i\})$ \\
|
|
move $p_i$ to the front of $P$ \\
|
|
\END
|
|
\END
|
|
\RETURN $mc$ \\
|
|
\end{pseudocode}
|
|
|
|
Note the following: (a) $|B|$ is always bounded by 3, thus the
|
|
computation of $mc(\emptyset,B)$ is easy. In our implementation, it is
|
|
done by the private member function \ccc{compute_circle}. (b) One can
|
|
check that the method maintains the invariant `$mc(P,B)$ exists'. This
|
|
justifies termination if $|B| = 3$, because then $mc(P,B)$ must be the
|
|
unique circle with the points of $B$ on the boundary, and $mc(P,B)$
|
|
exists if and only if this circle contains the points of $P$. Thus, no
|
|
subsequent in-circle tests are necessary anymore (for details
|
|
see~\cite{w-sedbe-91a}). (c) points which are found to lie outside the
|
|
current circle $mc$ are considered `important' and are moved to the front
|
|
of the linked list that stores $P$. This is crucial for the method's
|
|
efficiency.
|
|
|
|
It can also be advisable to bring $P$ into random order before
|
|
computation starts. There are `bad' insertion orders which cause the
|
|
method to be very slow -- random shuffling gives these orders a very
|
|
small probability.
|
|
|
|
@! ============================================================================
|
|
@! Specifications
|
|
@! ============================================================================
|
|
|
|
@! \clearpage
|
|
@! \section{Specifications}
|
|
@!
|
|
@! \emph{Note:} Below some references are undefined, they refer to sections
|
|
@! in the \cgal\ Reference Manual.
|
|
@!
|
|
@! \renewcommand{\ccFont}{\tt}
|
|
@! \renewcommand{\ccEndFont}{}
|
|
@! \newcommand{\cgalColumnLayout}{
|
|
@! \ccSetThreeColumns{Oriented_side}{}{\hspace*{10cm}}
|
|
@! \ccPropagateThreeToTwoColumns}
|
|
@! \newcommand{\cgalSetMinCircleLayout}{%
|
|
@! \ccSetThreeColumns{Support_point_iterator}{}{returns
|
|
@! \ccc{ON_BOUNDED_SIDE}, \ccc{ON_BOUNDARY}, or \ccc{ON_UNBOUNDED_SIDE}}
|
|
@! \ccPropagateThreeToTwoColumns}
|
|
@! \input{../../doc_tex/basic/Optimisation/Min_circle_2.tex}
|
|
@! \input{../../doc_tex/basic/Optimisation/Optimisation_circle_2.tex}
|
|
@! \input{../../doc_tex/basic/Optimisation/Min_circle_2_traits_2.tex}
|
|
@! \input{../../doc_tex/basic/Optimisation/Min_circle_2_adapterC2.tex}
|
|
@! \input{../../doc_tex/basic/Optimisation/Min_circle_2_adapterH2.tex}
|
|
|
|
@! ============================================================================
|
|
@! Implementations
|
|
@! ============================================================================
|
|
|
|
\clearpage
|
|
\section{Implementations}
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Class template Min_circle_2<Traits>
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Class template \ccFont Min\_circle\_2<Traits>}
|
|
|
|
First, we declare the class template \ccc{Min_circle_2}.
|
|
|
|
@macro<Min_circle_2 declaration> = @begin
|
|
template < class Traits_ >
|
|
class Min_circle_2;
|
|
@end
|
|
|
|
The actual work of the algorithm is done in the private member
|
|
functions \ccc{mc} and \ccc{compute_circle}. The former directly
|
|
realizes the pseudo-code of $\mc(P,B)$, the latter solves the basic
|
|
case $\mc(\emptyset,B)$, see Section~\ref{sec:algo}.
|
|
|
|
The class interface looks as follows.
|
|
|
|
@macro <Min_circle_2 interface> = @begin
|
|
template < class Traits_ >
|
|
class Min_circle_2 {
|
|
public:
|
|
@<Min_circle_2 public interface>
|
|
|
|
private:
|
|
// private data members
|
|
@<Min_circle_2 private data members>
|
|
|
|
// copying and assignment not allowed!
|
|
Min_circle_2( const Min_circle_2<Traits_>&);
|
|
Min_circle_2<Traits_>&
|
|
operator = ( const Min_circle_2<Traits_>&);
|
|
|
|
@<dividing line>
|
|
|
|
// Class implementation
|
|
// ====================
|
|
|
|
public:
|
|
// Access functions and predicates
|
|
// -------------------------------
|
|
@<Min_circle_2 access functions `number_of_...'>
|
|
|
|
@<Min_circle_2 predicates `is_...'>
|
|
|
|
@<Min_circle_2 access functions>
|
|
|
|
@<Min_circle_2 predicates>
|
|
|
|
private:
|
|
// Private member functions
|
|
// ------------------------
|
|
@<Min_circle_2 private member function `compute_circle'>
|
|
|
|
@<Min_circle_2 private member function `mc'>
|
|
|
|
public:
|
|
// Constructors
|
|
// ------------
|
|
@<Min_circle_2 constructors>
|
|
|
|
// Destructor
|
|
// ----------
|
|
@<Min_circle_2 destructor>
|
|
|
|
// Modifiers
|
|
// ---------
|
|
@<Min_circle_2 modifiers>
|
|
|
|
// Validity check
|
|
// --------------
|
|
@<Min_circle_2 validity check>
|
|
|
|
// Miscellaneous
|
|
// -------------
|
|
@<Min_circle_2 miscellaneous>
|
|
};
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Public Interface}
|
|
|
|
The functionality is described and documented in the specification
|
|
section, so we do not comment on it here.
|
|
|
|
@macro <Min_circle_2 public interface> = @begin
|
|
// types
|
|
typedef Traits_ Traits;
|
|
typedef typename Traits_::Point Point;
|
|
typedef typename Traits_::Circle Circle;
|
|
typedef typename std::list<Point>::const_iterator Point_iterator;
|
|
typedef const Point * Support_point_iterator;
|
|
|
|
/**************************************************************************
|
|
WORKAROUND: Some compilers are unable to match member functions defined
|
|
outside the class template. Therefore, all member functions are implemented
|
|
in the class interface.
|
|
|
|
// creation
|
|
template < class InputIterator >
|
|
Min_circle_2( InputIterator first,
|
|
InputIterator last,
|
|
bool randomize = false,
|
|
Random& random = default_random,
|
|
const Traits& traits = Traits());
|
|
|
|
Min_circle_2( const Traits& traits = Traits());
|
|
Min_circle_2( const Point& p,
|
|
const Traits& traits = Traits());
|
|
Min_circle_2( const Point& p, const Point& q,
|
|
const Traits& traits = Traits());
|
|
Min_circle_2( const Point& p1, const Point& p2, const Point& p3,
|
|
const Traits& traits = Traits());
|
|
~Min_circle_2( );
|
|
|
|
// access functions
|
|
int number_of_points ( ) const;
|
|
int number_of_support_points( ) const;
|
|
|
|
Point_iterator points_begin( ) const;
|
|
Point_iterator points_end ( ) const;
|
|
|
|
Support_point_iterator support_points_begin( ) const;
|
|
Support_point_iterator support_points_end ( ) const;
|
|
|
|
const Point& support_point( int i) const;
|
|
|
|
const Circle& circle( ) const;
|
|
|
|
// predicates
|
|
Bounded_side bounded_side( const Point& p) const;
|
|
bool has_on_bounded_side ( const Point& p) const;
|
|
bool has_on_boundary ( const Point& p) const;
|
|
bool has_on_unbounded_side ( const Point& p) const;
|
|
|
|
bool is_empty ( ) const;
|
|
bool is_degenerate( ) const;
|
|
|
|
// modifiers
|
|
void insert( const Point& p);
|
|
void insert( const Point* first,
|
|
const Point* last );
|
|
void insert( std::list<Point>::const_iterator first,
|
|
std::list<Point>::const_iterator last );
|
|
void insert( std::istream_iterator<Point,std::ptrdiff_t> first,
|
|
std::istream_iterator<Point,std::ptrdiff_t> last );
|
|
void clear( );
|
|
|
|
// validity check
|
|
bool is_valid( bool verbose = false, int level = 0) const;
|
|
|
|
// miscellaneous
|
|
const Traits& traits( ) const;
|
|
**************************************************************************/
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Private Data Members}
|
|
|
|
First, the traits class object is stored.
|
|
|
|
@macro <Min_circle_2 private data members> += @begin
|
|
Traits tco; // traits class object
|
|
@end
|
|
|
|
The points of $P$ are internally stored as a linked list that allows to
|
|
bring points to the front of the list in constant time. We use the
|
|
sequence container \ccc{list} from STL~\cite{sl-stl-95}.
|
|
|
|
@macro <Min_circle_2 private data members> += @begin
|
|
std::list<Point> points; // doubly linked list of points
|
|
@end
|
|
|
|
The support set $S$ of at most three support points is stored in an
|
|
array \ccc{support_points}, the actual number of support points is
|
|
given by \ccc{n_support_points}. During the computations, the set of
|
|
support points coincides with the set $B$ appearing in the pseudo-code
|
|
for $\mc(P,B)$, see Section~\ref{sec:algo}.
|
|
|
|
\emph{Workaround:} The array of support points is allocated dynamically,
|
|
because the SGI compiler (mipspro CC 7.1) does not accept a static
|
|
array here.
|
|
|
|
@macro <Min_circle_2 private data members> += @begin
|
|
int n_support_points; // number of support points
|
|
Point* support_points; // array of support points
|
|
@end
|
|
|
|
Finally, the actual circle is stored in a variable \ccc{circle}
|
|
provided by the traits class object, by the end of computation equal to
|
|
$mc(P)$. During computation, \ccc{tco.circle} equals the circle $mc$
|
|
appearing in the pseudo-code for $\mc(P,B)$, see Section~\ref{sec:algo}.
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Constructors and Destructor}
|
|
|
|
We provide several different constructors, which can be put into two
|
|
groups. The constructors in the first group, i.e. the more important
|
|
ones, build the smallest enclosing circle $mc(P)$ from a point set
|
|
$P$, given by a begin iterator and a past-the-end iterator, realized
|
|
as a member template.
|
|
|
|
All constructors of the first group copy the points into the internal
|
|
list \ccc{points}. If randomization is demanded, the points are copied to
|
|
a vector and shuffled at random, before being copied to \ccc{points}.
|
|
Finally the private member function $mc$ is called to compute
|
|
$mc(P)=mc(P,\emptyset)$.
|
|
|
|
@macro <Min_circle_2 constructors> += @begin
|
|
// STL-like constructor (member template)
|
|
template < class InputIterator >
|
|
Min_circle_2( InputIterator first,
|
|
InputIterator last,
|
|
bool randomize
|
|
#if !defined(__BORLANDC__) && (!defined(_MSC_VER) || _MSC_VER > 1300)
|
|
= false
|
|
#endif
|
|
,
|
|
Random& random = default_random,
|
|
const Traits& traits = Traits())
|
|
: tco( traits)
|
|
{
|
|
// allocate support points' array
|
|
support_points = new Point[ 3];
|
|
|
|
// range of points not empty?
|
|
if ( first != last) {
|
|
|
|
// store points
|
|
if ( randomize) {
|
|
|
|
// shuffle points at random
|
|
std::vector<Point> v( first, last);
|
|
std::random_shuffle( v.begin(), v.end(), random);
|
|
std::copy( v.begin(), v.end(),
|
|
std::back_inserter( points)); }
|
|
else
|
|
std::copy( first, last, std::back_inserter( points)); }
|
|
|
|
// compute mc
|
|
mc( points.end(), 0);
|
|
}
|
|
@end
|
|
|
|
The remaining constructors are actually specializations of the
|
|
previous ones, building the smallest enclosing circle for up to three
|
|
points. The idea is the following: recall that for any point set $P$
|
|
there exists $S \subseteq P$, $|S| \leq 3$ with $mc(S) = mc(P)$ (in
|
|
fact, such a set $S$ is determined by the algorithm). Once $S$ has
|
|
been computed (or given otherwise), $mc(P)$ can easily be
|
|
reconstructed from $S$ in constant time. To make this reconstruction
|
|
more convenient, a constructor is available for each size of $|S|$,
|
|
ranging from 0 to 3. For $|S|=0$, we get the default constructor,
|
|
building $mc(\emptyset)$.
|
|
|
|
@macro <Min_circle_2 constructors> += @begin
|
|
|
|
// default constructor
|
|
inline
|
|
Min_circle_2( const Traits& traits = Traits())
|
|
: tco( traits), n_support_points( 0)
|
|
{
|
|
// allocate support points' array
|
|
support_points = new Point[ 3];
|
|
|
|
// initialize circle
|
|
tco.circle.set();
|
|
|
|
CGAL_optimisation_postcondition( is_empty());
|
|
}
|
|
|
|
// constructor for one point
|
|
inline
|
|
Min_circle_2( const Point& p, const Traits& traits = Traits())
|
|
: tco( traits), points( 1, p), n_support_points( 1)
|
|
{
|
|
// allocate support points' array
|
|
support_points = new Point[ 3];
|
|
|
|
// initialize circle
|
|
support_points[ 0] = p;
|
|
tco.circle.set( p);
|
|
|
|
CGAL_optimisation_postcondition( is_degenerate());
|
|
}
|
|
|
|
// constructor for two points
|
|
inline
|
|
Min_circle_2( const Point& p1, const Point& p2,
|
|
const Traits& traits = Traits())
|
|
: tco( traits)
|
|
{
|
|
// allocate support points' array
|
|
support_points = new Point[ 3];
|
|
|
|
// store points
|
|
points.push_back( p1);
|
|
points.push_back( p2);
|
|
|
|
// compute mc
|
|
mc( points.end(), 0);
|
|
}
|
|
|
|
// constructor for three points
|
|
inline
|
|
Min_circle_2( const Point& p1, const Point& p2, const Point& p3,
|
|
const Traits& traits = Traits())
|
|
: tco( traits)
|
|
{
|
|
// allocate support points' array
|
|
support_points = new Point[ 3];
|
|
|
|
// store points
|
|
points.push_back( p1);
|
|
points.push_back( p2);
|
|
points.push_back( p3);
|
|
|
|
// compute mc
|
|
mc( points.end(), 0);
|
|
}
|
|
@end
|
|
|
|
The destructor only frees the memory of the support points' array.
|
|
|
|
@macro <Min_circle_2 destructor> = @begin
|
|
inline
|
|
~Min_circle_2( )
|
|
{
|
|
// free support points' array
|
|
delete[] support_points;
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Access Functions}
|
|
|
|
These functions are used to retrieve information about the current
|
|
status of the \ccc{Min_circle_2<Traits>} object. They are all very
|
|
simple (and therefore \ccc{inline}) and mostly rely on corresponding
|
|
access functions of the data members of \ccc{Min_circle_2<Traits>}.
|
|
|
|
First, we define the \ccc{number_of_...} methods.
|
|
|
|
@macro <Min_circle_2 access functions `number_of_...'> = @begin
|
|
// #points and #support points
|
|
inline
|
|
int
|
|
number_of_points( ) const
|
|
{
|
|
return( points.size());
|
|
}
|
|
|
|
inline
|
|
int
|
|
number_of_support_points( ) const
|
|
{
|
|
return( n_support_points);
|
|
}
|
|
@end
|
|
|
|
Then, we have the access functions for points and support points.
|
|
|
|
@macro <Min_circle_2 access functions> += @begin
|
|
// access to points and support points
|
|
inline
|
|
Point_iterator
|
|
points_begin( ) const
|
|
{
|
|
return( points.begin());
|
|
}
|
|
|
|
inline
|
|
Point_iterator
|
|
points_end( ) const
|
|
{
|
|
return( points.end());
|
|
}
|
|
|
|
inline
|
|
Support_point_iterator
|
|
support_points_begin( ) const
|
|
{
|
|
return( support_points);
|
|
}
|
|
|
|
inline
|
|
Support_point_iterator
|
|
support_points_end( ) const
|
|
{
|
|
return( support_points+n_support_points);
|
|
}
|
|
|
|
// random access for support points
|
|
inline
|
|
const Point&
|
|
support_point( int i) const
|
|
{
|
|
CGAL_optimisation_precondition( (i >= 0) &&
|
|
(i < number_of_support_points()));
|
|
return( support_points[ i]);
|
|
}
|
|
@end
|
|
|
|
Finally, the access function \ccc{circle}.
|
|
|
|
@macro <Min_circle_2 access functions> += @begin
|
|
// circle
|
|
inline
|
|
const Circle&
|
|
circle( ) const
|
|
{
|
|
return( tco.circle);
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Predicates}
|
|
|
|
The predicates \ccc{is_empty} and \ccc{is_degenerate} are used in
|
|
preconditions and postconditions of some member functions. Therefore we
|
|
define them \ccc{inline} and put them in a separate macro.
|
|
|
|
@macro <Min_circle_2 predicates `is_...'> = @begin
|
|
// is_... predicates
|
|
inline
|
|
bool
|
|
is_empty( ) const
|
|
{
|
|
return( number_of_support_points() == 0);
|
|
}
|
|
|
|
inline
|
|
bool
|
|
is_degenerate( ) const
|
|
{
|
|
return( number_of_support_points() < 2);
|
|
}
|
|
@end
|
|
|
|
The remaining predicates perform in-circle tests, based on the
|
|
corresponding predicates of class \ccc{Circle}.
|
|
|
|
@macro <Min_circle_2 predicates> = @begin
|
|
// in-circle test predicates
|
|
inline
|
|
CGAL::Bounded_side
|
|
bounded_side( const Point& p) const
|
|
{
|
|
return( tco.circle.bounded_side( p));
|
|
}
|
|
|
|
inline
|
|
bool
|
|
has_on_bounded_side( const Point& p) const
|
|
{
|
|
return( tco.circle.has_on_bounded_side( p));
|
|
}
|
|
|
|
inline
|
|
bool
|
|
has_on_boundary( const Point& p) const
|
|
{
|
|
return( tco.circle.has_on_boundary( p));
|
|
}
|
|
|
|
inline
|
|
bool
|
|
has_on_unbounded_side( const Point& p) const
|
|
{
|
|
return( tco.circle.has_on_unbounded_side( p));
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Modifiers}
|
|
|
|
There is another way to build up $mc(P)$, other than by supplying
|
|
the point set $P$ at once. Namely, $mc(P)$ can be built up
|
|
incrementally, adding one point after another. If you look at the
|
|
pseudo-code in the introduction, this comes quite naturally. The
|
|
modifying method \ccc{insert}, applied with point $p$ to a
|
|
\ccc{Min_circle_2<Traits>} object representing $mc(P)$,
|
|
computes $mc(P \cup \{p\})$, where work has to be done only if $p$
|
|
lies outside $mc(P)$. In this case, $mc(P \cup \{p\}) = mc(P,\{p\})$
|
|
holds, so the private member function \ccc{mc} is called with
|
|
support set $\{p\}$. After the insertion has been performed, $p$ is
|
|
moved to the front of the point list, just like in the pseudo-code in
|
|
Section~\ref{sec:algo}.
|
|
|
|
@macro <Min_circle_2 modifiers> += @begin
|
|
void
|
|
insert( const Point& p)
|
|
{
|
|
// p not in current circle?
|
|
if ( has_on_unbounded_side( p)) {
|
|
|
|
// p new support point
|
|
support_points[ 0] = p;
|
|
|
|
// recompute mc
|
|
mc( points.end(), 1);
|
|
|
|
// store p as the first point in list
|
|
points.push_front( p); }
|
|
else
|
|
|
|
// append p to the end of the list
|
|
points.push_back( p);
|
|
}
|
|
@end
|
|
|
|
Inserting a range of points is done by a single member template. In case
|
|
a compiler does not support this yet, we provide specialized \ccc{insert}
|
|
functions for C~arrays (using pointers as iterators), for STL sequence
|
|
containers \ccc{vector<Point>} and \ccc{list<Point>} and for the STL
|
|
input stream iterator \ccc{istream_iterator<Point>}. Actually, the
|
|
\ccc{insert} function for a C~array and a \ccc{vector<point>} are the
|
|
same, since the random access iterator of \ccc{vector<Point>} is
|
|
implemented as \ccc{Point*}.
|
|
|
|
The following \ccc{insert} functions perform a call \ccc{insert(p)} for
|
|
each point \ccc{p} in the range $[\mbox{\ccc{first}},\mbox{\ccc{last}})$.
|
|
|
|
@macro <Min_circle_2 modifiers> += @begin
|
|
template < class InputIterator >
|
|
void
|
|
insert( InputIterator first, InputIterator last)
|
|
{
|
|
for ( ; first != last; ++first)
|
|
insert( *first);
|
|
}
|
|
@end
|
|
|
|
The member function \ccc{clear} deletes all points from a
|
|
\ccc{Min_circle_2<Traits>} object and resets it to the
|
|
empty circle.
|
|
|
|
@macro <Min_circle_2 modifiers> += @begin
|
|
void
|
|
clear( )
|
|
{
|
|
points.erase( points.begin(), points.end());
|
|
n_support_points = 0;
|
|
tco.circle.set();
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Validity Check}
|
|
|
|
A \ccc{Min_circle_2<Traits>} object can be checked for validity. This
|
|
means, it is checked whether (a) the circle contains all points of its
|
|
defining set $P$, (b) the circle is the smallest circle spanned by its
|
|
support set, and (c) the support set is minimal, i.e.\ no support point is
|
|
redundant. If \ccc{verbose} is \ccc{true}, some messages concerning the
|
|
performed checks are written to standard error stream. The second parameter
|
|
\ccc{level} is not used, we provide it only for consistency with interfaces
|
|
of other classes.
|
|
|
|
@macro <Min_circle_2 validity check> = @begin
|
|
bool
|
|
is_valid( bool verbose = false, int level = 0) const
|
|
{
|
|
using namespace std;
|
|
|
|
CGAL::Verbose_ostream verr( verbose);
|
|
verr << endl;
|
|
verr << "CGAL::Min_circle_2<Traits>::" << endl;
|
|
verr << "is_valid( true, " << level << "):" << endl;
|
|
verr << " |P| = " << number_of_points()
|
|
<< ", |S| = " << number_of_support_points() << endl;
|
|
|
|
// containment check (a)
|
|
@<Min_circle_2 containment check>
|
|
|
|
// support set checks (b)+(c)
|
|
@<Min_circle_2 support set checks>
|
|
|
|
verr << " object is valid!" << endl;
|
|
return( true);
|
|
}
|
|
@end
|
|
|
|
The containment check (a) is easy to perform, just a loop over all
|
|
points in \ccc{points}.
|
|
|
|
@macro <Min_circle_2 containment check> = @begin
|
|
verr << " a) containment check..." << flush;
|
|
Point_iterator point_iter;
|
|
for ( point_iter = points_begin();
|
|
point_iter != points_end();
|
|
++point_iter)
|
|
if ( has_on_unbounded_side( *point_iter))
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"circle does not contain all points"));
|
|
verr << "passed." << endl;
|
|
@end
|
|
|
|
To check the support set (b) and (c), we distinguish four cases with
|
|
respect to the number of support points, which may range from 0 to 3.
|
|
|
|
@macro <Min_circle_2 support set checks> = @begin
|
|
verr << " b)+c) support set checks..." << flush;
|
|
switch( number_of_support_points()) {
|
|
|
|
case 0:
|
|
@<Min_circle_2 check no support point>
|
|
break;
|
|
|
|
case 1:
|
|
@<Min_circle_2 check one support point>
|
|
break;
|
|
|
|
case 2: {
|
|
@<Min_circle_2 check two support points> }
|
|
break;
|
|
|
|
case 3: {
|
|
@<Min_circle_2 check three support points> }
|
|
break;
|
|
|
|
default:
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"illegal number of support points, \
|
|
not between 0 and 3."));
|
|
};
|
|
verr << "passed." << endl;
|
|
@end
|
|
|
|
The case of no support point happens if and only if the defining
|
|
point set $P$ is empty.
|
|
|
|
@macro <Min_circle_2 check no support point> = @begin
|
|
if ( ! is_empty())
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"P is nonempty, \
|
|
but there are no support points."));
|
|
@end
|
|
|
|
If the smallest enclosing circle has one support point $p$, it must
|
|
be equal to that point, i.e.\ its center must be $p$ and its radius
|
|
$0$.
|
|
|
|
@macro <Min_circle_2 check one support point> = @begin
|
|
if ( ( circle().center() != support_point( 0) ) ||
|
|
( ! CGAL_NTS is_zero( circle().squared_radius())) )
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"circle differs from the circle \
|
|
spanned by its single support point."));
|
|
@end
|
|
|
|
In case of two support points $p,q$, these points must form a diameter
|
|
of the circle. The support set $\{p,q\}$ is minimal if and only if
|
|
$p,q$ are distinct.
|
|
|
|
The diameter property is checked as follows. If $p$ and $q$ both lie
|
|
on the circle's boundary and if $p$, $q$ (knowing they are distinct)
|
|
and the circle's center are collinear, then $p$ and $q$ form a
|
|
diameter of the circle.
|
|
|
|
@macro <Min_circle_2 check two support points> = @begin
|
|
const Point& p = support_point( 0),
|
|
q = support_point( 1);
|
|
|
|
// p equals q?
|
|
if ( p == q)
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"the two support points are equal."));
|
|
|
|
// segment(p,q) is not diameter?
|
|
if ( ( ! has_on_boundary( p) ) ||
|
|
( ! has_on_boundary( q) ) ||
|
|
( tco.orientation( p, q,
|
|
circle().center()) != CGAL::COLLINEAR) )
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"circle does not have its \
|
|
two support points as diameter."));
|
|
@end
|
|
|
|
If the number of support points is three (and they are distinct and
|
|
not collinear), the circle through them is unique, and must therefore
|
|
equal the current circle stored in \ccc{circle}. It is the smallest
|
|
one containing the three points if and only if the center of the
|
|
circle lies inside or on the boundary of the triangle defined by the
|
|
three points. The support set is minimal only if the center lies
|
|
properly inside the triangle.
|
|
|
|
Both triangle properties are checked by comparing the orientations of
|
|
three point triples, each containing two of the support points and the
|
|
center of the current circle, resp. If one of these orientations equals
|
|
\ccc{CGAL::COLLINEAR}, the center lies on the boundary of the triangle.
|
|
Otherwise, if two triples have opposite orientations, the center is not
|
|
contained in the triangle.
|
|
|
|
@macro <Min_circle_2 check three support points> = @begin
|
|
const Point& p = support_point( 0),
|
|
q = support_point( 1),
|
|
r = support_point( 2);
|
|
|
|
// p, q, r not pairwise distinct?
|
|
if ( ( p == q) || ( q == r) || ( r == p))
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"at least two of the three \
|
|
support points are equal."));
|
|
|
|
// p, q, r collinear?
|
|
if ( tco.orientation( p, q, r) == CGAL::COLLINEAR)
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"the three support points are collinear."));
|
|
|
|
// current circle not equal the unique circle through p,q,r ?
|
|
Circle c = circle();
|
|
c.set( p, q, r);
|
|
if ( circle() != c)
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"circle is not the unique circle \
|
|
through its three support points."));
|
|
|
|
// circle's center on boundary of triangle(p,q,r)?
|
|
const Point& center = circle().center();
|
|
CGAL::Orientation o_pqz = tco.orientation( p, q, center);
|
|
CGAL::Orientation o_qrz = tco.orientation( q, r, center);
|
|
CGAL::Orientation o_rpz = tco.orientation( r, p, center);
|
|
if ( ( o_pqz == CGAL::COLLINEAR) ||
|
|
( o_qrz == CGAL::COLLINEAR) ||
|
|
( o_rpz == CGAL::COLLINEAR) )
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"one of the three support points is redundant."));
|
|
|
|
// circle's center not inside triangle(p,q,r)?
|
|
if ( ( o_pqz != o_qrz) || ( o_qrz != o_rpz) || ( o_rpz != o_pqz))
|
|
return( CGAL::_optimisation_is_valid_fail( verr,
|
|
"circle's center is not in the \
|
|
convex hull of its three support points."));
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Miscellaneous}
|
|
|
|
The member function \ccc{traits} returns a const reference to the
|
|
traits class object.
|
|
|
|
@macro <Min_circle_2 miscellaneous> = @begin
|
|
inline
|
|
const Traits&
|
|
traits( ) const
|
|
{
|
|
return( tco);
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{I/O}
|
|
|
|
@macro <Min_circle_2 I/O operators declaration> = @begin
|
|
template < class Traits_ >
|
|
std::ostream&
|
|
operator << ( std::ostream& os, const Min_circle_2<Traits_>& mc);
|
|
|
|
template < class Traits_ >
|
|
std::istream&
|
|
operator >> ( std::istream& is, Min_circle_2<Traits_>& mc);
|
|
@end
|
|
|
|
@macro <Min_circle_2 I/O operators> = @begin
|
|
template < class Traits_ >
|
|
std::ostream&
|
|
operator << ( std::ostream& os,
|
|
const Min_circle_2<Traits_>& min_circle)
|
|
{
|
|
using namespace std;
|
|
|
|
typedef Min_circle_2<Traits_>::Point Point;
|
|
typedef ostream_iterator<Point> Os_it;
|
|
|
|
switch ( CGAL::get_mode( os)) {
|
|
|
|
case CGAL::IO::PRETTY:
|
|
os << endl;
|
|
os << "CGAL::Min_circle_2( |P| = " << min_circle.number_of_points()
|
|
<< ", |S| = " << min_circle.number_of_support_points() << endl;
|
|
os << " P = {" << endl;
|
|
os << " ";
|
|
copy( min_circle.points_begin(), min_circle.points_end(),
|
|
Os_it( os, ",\n "));
|
|
os << "}" << endl;
|
|
os << " S = {" << endl;
|
|
os << " ";
|
|
copy( min_circle.support_points_begin(),
|
|
min_circle.support_points_end(),
|
|
Os_it( os, ",\n "));
|
|
os << "}" << endl;
|
|
os << " circle = " << min_circle.circle() << endl;
|
|
os << ")" << endl;
|
|
break;
|
|
|
|
case CGAL::IO::ASCII:
|
|
copy( min_circle.points_begin(), min_circle.points_end(),
|
|
Os_it( os, "\n"));
|
|
break;
|
|
|
|
case CGAL::IO::BINARY:
|
|
copy( min_circle.points_begin(), min_circle.points_end(),
|
|
Os_it( os));
|
|
break;
|
|
|
|
default:
|
|
CGAL_optimisation_assertion_msg( false,
|
|
"CGAL::get_mode( os) invalid!");
|
|
break; }
|
|
|
|
return( os);
|
|
}
|
|
|
|
template < class Traits_ >
|
|
std::istream&
|
|
operator >> ( std::istream& is, CGAL::Min_circle_2<Traits_>& min_circle)
|
|
{
|
|
using namespace std;
|
|
|
|
switch ( CGAL::get_mode( is)) {
|
|
|
|
case CGAL::IO::PRETTY:
|
|
cerr << endl;
|
|
cerr << "Stream must be in ascii or binary mode" << endl;
|
|
break;
|
|
|
|
case CGAL::IO::ASCII:
|
|
case CGAL::IO::BINARY:
|
|
typedef CGAL::Min_circle_2<Traits_>::Point Point;
|
|
typedef istream_iterator<Point> Is_it;
|
|
min_circle.clear();
|
|
min_circle.insert( Is_it( is), Is_it());
|
|
break;
|
|
|
|
default:
|
|
CGAL_optimisation_assertion_msg( false, "CGAL::IO::mode invalid!");
|
|
break; }
|
|
|
|
return( is);
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Graphical Output}
|
|
|
|
@macro<Min_circle_2 graphical output operator> = @begin
|
|
#ifdef CGAL_MIN_CIRCLE_2_H
|
|
#ifndef CGAL_IO_WINDOW_STREAM_MIN_CIRCLE_2
|
|
#define CGAL_IO_WINDOW_STREAM_MIN_CIRCLE_2
|
|
|
|
template< class Traits_ >
|
|
CGAL::Window_stream&
|
|
operator << ( CGAL::Window_stream &ws,
|
|
const CGAL::Min_circle_2<Traits_>& min_circle)
|
|
{
|
|
typedef CGAL::Min_circle_2<Traits_>::Point_iterator Point_iterator;
|
|
|
|
Point_iterator first( min_circle.points_begin());
|
|
Point_iterator last ( min_circle.points_end());
|
|
for ( ; first != last; ++first)
|
|
ws << *first;
|
|
return( ws << min_circle.circle());
|
|
}
|
|
|
|
#endif // CGAL_IO_WINDOW_STREAM_MIN_CIRCLE_2
|
|
#endif // CGAL_MIN_CIRCLE_2_H
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Private Member Function {\ccFont compute\_circle}}
|
|
|
|
This is the method for computing the basic case $\mc(\emptyset,B)$,
|
|
the set $B$ given by the first \ccc{n_support_points} in the array
|
|
\ccc{support_points}. It is realized by a simple case analysis,
|
|
noting that $|B| \leq 3$.
|
|
|
|
@macro <Min_circle_2 private member function `compute_circle'> = @begin
|
|
// compute_circle
|
|
inline
|
|
void
|
|
compute_circle( )
|
|
{
|
|
switch ( n_support_points) {
|
|
case 3:
|
|
tco.circle.set( support_points[ 0],
|
|
support_points[ 1],
|
|
support_points[ 2]);
|
|
break;
|
|
case 2:
|
|
tco.circle.set( support_points[ 0], support_points[ 1]);
|
|
break;
|
|
case 1:
|
|
tco.circle.set( support_points[ 0]);
|
|
break;
|
|
case 0:
|
|
tco.circle.set( );
|
|
break;
|
|
default:
|
|
CGAL_optimisation_assertion( ( n_support_points >= 0) &&
|
|
( n_support_points <= 3) ); }
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Private Member Function {\ccFont mc}}
|
|
|
|
This function computes the general circle $mc(P,B)$, where $P$ contains
|
|
the points in the range $[$\ccc{points.begin()}$,$\ccc{last}$)$ and $B$
|
|
is given by the first \ccc{n_sp} support points in the array
|
|
\ccc{support_points}. The function is directly modeled after the
|
|
pseudo-code above.
|
|
|
|
@macro <Min_circle_2 private member function `mc'> = @begin
|
|
void
|
|
mc( const Point_iterator& last, int n_sp)
|
|
{
|
|
// compute circle through support points
|
|
n_support_points = n_sp;
|
|
compute_circle();
|
|
if ( n_sp == 3) return;
|
|
|
|
// test first n points
|
|
typename std::list<Point>::iterator point_iter = points.begin();
|
|
for ( ; last != point_iter; ) {
|
|
const Point& p = *point_iter;
|
|
|
|
// p not in current circle?
|
|
if ( has_on_unbounded_side( p)) {
|
|
|
|
// recursive call with p as additional support point
|
|
support_points[ n_sp] = p;
|
|
mc( point_iter, n_sp+1);
|
|
|
|
// move current point to front
|
|
points.splice( points.begin(), points, point_iter++); }
|
|
|
|
else
|
|
++point_iter; }
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Class template Optimisation_circle_2<K>
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Class template \ccFont Optimisation\_circle\_2<K>}
|
|
|
|
First, we declare the class template \ccc{Optimisation_circle_2},
|
|
|
|
@macro<Optimisation_circle_2 declaration> = @begin
|
|
template < class K_ >
|
|
class Optimisation_circle_2;
|
|
@end
|
|
|
|
The class interface looks as follows.
|
|
|
|
@macro <Optimisation_circle_2 interface> = @begin
|
|
template < class K_ >
|
|
class Optimisation_circle_2 {
|
|
public:
|
|
@<Optimisation_circle_2 public interface>
|
|
|
|
private:
|
|
// private data members
|
|
@<Optimisation_circle_2 private data members>
|
|
|
|
@<dividing line>
|
|
|
|
// Class implementation
|
|
// ====================
|
|
|
|
public:
|
|
// Constructor
|
|
// -----------
|
|
@<Optimisation_circle_2 constructor>
|
|
|
|
// Set functions
|
|
// -------------
|
|
@<Optimisation_circle_2 set functions>
|
|
|
|
// Access functions
|
|
// ----------------
|
|
@<Optimisation_circle_2 access functions>
|
|
|
|
// Equality tests
|
|
// --------------
|
|
@<Optimisation_circle_2 equality tests>
|
|
|
|
// Predicates
|
|
// ----------
|
|
@<Optimisation_circle_2 predicates>
|
|
};
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Public Interface}
|
|
|
|
The functionality is described and documented in the specification
|
|
section, so we do not comment on it here.
|
|
|
|
@macro <Optimisation_circle_2 public interface> = @begin
|
|
// types
|
|
typedef K_ K;
|
|
typedef CGAL::Point_2<K> Point;
|
|
typedef typename K_::FT Distance;
|
|
|
|
/**************************************************************************
|
|
WORKAROUND: Some compilers are unable to match member functions defined
|
|
outside the class template. Therefore, all member functions are implemented
|
|
in the class interface.
|
|
|
|
// creation
|
|
Optimisation_circle_2( );
|
|
|
|
void set( );
|
|
void set( const Point& p);
|
|
void set( const Point& p, const Point& q);
|
|
void set( const Point& p, const Point& q, const Point& r);
|
|
void set( const Point& center, const Distance& squared_radius);
|
|
|
|
// access functions
|
|
const Point& center ( ) const;
|
|
const Distance& squared_radius( ) const
|
|
|
|
// equality tests
|
|
bool operator == ( const Optimisation_circle_2<K>& c) const;
|
|
bool operator != ( const Optimisation_circle_2<K>& c) const;
|
|
|
|
// predicates
|
|
CGAL::Bounded_side bounded_side( const Point& p) const;
|
|
bool has_on_bounded_side ( const Point& p) const;
|
|
bool has_on_boundary ( const Point& p) const;
|
|
bool has_on_unbounded_side ( const Point& p) const;
|
|
|
|
bool is_empty ( ) const;
|
|
bool is_degenerate( ) const;
|
|
**************************************************************************/
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Private Data Members}
|
|
|
|
The circle is represented by its center and squared radius.
|
|
|
|
@macro <Optimisation_circle_2 private data members> = @begin
|
|
Point _center;
|
|
Distance _squared_radius;
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Constructor}
|
|
|
|
Only a default constructor is needed.
|
|
|
|
@macro <Optimisation_circle_2 constructor> = @begin
|
|
inline
|
|
Optimisation_circle_2( )
|
|
{ }
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Set Functions}
|
|
|
|
We provide set functions taking zero, one, two, or three boundary
|
|
points and another set function taking a center point and a squared
|
|
radius.
|
|
|
|
@macro <Optimisation_circle_2 set functions> = @begin
|
|
inline
|
|
void
|
|
set( )
|
|
{
|
|
_center = Point( CGAL::ORIGIN);
|
|
_squared_radius = -Distance( 1);
|
|
}
|
|
|
|
inline
|
|
void
|
|
set( const Point& p)
|
|
{
|
|
_center = p;
|
|
_squared_radius = Distance( 0);
|
|
}
|
|
|
|
inline
|
|
void
|
|
set( const Point& p, const Point& q)
|
|
{
|
|
_center = CGAL::midpoint( p, q);
|
|
_squared_radius = CGAL::squared_distance( p, _center);
|
|
}
|
|
|
|
inline
|
|
void
|
|
set( const Point& p, const Point& q, const Point& r)
|
|
{
|
|
_center = CGAL::circumcenter( p, q, r);
|
|
_squared_radius = CGAL::squared_distance( p, _center);
|
|
}
|
|
|
|
inline
|
|
void
|
|
set( const Point& center, const Distance& squared_radius)
|
|
{
|
|
_center = center;
|
|
_squared_radius = squared_radius;
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Access Functions}
|
|
|
|
These functions are used to get the current center point or
|
|
squared radius, resp.
|
|
|
|
@macro <Optimisation_circle_2 access functions> = @begin
|
|
inline
|
|
const Point&
|
|
center( ) const
|
|
{
|
|
return( _center);
|
|
}
|
|
|
|
inline
|
|
const Distance&
|
|
squared_radius( ) const
|
|
{
|
|
return( _squared_radius);
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Equality Tests}
|
|
|
|
@macro <Optimisation_circle_2 equality tests> = @begin
|
|
bool
|
|
operator == ( const Optimisation_circle_2<K>& c) const
|
|
{
|
|
return( ( _center == c._center ) &&
|
|
( _squared_radius == c._squared_radius) );
|
|
}
|
|
|
|
bool
|
|
operator != ( const Optimisation_circle_2<K>& c) const
|
|
{
|
|
return( ! operator==( c));
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Predicates}
|
|
|
|
The following predicates perform in-circle tests and check for
|
|
emptiness and degeneracy, resp.
|
|
|
|
@macro <Optimisation_circle_2 predicates> = @begin
|
|
inline
|
|
CGAL::Bounded_side
|
|
bounded_side( const Point& p) const
|
|
{
|
|
return( CGAL::Bounded_side( CGAL_NTS sign(
|
|
_squared_radius - CGAL::squared_distance( p, _center))));
|
|
}
|
|
|
|
inline
|
|
bool
|
|
has_on_bounded_side( const Point& p) const
|
|
{
|
|
return( CGAL::squared_distance( p, _center) < _squared_radius);
|
|
}
|
|
|
|
inline
|
|
bool
|
|
has_on_boundary( const Point& p) const
|
|
{
|
|
return( CGAL::squared_distance( p, _center) == _squared_radius);
|
|
}
|
|
|
|
inline
|
|
bool
|
|
has_on_unbounded_side( const Point& p) const
|
|
{
|
|
return( _squared_radius < CGAL::squared_distance( p, _center));
|
|
}
|
|
|
|
inline
|
|
bool
|
|
is_empty( ) const
|
|
{
|
|
return( CGAL::is_negative( _squared_radius));
|
|
}
|
|
|
|
inline
|
|
bool
|
|
is_degenerate( ) const
|
|
{
|
|
return( ! CGAL::is_positive( _squared_radius));
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{I/O}
|
|
|
|
@macro <Optimisation_circle_2 I/O operators declaration> = @begin
|
|
template < class K_ >
|
|
std::ostream&
|
|
operator << ( std::ostream&, const CGAL::Optimisation_circle_2<K_>&);
|
|
|
|
template < class K_ >
|
|
std::istream&
|
|
operator >> ( std::istream&, CGAL::Optimisation_circle_2<K_>&);
|
|
@end
|
|
|
|
@macro <Optimisation_circle_2 I/O operators> = @begin
|
|
template < class K_ >
|
|
std::ostream&
|
|
operator << ( std::ostream& os, const CGAL::Optimisation_circle_2<K_>& c)
|
|
{
|
|
switch ( CGAL::get_mode( os)) {
|
|
|
|
case CGAL::IO::PRETTY:
|
|
os << "CGAL::Optimisation_circle_2( "
|
|
<< c.center() << ", "
|
|
<< c.squared_radius() << ')';
|
|
break;
|
|
|
|
case CGAL::IO::ASCII:
|
|
os << c.center() << ' ' << c.squared_radius();
|
|
break;
|
|
|
|
case CGAL::IO::BINARY:
|
|
os << c.center();
|
|
CGAL::write( os, c.squared_radius());
|
|
break;
|
|
|
|
default:
|
|
CGAL_optimisation_assertion_msg( false,
|
|
"CGAL::get_mode( os) invalid!");
|
|
break; }
|
|
|
|
return( os);
|
|
}
|
|
|
|
template < class K_ >
|
|
std::istream&
|
|
operator >> ( std::istream& is, CGAL::Optimisation_circle_2<K_>& c)
|
|
{
|
|
typedef CGAL::Optimisation_circle_2<K_>::Point Point;
|
|
typedef CGAL::Optimisation_circle_2<K_>::Distance Distance;
|
|
|
|
switch ( CGAL::get_mode( is)) {
|
|
|
|
case CGAL::IO::PRETTY:
|
|
cerr << std::endl;
|
|
cerr << "Stream must be in ascii or binary mode" << std::endl;
|
|
break;
|
|
|
|
case CGAL::IO::ASCII: {
|
|
Point center;
|
|
Distance squared_radius;
|
|
is >> center >> squared_radius;
|
|
c.set( center, squared_radius); }
|
|
break;
|
|
|
|
case CGAL::IO::BINARY: {
|
|
Point center;
|
|
Distance squared_radius;
|
|
is >> center;
|
|
CGAL::read( is, squared_radius);
|
|
c.set( center, squared_radius); }
|
|
break;
|
|
|
|
default:
|
|
CGAL_optimisation_assertion_msg( false,
|
|
"CGAL::get_mode( is) invalid!");
|
|
break; }
|
|
|
|
return( is);
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Graphical Output}
|
|
|
|
@macro<Optimisation_circle_2 graphical output operator> = @begin
|
|
#ifdef CGAL_OPTIMISATION_CIRCLE_2_H
|
|
#ifndef CGAL_IO_WINDOW_STREAM_OPTIMISATION_CIRCLE_2
|
|
#define CGAL_IO_WINDOW_STREAM_OPTIMISATION_CIRCLE_2
|
|
|
|
template< class K_ >
|
|
CGAL::Window_stream&
|
|
operator << ( CGAL::Window_stream &ws,
|
|
const CGAL::Optimisation_circle_2<K_>& oc)
|
|
{
|
|
double cx( CGAL::to_double( oc.center().x()));
|
|
double cy( CGAL::to_double( oc.center().y()));
|
|
double sr( CGAL::to_double( oc.squared_radius()));
|
|
|
|
if ( ! CGAL_NTS is_negative( sr))
|
|
ws.draw_circle( cx, cy, CGAL::sqrt( sr));
|
|
return( ws);
|
|
}
|
|
|
|
#endif // CGAL_IO_WINDOW_STREAM_OPTIMISATION_CIRCLE_2
|
|
#endif // CGAL_OPTIMISATION_CIRCLE_2_H
|
|
@end
|
|
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Class template Min_circle_2_traits_2<K>
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Class template \ccFont Min\_circle\_2\_traits\_2<K>}
|
|
|
|
First, we declare the class templates \ccc{Min_circle_2} and
|
|
\ccc{Min_circle_2_traits_2}.
|
|
|
|
@macro<Min_circle_2_traits_2 declarations> = @begin
|
|
template < class Traits_ >
|
|
class Min_circle_2;
|
|
|
|
template < class K_ >
|
|
class Min_circle_2_traits_2;
|
|
@end
|
|
|
|
Since the actual work of the traits class is done in the nested type
|
|
\ccc{Circle}, we implement the whole class template in its interface.
|
|
|
|
The variable \ccc{circle} containing the current circle is declared
|
|
\ccc{private} to disallow the user from directly accessing or modifying
|
|
it. Since the algorithm needs to access and modify the current circle,
|
|
it is declared \ccc{friend}.
|
|
|
|
@macro <Min_circle_2_traits_2 interface and implementation> = @begin
|
|
template < class K_ >
|
|
class Min_circle_2_traits_2 {
|
|
public:
|
|
// types
|
|
typedef K_ K;
|
|
typedef CGAL::Point_2<K> Point;
|
|
typedef CGAL::Optimisation_circle_2<K> Circle;
|
|
|
|
private:
|
|
// data members
|
|
Circle circle; // current circle
|
|
|
|
// friends
|
|
friend class CGAL::Min_circle_2< CGAL::Min_circle_2_traits_2<K> >;
|
|
|
|
public:
|
|
// creation (use default implementations)
|
|
// CGAL::Min_circle_2_traits_2( );
|
|
// CGAL::Min_circle_2_traits_2( CGAL::Min_circle_2_traits_2<K> const&);
|
|
|
|
// operations
|
|
inline
|
|
CGAL::Orientation
|
|
orientation( const Point& p, const Point& q, const Point& r) const
|
|
{
|
|
return( CGAL::orientation( p, q, r));
|
|
}
|
|
};
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Class template Min_circle_2_adapterC2<PT,DA>
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Class template \ccFont Min\_circle\_2\_adapterC2<PT,DA>}
|
|
|
|
First, we declare the class templates \ccc{Min_circle_2},
|
|
\ccc{Min_circle_2_adapterC2} and
|
|
\ccc{_Min_circle_2_adapterC2__Circle}.
|
|
|
|
@macro<Min_circle_2_adapterC2 declarations> = @begin
|
|
template < class Traits_ >
|
|
class Min_circle_2;
|
|
|
|
template < class PT_, class DA_ >
|
|
class Min_circle_2_adapterC2;
|
|
|
|
template < class PT_, class DA_ >
|
|
class _Min_circle_2_adapterC2__Circle;
|
|
@end
|
|
|
|
The actual work of the adapter is done in the nested class
|
|
\ccc{Circle}. Therefore, we implement the whole adapter in its
|
|
interface.
|
|
|
|
The variable \ccc{circle} containing the current circle is declared
|
|
\ccc{private} to disallow the user from directly accessing or modifying
|
|
it. Since the algorithm needs to access and modify the current circle,
|
|
it is declared \ccc{friend}.
|
|
|
|
@macro <Min_circle_2_adapterC2 interface and implementation> = @begin
|
|
template < class PT_, class DA_ >
|
|
class Min_circle_2_adapterC2 {
|
|
public:
|
|
// types
|
|
typedef PT_ PT;
|
|
typedef DA_ DA;
|
|
|
|
// nested types
|
|
typedef PT Point;
|
|
typedef CGAL::_Min_circle_2_adapterC2__Circle<PT,DA> Circle;
|
|
|
|
private:
|
|
DA dao; // data accessor object
|
|
Circle circle; // current circle
|
|
friend class CGAL::Min_circle_2< CGAL::Min_circle_2_adapterC2<PT,DA> >;
|
|
|
|
public:
|
|
// creation
|
|
@<Min_circle_2_adapterC2 constructors>
|
|
|
|
// operations
|
|
@<Min_circle_2_adapterC2 operations>
|
|
};
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Constructors}
|
|
|
|
@macro <Min_circle_2_adapterC2 constructors> = @begin
|
|
Min_circle_2_adapterC2( const DA& da = DA())
|
|
: dao( da), circle( da)
|
|
{ }
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Operations}
|
|
|
|
@macro <Min_circle_2_adapterC2 operations> = @begin
|
|
CGAL::Orientation
|
|
orientation( const Point& p, const Point& q, const Point& r) const
|
|
{
|
|
typedef typename DA_::FT FT;
|
|
|
|
FT px;
|
|
FT py;
|
|
FT qx;
|
|
FT qy;
|
|
FT rx;
|
|
FT ry;
|
|
|
|
dao.get( p, px, py);
|
|
dao.get( q, qx, qy);
|
|
dao.get( r, rx, ry);
|
|
|
|
return( static_cast< CGAL::Orientation>(
|
|
CGAL_NTS sign( ( px-rx) * ( qy-ry) - ( py-ry) * ( qx-rx))));
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Nested Type \ccFont Circle}
|
|
|
|
@macro <Min_circle_2_adapterC2 nested type `Circle'> = @begin
|
|
template < class PT_, class DA_ >
|
|
std::ostream&
|
|
operator << ( std::ostream&,
|
|
const CGAL::_Min_circle_2_adapterC2__Circle<PT_,DA_>&);
|
|
|
|
template < class PT_, class DA_ >
|
|
std::istream&
|
|
operator >> ( std::istream&,
|
|
CGAL::_Min_circle_2_adapterC2__Circle<PT_,DA_>&);
|
|
|
|
template < class PT_, class DA_ >
|
|
class _Min_circle_2_adapterC2__Circle {
|
|
public:
|
|
// typedefs
|
|
typedef PT_ PT;
|
|
typedef DA_ DA;
|
|
|
|
typedef typename DA_::FT FT;
|
|
|
|
private:
|
|
// data members
|
|
DA dao; // data accessor object
|
|
|
|
FT center_x; // center's x-coordinate
|
|
FT center_y; // center's y-coordinate
|
|
FT sqr_rad; // squared radius
|
|
|
|
// private member functions
|
|
FT
|
|
sqr_dist( const FT& px, const FT& py, const FT& qx, const FT& qy) const
|
|
{
|
|
FT dx( px - qx);
|
|
FT dy( py - qy);
|
|
return( dx*dx + dy*dy);
|
|
}
|
|
|
|
friend std::ostream& operator << <> ( std::ostream&,
|
|
const CGAL::_Min_circle_2_adapterC2__Circle<PT_,DA_>&);
|
|
|
|
friend std::istream& operator >> <> ( std::istream&,
|
|
CGAL::_Min_circle_2_adapterC2__Circle<PT_,DA_>&);
|
|
|
|
public:
|
|
// types
|
|
typedef PT Point;
|
|
typedef FT Distance;
|
|
|
|
// creation
|
|
_Min_circle_2_adapterC2__Circle( const DA& da) : dao( da) { }
|
|
|
|
void set( )
|
|
{
|
|
center_x = FT( 0);
|
|
center_y = FT( 0);
|
|
sqr_rad = -FT( 1);
|
|
}
|
|
|
|
void set( const Point& p)
|
|
{
|
|
dao.get( p, center_x, center_y);
|
|
sqr_rad = FT( 0);
|
|
}
|
|
|
|
void set( const Point& p, const Point& q)
|
|
{
|
|
FT px;
|
|
FT py;
|
|
FT qx;
|
|
FT qy;
|
|
|
|
dao.get( p, px, py);
|
|
dao.get( q, qx, qy);
|
|
|
|
center_x = ( px+qx) / FT( 2);
|
|
center_y = ( py+qy) / FT( 2);
|
|
sqr_rad = sqr_dist( px, py, center_x, center_y);
|
|
}
|
|
|
|
void set( const Point& p, const Point& q, const Point& r)
|
|
{
|
|
FT px;
|
|
FT py;
|
|
FT qx;
|
|
FT qy;
|
|
FT rx;
|
|
FT ry;
|
|
|
|
dao.get( p, px, py);
|
|
dao.get( q, qx, qy);
|
|
dao.get( r, rx, ry);
|
|
|
|
FT qx_px( qx - px);
|
|
FT qy_py( qy - py);
|
|
FT rx_px( rx - px);
|
|
FT ry_py( ry - py);
|
|
|
|
FT p2 ( px*px + py*py);
|
|
FT q2_p2( qx*qx + qy*qy - p2);
|
|
FT r2_p2( rx*rx + ry*ry - p2);
|
|
FT denom( ( qx_px*ry_py - rx_px*qy_py) * FT( 2));
|
|
|
|
center_x = ( q2_p2*ry_py - r2_p2*qy_py) / denom;
|
|
center_y = ( r2_p2*qx_px - q2_p2*rx_px) / denom;
|
|
sqr_rad = sqr_dist( px, py, center_x, center_y);
|
|
}
|
|
|
|
// predicates
|
|
CGAL::Bounded_side
|
|
bounded_side( const Point& p) const
|
|
{
|
|
FT px;
|
|
FT py;
|
|
dao.get( p, px, py);
|
|
return( CGAL::Bounded_side(
|
|
CGAL_NTS sign( sqr_rad - sqr_dist( px, py, center_x, center_y))));
|
|
}
|
|
|
|
bool
|
|
has_on_bounded_side( const Point& p) const
|
|
{
|
|
FT px;
|
|
FT py;
|
|
dao.get( p, px, py);
|
|
return( sqr_dist( px, py, center_x, center_y) < sqr_rad);
|
|
}
|
|
|
|
bool
|
|
has_on_boundary( const Point& p) const
|
|
{
|
|
FT px;
|
|
FT py;
|
|
dao.get( p, px, py);
|
|
return( sqr_dist( px, py, center_x, center_y) == sqr_rad);
|
|
}
|
|
|
|
bool
|
|
has_on_unbounded_side( const Point& p) const
|
|
{
|
|
FT px;
|
|
FT py;
|
|
dao.get( p, px, py);
|
|
return( sqr_rad < sqr_dist( px, py, center_x, center_y));
|
|
}
|
|
|
|
bool
|
|
is_empty( ) const
|
|
{
|
|
return( CGAL::is_negative( sqr_rad));
|
|
}
|
|
|
|
bool
|
|
is_degenerate( ) const
|
|
{
|
|
return( ! CGAL::is_positive( sqr_rad));
|
|
}
|
|
|
|
// additional operations for checking
|
|
bool
|
|
operator == (
|
|
const CGAL::_Min_circle_2_adapterC2__Circle<PT_,DA_>& c) const
|
|
{
|
|
return( ( center_x == c.center_x) &&
|
|
( center_y == c.center_y) &&
|
|
( sqr_rad == c.sqr_rad ) );
|
|
}
|
|
|
|
bool
|
|
operator != (
|
|
const CGAL::_Min_circle_2_adapterC2__Circle<PT_,DA_>& c) const
|
|
{
|
|
return( ! ( *this == c));
|
|
}
|
|
|
|
Point
|
|
center( ) const
|
|
{
|
|
Point p;
|
|
dao.set( p, center_x, center_y);
|
|
return( p);
|
|
}
|
|
|
|
const Distance&
|
|
squared_radius( ) const
|
|
{
|
|
return( sqr_rad);
|
|
}
|
|
};
|
|
|
|
// I/O
|
|
template < class PT_, class DA_ >
|
|
std::ostream&
|
|
operator << ( std::ostream& os,
|
|
const CGAL::_Min_circle_2_adapterC2__Circle<PT_,DA_>& c)
|
|
{
|
|
switch ( CGAL::get_mode( os)) {
|
|
|
|
case CGAL::IO::PRETTY:
|
|
os << "CGAL::Min_circle_2_adapterC2::Circle( "
|
|
<< c.center_x << ", "
|
|
<< c.center_y << ", "
|
|
<< c.sqr_rad << ')';
|
|
break;
|
|
|
|
case CGAL::IO::ASCII:
|
|
os << c.center_x << ' ' << c.center_y << ' ' << c.sqr_rad;
|
|
break;
|
|
|
|
case CGAL::IO::BINARY:
|
|
CGAL::write( os, c.center_x);
|
|
CGAL::write( os, c.center_y);
|
|
CGAL::write( os, c.sqr_rad);
|
|
break;
|
|
|
|
default:
|
|
CGAL_optimisation_assertion_msg( false,
|
|
"CGAL::get_mode( os) invalid!");
|
|
break; }
|
|
|
|
return( os);
|
|
}
|
|
|
|
template < class PT_, class DA_ >
|
|
std::istream&
|
|
operator >> ( std::istream& is,
|
|
CGAL::_Min_circle_2_adapterC2__Circle<PT_,DA_>& c)
|
|
{
|
|
switch ( CGAL::get_mode( is)) {
|
|
|
|
case CGAL::IO::PRETTY:
|
|
cerr << std::endl;
|
|
cerr << "Stream must be in ascii or binary mode" << std::endl;
|
|
break;
|
|
|
|
case CGAL::IO::ASCII:
|
|
is >> c.center_x >> c.center_y >> c.sqr_rad;
|
|
break;
|
|
|
|
case CGAL::IO::BINARY:
|
|
CGAL::read( is, c.center_x);
|
|
CGAL::read( is, c.center_y);
|
|
CGAL::read( is, c.sqr_rad);
|
|
break;
|
|
|
|
default:
|
|
CGAL_optimisation_assertion_msg( false,
|
|
"CGAL::IO::mode invalid!");
|
|
break; }
|
|
|
|
return( is);
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Class template Min_circle_2_adapterH2<PT,DA>
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Class template \ccFont Min\_circle\_2\_adapterH2<PT,DA>}
|
|
|
|
First, we declare the class templates \ccc{Min_circle_2},
|
|
\ccc{Min_circle_2_adapterH2} and
|
|
\ccc{_Min_circle_2_adapterH2__Circle}.
|
|
|
|
@macro<Min_circle_2_adapterH2 declarations> = @begin
|
|
template < class Traits_ >
|
|
class Min_circle_2;
|
|
|
|
template < class PT_, class DA_ >
|
|
class Min_circle_2_adapterH2;
|
|
|
|
template < class PT_, class DA_ >
|
|
class _Min_circle_2_adapterH2__Circle;
|
|
@end
|
|
|
|
The actual work of the adapter is done in the nested class
|
|
\ccc{Circle}. Therefore, we implement the whole adapter in its
|
|
interface.
|
|
|
|
The variable \ccc{circle} containing the current circle is declared
|
|
\ccc{private} to disallow the user from directly accessing or modifying
|
|
it. Since the algorithm needs to access and modify the current circle,
|
|
it is declared \ccc{friend}.
|
|
|
|
@macro <Min_circle_2_adapterH2 interface and implementation> = @begin
|
|
template < class PT_, class DA_ >
|
|
class Min_circle_2_adapterH2 {
|
|
public:
|
|
// types
|
|
typedef PT_ PT;
|
|
typedef DA_ DA;
|
|
|
|
// nested types
|
|
typedef PT Point;
|
|
typedef CGAL::_Min_circle_2_adapterH2__Circle<PT,DA> Circle;
|
|
|
|
private:
|
|
DA dao; // data accessor object
|
|
Circle circle; // current circle
|
|
friend class CGAL::Min_circle_2< CGAL::Min_circle_2_adapterH2<PT,DA> >;
|
|
|
|
public:
|
|
// creation
|
|
@<Min_circle_2_adapterH2 constructors>
|
|
|
|
// operations
|
|
@<Min_circle_2_adapterH2 operations>
|
|
};
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Constructors}
|
|
|
|
@macro <Min_circle_2_adapterH2 constructors> = @begin
|
|
Min_circle_2_adapterH2( const DA& da = DA())
|
|
: dao( da), circle( da)
|
|
{ }
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Operations}
|
|
|
|
@macro <Min_circle_2_adapterH2 operations> = @begin
|
|
CGAL::Orientation
|
|
orientation( const Point& p, const Point& q, const Point& r) const
|
|
{
|
|
typedef typename DA_::RT RT;
|
|
|
|
RT phx;
|
|
RT phy;
|
|
RT phw;
|
|
RT qhx;
|
|
RT qhy;
|
|
RT qhw;
|
|
RT rhx;
|
|
RT rhy;
|
|
RT rhw;
|
|
|
|
dao.get( p, phx, phy, phw);
|
|
dao.get( q, qhx, qhy, qhw);
|
|
dao.get( r, rhx, rhy, rhw);
|
|
|
|
return( static_cast< CGAL::Orientation>(
|
|
CGAL_NTS sign( ( phx*rhw - rhx*phw) * ( qhy*rhw - rhy*qhw)
|
|
- ( phy*rhw - rhy*phw) * ( qhx*rhw - rhx*qhw))));
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
\subsubsection{Nested Type \ccFont Circle}
|
|
|
|
@macro <Min_circle_2_adapterH2 nested type `Circle'> = @begin
|
|
template < class PT_, class DA_ >
|
|
std::ostream&
|
|
operator << ( std::ostream&,
|
|
const CGAL::_Min_circle_2_adapterH2__Circle<PT_,DA_>&);
|
|
|
|
template < class PT_, class DA_ >
|
|
std::istream&
|
|
operator >> ( std::istream&,
|
|
CGAL::_Min_circle_2_adapterH2__Circle<PT_,DA_>&);
|
|
|
|
template < class PT_, class DA_ >
|
|
class _Min_circle_2_adapterH2__Circle {
|
|
public:
|
|
// typedefs
|
|
typedef PT_ PT;
|
|
typedef DA_ DA;
|
|
|
|
typedef typename DA_::RT RT;
|
|
typedef CGAL::Quotient<RT> FT;
|
|
|
|
private:
|
|
// data members
|
|
DA dao; // data accessor object
|
|
|
|
RT center_hx; // center's hx-coordinate
|
|
RT center_hy; // center's hy-coordinate
|
|
RT center_hw; // center's hw-coordinate
|
|
FT sqr_rad; // squared radius
|
|
|
|
// private member functions
|
|
FT
|
|
sqr_dist( const RT& phx, const RT& phy, const RT& phw,
|
|
const RT& qhx, const RT& qhy, const RT& qhw) const
|
|
{
|
|
RT dhx( phx*qhw - qhx*phw);
|
|
RT dhy( phy*qhw - qhy*phw);
|
|
RT dhw( phw*qhw);
|
|
return( FT( dhx*dhx + dhy*dhy, dhw*dhw));
|
|
}
|
|
|
|
friend std::ostream& operator << <> ( std::ostream&,
|
|
const CGAL::_Min_circle_2_adapterH2__Circle<PT_,DA_>&);
|
|
|
|
friend std::istream& operator >> <> ( std::istream&,
|
|
CGAL::_Min_circle_2_adapterH2__Circle<PT_,DA_>&);
|
|
|
|
public:
|
|
// types
|
|
typedef PT Point;
|
|
typedef FT Distance;
|
|
|
|
// creation
|
|
_Min_circle_2_adapterH2__Circle( const DA& da) : dao( da) { }
|
|
|
|
void set( )
|
|
{
|
|
center_hx = RT( 0);
|
|
center_hy = RT( 0);
|
|
center_hw = RT( 1);
|
|
sqr_rad = -FT( 1);
|
|
}
|
|
|
|
void set( const Point& p)
|
|
{
|
|
dao.get( p, center_hx, center_hy, center_hw);
|
|
sqr_rad = FT( 0);
|
|
}
|
|
|
|
void set( const Point& p, const Point& q)
|
|
{
|
|
RT phx;
|
|
RT phy;
|
|
RT phw;
|
|
RT qhx;
|
|
RT qhy;
|
|
RT qhw;
|
|
|
|
dao.get( p, phx, phy, phw);
|
|
dao.get( q, qhx, qhy, qhw);
|
|
center_hx = ( phx*qhw + qhx*phw);
|
|
center_hy = ( phy*qhw + qhy*phw);
|
|
center_hw = ( phw*qhw * RT( 2));
|
|
sqr_rad = sqr_dist( phx, phy, phw,
|
|
center_hx, center_hy, center_hw);
|
|
}
|
|
|
|
void set( const Point& p, const Point& q, const Point& r)
|
|
{
|
|
RT phx;
|
|
RT phy;
|
|
RT phw;
|
|
RT qhx;
|
|
RT qhy;
|
|
RT qhw;
|
|
RT rhx;
|
|
RT rhy;
|
|
RT rhw;
|
|
|
|
dao.get( p, phx, phy, phw);
|
|
dao.get( q, qhx, qhy, qhw);
|
|
dao.get( r, rhx, rhy, rhw);
|
|
|
|
RT qhx_phx( qhx*phw - phx*qhw);
|
|
RT qhy_phy( qhy*phw - phy*qhw); // denominator: qhw*phw
|
|
|
|
RT rhx_phx( rhx*phw - phx*rhw);
|
|
RT rhy_phy( rhy*phw - phy*rhw); // denominator: rhw*phw
|
|
|
|
RT phw2( phw*phw);
|
|
RT qhw2( qhw*qhw);
|
|
RT rhw2( rhw*rhw);
|
|
|
|
RT p2( phx*phx + phy*phy); // denominator: phw2
|
|
|
|
RT q2_p2( ( qhx*qhx + qhy*qhy) * phw2 - p2 * qhw2);
|
|
// denominator: qhw2*phw2
|
|
|
|
RT r2_p2( ( rhx*rhx + rhy*rhy) * phw2 - p2 * rhw2);
|
|
// denominator: rhw2*phw2
|
|
|
|
center_hx = q2_p2*rhy_phy * rhw - r2_p2*qhy_phy * qhw;
|
|
center_hy = r2_p2*qhx_phx * qhw - q2_p2*rhx_phx * rhw;
|
|
center_hw = ( qhx_phx*rhy_phy - rhx_phx*qhy_phy)
|
|
* phw*qhw*rhw * RT( 2);
|
|
sqr_rad = sqr_dist( phx, phy, phw,
|
|
center_hx, center_hy, center_hw);
|
|
}
|
|
|
|
// predicates
|
|
CGAL::Bounded_side
|
|
bounded_side( const Point& p) const
|
|
{
|
|
RT phx;
|
|
RT phy;
|
|
RT phw;
|
|
dao.get( p, phx, phy, phw);
|
|
return( CGAL::Bounded_side( CGAL_NTS sign(
|
|
sqr_rad - sqr_dist( phx, phy, phw,
|
|
center_hx, center_hy, center_hw))));
|
|
}
|
|
|
|
bool
|
|
has_on_bounded_side( const Point& p) const
|
|
{
|
|
RT phx;
|
|
RT phy;
|
|
RT phw;
|
|
dao.get( p, phx, phy, phw);
|
|
return( sqr_dist( phx, phy, phw,
|
|
center_hx, center_hy, center_hw) < sqr_rad);
|
|
}
|
|
|
|
bool
|
|
has_on_boundary( const Point& p) const
|
|
{
|
|
RT phx;
|
|
RT phy;
|
|
RT phw;
|
|
dao.get( p, phx, phy, phw);
|
|
return( sqr_dist( phx, phy, phw,
|
|
center_hx, center_hy, center_hw) == sqr_rad);
|
|
}
|
|
|
|
bool
|
|
has_on_unbounded_side( const Point& p) const
|
|
{
|
|
RT phx;
|
|
RT phy;
|
|
RT phw;
|
|
dao.get( p, phx, phy, phw);
|
|
return( sqr_rad < sqr_dist( phx, phy, phw,
|
|
center_hx, center_hy, center_hw));
|
|
}
|
|
|
|
bool
|
|
is_empty( ) const
|
|
{
|
|
return( CGAL::is_negative( sqr_rad));
|
|
}
|
|
|
|
bool
|
|
is_degenerate( ) const
|
|
{
|
|
return( ! CGAL::is_positive( sqr_rad));
|
|
}
|
|
|
|
// additional operations for checking
|
|
bool
|
|
operator == (
|
|
const CGAL::_Min_circle_2_adapterH2__Circle<PT_,DA_>& c) const
|
|
{
|
|
return( ( center_hx*c.center_hw == c.center_hx*center_hw) &&
|
|
( center_hy*c.center_hw == c.center_hy*center_hw) &&
|
|
( sqr_rad == c.sqr_rad ) );
|
|
}
|
|
|
|
bool
|
|
operator != (
|
|
const CGAL::_Min_circle_2_adapterH2__Circle<PT_,DA_>& c) const
|
|
{
|
|
return( ! ( *this == c));
|
|
}
|
|
|
|
Point
|
|
center( ) const
|
|
{
|
|
Point p;
|
|
dao.set( p, center_hx, center_hy, center_hw);
|
|
return( p);
|
|
}
|
|
|
|
const Distance&
|
|
squared_radius( ) const
|
|
{
|
|
return( sqr_rad);
|
|
}
|
|
};
|
|
|
|
// I/O
|
|
template < class PT_, class DA_ >
|
|
std::ostream&
|
|
operator << ( std::ostream& os,
|
|
const CGAL::_Min_circle_2_adapterH2__Circle<PT_,DA_>& c)
|
|
{
|
|
switch ( CGAL::get_mode( os)) {
|
|
|
|
case CGAL::IO::PRETTY:
|
|
os << "CGAL::Min_circle_2_adapterH2::Circle( "
|
|
<< c.center_hx << ", "
|
|
<< c.center_hy << ", "
|
|
<< c.center_hw << ", "
|
|
<< c.sqr_rad << ')';
|
|
break;
|
|
|
|
case CGAL::IO::ASCII:
|
|
os << c.center_hx << ' '
|
|
<< c.center_hy << ' '
|
|
<< c.center_hw << ' '
|
|
<< c.sqr_rad;
|
|
break;
|
|
|
|
case CGAL::IO::BINARY:
|
|
CGAL::write( os, c.center_hx);
|
|
CGAL::write( os, c.center_hy);
|
|
CGAL::write( os, c.center_hw);
|
|
CGAL::write( os, c.sqr_rad);
|
|
break;
|
|
|
|
default:
|
|
CGAL_optimisation_assertion_msg( false,
|
|
"CGAL::get_mode( os) invalid!");
|
|
break; }
|
|
|
|
return( os);
|
|
}
|
|
|
|
template < class PT_, class DA_ >
|
|
std::istream&
|
|
operator >> ( std::istream& is,
|
|
CGAL::_Min_circle_2_adapterH2__Circle<PT_,DA_>& c)
|
|
{
|
|
switch ( CGAL::get_mode( is)) {
|
|
|
|
case CGAL::IO::PRETTY:
|
|
cerr << std::endl;
|
|
cerr << "Stream must be in ascii or binary mode" << std::endl;
|
|
break;
|
|
|
|
case CGAL::IO::ASCII:
|
|
is >> c.center_hx >> c.center_hy >> c.center_hw >> c.sqr_rad;
|
|
break;
|
|
|
|
case CGAL::IO::BINARY:
|
|
CGAL::read( is, c.center_hx);
|
|
CGAL::read( is, c.center_hy);
|
|
CGAL::read( is, c.center_hw);
|
|
CGAL::read( is, c.sqr_rad);
|
|
break;
|
|
|
|
default:
|
|
CGAL_optimisation_assertion_msg( false,
|
|
"CGAL::IO::mode invalid!");
|
|
break; }
|
|
|
|
return( is);
|
|
}
|
|
@end
|
|
|
|
@! ============================================================================
|
|
@! Tests
|
|
@! ============================================================================
|
|
|
|
\clearpage
|
|
\section{Test}
|
|
|
|
We test \ccc{Min_circle_2} with the traits class implementation
|
|
for optimisation algorithms, using exact arithmetic, i.e.\ Cartesian
|
|
representation with number type \ccc{Quotient<Gmpz>} and
|
|
homogeneous representation with number type \ccc{Gmpz}.
|
|
|
|
@macro <Min_circle_2 test (includes and typedefs)> = @begin
|
|
#include <CGAL/Cartesian.h>
|
|
#include <CGAL/Homogeneous.h>
|
|
#include <CGAL/Min_circle_2.h>
|
|
#include <CGAL/Min_circle_2_traits_2.h>
|
|
#include <CGAL/Min_circle_2_adapterC2.h>
|
|
#include <CGAL/Min_circle_2_adapterH2.h>
|
|
#include <CGAL/IO/Verbose_ostream.h>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
#include <fstream>
|
|
|
|
#ifdef CGAL_USE_LEDA_FOR_OPTIMISATION_TEST
|
|
# include <CGAL/leda_integer.h>
|
|
typedef leda_integer Rt;
|
|
typedef CGAL::Quotient< leda_integer > Ft;
|
|
#else
|
|
# include <CGAL/Gmpz.h>
|
|
typedef CGAL::Gmpz Rt;
|
|
typedef CGAL::Quotient< CGAL::Gmpz > Ft;
|
|
#endif
|
|
|
|
typedef CGAL::Cartesian< Ft > KerC;
|
|
typedef CGAL::Homogeneous< Rt > KerH;
|
|
typedef CGAL::Min_circle_2_traits_2< KerC > TraitsC;
|
|
typedef CGAL::Min_circle_2_traits_2< KerH > TraitsH;
|
|
@end
|
|
|
|
The command line option \ccc{-verbose} enables verbose output.
|
|
|
|
@macro <Min_circle_2 test (verbose option)> = @begin
|
|
bool verbose = false;
|
|
if ( ( argc > 1) && ( CGAL_CLIB_STD::strcmp( argv[ 1], "-verbose") == 0)) {
|
|
verbose = true;
|
|
--argc;
|
|
++argv; }
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Code Coverage
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Code Coverage}
|
|
|
|
We call each function of class \ccc{Min_circle_2<Traits>} at least
|
|
once to ensure code coverage.
|
|
|
|
@macro <Min_circle_2 test (code coverage)> = @begin
|
|
cover_Min_circle_2( verbose, TraitsC(), Rt());
|
|
cover_Min_circle_2( verbose, TraitsH(), Rt());
|
|
@end
|
|
|
|
@macro <Min_circle_2 test (code coverage test function)> = @begin
|
|
template < class Traits, class RT >
|
|
void
|
|
cover_Min_circle_2( bool verbose, const Traits&, const RT&)
|
|
{
|
|
using namespace std;
|
|
|
|
typedef CGAL::Min_circle_2< Traits > Min_circle;
|
|
typedef typename Min_circle::Point Point;
|
|
typedef typename Min_circle::Circle Circle;
|
|
|
|
CGAL::Verbose_ostream verr( verbose);
|
|
|
|
// generate `n' points at random
|
|
const int n = 20;
|
|
CGAL::Random random_x, random_y;
|
|
Point random_points[ n];
|
|
int i;
|
|
verr << n << " random points from [0,128)^2:" << endl;
|
|
for ( i = 0; i < n; ++i) {
|
|
random_points[ i] = Point( RT( random_x( 128)),
|
|
RT( random_y( 128)));
|
|
verr << i << ": " << random_points[ i] << endl;
|
|
}
|
|
|
|
// cover code
|
|
verr << endl << "default constructor...";
|
|
{
|
|
Min_circle mc;
|
|
bool is_valid = mc.is_valid( verbose);
|
|
bool is_empty = mc.is_empty();
|
|
assert( is_valid);
|
|
assert( is_empty);
|
|
}
|
|
|
|
verr << endl << "one point constructor...";
|
|
{
|
|
Min_circle mc( random_points[ 0]);
|
|
bool is_valid = mc.is_valid( verbose);
|
|
bool is_degenerate = mc.is_degenerate();
|
|
assert( is_valid);
|
|
assert( is_degenerate);
|
|
}
|
|
|
|
verr << endl << "two points constructor...";
|
|
{
|
|
Min_circle mc( random_points[ 1],
|
|
random_points[ 2]);
|
|
bool is_valid = mc.is_valid( verbose);
|
|
assert( is_valid);
|
|
assert( mc.number_of_points() == 2);
|
|
}
|
|
|
|
verr << endl << "three points constructor...";
|
|
{
|
|
Min_circle mc( random_points[ 3],
|
|
random_points[ 4],
|
|
random_points[ 5]);
|
|
bool is_valid = mc.is_valid( verbose);
|
|
assert( is_valid);
|
|
assert( mc.number_of_points() == 3);
|
|
}
|
|
|
|
verr << endl << "Point* constructor...";
|
|
Min_circle mc( random_points, random_points+9, false);
|
|
{
|
|
Min_circle mc2( random_points, random_points+9, true);
|
|
bool is_valid = mc .is_valid( verbose);
|
|
bool is_valid2 = mc2.is_valid( verbose);
|
|
assert( is_valid);
|
|
assert( is_valid2);
|
|
assert( mc .number_of_points() == 9);
|
|
assert( mc2.number_of_points() == 9);
|
|
assert( mc.circle() == mc2.circle());
|
|
}
|
|
|
|
verr << endl << "list<Point>::const_iterator constructor...";
|
|
{
|
|
Min_circle mc1( mc.points_begin(), mc.points_end(), false);
|
|
Min_circle mc2( mc.points_begin(), mc.points_end(), true);
|
|
bool is_valid1 = mc1.is_valid( verbose);
|
|
bool is_valid2 = mc2.is_valid( verbose);
|
|
assert( is_valid1);
|
|
assert( is_valid2);
|
|
assert( mc1.number_of_points() == 9);
|
|
assert( mc2.number_of_points() == 9);
|
|
assert( mc.circle() == mc1.circle());
|
|
assert( mc.circle() == mc2.circle());
|
|
}
|
|
|
|
verr << endl << "#points already called above.";
|
|
|
|
verr << endl << "points access already called above.";
|
|
|
|
verr << endl << "support points access...";
|
|
{
|
|
typedef typename Min_circle::Support_point_iterator
|
|
Support_point_iterator;
|
|
Point support_point;
|
|
Support_point_iterator iter( mc.support_points_begin());
|
|
for ( i = 0; i < mc.number_of_support_points(); ++i, ++iter) {
|
|
support_point = mc.support_point( i);
|
|
assert( support_point == *iter); }
|
|
Support_point_iterator end_iter( mc.support_points_end());
|
|
assert( iter == end_iter);
|
|
}
|
|
|
|
verr << endl << "circle access already called above...";
|
|
|
|
verr << endl << "in-circle predicates...";
|
|
{
|
|
Point p;
|
|
CGAL::Bounded_side bounded_side;
|
|
bool has_on_bounded_side;
|
|
bool has_on_boundary;
|
|
bool has_on_unbounded_side;
|
|
for ( i = 0; i < 9; ++i) {
|
|
p = random_points[ i];
|
|
bounded_side = mc.bounded_side( p);
|
|
has_on_bounded_side = mc.has_on_bounded_side( p);
|
|
has_on_boundary = mc.has_on_boundary( p);
|
|
has_on_unbounded_side = mc.has_on_unbounded_side( p);
|
|
assert( bounded_side != CGAL::ON_UNBOUNDED_SIDE);
|
|
assert( has_on_bounded_side || has_on_boundary);
|
|
assert( ! has_on_unbounded_side); }
|
|
}
|
|
|
|
verr << endl << "is_... predicates already called above.";
|
|
|
|
verr << endl << "single point insert...";
|
|
mc.insert( random_points[ 9]);
|
|
{
|
|
bool is_valid = mc.is_valid( verbose);
|
|
assert( is_valid);
|
|
assert( mc.number_of_points() == 10);
|
|
}
|
|
|
|
verr << endl << "Point* insert...";
|
|
mc.insert( random_points+10, random_points+n);
|
|
{
|
|
bool is_valid = mc.is_valid( verbose);
|
|
assert( is_valid);
|
|
assert( mc.number_of_points() == n);
|
|
}
|
|
|
|
verr << endl << "list<Point>::const_iterator insert...";
|
|
{
|
|
Min_circle mc2;
|
|
mc2.insert( mc.points_begin(), mc.points_end());
|
|
bool is_valid = mc2.is_valid( verbose);
|
|
assert( is_valid);
|
|
assert( mc2.number_of_points() == n);
|
|
|
|
verr << endl << "clear...";
|
|
mc2.clear();
|
|
is_valid = mc2.is_valid( verbose);
|
|
bool is_empty = mc2.is_empty();
|
|
assert( is_valid);
|
|
assert( is_empty);
|
|
}
|
|
|
|
verr << endl << "validity check already called several times.";
|
|
|
|
verr << endl << "traits class access...";
|
|
{
|
|
Traits traits( mc.traits());
|
|
}
|
|
|
|
verr << endl << "I/O...";
|
|
{
|
|
verr << endl << " writing `test_Min_circle_2.ascii'...";
|
|
ofstream os( "test_Min_circle_2.ascii");
|
|
CGAL::set_ascii_mode( os);
|
|
os << mc;
|
|
}
|
|
{
|
|
verr << endl << " writing `test_Min_circle_2.pretty'...";
|
|
ofstream os( "test_Min_circle_2.pretty");
|
|
CGAL::set_pretty_mode( os);
|
|
os << mc;
|
|
}
|
|
{
|
|
verr << endl << " writing `test_Min_circle_2.binary'...";
|
|
ofstream os( "test_Min_circle_2.binary");
|
|
CGAL::set_binary_mode( os);
|
|
os << mc;
|
|
}
|
|
{
|
|
verr << endl << " reading `test_Min_circle_2.ascii'...";
|
|
Min_circle mc_in;
|
|
ifstream is( "test_Min_circle_2.ascii");
|
|
CGAL::set_ascii_mode( is);
|
|
is >> mc_in;
|
|
bool is_valid = mc_in.is_valid( verbose);
|
|
assert( is_valid);
|
|
assert( mc_in.number_of_points() == n);
|
|
assert( mc_in.circle() == mc.circle());
|
|
}
|
|
verr << endl;
|
|
}
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Adapters
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Traits Class Adapters}
|
|
|
|
We define two point classes (one with Cartesian, one with homogeneous
|
|
representation) and corresponding data accessors.
|
|
|
|
@macro <Min_circle_2 test (point classes)> = @begin
|
|
// 2D Cartesian point class
|
|
class MyPointC2;
|
|
|
|
std::ostream& operator << ( std::ostream&, const MyPointC2&);
|
|
std::istream& operator >> ( std::istream&, MyPointC2&);
|
|
|
|
class MyPointC2 {
|
|
public:
|
|
typedef ::Ft FT;
|
|
private:
|
|
FT x_;
|
|
FT y_;
|
|
public:
|
|
MyPointC2( ) { }
|
|
MyPointC2( const FT& x, const FT& y) : x_( x), y_( y) { }
|
|
|
|
const FT& x( ) const { return( x_); }
|
|
const FT& y( ) const { return( y_); }
|
|
|
|
bool
|
|
operator == ( const MyPointC2& p) const
|
|
{
|
|
return( ( x_ == p.x_) && ( y_ == p.y_));
|
|
}
|
|
|
|
bool
|
|
operator != ( const MyPointC2& p) const
|
|
{
|
|
return( ( x_ != p.x_) || ( y_ != p.y_));
|
|
}
|
|
|
|
friend
|
|
std::ostream& operator << ( std::ostream& os, const MyPointC2& p);
|
|
|
|
friend
|
|
std::istream& operator >> ( std::istream& is, MyPointC2& p);
|
|
};
|
|
|
|
std::ostream&
|
|
operator << ( std::ostream& os, const MyPointC2& p)
|
|
{
|
|
return( os << p.x_ << ' ' << p.y_);
|
|
}
|
|
|
|
std::istream&
|
|
operator >> ( std::istream& is, MyPointC2& p)
|
|
{
|
|
return( is >> p.x_ >> p.y_);
|
|
}
|
|
|
|
// 2D Cartesian point class data accessor
|
|
class MyPointC2DA {
|
|
public:
|
|
typedef ::Ft FT;
|
|
|
|
MyPointC2DA( ) { }
|
|
|
|
const FT& get_x( const MyPointC2& p) const { return( p.x()); }
|
|
const FT& get_y( const MyPointC2& p) const { return( p.y()); }
|
|
|
|
void
|
|
get( const MyPointC2& p, FT& x, FT& y) const
|
|
{
|
|
x = get_x( p);
|
|
y = get_y( p);
|
|
}
|
|
|
|
void
|
|
set( MyPointC2& p, const FT& x, const FT& y) const
|
|
{
|
|
p = MyPointC2( x, y);
|
|
}
|
|
};
|
|
|
|
|
|
// 2D homogeneous point class
|
|
class MyPointH2;
|
|
|
|
std::ostream& operator << ( std::ostream&, const MyPointH2&);
|
|
std::istream& operator >> ( std::istream&, MyPointH2&);
|
|
|
|
class MyPointH2 {
|
|
public:
|
|
typedef ::Rt RT;
|
|
private:
|
|
RT hx_;
|
|
RT hy_;
|
|
RT hw_;
|
|
public:
|
|
MyPointH2( ) { }
|
|
MyPointH2( const RT& hx, const RT& hy, const RT& hw = RT( 1))
|
|
: hx_( hx), hy_( hy), hw_( hw) { }
|
|
|
|
const RT& hx( ) const { return( hx_); }
|
|
const RT& hy( ) const { return( hy_); }
|
|
const RT& hw( ) const { return( hw_); }
|
|
|
|
bool
|
|
operator == ( const MyPointH2& p) const
|
|
{
|
|
return( ( hx_*p.hw_ == p.hx_*hw_) && ( hy_*p.hw_ == p.hy_*hw_));
|
|
}
|
|
|
|
bool
|
|
operator != ( const MyPointH2& p) const
|
|
{
|
|
return( ( hx_*p.hw_ != p.hx_*hw_) || ( hy_*p.hw_ != p.hy_*hw_));
|
|
}
|
|
|
|
friend
|
|
std::ostream& operator << ( std::ostream& os, const MyPointH2& p);
|
|
|
|
friend
|
|
std::istream& operator >> ( std::istream& is, MyPointH2& p);
|
|
};
|
|
|
|
std::ostream&
|
|
operator << ( std::ostream& os, const MyPointH2& p)
|
|
{
|
|
return( os << p.hx_ << ' ' << p.hy_ << ' ' << p.hw_);
|
|
}
|
|
|
|
std::istream&
|
|
operator >> ( std::istream& is, MyPointH2& p)
|
|
{
|
|
return( is >> p.hx_ >> p.hy_ >> p.hw_);
|
|
}
|
|
|
|
// 2D homogeneous point class data accessor
|
|
class MyPointH2DA {
|
|
public:
|
|
typedef ::Rt RT;
|
|
|
|
MyPointH2DA( ) { }
|
|
|
|
const RT& get_hx( const MyPointH2& p) const { return( p.hx()); }
|
|
const RT& get_hy( const MyPointH2& p) const { return( p.hy()); }
|
|
const RT& get_hw( const MyPointH2& p) const { return( p.hw()); }
|
|
|
|
void
|
|
get( const MyPointH2& p, RT& hx, RT& hy, RT& hw) const
|
|
{
|
|
hx = get_hx( p);
|
|
hy = get_hy( p);
|
|
hw = get_hw( p);
|
|
}
|
|
|
|
void
|
|
set( MyPointH2& p, const RT& hx, const RT& hy, const RT& hw) const
|
|
{
|
|
p = MyPointH2( hx, hy, hw);
|
|
}
|
|
};
|
|
@end
|
|
|
|
To test the traits class adapters we use the code coverage test function.
|
|
|
|
@macro <Min_circle_2 test (adapters test)> = @begin
|
|
typedef CGAL::Min_circle_2_adapterC2< MyPointC2, MyPointC2DA > AdapterC2;
|
|
typedef CGAL::Min_circle_2_adapterH2< MyPointH2, MyPointH2DA > AdapterH2;
|
|
cover_Min_circle_2( verbose, AdapterC2(), Rt());
|
|
cover_Min_circle_2( verbose, AdapterH2(), Rt());
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! External Test Sets
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{External Test Sets}
|
|
|
|
In addition, some data files can be given as command line arguments.
|
|
A data file contains pairs of \ccc{int}s, namely the x- and
|
|
y-coordinates of a set of points. The first number in the file is the
|
|
number of points. A short description of the test set is given at the
|
|
end of each file.
|
|
|
|
@macro <Min_circle_2 test (external test sets)> = @begin
|
|
while ( argc > 1) {
|
|
|
|
typedef CGAL::Min_circle_2< TraitsH > Min_circle;
|
|
typedef Min_circle::Point Point;
|
|
typedef Min_circle::Circle Circle;
|
|
|
|
CGAL::Verbose_ostream verr( verbose);
|
|
|
|
// read points from file
|
|
verr << std::endl << "input file: `" << argv[ 1] << "'" << std::flush;
|
|
|
|
std::list<Point> points;
|
|
int n, x, y;
|
|
std::ifstream in( argv[ 1]);
|
|
in >> n;
|
|
assert( in);
|
|
for ( int i = 0; i < n; ++i) {
|
|
in >> x >> y;
|
|
assert( in);
|
|
points.push_back( Point( x, y)); }
|
|
|
|
// compute and check min_circle
|
|
Min_circle mc2( points.begin(), points.end(), false);
|
|
bool is_valid = mc2.is_valid( verbose);
|
|
assert( is_valid);
|
|
|
|
// next file
|
|
--argc;
|
|
++argv; }
|
|
@end
|
|
|
|
@! ==========================================================================
|
|
@! Files
|
|
@! ==========================================================================
|
|
|
|
\clearpage
|
|
\section{Files}
|
|
|
|
@i share/namespace.awi
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Min_circle_2.h
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Min\_circle\_2.h}
|
|
|
|
@file <include/CGAL/Min_circle_2.h> = @begin
|
|
@<file header>(
|
|
"include/CGAL/Min_circle_2.h",
|
|
"2D Smallest Enclosing Circle")
|
|
|
|
#ifndef CGAL_MIN_CIRCLE_2_H
|
|
#define CGAL_MIN_CIRCLE_2_H
|
|
|
|
// includes
|
|
#ifndef CGAL_OPTIMISATION_BASIC_H
|
|
# include <CGAL/Optimisation/basic.h>
|
|
#endif
|
|
#ifndef CGAL_RANDOM_H
|
|
# include <CGAL/Random.h>
|
|
#endif
|
|
#ifndef CGAL_PROTECT_LIST
|
|
# include <list>
|
|
# define CGAL_PROTECT_LIST
|
|
#endif
|
|
#ifndef CGAL_PROTECT_VECTOR
|
|
# include <vector>
|
|
# define CGAL_PROTECT_VECTOR
|
|
#endif
|
|
#ifndef CGAL_PROTECT_ALGORITHM
|
|
# include <algorithm>
|
|
# define CGAL_PROTECT_ALGORITHM
|
|
#endif
|
|
#ifndef CGAL_PROTECT_IOSTREAM
|
|
# include <iostream>
|
|
# define CGAL_PROTECT_IOSTREAM
|
|
#endif
|
|
|
|
@<namespace begin>("CGAL")
|
|
|
|
// Class declaration
|
|
// =================
|
|
@<Min_circle_2 declaration>
|
|
|
|
// Class interface
|
|
// ===============
|
|
@<Min_circle_2 interface>
|
|
|
|
// Function declarations
|
|
// =====================
|
|
// I/O
|
|
// ---
|
|
@<Min_circle_2 I/O operators declaration>
|
|
|
|
@<namespace end>("CGAL")
|
|
|
|
#ifdef CGAL_CFG_NO_AUTOMATIC_TEMPLATE_INCLUSION
|
|
# include <CGAL/Min_circle_2.C>
|
|
#endif
|
|
|
|
#endif // CGAL_MIN_CIRCLE_2_H
|
|
|
|
@<end of file line>
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Min_circle_2.C
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Min\_circle\_2.C}
|
|
|
|
@file <include/CGAL/Min_circle_2.C> = @begin
|
|
@<file header>(
|
|
"include/CGAL/Min_circle_2.C",
|
|
"2D Smallest Enclosing Circle")
|
|
|
|
@<namespace begin>("CGAL")
|
|
|
|
// Class implementation (continued)
|
|
// ================================
|
|
// I/O
|
|
// ---
|
|
@<Min_circle_2 I/O operators>
|
|
|
|
@<namespace end>("CGAL")
|
|
|
|
@<end of file line>
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Optimisation_circle_2.h
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Optimisation\_circle\_2.h}
|
|
|
|
@file <include/CGAL/Optimisation_circle_2.h> = @begin
|
|
@<file header>(
|
|
"include/CGAL/Optimisation_circle_2.h",
|
|
"2D Optimisation Circle")
|
|
|
|
#ifndef CGAL_OPTIMISATION_CIRCLE_2_H
|
|
#define CGAL_OPTIMISATION_CIRCLE_2_H
|
|
|
|
// includes
|
|
#ifndef CGAL_POINT_2_H
|
|
# include <CGAL/Point_2.h>
|
|
#endif
|
|
#ifndef CGAL_BASIC_CONSTRUCTIONS_2_H
|
|
# include <CGAL/basic_constructions_2.h>
|
|
#endif
|
|
#ifndef CGAL_SQUARED_DISTANCE_2_H
|
|
# include <CGAL/squared_distance_2.h>
|
|
#endif
|
|
|
|
@<namespace begin>("CGAL")
|
|
|
|
// Class declaration
|
|
// =================
|
|
@<Optimisation_circle_2 declaration>
|
|
|
|
// Class interface
|
|
// ===============
|
|
@<Optimisation_circle_2 interface>
|
|
|
|
// Function declarations
|
|
// =====================
|
|
// I/O
|
|
// ---
|
|
@<Optimisation_circle_2 I/O operators declaration>
|
|
|
|
@<namespace end>("CGAL")
|
|
|
|
#ifdef CGAL_CFG_NO_AUTOMATIC_TEMPLATE_INCLUSION
|
|
# include <CGAL/Optimisation_circle_2.C>
|
|
#endif
|
|
|
|
#endif // CGAL_OPTIMISATION_CIRCLE_2_H
|
|
|
|
@<end of file line>
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Optimisation_circle_2.C
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Optimisation\_circle\_2.C}
|
|
|
|
@file <include/CGAL/Optimisation_circle_2.C> = @begin
|
|
@<file header>(
|
|
"include/CGAL/Optimisation_circle_2.C",
|
|
"2D Optimisation Circle")
|
|
|
|
// includes
|
|
#ifndef CGAL_OPTIMISATION_ASSERTIONS_H
|
|
# include <CGAL/Optimisation/assertions.h>
|
|
#endif
|
|
|
|
@<namespace begin>("CGAL")
|
|
|
|
// Class implementation (continued)
|
|
// ================================
|
|
|
|
// I/O
|
|
// ---
|
|
@<Optimisation_circle_2 I/O operators>
|
|
|
|
@<namespace end>("CGAL")
|
|
|
|
@<end of file line>
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Min_circle_2_traits_2.h
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Min\_circle\_2\_traits\_2.h}
|
|
|
|
@file <include/CGAL/Min_circle_2_traits_2.h> = @begin
|
|
@<file header>(
|
|
"include/CGAL/Min_circle_2_traits_2.h",
|
|
"default traits class for 2D Smallest Enclosing Circle")
|
|
|
|
#ifndef CGAL_MIN_CIRCLE_2_TRAITS_2_H
|
|
#define CGAL_MIN_CIRCLE_2_TRAITS_2_H
|
|
|
|
// includes
|
|
#ifndef CGAL_POINT_2_H
|
|
# include <CGAL/Point_2.h>
|
|
#endif
|
|
#ifndef CGAL_OPTIMISATION_CIRCLE_2_H
|
|
# include <CGAL/Optimisation_circle_2.h>
|
|
#endif
|
|
#ifndef CGAL_PREDICATES_ON_POINTS_2_H
|
|
# include <CGAL/predicates_on_points_2.h>
|
|
#endif
|
|
|
|
@<namespace begin>("CGAL")
|
|
|
|
// Class declarations
|
|
// ==================
|
|
@<Min_circle_2_traits_2 declarations>
|
|
|
|
// Class interface and implementation
|
|
// ==================================
|
|
@<Min_circle_2_traits_2 interface and implementation>
|
|
|
|
@<namespace end>("CGAL")
|
|
|
|
#endif // CGAL_MIN_CIRCLE_2_TRAITS_2_H
|
|
|
|
@<end of file line>
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Min_circle_2_adapterC2.h
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Min\_circle\_2\_adapterC2.h}
|
|
|
|
@file <include/CGAL/Min_circle_2_adapterC2.h> = @begin
|
|
@<file header>(
|
|
"include/CGAL/Min_circle_2_adapterC2.h",
|
|
"traits class adapter for 2D Smallest Enclosing Circle")
|
|
|
|
#ifndef CGAL_MIN_CIRCLE_2_ADAPTERC2_H
|
|
#define CGAL_MIN_CIRCLE_2_ADAPTERC2_H
|
|
|
|
// includes
|
|
#ifndef CGAL_OPTIMISATION_BASIC_H
|
|
# include <CGAL/Optimisation/basic.h>
|
|
#endif
|
|
|
|
@<namespace begin>("CGAL")
|
|
|
|
// Class declarations
|
|
// ==================
|
|
@<Min_circle_2_adapterC2 declarations>
|
|
|
|
// Class interface and implementation
|
|
// ==================================
|
|
@<Min_circle_2_adapterC2 interface and implementation>
|
|
|
|
// Nested type `Circle'
|
|
@<Min_circle_2_adapterC2 nested type `Circle'>
|
|
|
|
@<namespace end>("CGAL")
|
|
|
|
#endif // CGAL_MIN_CIRCLE_2_ADAPTERC2_H
|
|
|
|
@<end of file line>
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Min_circle_2_adapterH2.h
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Min\_circle\_2\_adapterH2.h}
|
|
|
|
@file <include/CGAL/Min_circle_2_adapterH2.h> = @begin
|
|
@<file header>(
|
|
"include/CGAL/Min_circle_2_adapterH2.h",
|
|
"traits class adapter for 2D Smallest Enclosing Circle")
|
|
|
|
#ifndef CGAL_MIN_CIRCLE_2_ADAPTERH2_H
|
|
#define CGAL_MIN_CIRCLE_2_ADAPTERH2_H
|
|
|
|
// includes
|
|
#ifndef CGAL_OPTIMISATION_BASIC_H
|
|
# include <CGAL/Optimisation/basic.h>
|
|
#endif
|
|
|
|
@<namespace begin>("CGAL")
|
|
|
|
// Class declarations
|
|
// ==================
|
|
@<Min_circle_2_adapterH2 declarations>
|
|
|
|
// Class interface and implementation
|
|
// ==================================
|
|
@<Min_circle_2_adapterH2 interface and implementation>
|
|
|
|
// Nested type `Circle'
|
|
@<Min_circle_2_adapterH2 nested type `Circle'>
|
|
|
|
@<namespace end>("CGAL")
|
|
|
|
#endif // CGAL_MIN_CIRCLE_2_ADAPTERH2_H
|
|
|
|
@<end of file line>
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! Min_circle_2_Window_stream.h
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{Min\_circle\_2\_Window\_stream.h}
|
|
|
|
@file <include/CGAL/IO/Min_circle_2_Window_stream.h> = @begin
|
|
@<file header>(
|
|
"include/CGAL/IO/Min_circle_2_Window_stream.h",
|
|
"graphical output to `leda_window' for Min_circle_2 algorith.")
|
|
|
|
// Each of the following operators is individually
|
|
// protected against multiple inclusion.
|
|
|
|
// Window_stream I/O operators
|
|
// ===========================
|
|
|
|
// Optimisation_circle_2
|
|
// ---------------------
|
|
@<Optimisation_circle_2 graphical output operator>
|
|
|
|
// Min_circle_2
|
|
// ------------
|
|
@<Min_circle_2 graphical output operator>
|
|
|
|
@<end of file line>
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! test_Min_circle_2.C
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection{test\_Min\_circle\_2.C}
|
|
|
|
@file <test/Min_circle_2/test_Min_circle_2.C> = @begin
|
|
@<file header>(
|
|
"test/Min_circle_2/test_Min_circle_2.C",
|
|
"test program for 2D Smallest Enclosing Circle")
|
|
|
|
@<Min_circle_2 test (includes and typedefs)>
|
|
|
|
// code coverage test function
|
|
// ---------------------------
|
|
@<Min_circle_2 test (code coverage test function)>
|
|
|
|
// point classes for adapters test
|
|
// -------------------------------
|
|
@<Min_circle_2 test (point classes)>
|
|
|
|
// main
|
|
// ----
|
|
int
|
|
main( int argc, char* argv[])
|
|
{
|
|
// command line options
|
|
// --------------------
|
|
// option `-verbose'
|
|
@<Min_circle_2 test (verbose option)>
|
|
|
|
// code coverage
|
|
// -------------
|
|
@<Min_circle_2 test (code coverage)>
|
|
|
|
// adapters test
|
|
// -------------
|
|
@<Min_circle_2 test (adapters test)>
|
|
|
|
// external test sets
|
|
// -------------------
|
|
@<Min_circle_2 test (external test sets)>
|
|
|
|
return( 0);
|
|
}
|
|
|
|
@<end of file line>
|
|
@end
|
|
|
|
@! ----------------------------------------------------------------------------
|
|
@! File Header
|
|
@! ----------------------------------------------------------------------------
|
|
|
|
\subsection*{File Header}
|
|
|
|
@i share/file_header.awi
|
|
|
|
And here comes the specific file header for the product files of this
|
|
web file.
|
|
|
|
@macro <file header>(2) many = @begin
|
|
@<copyright notice>
|
|
@<file name>(@1)
|
|
@<file description>(
|
|
"Min_circle_2",
|
|
"Geometric Optimisation",
|
|
"Min_circle_2",
|
|
"$Id$","$Date$",
|
|
"Sven Schönherr <sven@@inf.ethz.ch>, Bernd Gärtner",
|
|
"ETH Zürich (Bernd Gärtner <gaertner@@inf.ethz.ch>)",
|
|
"@2")
|
|
@end
|
|
|
|
@! ============================================================================
|
|
@! Bibliography
|
|
@! ============================================================================
|
|
|
|
\clearpage
|
|
\bibliographystyle{plain}
|
|
\bibliography{geom,../doc_tex/basic/Optimisation/cgal}
|
|
|
|
@! ===== EOF ==================================================================
|