diff --git a/Packages/Min_circle_2/web/Min_circle_2.aw b/Packages/Min_circle_2/web/Min_circle_2.aw index f8e8cf00caa..6f4b810c924 100644 --- a/Packages/Min_circle_2/web/Min_circle_2.aw +++ b/Packages/Min_circle_2/web/Min_circle_2.aw @@ -70,13 +70,13 @@ 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{CGAL_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. +in the plane. The class template \ccc{CGAL_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 @@ -90,7 +90,6 @@ checks. Finally the product files are created in Section~5. @! The Algorithm @! ============================================================================ -\setlength{\parskip}{0.8ex} \clearpage \section{The Algorithm} \label{sec:algo} @@ -155,12 +154,13 @@ in the \cgal\ Reference Manual. \renewcommand{\ccSection}{\ccSubsection} \renewcommand{\ccFont}{\tt} \renewcommand{\ccEndFont}{} -\ccSetThreeColumns{typedef Traits::Circle}{}{% +\ccSetThreeColumns{typedef CGAL_Point_2}{}{% creates a variable \ccc{min_circle} of type \ccc{CGAL_Min_circle_2}.} \ccPropagateThreeToTwoColumns -\input{../spec/Min_circle_2.tex} -\input{../spec/Min_circle_2_adapterC2.tex} -\input{../spec/Min_circle_2_adapterH2.tex} +\input{../../spec/Optimisation/Min_circle_2.tex} +\input{../../spec/Optimisation/Optimisation_circle_2.tex} +\input{../../spec/Optimisation/Min_circle_2_adapterC2.tex} +\input{../../spec/Optimisation/Min_circle_2_adapterH2.tex} @! ============================================================================ @! Implementations @@ -1174,6 +1174,336 @@ pseudocode above. } @end +@! ---------------------------------------------------------------------------- +@! Class template CGAL_Optimisation_circle_2 +@! ---------------------------------------------------------------------------- + +\subsection{Class template \ccFont CGAL\_Optimisation\_circle\_2} + +First, we declare the class template \ccc{CGAL_Optimisation_circle_2}, + +@macro = @begin + template < class _R > + class CGAL_Optimisation_circle_2; +@end + +\emph{Workaround:} The GNU compiler (g++ 2.7.2[.?]) does not accept types +with scope operator as argument type or return type in class template +member functions. Therefore, all member functions are implemented in +the class interface. + +The class interface looks as follows. + +@macro = @begin + template < class _R > + class CGAL_Optimisation_circle_2 { + public: + @ + + private: + // private data members + @ + + @ + + // Class implementation + // ==================== + + public: + // Set functions + // ------------- + @ + + // Access functions + // ---------------- + @ + + // Equality tests + // -------------- + @ + + // Predicates + // ---------- + @ + }; +@end + +@! ---------------------------------------------------------------------------- +\subsubsection{Public Interface} + +The functionality is described and documented in the specification +section, so we do not comment on it here. + +@macro = @begin + // types + typedef _R R; + typedef CGAL_Point_2 Point; + typedef typename _R::FT Distance; + + /************************************************************************** + WORKAROUND: The GNU compiler (g++ 2.7.2[.*]) does not accept types + with scope operator as argument type or return type in class template + member functions. Therefore, all member functions are implemented in + the class interface. + + // creation + void set( ); + void set( Point const& p); + void set( Point const& p, Point const& q); + void set( Point const& p, Point const& q, Point const& r); + void set( Point const& center, Distance const& squared_radius); + + // access functions + Point const& center ( ) const; + Distance const& squared_radius( ) const + + // equality tests + bool operator == ( CGAL_Optimisation_circle_2 const& c) const; + bool operator != ( CGAL_Optimisation_circle_2 const& c) const; + + // predicates + CGAL_Bounded_side bounded_side( Point const& p) const; + bool has_on_bounded_side ( Point const& p) const; + bool has_on_boundary ( Point const& p) const; + bool has_on_unbounded_side ( Point const& 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 = @begin + Point _center; + Distance _squared_radius; +@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 = @begin + inline + void + set( ) + { + _center = Point( CGAL_ORIGIN); + _squared_radius = -Distance( 1); + } + + inline + void + set( Point const& p) + { + _center = p; + _squared_radius = Distance( 0); + } + + inline + void + set( Point const& p, Point const& q) + { + _center = CGAL_midpoint( p, q); + _squared_radius = CGAL_squared_distance( p, _center); + } + + inline + void + set( Point const& p, Point const& q, Point const& r) + { + _center = CGAL_circumcenter( p, q, r); + _squared_radius = CGAL_squared_distance( p, _center); + } + + inline + void + set( Point const& center, Distance const& 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 = @begin + inline + Point const& + center( ) const + { + return( _center); + } + + inline + Distance const& + squared_radius( ) const + { + return( _squared_radius); + } +@end + +@! ---------------------------------------------------------------------------- +\subsubsection{Equality Tests} + +@macro = @begin + bool + operator == ( CGAL_Optimisation_circle_2 const& c) const + { + return( ( _center == c._center ) && + ( _squared_radius == c._squared_radius) ); + } + + bool + operator != ( CGAL_Optimisation_circle_2 const& c) const + { + return( ! operator==( c)); + } +@end + +@! ---------------------------------------------------------------------------- +\subsubsection{Predicates} + +The following predicates perform in-circle tests and check for +emptyness and degeneracy, resp. + +@macro = @begin + inline + CGAL_Bounded_side + bounded_side( Point const& p) const + { + return( CGAL_static_cast( CGAL_Bounded_side, + CGAL_sign( CGAL_squared_distance( p, _center) + - _squared_radius))); + } + + inline + bool + has_on_bounded_side( Point const& p) const + { + return( CGAL_squared_distance( p, _center) < _squared_radius); + } + + inline + bool + has_on_boundary( Point const& p) const + { + return( CGAL_squared_distance( p, _center) == _squared_radius); + } + + inline + bool + has_on_unbounded_side( Point const& 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 = @begin + template < class _R > + ostream& + operator << ( ostream& os, CGAL_Optimisation_circle_2<_R> const& c); + + template < class _R > + istream& + operator >> ( istream& is, CGAL_Optimisation_circle_2<_R> & c); +@end + +@macro = @begin + template < class _R > + ostream& + operator << ( ostream& os, CGAL_Optimisation_circle_2<_R> const& 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 _R > + istream& + operator >> ( istream& is, CGAL_Optimisation_circle_2<_R>& c) + { + typedef typename CGAL_Optimisation_circle_2<_R>::Point Point; + typedef typename CGAL_Optimisation_circle_2<_R>::Distance Distance; + + 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: { + 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 + @! ---------------------------------------------------------------------------- @! Class template CGAL_Min_circle_2_adapterC2 @! ---------------------------------------------------------------------------- @@ -2260,6 +2590,7 @@ To test the traits class adapters we use the code coverage test function. cover_Min_circle_2( verbose, AdapterC2(), Rt()); cover_Min_circle_2( verbose, AdapterH2(), Rt()); @end + @! ---------------------------------------------------------------------------- @! External Test Sets @! ---------------------------------------------------------------------------- @@ -2304,7 +2635,6 @@ end of each file. ++argv; } @end - @! ========================================================================== @! Files @! ========================================================================== @@ -2318,8 +2648,8 @@ end of each file. \subsection{Min\_circle\_2.h} -@file = @begin - @("include/CGAL/Min_circle_2.h") +@file <../../include/CGAL/Optimisation/Min_circle_2.h> = @begin + @("include/CGAL/Optimisation/Min_circle_2.h") #ifndef CGAL_MIN_CIRCLE_2_H #define CGAL_MIN_CIRCLE_2_H @@ -2368,8 +2698,8 @@ end of each file. \subsection{Min\_circle\_2.C} -@file = @begin - @("include/CGAL/Min_circle_2.C") +@file <../../include/CGAL/Optimisation/Min_circle_2.C> = @begin + @("include/CGAL/Optimisation/Min_circle_2.C") // Class implementation (continued) // ================================ @@ -2380,14 +2710,83 @@ end of each file. @ @end +@! ---------------------------------------------------------------------------- +@! Optimisation_circle_2.h +@! ---------------------------------------------------------------------------- + +\subsection{Optimisation\_circle\_2.h} + +@file <../../include/CGAL/Optimisation/Optimisation_circle_2.h> = @begin + @("include/CGAL/Optimisation/Optimisation_circle_2.h") + + #ifndef CGAL_OPTIMISATION_CIRCLE_2_H + #define CGAL_OPTIMISATION_CIRCLE_2_H + + // Class declaration + // ================= + @ + + // Class interface + // =============== + // includes + #ifndef CGAL_POINT_2_H + # include + #endif + #ifndef CGAL_BASIC_CONSTRUCTIONS_2_H + # include + #endif + #ifndef CGAL_SQUARED_DISTANCE_2_H + # include + #endif + + @ + + // Function declarations + // ===================== + // I/O + // --- + @ + + #ifdef CGAL_INCLUDE_TEMPLATE_CODE + # include + #endif + + #endif // CGAL_OPTIMISATION_CIRCLE_2_H + + @ +@end + +@! ---------------------------------------------------------------------------- +@! Optimisation_circle_2.C +@! ---------------------------------------------------------------------------- + +\subsection{Optimisation\_circle\_2.C} + +@file <../../include/CGAL/Optimisation/Optimisation_circle_2.C> = @begin + @("include/CGAL/Optimisation/Optimisation_circle_2.C") + + // Class implementation (continued) + // ================================ + // includes + #ifndef CGAL_OPTIMISATION_ASSERTIONS_H + # include + #endif + + // I/O + // --- + @ + + @ +@end + @! ---------------------------------------------------------------------------- @! Min_circle_2_adapterC2.h @! ---------------------------------------------------------------------------- \subsection{Min\_circle\_2\_adapterC2.h} -@file = @begin - @("include/CGAL/Min_circle_2_adapterC2.h") +@file <../../include/CGAL/Optimisation/Min_circle_2_adapterC2.h> = @begin + @("include/CGAL/Optimisation/Min_circle_2_adapterC2.h") #ifndef CGAL_MIN_CIRCLE_2_ADAPTERC2_H #define CGAL_MIN_CIRCLE_2_ADAPTERC2_H @@ -2422,8 +2821,8 @@ end of each file. \subsection{Min\_circle\_2\_adapterH2.h} -@file = @begin - @("include/CGAL/Min_circle_2_adapterH2.h") +@file <../../include/CGAL/Optimisation/Min_circle_2_adapterH2.h> = @begin + @("include/CGAL/Optimisation/Min_circle_2_adapterH2.h") #ifndef CGAL_MIN_CIRCLE_2_ADAPTERH2_H #define CGAL_MIN_CIRCLE_2_ADAPTERH2_H @@ -2458,8 +2857,8 @@ end of each file. \subsection{test\_Min\_circle\_2.C} -@file = @begin - @("test/test_Min_circle_2.C") +@file <../../test/Optimisation/test_Min_circle_2.C> = @begin + @("test/optimisation/test_Min_circle_2.C") @ @@ -2497,11 +2896,18 @@ end of each file. @ @end -@i file_header.awlib +@i ../file_header.awi @macro (1) many = @begin - @("2D Smallest Enclosing Circle",@1,"Min_circle_2", - "Bernd Gärtner, Sven Schönherr (sven@@inf.fu-berlin.de)", + @("2D Smallest Enclosing Circle",@1, + "Optimisation/Min_circle_2","Bernd Gärtner, Sven Schönherr", + "$Revision$","$Date$") +@end + +@macro (1) many = @begin + @("2D Optimisation Circle",@1, + "Optimisation/Optimisation_circle_2", + "Bernd Gärtner, Sven Schönherr", "$Revision$","$Date$") @end diff --git a/Packages/Min_ellipse_2/web/Min_ellipse_2.aw b/Packages/Min_ellipse_2/web/Min_ellipse_2.aw index bc60af789e0..b256d82224d 100644 --- a/Packages/Min_ellipse_2/web/Min_ellipse_2.aw +++ b/Packages/Min_ellipse_2/web/Min_ellipse_2.aw @@ -2,17 +2,27 @@ @! The CGAL Project @! Implementation: 2D Smallest Enclosing Ellipse @! ---------------------------------------------------------------------------- -@! file : Library/web/Min_ellipse_2.aw +@! file : web/Optimisation/Min_ellipse_2.aw @! author: Bernd Gärtner, Sven Schönherr (sven@inf.fu-berlin.de) -@! $Id$ +@! ---------------------------------------------------------------------------- +@! $Revision$ +@! $Date$ @! ============================================================================ +@p maximum_input_line_length = 180 +@p maximum_output_line_length = 180 + @documentclass[twoside]{article} +@usepackage[latin1]{inputenc} @usepackage{a4wide2} @usepackage{amssymb} +@usepackage{cc_manual} +@article + +\input{cprog.sty} +\setlength{\parskip}{1ex} @! LaTeX macros -\newcommand{\R}{\mathbb{R}} \newenvironment{pseudocode}[1]% {\vspace*{-0.5\baselineskip} \upshape \begin{tabbing} 99 \= bla \= bla \= bla \= bla \= bla \= bla \= bla \= bla \kill @@ -30,59 +40,77 @@ \newcommand{\RETURN}{\keyword{RETURN} } \newcommand{\me}{\texttt{me}} +\newcommand{\SaveSpaceByHand}[1]{#1} -@article -@p maximum_input_line_length = 180 -@p maximum_output_line_length = 180 +@! ============================================================================ +@! Title +@! ============================================================================ -@thickline +\RCSdef{\rcsrevision}{$Revision$} +\RCSdefDate{\rcsdate}{$Date$} @t vskip 5 mm -@t title titlefont centre "CGAL: 2D Smallest Enclosing Ellipse" +@t title titlefont centre "CGAL -- 2D Smallest Enclosing Ellipse*" @t vskip 1 mm @t title smalltitlefont centre "Implementation Documentation" @t vskip 8 mm -@t title smalltitlefont centre "Bernd Gärtner, Sven Schönherr" -@t title normalfont centre "$Revision$, $Date$" +@t title smalltitlefont centre "Bernd Gärtner and Sven Schönherr" +\smallskip +\centerline{\rcsrevision\ , \rcsdate} @t vskip 1 mm -@thickline -@thinline -@t table_of_contents - -@thinline +\renewcommand{\thefootnote}{\fnsymbol{footnote}} +\footnotetext[1]{This work was supported by the ESPRIT IV LTR Project + No.~21957 (CGAL).} @! ============================================================================ -@section{ Introduction} +@! Introduction and Contents @! ============================================================================ -We define a class template @prg{CGAL_Min_ellipse_2}. An object of -this class represents the smallest (w.r.t. area) enclosing ellipse of a -finite point set $P$ in the plane, denoted by $\me(P)$. The template -parameter of the representation class $R$ (the domain of the point -coordinates) is any number type that fulfills the CGAL number type -requirements, but correct results are in this version only guaranteed -if the number type is an exact one (like LEDA's @prg{integer}). In -particular, using the number type @prg{double} might lead to wrong -results. A correct @prg{double} implementation is planned for the next -release. +\section*{Introduction} -The implementation is based on an algorithm by Welzl \cite{Wel}, which -we shortly describe now. $\me(P)$ is built up incrementally, adding -one point after another. Assume $\me(P)$ has been constructed, and we -would like to obtain $\me(P \cup \{p\})$, $p$ some new point. There -are two cases: if $p$ already lies inside $\me(P)$, then $\me(P \cup -\{p\}) = \me(P)$. Otherwise $p$ must lie on the boundary of $\me(P -\cup \{p\})$ (this is proved in \cite{Wel} and not hard to see), so we -need to compute $\me(P,\{p\})$, the smallest ellipse enclosing $P$ with -$p$ on the boundary. This is recursively done in the same manner. In -general, for point sets $P$,$B$, define $\me(P,B)$ as the smallest -ellipse enclosing $P$ that has the points of $B$ on the boundary (if -defined). Although the algorithm finally delivers an ellipse -$\me(P,\emptyset)$, it internally deals with ellipses that have a -possibly nonempty set $B$. Here is the pseudocode of Welzl's method. -To compute $\me(P)$, it is called with the pair $(P,\emptyset)$, -assuming that $P=\{p_1,\ldots,p_n\}$ is stored in a linked list. +We provide an implementation of an optimisation algorithm for computing +the smallest (w.r.t.\ area) enclosing ellipse of a finite point set $P$ +in the plane. The class template \ccc{CGAL_Min_ellipse_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 +ellipse of a finite point set $P$ in the plane, denoted by $me(P)$, is +built up incrementally, adding one point after another. Assume $me(P)$ +has been constructed, and we would like to obtain $me(P \cup \{p\})$, $p$ +some new point. There are two cases: if $p$ already lies inside $me(P)$, +then $me(P \cup \{p\}) = me(P)$. Otherwise $p$ must lie on the boundary +of $me(P \cup \{p\})$ (this is proved in~\cite{w-sedbe-91a} and not hard +to see), so we need to compute $me(P,\{p\})$, the smallest ellipse +enclosing $P$ with $p$ on the boundary. This is recursively done in the +same manner. In general, for point sets $P$,$B$, define $me(P,B)$ as the +smallest ellipse enclosing $P$ that has the points of $B$ on the boundary +(if defined). Although the algorithm finally delivers a ellipse +$me(P,\emptyset)$, it internally deals with ellipses that have a possibly +nonempty set $B$. Here is the pseudocode of Welzl's method. To compute +$me(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}{$\me(P,B)$:} $me := \me(\emptyset,B)$ \\ @@ -96,180 +124,1396 @@ assuming that $P=\{p_1,\ldots,p_n\}$ is stored in a linked list. \RETURN $me$ \\ \end{pseudocode} -Note the following: (a) $|B|$ is always bounded by 5, thus the -computation of $\me(\emptyset,B)$ is a constant-time operation. -In our implementation, it -is done by the private member function @prg{compute_ellipse}. (b) One -can check that the method maintains the invariant `$\me(P,B)$ exists'. -This justifies termination if $|B| = 5$, because then $\me(P,B)$ must -be the unique ellipse with the points of $B$ on the boundary, and -$\me(P,B)$ exists if and only if this ellipse contains the points of -$P$. Thus, no subsequent in-ellipse tests are necessary anymore (for -details see \cite{Wel}). (c) points which are found to lie outside the -current ellipse $me$ are considered `important' and are moved to the -front of the linked list that stores $P$. This is crucial for the -method's efficiency. +Note the following: (a) $|B|$ is always bounded by 5, thus the computation of +$me(\emptyset,B)$ is easy. In our implementation, it is done by the private +member function \ccc{compute_ellipse}. (b) One can check that the method +maintains the invariant `$me(P,B)$ exists'. This justifies termination if +$|B| = 5$, because then $me(P,B)$ must be the unique ellipse with the points +of $B$ on the boundary, and $me(P,B)$ exists if and only if this ellipse +contains the points of $P$. Thus, no subsequent in-ellipse tests are +necessary anymore (for details see~\cite{w-sedbe-91a}). (c) points which are +found to lie outside the current ellipse $me$ 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. - -The private member function @prg{me} directly realizes the pseudocode -above. +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. @! ============================================================================ -@section{ Class \texttt{CGAL\_Min\_ellipse\_2}: Interface} +@! Specifications @! ============================================================================ +\clearpage +\section{Specifications} + +\emph{Note:} Below some references are undefined, they refer to sections +in the \cgal\ Reference Manual. + +\renewcommand{\ccSection}{\ccSubsection} +\renewcommand{\ccFont}{\tt} +\renewcommand{\ccEndFont}{} +\ccSetThreeColumns{typedef Traits::Ellipse}{}{% + creates a variable \ccc{min_ellipse} of type + \ccc{CGAL_Min_ellipse_2}.} +\ccPropagateThreeToTwoColumns +\input{../../spec/Optimisation/Min_ellipse_2.tex} +\input{../../spec/Optimisation/Min_ellipse_2_adapterC2.tex} +\input{../../spec/Optimisation/Min_ellipse_2_adapterH2.tex} + +@! ============================================================================ +@! Implementations +@! ============================================================================ + +\clearpage +\section{Implementations} + +@! ---------------------------------------------------------------------------- +@! Class template CGAL_Min_ellipse_2 +@! ---------------------------------------------------------------------------- + +\subsection{Class template \ccFont CGAL\_Min\_ellipse\_2} + +First, we declare the class template \ccc{CGAL_Min_ellipse_2}. + +@macro = @begin + template < class _Traits > + class CGAL_Min_ellipse_2; +@end + +The actual work of the algorithm is done in the private member +functions \ccc{me} and \ccc{compute_ellipse}. The former directly +realizes the pseudocode of $\me(P,B)$, the latter solves the basic +case $\me(\emptyset,B)$, see Section~\ref{sec:algo}. + +\emph{Workaround:} The GNU compiler (g++ 2.7.2[.?]) does not accept types +with scope operator as argument type or return type in class template +member functions. Therefore, all member functions are implemented in +the class interface. + The class interface looks as follows. @macro = @begin - template < class R > + template < class _Traits > class CGAL_Min_ellipse_2 { - public: - @ + @ private: - @ - @ - @ + // private data members + @ + + // copying and assignment not allowed! + CGAL_Min_ellipse_2( CGAL_Min_ellipse_2<_Traits> const&); + CGAL_Min_ellipse_2<_Traits>& + operator = ( CGAL_Min_ellipse_2<_Traits> const&); + + @ + + // Class implementation + // ==================== + + public: + // Access functions and predicates + // ------------------------------- + @ + + @ + + @ + + @ + + private: + // Privat member functions + // ----------------------- + @ + + @ + + public: + // Constructors + // ------------ + @ + + // Destructor + // ---------- + @ + + // Modifiers + // --------- + @ + + // Validity check + // -------------- + // Not yet implemented! + @! + + // Miscellaneous + // ------------- + @ }; @end -@! ============================================================================ -@subsection{ Public Interface} -@! ============================================================================ +@! ---------------------------------------------------------------------------- +\subsubsection{Public Interface} -The public interface is described and documented in the CGAL Reference -Manual, so we do not comment on it here. The interface is very similar -to the one of \texttt{CGAL\_Min\_circle\_2}. The major difference is -that no method exists to convert a \texttt{CGAL\_Min\_ellipse\_2} to -a \texttt{CGAL\_Ellipse\_2}, because this type does not exist yet. -Thus, the usage of \texttt{CGAL\_Min\_ellipse\_2} is restricted; in this -version, it can merely be drawn. Also, a bounding box and a check function -do not exist -in this version. To check, we would need to test the sign of a root of -a cubic equation; future releases of the LEDA-type \texttt{real} will -provide this feature, and we add a checker as soon as a stable version -is available. Thus, checking is done visually, by looking at the drawing. +The functionality is described and documented in the specification +section, so we do not comment on it here. + +@macro = @begin + // types + typedef _Traits Traits; + typedef typename _Traits::Point Point; + typedef typename _Traits::Ellipse Ellipse; + typedef typename list::const_iterator Point_iterator; + typedef const Point * Support_point_iterator; + + /************************************************************************** + WORKAROUND: The GNU compiler (g++ 2.7.2[.*]) does not accept types + with scope operator as argument type or return type in class template + member functions. Therefore, all member functions are implemented in + the class interface. -@macro = @begin // creation - CGAL_Min_ellipse_2( ); - CGAL_Min_ellipse_2( const CGAL_Point_2& p); - CGAL_Min_ellipse_2( const CGAL_Point_2& p1, - const CGAL_Point_2& p2); - CGAL_Min_ellipse_2( const CGAL_Point_2& p1, - const CGAL_Point_2& p2, - const CGAL_Point_2& p3); - CGAL_Min_ellipse_2( const CGAL_Point_2& p1, - const CGAL_Point_2& p2, - const CGAL_Point_2& p3, - const CGAL_Point_2& p4); - CGAL_Min_ellipse_2( const CGAL_Point_2& p1, - const CGAL_Point_2& p2, - const CGAL_Point_2& p3, - const CGAL_Point_2& p4, - const CGAL_Point_2& p5); - CGAL_Min_ellipse_2( const CGAL_Point_2* first, - const CGAL_Point_2* last, - bool randomize = false); + CGAL_Min_ellipse_2( const Point* first, + const Point* last, + bool randomize = false, + CGAL_Random& random = CGAL_random, + Traits const& traits = Traits()); + CGAL_Min_ellipse_2( list::const_iterator first, + list::const_iterator last, + bool randomize = false, + CGAL_Random& random = CGAL_random, + Traits const& traits = Traits()); + CGAL_Min_ellipse_2( istream_iterator first, + istream_iterator last, + bool randomize = false, + CGAL_Random& random = CGAL_random, + Traits const& traits = Traits()) + CGAL_Min_ellipse_2( Traits const& traits = Traits()); + CGAL_Min_ellipse_2( Point const& p, + Traits const& traits = Traits()); + CGAL_Min_ellipse_2( Point const& p, + Point const& q, + Traits const& traits = Traits()); + CGAL_Min_ellipse_2( Point const& p1, + Point const& p2, + Point const& p3, + Traits const& traits = Traits()); ~CGAL_Min_ellipse_2( ); - // access + // access functions int number_of_points ( ) const; int number_of_support_points( ) const; - const CGAL_Point_2& point ( int i) const; - const CGAL_Point_2& support_point( int i) const; - const CGAL_Point_2& operator [] ( int i) const; + Point_iterator points_begin( ) const; + Point_iterator points_end ( ) const; - // bounding box not supported in this version - // CGAL_Bbox_2 bbox( ) const; + Support_point_iterator support_points_begin( ) const; + Support_point_iterator support_points_end ( ) const; - // updates - void insert ( const CGAL_Point_2& p); - void reserve( int n); + Point const& support_point( int i) const; - // predicates; note: in-ellipse tests are non-const functions here - CGAL_Bounded_side bounded_side( const CGAL_Point_2& p) const; - bool has_on_bounded_side ( const CGAL_Point_2& p) const; - bool has_on_boundary ( const CGAL_Point_2& p) const; - bool has_on_unbounded_side ( const CGAL_Point_2& p) const; + Ellipse const& ellipse( ) const; + + // predicates + CGAL_Bounded_side bounded_side( Point const& p) const; + bool has_on_bounded_side ( Point const& p) const; + bool has_on_boundary ( Point const& p) const; + bool has_on_unbounded_side ( Point const& p) const; bool is_empty ( ) const; bool is_degenerate( ) const; + + // modifiers + void insert( Point const& p); + void insert( const Point* first, + const Point* last ); + void insert( list::const_iterator first, + list::const_iterator last ); + void insert( istream_iterator first, + istream_iterator last ); + void clear( ); + + // validity check + bool is_valid( bool verbose = false, int level = 0) const; + + // miscellaneous + Traits const& traits( ) const; + **************************************************************************/ @end @! ---------------------------------------------------------------------------- -@subsection{ Private Interface} +\subsubsection{Private Data Members} + +First, the traits class object is stored. + +@macro += @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 += @begin + list points; // doubly linked list of points +@end + +The support set $S$ of at most five 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 pseudocode +for $\me(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 += @begin + int n_support_points; // number of support points + Point* support_points; // array of support points +@end + +Finally, the actual ellipse is stored in a variable \ccc{ellipse} +provided by the traits class object, by the end of computation equal to +$me(P)$. During computation, \ccc{tco.ellipse} equals the ellipse $me$ +appearing in the pseudocode for $\me(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 ellipse $me(P)$ from a point set $P$, +given by a begin iterator and a past-the-end iterator. Usually this +would be done by a single template member function, but since most +compilers do not support this yet, we provide specialized constructors +for C~arrays (using pointers as iterators), for STL sequence containers +\ccc{vector} and \ccc{list} and for the STL input stream +iterator \ccc{istream_iterator}. Actually, the constructors for +a C~array and a \ccc{vector} are the same, since the random +access iterator of \ccc{vector} is implemented as \ccc{Point*}. + +All three 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 $me$ is called to +compute $me(P)=me(P,\emptyset)$. + +@macro += @begin + // STL-like constructor for C array and vector + CGAL_Min_ellipse_2( const Point* first, + const Point* last, + bool randomize = false, + CGAL_Random& random = CGAL_random, + Traits const& traits = Traits()) + : tco( traits) + { + // allocate support points' array + support_points = new Point[ 5]; + + // range not empty? + if ( ( last-first) > 0) { + + // store points + if ( randomize) { + + // shuffle points at random + vector v( first, last); + random_shuffle( v.begin(), v.end(), random); + copy( v.begin(), v.end(), back_inserter( points)); } + else + copy( first, last, back_inserter( points)); } + + // compute me + me( points.end(), 0); + } + + // STL-like constructor for list + CGAL_Min_ellipse_2( list::const_iterator first, + list::const_iterator last, + bool randomize = false, + CGAL_Random& random = CGAL_random, + Traits const& traits = Traits()) + : tco( traits) + { + // allocate support points' array + support_points = new Point[ 5]; + + // compute number of points + list::size_type n = 0; + CGAL__distance( first, last, n); + if ( n > 0) { + + // store points + if ( randomize) { + + // shuffle points at random + vector v; + v.reserve( n); + copy( first, last, back_inserter( v)); + random_shuffle( v.begin(), v.end(), random); + copy( v.begin(), v.end(), back_inserter( points)); } + else + copy( first, last, back_inserter( points)); } + + // compute me + me( points.end(), 0); + } + + // STL-like constructor for input stream iterator istream_iterator + CGAL_Min_ellipse_2( istream_iterator first, + istream_iterator last, + bool randomize = false, + CGAL_Random& random = CGAL_random, + Traits const& traits = Traits()) + : tco( traits) + { + // allocate support points' array + support_points = new Point[ 5]; + + // range not empty? + if ( first != last) { + + // store points + if ( randomize) { + + // shuffle points at random + vector v; + copy( first, last, back_inserter( v)); + random_shuffle( v.begin(), v.end(), random); + copy( v.begin(), v.end(), back_inserter( points)); } + else + copy( first, last, back_inserter( points)); } + + // compute me + me( points.end(), 0); + } + +@end + +The remaining constructors are actually specializations of the previous +ones, building the smallest enclosing ellipse for up to five points. +The idea is the following: recall that for any point set $P$ there +exists $S \subseteq P$, $|S| \leq 5$ with $me(S) = me(P)$ (in fact, +such a set $S$ is determined by the algorithm). Once $S$ has been +computed (or given otherwise), $me(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 5. +For $|S|=0$, we get the default constructor, building $me(\emptyset)$. + +@macro += @begin + + // default constructor + inline + CGAL_Min_ellipse_2( Traits const& traits = Traits()) + : tco( traits), n_support_points( 0) + { + // allocate support points' array + support_points = new Point[ 5]; + + // initialize ellipse + tco.ellipse.set(); + + CGAL_optimisation_postcondition( is_empty()); + } + + // constructor for one point + inline + CGAL_Min_ellipse_2( Point const& p, Traits const& traits = Traits()) + : tco( traits), points( 1, p), n_support_points( 1) + { + // allocate support points' array + support_points = new Point[ 5]; + + // initialize ellipse + support_points[ 0] = p; + tco.ellipse.set( p); + + CGAL_optimisation_postcondition( is_degenerate()); + } + + // constructor for two points + inline + CGAL_Min_ellipse_2( Point const& p, + Point const& q, + Traits const& traits = Traits()) + : tco( traits) + { + // allocate support points' array + support_points = new Point[ 5]; + + // store points + points.push_back( p); + points.push_back( q); + + // compute me + me( points.end(), 0); + } + + // constructor for three points + inline + CGAL_Min_ellipse_2( Point const& p1, + Point const& p2, + Point const& p3, + Traits const& traits = Traits()) + : tco( traits) + { + // allocate support points' array + support_points = new Point[ 5]; + + // store points + points.push_back( p1); + points.push_back( p2); + points.push_back( p3); + + // compute me + me( points.end(), 0); + } + + // constructor for four points + inline + CGAL_Min_ellipse_2( Point const& p1, + Point const& p2, + Point const& p3, + Point const& p4, + Traits const& traits = Traits()) + : tco( traits) + { + // allocate support points' array + support_points = new Point[ 5]; + + // store points + points.push_back( p1); + points.push_back( p2); + points.push_back( p3); + points.push_back( p4); + + // compute me + me( points.end(), 0); + } + + // constructor for five points + inline + CGAL_Min_ellipse_2( Point const& p1, + Point const& p2, + Point const& p3, + Point const& p4, + Point const& p5, + Traits const& traits = Traits()) + : tco( traits) + { + // allocate support points' array + support_points = new Point[ 5]; + + // store points + points.push_back( p1); + points.push_back( p2); + points.push_back( p3); + points.push_back( p4); + points.push_back( p3); + + // compute me + me( points.end(), 0); + } +@end + +The destructor only frees the memory of the support points' array. + +@macro = @begin + inline + ~CGAL_Min_ellipse_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{CGAL_Min_ellipse_2} object. They are all very +simple (and therefore \ccc{inline}) and mostly rely on corresponding +access functions of the data members of \ccc{CGAL_Min_ellipse_2}. + +First, we define the \ccc{number_of_...} methods. + +@macro = @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 += @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 + Point const& + 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{ellipse}. + +@macro += @begin + // ellipse + inline + Ellipse const& + ellipse( ) const + { + return( tco.ellipse); + } +@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 = @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-ellipse tests, based on the +corresponding predicates of class \ccc{Ellipse}. + +@macro = @begin + // in-ellipse test predicates + inline + CGAL_Bounded_side + bounded_side( Point const& p) const + { + return( tco.ellipse.bounded_side( p)); + } + + inline + bool + has_on_bounded_side( Point const& p) const + { + return( tco.ellipse.has_on_bounded_side( p)); + } + + inline + bool + has_on_boundary( Point const& p) const + { + return( tco.ellipse.has_on_boundary( p)); + } + + inline + bool + has_on_unbounded_side( Point const& p) const + { + return( tco.ellipse.has_on_unbounded_side( p)); + } +@end + +@! ---------------------------------------------------------------------------- +\subsubsection{Modifiers} + +There is another way to build up $me(P)$, other than by supplying +the point set $P$ at once. Namely, $me(P)$ can be built up +incrementally, adding one point after another. If you look at the +pseudocode in the introduction, this comes quite naturally. The +modifying method \ccc{insert}, applied with point $p$ to a +\ccc{CGAL_Min_ellipse_2} object representing $me(P)$, +computes $me(P \cup \{p\})$, where work has to be done only if $p$ +lies outside $me(P)$. In this case, $me(P \cup \{p\}) = me(P,\{p\})$ +holds, so the private member function \ccc{me} 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 pseudocode in +Section~\ref{sec:algo}. + +@macro += @begin + void + insert( Point const& p) + { + // p not in current ellipse? + if ( has_on_unbounded_side( p)) { + + // p new support point + support_points[ 0] = p; + + // recompute me + me( 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 would usually be done by a single template +member function, but since most compilers do not support this yet, we +provide specialized \ccc{insert} functions for C~arrays (using pointers +as iterators), for STL sequence containers \ccc{vector} and +\ccc{list} and for the STL input stream iterator +\ccc{istream_iterator}. Actually, the \ccc{insert} function for +a C~array and a \ccc{vector} are the same, since the random +access iterator of \ccc{vector} is implemented as \ccc{Point*}. + +The following \ccc{insert} functions perform for each point \ccc{p} in +the range $[\mbox{\ccc{first}},\mbox{\ccc{last}})$ a call \ccc{insert(p)}. + +@macro += @begin + inline + void + insert( const Point* first, const Point* last) + { + for ( ; first != last; ++first) + insert( *first); + } + + inline + void + insert( list::const_iterator first, + list::const_iterator last ) + { + for ( ; first != last; ++first) + insert( *first); + } + + inline + void + insert( istream_iterator first, + istream_iterator last ) + { + for ( ; first != last; ++first) + insert( *first); + } +@end + +The member function \ccc{clear} deletes all points from a +\ccc{CGAL_Min_ellipse_2} object and resets it to the +empty ellipse. + +@macro += @begin + void clear( ) + { + points.erase( points.begin(), points.end()); + n_support_points = 0; + tco.ellipse.set(); + } +@end + +@! ---------------------------------------------------------------------------- +\subsubsection{Miscellaneous} + +The member function \ccc{traits} returns a const reference to the +traits class object. + +@macro = @begin + inline + Traits const& + traits( ) const + { + return( tco); + } +@end + +@! ---------------------------------------------------------------------------- +\subsubsection{I/O} + +@macro = @begin + template < class _Traits > + ostream& operator << ( ostream& os, CGAL_Min_ellipse_2<_Traits> const& me); + + template < class _Traits > + istream& operator >> ( istream& is, CGAL_Min_ellipse_2<_Traits> & me); +@end + +@macro = @begin + template < class _Traits > + ostream& + operator << ( ostream& os, CGAL_Min_ellipse_2<_Traits> const& min_ellipse) + { + typedef typename CGAL_Min_ellipse_2<_Traits>::Point Point; + + switch ( CGAL_get_mode( os)) { + + case CGAL_IO::PRETTY: + os << endl; + os << "CGAL_Min_ellipse_2( |P| = "<< min_ellipse.number_of_points() + << ", |S| = " << min_ellipse.number_of_support_points() << endl; + os << " P = {" << endl; + os << " "; + copy( min_ellipse.points_begin(), min_ellipse.points_end(), + ostream_iterator( os, ",\n ")); + os << "}" << endl; + os << " S = {" << endl; + os << " "; + copy( min_ellipse.support_points_begin(), + min_ellipse.support_points_end(), + ostream_iterator( os, ",\n ")); + os << "}" << endl; + os << " ellipse = " << min_ellipse.ellipse() << endl; + os << ")" << endl; + break; + + case CGAL_IO::ASCII: + copy( min_ellipse.points_begin(), min_ellipse.points_end(), + ostream_iterator( os, "\n")); + break; + + case CGAL_IO::BINARY: + copy( min_ellipse.points_begin(), min_ellipse.points_end(), + ostream_iterator( os)); + break; + + default: + CGAL_optimisation_assertion_msg( false, + "CGAL_get_mode( os) invalid!"); + break; } + + return( os); + } + + template < class Traits > + istream& + operator >> ( istream& is, CGAL_Min_ellipse_2& min_ellipse) + { + 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 typename CGAL_Min_ellipse_2::Point Point; + typedef istream_iterator Is_it; + min_ellipse.clear(); + min_ellipse.insert( Is_it( is), Is_it()); + break; + + default: + CGAL_optimisation_assertion_msg( false, "CGAL_IO::mode invalid!"); + break; } + + return( is); + } +@end + +@! ---------------------------------------------------------------------------- +\subsubsection{Private Member Function {\ccFont compute\_ellipse}} + +This is the method for computing the basic case $\me(\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 5$. + +@macro = @begin + // compute_ellipse + inline + void + compute_ellipse( ) + { + switch ( n_support_points) { + case 5: + tco.ellipse.set( support_points[ 0], + support_points[ 1], + support_points[ 2], + support_points[ 3], + support_points[ 4]); + break; + case 4: + tco.ellipse.set( support_points[ 0], + support_points[ 1], + support_points[ 2], + support_points[ 3]); + break; + case 3: + tco.ellipse.set( support_points[ 0], + support_points[ 1], + support_points[ 2]); + break; + case 2: + tco.ellipse.set( support_points[ 0], support_points[ 1]); + break; + case 1: + tco.ellipse.set( support_points[ 0]); + break; + case 0: + tco.ellipse.set( ); + break; + default: + CGAL_optimisation_assertion( ( n_support_points >= 0) && + ( n_support_points <= 5) ); } + } +@end + +@! ---------------------------------------------------------------------------- +\subsubsection{Private Member Function {\ccFont me}} + +This function computes the general ellipse $me(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 modelled after the +pseudocode above. + +@macro = @begin + void + me( Point_iterator const& last, int n_sp) + { + // compute ellipse through support points + n_support_points = n_sp; + compute_ellipse(); + if ( n_sp == 5) return; + + // test first n points + list::iterator point_iter( points.begin()); + for ( ; last != point_iter; ) { + Point const& p( *point_iter); + + // p not in current ellipse? + if ( has_on_unbounded_side( p)) { + + // recursive call with p as additional support point + support_points[ n_sp] = p; + me( point_iter, n_sp+1); + + // move current point to front + if ( point_iter != points.begin()) { // p not first? + points.push_front( p); + points.erase( point_iter++); } + else + ++point_iter; } + else + ++point_iter; } + } +@end + +@! ============================================================================ +@! Tests +@! ============================================================================ + +\clearpage +\section{Test} + +We test \ccc{CGAL_Min_ellipse_2} with the traits class implementation +for optimisation algorithms, using exact arithmetic, i.e.\ Cartesian +representation with number type \ccc{CGAL_Quotient} and +homogeneous representation with number type \ccc{CGAL_Gmpz}. + +@macro = @begin + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + typedef CGAL_Gmpz Rt; + typedef CGAL_Quotient< CGAL_Gmpz > Ft; + + typedef CGAL_Cartesian< Ft > RepC; + typedef CGAL_Homogeneous< Rt > RepH; + typedef CGAL_Optimisation_traits_2< RepC > TraitsC; + typedef CGAL_Optimisation_traits_2< RepH > TraitsH; +@end + +The command line option \ccc{-verbose} enables verbose output. + +@macro = @begin + bool verbose = false; + if ( ( argc > 1) && ( strcmp( argv[ 1], "-verbose") == 0)) { + verbose = true; + --argc; + ++argv; } +@end + +@! ---------------------------------------------------------------------------- +@! Code Coverage @! ---------------------------------------------------------------------------- -The private member functions @prg{compute_ellipse} and @prg{me} -are in detail described in the implementation section below. +\subsection{Code Coverage} -@macro = @begin - // copying and assignment not allowed! - CGAL_Min_ellipse_2( const CGAL_Min_ellipse_2&); - CGAL_Min_ellipse_2& operator = ( const CGAL_Min_ellipse_2&); +We call each function of class \ccc{CGAL_Min_ellipse_2} at least +once to ensure code coverage. - // functions for actual computation - void me( int n, int n_sp); - void compute_ellipse( ); +@macro = @begin + cover_Min_ellipse_2( verbose, TraitsC(), Rt()); + cover_Min_ellipse_2( verbose, TraitsH(), Rt()); @end -Now let us focus on the private classes and data members, where the -difference to the -class @prg{CGAL_Min_circle_2} is most apparant. The linked list -to store the points, however, is still the same. +@macro = @begin + template < class Traits, class RT > + void + cover_Min_ellipse_2( bool verbose, Traits const&, RT const&) + { + typedef CGAL_Min_ellipse_2< Traits > Min_ellipse; + typedef Min_ellipse::Point Point; + typedef Min_ellipse::Ellipse Ellipse; -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. The linked -list is realized as an STL-@prg{vector} whose entries are points with -successor and predecessor information, realized in the class -@prg{_Point}. + CGAL_Verbose_ostream verr( verbose); -@macro += @begin - // doubly linked list element, used for move-to-front heuristic - class _Point { - public: - CGAL_Point_2 point; - int pred, succ; - _Point( ) { } - _Point( const CGAL_Point_2& _point, int _pred = -1, int _succ = -1) - : point( _point), pred( _pred), succ( _succ) - { } - }; + // 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))); + if ( verbose) + for ( i = 0; i < n; ++i) + cerr << i << ": " << random_points[ i] << endl; + + // cover code + verr << endl << "default constructor..."; + { + Min_ellipse me; + bool is_valid = me.is_valid( verbose); + bool is_empty = me.is_empty(); + assert( is_valid); + assert( is_empty); + } + + verr << endl << "one point constructor..."; + { + Min_ellipse me( random_points[ 0]); + bool is_valid = me.is_valid( verbose); + bool is_degenerate = me.is_degenerate(); + assert( is_valid); + assert( is_degenerate); + } + + verr << endl << "two points constructor..."; + { + Min_ellipse me( random_points[ 1], + random_points[ 2]); + bool is_valid = me.is_valid( verbose); + assert( is_valid); + assert( me.number_of_points() == 2); + } + + verr << endl << "three points constructor..."; + { + Min_ellipse me( random_points[ 3], + random_points[ 4], + random_points[ 5]); + bool is_valid = me.is_valid( verbose); + assert( is_valid); + assert( me.number_of_points() == 3); + } + + verr << endl << "four points constructor..."; + { + Min_ellipse me( random_points[ 6], + random_points[ 7], + random_points[ 8], + random_points[ 9]); + bool is_valid = me.is_valid( verbose); + assert( is_valid); + assert( me.number_of_points() == 4); + } + + verr << endl << "five points constructor..."; + { + Min_ellipse me( random_points[ 10], + random_points[ 11], + random_points[ 12], + random_points[ 13], + random_points[ 14]); + bool is_valid = me.is_valid( verbose); + assert( is_valid); + assert( me.number_of_points() == 5); + } + + verr << endl << "Point* constructor..."; + Min_ellipse me( random_points, random_points+9); + { + Min_ellipse me2( random_points, random_points+9, true); + bool is_valid = me .is_valid( verbose); + bool is_valid2 = me2.is_valid( verbose); + assert( is_valid); + assert( is_valid2); + assert( me .number_of_points() == 9); + assert( me2.number_of_points() == 9); + assert( me.ellipse() == me2.ellipse()); + } + + verr << endl << "list::const_iterator constructor..."; + { + Min_ellipse me1( me.points_begin(), me.points_end()); + Min_ellipse me2( me.points_begin(), me.points_end(), true); + bool is_valid1 = me1.is_valid( verbose); + bool is_valid2 = me2.is_valid( verbose); + assert( is_valid1); + assert( is_valid2); + assert( me1.number_of_points() == 9); + assert( me2.number_of_points() == 9); + assert( me.ellipse() == me1.ellipse()); + assert( me.ellipse() == me2.ellipse()); + } + + verr << endl << "#points already called above."; + + verr << endl << "points access already called above."; + + verr << endl << "support points access..."; + { + Point support_point; + Min_ellipse::Support_point_iterator + iter( me.support_points_begin()); + for ( i = 0; i < me.number_of_support_points(); ++i, ++iter) { + support_point = me.support_point( i); + assert( support_point == *iter); } + Min_ellipse::Support_point_iterator + end_iter( me.support_points_end()); + assert( iter == end_iter); + } + + verr << endl << "ellipse access already called above..."; + + verr << endl << "in-ellipse 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 = me.bounded_side( p); + has_on_bounded_side = me.has_on_bounded_side( p); + has_on_boundary = me.has_on_boundary( p); + has_on_unbounded_side = me.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..."; + me.insert( random_points[ 9]); + { + bool is_valid = me.is_valid( verbose); + assert( is_valid); + assert( me.number_of_points() == 10); + } + + verr << endl << "Point* insert..."; + me.insert( random_points+10, random_points+n); + { + bool is_valid = me.is_valid( verbose); + assert( is_valid); + assert( me.number_of_points() == n); + } + + verr << endl << "list::const_iterator insert..."; + { + Min_ellipse me2; + me2.insert( me.points_begin(), me.points_end()); + bool is_valid = me2.is_valid( verbose); + assert( is_valid); + assert( me2.number_of_points() == n); + + verr << endl << "clear..."; + me2.clear(); + is_valid = me2.is_valid( verbose); + bool is_empty = me2.is_empty(); + assert( is_valid); + assert( is_empty); + } + + verr << endl << "validity check already called several times."; + + verr << endl << "traits class access..."; + { + Traits traits( me.traits()); + } + + verr << endl << "I/O..."; + { + verr << endl << " writing `test_Min_ellipse_2.ascii'..."; + ofstream os( "test_Min_ellipse_2.ascii"); + CGAL_set_ascii_mode( os); + os << me; + } + { + verr << endl << " writing `test_Min_ellipse_2.pretty'..."; + ofstream os( "test_Min_ellipse_2.pretty"); + CGAL_set_pretty_mode( os); + os << me; + } + { + verr << endl << " writing `test_Min_ellipse_2.binary'..."; + ofstream os( "test_Min_ellipse_2.binary"); + CGAL_set_binary_mode( os); + os << me; + } + { + verr << endl << " reading `test_Min_ellipse_2.ascii'..."; + Min_ellipse me_in; + ifstream is( "test_Min_ellipse_2.ascii"); + CGAL_set_ascii_mode( is); + is >> me_in; + bool is_valid = me_in.is_valid( verbose); + assert( is_valid); + assert( me_in.number_of_points() == n); + assert( me_in.ellipse() == me.ellipse()); + } + verr << endl; + } @end -Here is the vector @prg{points} itself, along with an index -@prg{i_first_point} in @prg{points} referring to the current front -element of the linked list. +@! ---------------------------------------------------------------------------- +@! External Test Sets +@! ---------------------------------------------------------------------------- -@macro += @begin - vector< _Point > points; - int i_first_point; +\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 = @begin + while ( argc > 1) { + + typedef CGAL_Min_ellipse_2< TraitsH > Min_ellipse; + typedef Min_ellipse::Point Point; + typedef Min_ellipse::Ellipse Ellipse; + + CGAL_Verbose_ostream verr( verbose); + + // read points from file + verr << endl << "input file: `" << argv[ 1] << "'" << flush; + + list points; + int n, x, y; + 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_ellipse + Min_ellipse me2( points.begin(), points.end()); + bool is_valid = me2.is_valid( verbose); + assert( is_valid); + + // next file + --argc; + ++argv; } @end -A @prg{CGAL_Min_ellipse_2} object maintains an array -@prg{support_points} of at most five \emph{support points} (the -actual number is given by @prg{n_support_points}, which at the end of -the computation contains the indices of a minimal subset $S \subseteq -P$ with $\me(P)= \me(S)$. (Note: that subset is not necessarily -\emph{minimum}). During the computations, the set of support points -coincides with the set $B$ appearing in the pseudocode for $\me(P,B)$, -see the introduction above. +@! ========================================================================== +@! Files +@! ========================================================================== -@macro += @begin - int n_support_points; - CGAL_Point_2 support_points[ 5]; +\clearpage +\section{Files} + +@! ---------------------------------------------------------------------------- +@! Min_ellipse_2.h +@! ---------------------------------------------------------------------------- + +\subsection{Min\_ellipse\_2.h} + +@file <../../include/CGAL/Optimisation/Min_ellipse_2.h> = @begin + @("include/CGAL/Optimisation/Min_ellipse_2.h") + + #ifndef CGAL_MIN_ELLIPSE_2_H + #define CGAL_MIN_ELLIPSE_2_H + + // Class declaration + // ================= + @ + + // Class interface + // =============== + // includes + #ifndef CGAL_RANDOM_H + # include + #endif + #ifndef CGAL_OPTIMISATION_ASSERTIONS_H + # include + #endif + #ifndef CGAL_OPTIMISATION_MISC_H + # include + #endif + #include + #include + #include + #include + + @ + + // Function declarations + // ===================== + // I/O + // --- + @ + + #ifdef CGAL_INCLUDE_TEMPLATE_CODE + # include + #endif + + #endif // CGAL_MIN_ELLIPSE_2_H + + @ @end -Most important, a @prg{CGAL_Min_ellipse_2} object at any time +@! ---------------------------------------------------------------------------- +@! Min_ellipse_2.C +@! ---------------------------------------------------------------------------- + +\subsection{Min\_ellipse\_2.C} + +@file <../../include/CGAL/Optimisation/Min_ellipse_2.C> = @begin + @("include/CGAL/Optimisation/Min_ellipse_2.C") + + // Class implementation (continued) + // ================================ + // I/O + // --- + @ + + @ +@end + +@i ../file_header.awi + +@macro (1) many = @begin + @("2D Smallest Enclosing Ellipse",@1, + "Optimisation/Min_ellipse_2", + "Bernd Gärtner, Sven Schönherr", + "$Revision$","$Date$") +@end + +@! ---------------------------------------------------------------------------- +@! test_Min_ellipse_2.C +@! ---------------------------------------------------------------------------- + +\subsection{test\_Min\_ellipse\_2.C} + +@file <../../test/Optimisation/test_Min_ellipse_2.C> = @begin + @("test/Optimisation/test_Min_ellipse_2.C") + + @ + + // code coverage test function + // --------------------------- + @ + + // main + // ---- + int + main( int argc, char* argv[]) + { + // command line options + // -------------------- + // option `-verbose' + @ + + // code coverage + // ------------- + @ + + // external test sets + // ------------------- + @ + } + + @ +@end + +@! ============================================================================ +@! Bibliography +@! ============================================================================ + +\clearpage +\bibliographystyle{plain} +\bibliography{geom,cgal} + +@! ===== EOF ================================================================== + +\clearpage + +@section{OLD} +@subsection{old} + +Most important, a \ccc{CGAL_Min_ellipse_2} object at any time keeps the actual ellipse $\me(\emptyset,B)$. Unlike in the class -@prg{CGAL_Min_circle_2}, this is not a @prg{CGAL_Ellipse_2}, on +\ccc{CGAL_Min_ellipse_2}, this is not a \ccc{CGAL_Ellipse_2}, on the one hand, because this type does not exist yet, on the other hand because the representation of $\me(\emptyset,B)$ is different for any number of support points. For $|B|=3,5$, we store an explicit @@ -282,14 +1526,14 @@ from the set $B$. Although at any point in time, only one representation is valid and will be accessed, all three representations (for $|B|=3,4,5$) -are simultaneously stored in a @prg{CGAL_Min_ellipse_2} object. Since +are simultaneously stored in a \ccc{CGAL_Min_ellipse_2} object. Since none of them is really space-consuming, this is not a problem. (Unions, which would be just the right concept in this situation, are not allowed to be used with classes as members, even if the respective constructors do absolutely nothing). Each representation has its own class. -@macro += @begin +@macro zero += @begin @ @ @ @@ -297,7 +1541,7 @@ class. Here are the actual representations. -@macro += @begin +@macro zero += @begin Ellipse_3 ellipse_3; Ellipse_4 ellipse_4; Ellipse_5 ellipse_5; @@ -309,13 +1553,13 @@ Here are the actual representations. @! ---------------------------------------------------------------------------- \label{ellipse_rep} We have three classes, -@prg{Ellipse_3}, @prg{Ellipse_4} and @prg{Ellipse_5}, being in charge -of sets $B$ with 3,4, or 5 points. All classes have a method @prg{set} to +\ccc{Ellipse_3}, \ccc{Ellipse_4} and \ccc{Ellipse_5}, being in charge +of sets $B$ with 3,4, or 5 points. All classes have a method \ccc{set} to compute some representation of $\me(\emptyset,B)$, suitable to do in-ellipse tests `$p\in \me(\emptyset,B)$'. To perform these tests, each class has a -@prg{bounded_side} method. +\ccc{bounded_side} method. -@macro = @begin +@macro zero = @begin class Ellipse_3 { public: @ @@ -341,7 +1585,7 @@ tests `$p\in \me(\emptyset,B)$'. To perform these tests, each class has a }; @end -@macro = @begin +@macro zero = @begin class Ellipse_4 { public: @ @@ -367,17 +1611,17 @@ tests `$p\in \me(\emptyset,B)$'. To perform these tests, each class has a }; @end -The class @prg{Ellipse_5} does not have a method to compute the ellipse +The class \ccc{Ellipse_5} does not have a method to compute the ellipse from its five support points. The reason is that by the time an -@prg{Ellipse_5} object is set up, the ellipse through the five points -has already been computed and stored in the @prg{Ellipse_4} representation, +\ccc{Ellipse_5} object is set up, the ellipse through the five points +has already been computed and stored in the \ccc{Ellipse_4} representation, see implementation section below. Thus it suffices to `steal' this ellipse. -To this end, a reference to the @prg{Ellipse_4} object is passed to the -@prg{set} method. Because the ellipse in question is computed by the -@prg{bounded_side} method of the @prg{Ellipse_4} class, the latter method -is not a @prg{const} method, unlike all other @prg{bounded_side} methods. +To this end, a reference to the \ccc{Ellipse_4} object is passed to the +\ccc{set} method. Because the ellipse in question is computed by the +\ccc{bounded_side} method of the \ccc{Ellipse_4} class, the latter method +is not a \ccc{const} method, unlike all other \ccc{bounded_side} methods. -@macro = @begin +@macro zero = @begin class Ellipse_5 { public: @ @@ -408,192 +1652,18 @@ is not a @prg{const} method, unlike all other @prg{bounded_side} methods. The implementation consists of several parts, each of which is described in the sequel. The actual work is hidden in the member -functions @prg{set} and @prg{bounded_side} of the ellipse +functions \ccc{set} and \ccc{bounded_side} of the ellipse representation classes. The remaining functions -- in particular -the private member functions @prg{me} and @prg{compute_ellipse} -- are +the private member functions \ccc{me} and \ccc{compute_ellipse} -- are implemented completely similar to the corresponding functions of the -class @prg{CGAL_Min_circle_2}. An exception are the predicates for -the in-ellipse tests. In @prg{CGAL_Min_circle_2}, the in-circle predicates +class \ccc{CGAL_Min_ellipse_2}. An exception are the predicates for +the in-ellipse tests. In \ccc{CGAL_Min_ellipse_2}, the in-ellipse predicates were directly mapped to the corresponding predicates over the -@prg{CGAL_circle_2} object stored in the class. In our case, -the @prg{bounded_side} method is mapped to the corresponding one +\ccc{CGAL_ellipse_2} object stored in the class. In our case, +the \ccc{bounded_side} method is mapped to the corresponding one of the respective ellipse representation class (and evaluated directly -if the current ellipse $me$ is defined by less than three points); the predicates (@prg{has_on_bounded_side}, \ldots) are then implemented by -directly referring to the @prg{bounded_side} method. - -@macro = @begin - @ - @ - @ - @ -@end - -@! ---------------------------------------------------------------------------- -@subsection{ Constructors} -@! ---------------------------------------------------------------------------- - -In this version, @prg{CGAL_Min_ellipse_2} has seven different -construction methods, where the most important one builds the -@prg{CGAL_Min_ellipse_2} $\me(P)$ from a point set $P$, stored in a -piece of memory delimited by two pointers (As soon as member templates -are available, the pointers will become iterators). The constructor -copies the points into the internal array @prg{points}, performs a -random reordering if the corresponding flag requires that, then builds -up the linked list over the point set, and finally calls the private -method $\me$ to compute $\me(P)=\me(P,\emptyset)$. - -@macro += @begin - // constructors - // ------------ - template < class R > - CGAL_Min_ellipse_2:: - CGAL_Min_ellipse_2( const CGAL_Point_2* first, - const CGAL_Point_2* last, - bool randomize) - { - // store points - int n = 0; - distance( first, last, n); - if ( n > 0) { - points.reserve( n); - copy( first, last, back_inserter( points)); - - // shuffle points at random - if ( randomize) - random_shuffle( points.begin(), points.end()); - - // link points - for ( int i = 0; i < number_of_points(); ++i) { - points[ i].pred = i-1; - points[ i].succ = i+1; } - points[ 0].pred = points[ number_of_points()-1].succ = -1; - i_first_point = 0; } - else - i_first_point = -1; - - // compute me - me( points.size(), 0); - } -@end - -The remaining constructors are actually specializations of the -previous one, building a @prg{CGAL_Min_ellipse_2} for up to five -points. The idea is the following: recall that for any point set $P$ -there exists $S \subseteq P$, $|S| \leq 5$ with $\me(S) = \me(P)$ (in -fact, such a set $S$ is determined during a @prg{CGAL_Min_ellipse_2} -computation). Once $S$ has been computed (or given otherwise), -$\me(P)$ can easily be reconstructed from $S$ in constant time. To -make this reconstruction more convenient, specialized construction -methods are available for point sets $P$ of size at most 5. For $|P| = 0$, -we get the default constructor, building the empty @prg{CGAL_Min_ellipse_2} -$\me(\emptyset)$. - -@macro += @begin - - // default constructor - template < class R > - CGAL_Min_ellipse_2:: - CGAL_Min_ellipse_2( ) - : i_first_point( -1), - n_support_points( 0) - { } - - // constructor for one point - template < class R > - CGAL_Min_ellipse_2:: - CGAL_Min_ellipse_2( const CGAL_Point_2& p) - : points( 1, _Point( p)), - i_first_point( 0), - n_support_points( 1) - { - support_points[ 0] = p; - } - - // constructor for two points - template < class R > - CGAL_Min_ellipse_2:: - CGAL_Min_ellipse_2( const CGAL_Point_2& p1, const CGAL_Point_2& p2) - { - // store points - points.reserve( 2); - points.push_back( _Point( p1, -1, 1)); - points.push_back( _Point( p2, 0, -1)); - i_first_point = 0; - - // compute me - me( 2, 0); - } - - // constructor for three points - template < class R > - CGAL_Min_ellipse_2:: - CGAL_Min_ellipse_2( const CGAL_Point_2& p1, - const CGAL_Point_2& p2, - const CGAL_Point_2& p3) - { - // store points - points.reserve( 3); - points.push_back( _Point( p1, -1, 1)); - points.push_back( _Point( p2, 0, 2)); - points.push_back( _Point( p3, 1, -1)); - i_first_point = 0; - - // compute me - me( 3, 0); - } - - // constructor for four points - template < class R > - CGAL_Min_ellipse_2:: - CGAL_Min_ellipse_2( const CGAL_Point_2& p1, - const CGAL_Point_2& p2, - const CGAL_Point_2& p3, - const CGAL_Point_2& p4) - { - // store points - points.reserve( 4); - points.push_back( _Point( p1, -1, 1)); - points.push_back( _Point( p2, 0, 2)); - points.push_back( _Point( p3, 1, 3)); - points.push_back( _Point( p3, 2, -1)); - i_first_point = 0; - - // compute me - me( 4, 0); - } - - // constructor for five points - template < class R > - CGAL_Min_ellipse_2:: - CGAL_Min_ellipse_2( const CGAL_Point_2& p1, - const CGAL_Point_2& p2, - const CGAL_Point_2& p3, - const CGAL_Point_2& p4, - const CGAL_Point_2& p5) - { - // store points - points.reserve( 5); - points.push_back( _Point( p1, -1, 1)); - points.push_back( _Point( p2, 0, 2)); - points.push_back( _Point( p3, 1, 3)); - points.push_back( _Point( p3, 2, 4)); - points.push_back( _Point( p3, 3, -1)); - i_first_point = 0; - - // compute me - me( 5, 0); - } -@end - -Finally, we have a (default) destructor. - -@macro += @begin - // destructor - template < class R > - CGAL_Min_ellipse_2:: - ~CGAL_Min_ellipse_2( ) - { } -@end +if the current ellipse $me$ is defined by less than three points); the predicates (\ccc{has_on_bounded_side}, \ldots) are then implemented by +directly referring to the \ccc{bounded_side} method. @! ---------------------------------------------------------------------------- @subsection{ Update operations} @@ -602,8 +1672,8 @@ Finally, we have a (default) destructor. There is another way to build up $\me(P)$, other than by supplying the point set $P$ at once. Namely, $\me(P)$ can be built up incrementally, adding one point after another. If you look at the pseudocode in the -introduction, this comes quite naturally. The method @prg{insert}, -applied with point $p$ to a @prg{CGAL_Min_ellipse_2} object +introduction, this comes quite naturally. The method \ccc{insert}, +applied with point $p$ to a \ccc{CGAL_Min_ellipse_2} object representing $\me(P)$, computes $\me(P \cup \{p\})$, where work has to be done only if $p$ lies outside $\me(P)$. In this case, $\me(P \cup \{p\}) = \me(P,\{p\})$ holds, so the method $\me$ is called with @@ -611,7 +1681,7 @@ support set $\{p\}$. After the insertion has been performed, $p$ is moved to the front of the point list, just like in the pseudocode and the `main' constructor above. -@macro += @begin +@macro zero += @begin // update operations // ----------------- template < class R > @@ -629,7 +1699,7 @@ the `main' constructor above. // p new support point support_points[ 0] = p; - // recompute mc + // recompute me me( old_n, 1); } // make p the first point in list @@ -640,11 +1710,11 @@ the `main' constructor above. } @end -The operation @prg{reserve} does nothing but tell the -@prg{CGAL_Min_ellipse_2} that some number $n$ of points might +The operation \ccc{reserve} does nothing but tell the +\ccc{CGAL_Min_ellipse_2} that some number $n$ of points might eventually be inserted, allowing the object to allocate storage for them at once. Inserting the points without doing this might lead to -overhead caused by moving the array @prg{points} around in memory +overhead caused by moving the array \ccc{points} around in memory while it grows. @macro += @begin @@ -662,95 +1732,23 @@ while it grows. @subsection{ Access Operations and Predicates} @! ---------------------------------------------------------------------------- -These operations are used to retrieve information about the current -status of the @prg{CGAL_Min_ellipse_2} object. We first have -operations to get information about points or support points and -their numbers. - -@macro += @begin - // 'number_of_' operations - // ----------------------- - template < class R > inline - int - CGAL_Min_ellipse_2:: - number_of_points( ) const - { - return( points.size()); - } - - template < class R > inline - int - CGAL_Min_ellipse_2:: - number_of_support_points( ) const - { - return( n_support_points); - } - - // 'is_' predicates - // ---------------- - template < class R > inline - bool - CGAL_Min_ellipse_2:: - is_empty( ) const - { - return( number_of_support_points() == 0); - } - - template < class R > inline - bool - CGAL_Min_ellipse_2:: - is_degenerate( ) const - { - return( number_of_support_points() < 3); - } - - // access operations - // ----------------- - template < class R > inline - const CGAL_Point_2& - CGAL_Min_ellipse_2:: - point( int i) const - { - CGAL_Min_ellipse_2_precondition( (i >= 0) && (i < number_of_points())); - return( points[ i].point); - } - - template < class R > inline - const CGAL_Point_2& - CGAL_Min_ellipse_2:: - support_point( int i) const - { - CGAL_Min_ellipse_2_precondition( (i >= 0) && - (i < number_of_support_points())); - return( support_points[ i]); - } - - template < class R > inline - const CGAL_Point_2& - CGAL_Min_ellipse_2:: - operator [] ( int i) const - { - return( point( i)); - } -@end - Next we have predicates testing the relative position of a point -w.r.t. the ellipse. They rely on the @prg{bounded_side} method +w.r.t. the ellipse. They rely on the \ccc{bounded_side} method which for less than 3 support points is evaluated directly, while for at least three support points, the corresponding methods of the ellipse representation classes are used. A degenerate ellipse defined by less than two support points has no bounded side. In this case, the ellipse itself is the boundary, everything else -belongs to the unbounded side. Note that the @prg{bounded_side} method -is a @prg{const} method although the underlying method of the class -@prg{Ellipse_4} is not. The difference is that, `from the outside', the -@prg{CGAL_Min_ellipse_2} object appears unchanged after calling -@prg{bounded_side} (logical constness), while internally, -we explicitly make use of the changes to an @prg{Ellipse_4} object -caused by a call to @prg{bounded_side}, see the discussion in +belongs to the unbounded side. Note that the \ccc{bounded_side} method +is a \ccc{const} method although the underlying method of the class +\ccc{Ellipse_4} is not. The difference is that, `from the outside', the +\ccc{CGAL_Min_ellipse_2} object appears unchanged after calling +\ccc{bounded_side} (logical constness), while internally, +we explicitly make use of the changes to an \ccc{Ellipse_4} object +caused by a call to \ccc{bounded_side}, see the discussion in subsection \ref{ellipse_rep}. -@macro += @begin +@macro zero += @begin // in-ellipse predicates // ------------------- template < class R > inline @@ -793,44 +1791,20 @@ subsection \ref{ellipse_rep}. break; } } - - template < class R > inline - bool - CGAL_Min_ellipse_2:: - has_on_bounded_side( const CGAL_Point_2& p) const - { - return( bounded_side( p) == CGAL_ON_BOUNDED_SIDE); - } - - template < class R > inline - bool - CGAL_Min_ellipse_2:: - has_on_boundary( const CGAL_Point_2& p) const - { - return( bounded_side( p) == CGAL_ON_BOUNDARY); - } - - template < class R > inline - bool - CGAL_Min_ellipse_2:: - has_on_unbounded_side( const CGAL_Point_2& p) const - { - return( bounded_side( p) == CGAL_ON_UNBOUNDED_SIDE); - } @end - + @! ---------------------------------------------------------------------------- @subsection{ Private Member Function \texttt{compute\_ellipse}} @! ---------------------------------------------------------------------------- This is the method for computing $me(\emptyset,B)$ the set $B$ given -by the first @prg{n_support_points} indices in the array -@prg{i_support_points}. It is realized by a case analysis, +by the first \ccc{n_support_points} indices in the array +\ccc{i_support_points}. It is realized by a case analysis, noting that $|B| \leq 5$. If $|B|\leq 2$, nothing is done, -in the other cases the @prg{set} methods for @prg{Ellipse_3}, -@prg{Ellipse_4}, or @prg{Ellipse_5} are called. +in the other cases the \ccc{set} methods for \ccc{Ellipse_3}, +\ccc{Ellipse_4}, or \ccc{Ellipse_5} are called. -@macro += @begin +@macro zero += @begin template < class R > void CGAL_Min_ellipse_2:: @@ -856,56 +1830,6 @@ in the other cases the @prg{set} methods for @prg{Ellipse_3}, } @end - -@! ---------------------------------------------------------------------------- -@subsection{ Private Member Function \texttt{me}} -@! ---------------------------------------------------------------------------- - -This function computes the general ellipse $\me(P,B)$, where $P$ -contains the first @prg{n} points stored in the array @prg{points} and -$B$ is given by the first @prg{n_support_points} indices in the array -@prg{i_support_points}. The function is directly modelled after the -pseudocode in the introduction. - -@macro += @begin - - template < class R > - void - CGAL_Min_ellipse_2:: - me( int n, int n_sp) - { - // compute ellipse through support points - n_support_points = n_sp; - compute_ellipse( ); - if ( n_sp == 5) return; - - // test first n points - int index = i_first_point, succ; - for ( int i = 0; i < n; ++i) { - _Point& p = points[ index]; - succ = p.succ; - - // p not in current ellipse? - if ( has_on_unbounded_side( p.point)) { - - // recursive call with p as additional support point - support_points[ n_sp] = p.point; - me( i, n_sp+1); - - // move current point to front - if ( index != i_first_point) { // p not first? - points[ p.pred].succ = succ; - if ( succ != -1) // p not last? - points[ succ].pred = p.pred; - points[ i_first_point].pred = index; - p.pred = -1; - p.succ = i_first_point; - i_first_point = index; } } - // next point - index = succ; } - } -@end - @! ---------------------------------------------------------------------------- @subsection{ Class \texttt{Conic}} @! ---------------------------------------------------------------------------- @@ -913,7 +1837,7 @@ pseudocode in the introduction. In their implementations, the ellipse representation classes rely on a concept more general than ellipses, namely on {\em conics}. Ellipses are special conics, in addition there are {\em hyperbolas} and {\em parabolas}. -Conics play a particularly important role in the @prg{Ellipse_4} class. +Conics play a particularly important role in the \ccc{Ellipse_4} class. A conic (in linear form) is the set of points $q=(x,y)^T$ satisfying \begin{equation} @@ -950,7 +1874,7 @@ is positive definite afterwards (which is important for doing in-ellipse tests, see subsequent subsections). \end{itemize} -@macro = @begin +@macro zero = @begin template class Conic { public: @@ -1019,7 +1943,7 @@ $c\in \R^2$ the center. For support points $p_1,p_2,p_3$, the ellipse is given by $$c=\frac{1}{3}\sum_{i=1}^3p_i,\quad M^{-1} = \frac{2}{3}\sum_{i=1}^3(p_i-c)(p_i-c)^T, \quad z = 1,$$ -see \cite{GS}. +see \cite{gs-seefe-97}. Let $$M^{-1} = \frac{2}{3} \left(\begin{array}{cc} m_{11} & m_{12} \\ m_{12} & m_{22} @@ -1047,13 +1971,13 @@ which is equal in sign to the fact that $M$ is positive definite, hence $\det(M),\det(M')$ and $\det(M'^{-1})$ are positive.) If $z'$ denotes $2(m_{11}m_{22}-m_{12}^2)/3$, an -@prg{Ellipse_3} object stores the values +\ccc{Ellipse_3} object stores the values $c, z', m_{11},2m_{12},m_{22}$. This enables the subsequent -@prg{bounded_side} routine to perform the in-ellipse test by +\ccc{bounded_side} routine to perform the in-ellipse test by just evaluating the sign of (\ref{ellipse_3_test}). -@macro = @begin +@macro zero = @begin R::FT cx; R::FT cy; R::FT z; @@ -1069,7 +1993,7 @@ just evaluating the sign of (\ref{ellipse_3_test}). Using the formulas above, the private data members are straightforward to set. -@macro = @begin +@macro zero = @begin R::FT x1 = p1.x(); R::FT y1 = p1.y(); R::FT x2 = p2.x(); @@ -1111,7 +2035,7 @@ $$(x-c_x,y-c_y)^T \left(\begin{array}{cc} m_{22} & -m_{12} \\ -m_{12} & m_{11} \end{array}\right) (x-c_x,y-c_y) - z' \left\{\begin{array}{c}<\\=\\> \end{array}\right. 0.$$ -@macro = @begin +@macro zero = @begin R::FT x = p.x(); R::FT y = p.y(); R::FT x_cx = x-cx; @@ -1126,8 +2050,8 @@ $$(x-c_x,y-c_y)^T \left(\begin{array}{cc} m_{22} & -m_{12} \\ -m_{12} & m_{11} @! ---------------------------------------------------------------------------- This is by far the most complicated one among the three representation -classes. The @prg{set} method computes some implicit representation of -the ellipse, derived from the four support points. The @prg{bounded_side} +classes. The \ccc{set} method computes some implicit representation of +the ellipse, derived from the four support points. The \ccc{bounded_side} predicate works over this implicit representation and is not straightforward anymore. @@ -1153,7 +2077,7 @@ swap points $p_1$ and $p_2$. If $p_1,p_4$ lie on the same side of $\overline{p_3p_2}$, then $\overline{p_1p_2}$ must be a diagonal. For the correct order, we swap $p_2$ and $p_3$. -@macro = @begin +@macro zero = @begin // copy p_i's to allow swapping CGAL_Point_2 q1 = p1; CGAL_Point_2 q2 = p2; @@ -1182,7 +2106,7 @@ the correct order, we swap $p_2$ and $p_3$. @ @end -In all terminology that follows, we refer to \cite{GS}. +In all terminology that follows, we refer to \cite{gs-epsee-97,gs-seefe-97}. The implicit representation of $\me(\emptyset,\{p_1,p_2,p_3,p_4\})$ first of all consists of two special conics ${\cal C}_1,{\cal C}_2$ through the for points. @@ -1207,14 +2131,14 @@ and \end{eqnarray*} ${\cal C}_1$ and ${\cal C}_2$ are stored as data members in an -@prg{Ellipse_4} object. +\ccc{Ellipse_4} object. -@macro += @begin +@macro zero += @begin Conic conic1; Conic conic2; @end -@macro += @begin +@macro zero += @begin // point coordinates R::FT x1 = q1.x(); R::FT y1 = q1.y(); @@ -1258,7 +2182,8 @@ In addition, we store values that are needed to perform the in-ellipse test w.r.t. $\me(\emptyset,\{p_1,p_2,p_3,p_4\})$, given a fifth point $p$. Some of these values are independent of $p$, they are computed here. -In \cite{GS} it is shown that the unique conic ${\cal C}_0$ through $\{p_1,p_2,p_3,p_4,p\}$ is given by +In \cite{gs-epsee-97,gs-seefe-97} it is shown that the unique conic +${\cal C}_0$ through $\{p_1,p_2,p_3,p_4,p\}$ is given by $$\lambda_0 {\cal C}_1 + \mu_0 {\cal C}_2, $$ where $\lambda_0,\mu_0$ are given by $\lambda_0 = {\cal C}_2(p), \mu_0 = -{\cal C}_1(p).$ @@ -1316,7 +2241,7 @@ with \begin{eqnarray*} \end{eqnarray*} $\alpha = \det({\cal C}_1), \gamma = \det({\cal C}_2), \beta = r_1s_2+r_2s_1-2t_1t_2$. -This ellipse is stored as another conic in @prg{Ellipse_4}. +This ellipse is stored as another conic in \ccc{Ellipse_4}. @macro += @begin Conic ellipse; @@ -1339,13 +2264,13 @@ This ellipse is stored as another conic in @prg{Ellipse_4}. Given a fifth point $p$, the first action is to compute the unique conic ${\cal C}_0$ through $p_1,p_2,p_3,p_4,p$, as already described in the previous subsubsection. Since ${\cal C}_0$ is possibly being -recycled for usage in the @prg{Ellipse_5} class later, we need to -store it. Thus, ${\cal C}_0$ is the only data member of @prg{Ellipse_4} +recycled for usage in the \ccc{Ellipse_5} class later, we need to +store it. Thus, ${\cal C}_0$ is the only data member of \ccc{Ellipse_4} that is not independent of the query point $p$. (For this reason, the -@prg{bounded_side} method is not a @prg{const} method; moreover, the change -to the @prg{Ellipse_4} object caused by calling the method does not fall +\ccc{bounded_side} method is not a \ccc{const} method; moreover, the change +to the \ccc{Ellipse_4} object caused by calling the method does not fall under logical constness, because the change becomes quite visible when -${\cal C}_0$ is later passed to the @prg{set} method of @prg{Ellipse_5}.) +${\cal C}_0$ is later passed to the \ccc{set} method of \ccc{Ellipse_5}.) @macro += @begin Conic conic0; @@ -1354,7 +2279,7 @@ ${\cal C}_0$ is later passed to the @prg{set} method of @prg{Ellipse_5}.) Depending on the type of ${\cal C}_0$ (given by its determinant), different actions are taken. -@macro = @begin +@macro zero = @begin R::FT lambda_0 = conic2.eval(p); R::FT mu_0 = -conic1.eval(p); conic0.set (lambda_0, conic1, mu_0, conic2); @@ -1368,11 +2293,11 @@ different actions are taken. @end In the hyperbola/parabola case, we test $p$ against the ellipse -$E$ precomputed by the @prg{Ellipse_4} @prg{set} method, and just return +$E$ precomputed by the \ccc{Ellipse_4} \ccc{set} method, and just return the result (which is the same for all ellipses, in particular for $\me(\emptyset,B)$). -@macro = @begin +@macro zero = @begin R::FT discr = ellipse.eval(p); return static_cast (CGAL_Bounded_side, CGAL_sign (discr)); @end @@ -1389,7 +2314,7 @@ E^{\tau}(p) &=& \end{eqnarray*} This means, $$\rho = \lambda_0r_1 + \mu_0r_2 = r_0.$$ -@macro += @begin +@macro zero += @begin R::FT rho = conic0.r; @end @@ -1449,7 +2374,7 @@ Z' &=& u'Z_1 + uZ_1' + v'Z_2 + v Z_2'. Evaluated for $\tau=0$, all these values can be computed from $r(0),s(0),t(0),u(0),v(0),w(0)$ (the defining values of the conic ${\cal C}_0$) and their corresponding primed values which have already -been computed by the @prg{set} method. $d(0)=\det({\cal C}_0)$ is already +been computed by the \ccc{set} method. $d(0)=\det({\cal C}_0)$ is already defined, the other values follow (recall that $r'(0)=0$). For all this, ${\cal C}_0$ is assumed to be normalized. @@ -1466,7 +2391,7 @@ ${\cal C}_0$ is assumed to be normalized. @end The sign of $f(0)$ is the one we are interested in. We deduce -from \cite{GS} that +from \cite{gs-epsee-97,gs-seefe-97} that $$p \left\{\begin{array}{c} {\rm inside} \\ {\rm on} \\ {\rm outside} \end{array}\right\} E^* \Leftrightarrow \rho~f(0) \left\{\begin{array}{c}< 0 \\ = 0 \\ > 0 @@ -1487,147 +2412,23 @@ $B$ attains cardinality five only if previously, a point $p$ was found to lie outside $\me(\emptyset,\{p_1,p_2,p_3,p_4\})$, $\{p_1,p_2,p_3,p_4\}$ the support set at that time. However, during this test with $p$, the unique conic (which is then an ellipse) through -$\{p_1,p_2,p_3,p_4,p\}$ has already been computed by the @prg{Ellipse_4} +$\{p_1,p_2,p_3,p_4,p\}$ has already been computed by the \ccc{Ellipse_4} representation. In fact, it is the conic ${\cal C}_0$ addressed in the previous subsection, and it suffices to store a pointer to it in the -@prg{Ellipse_5} object, which is then initialized by the @prg{set} method. +\ccc{Ellipse_5} object, which is then initialized by the \ccc{set} method. -@macro = @begin +@macro zero = @begin Conic* ellipse; @end -@macro = @begin +@macro zero = @begin ellipse = &(ellipse_4.conic0); @end -The @prg{bounded_side} method is then straightforward, noting that the -ellipse has already been normalized by @prg{ellipse_4}. +The \ccc{bounded_side} method is then straightforward, noting that the +ellipse has already been normalized by \ccc{ellipse_4}. -@macro = @begin +@macro zero = @begin R::FT discr = (*ellipse).eval(p); return static_cast (CGAL_Bounded_side, CGAL_sign (discr)); @end - -@! ========================================================================== -@section{ File Organisation} -@! ========================================================================== - -@file = @begin - @("2D Smallest Enclosing Ellipse", - "include/CGAL/Min_ellipse_2.h","Min_ellipse_2", - "Bernd Gärtner, Sven Schönherr (sven@@inf.fu-berlin.de)") - #ifndef CGAL_MIN_ELLIPSE_2_H - #define CGAL_MIN_ELLIPSE_2_H - - // check macros - // ------------ - #ifdef CGAL_CHECK_ASSERTIONS - #define CGAL_Min_ellipse_2_assertion(EX) \ - ((EX) ? ((void)0) : cgal_assertion_fail( #EX , __FILE__, __LINE__, NULL)) - #define CGAL_Min_ellipse_2_assertion_msg(EX,MSG) \ - ((EX) ? ((void)0) : cgal_assertion_fail( #EX , __FILE__, __LINE__, MSG)) - #else - #define CGAL_Min_ellipse_2_assertion(EX) ((void)0) - #define CGAL_Min_ellipse_2_assertion_msg(EX,MSG) ((void)0) - #endif // CGAL_CHECK_ASSERTIONS - - #ifdef CGAL_CHECK_PRECONDITIONS - #define CGAL_Min_ellipse_2_precondition(EX) \ - ((EX) ? ((void)0) : cgal_precondition_fail( #EX , __FILE__, __LINE__, NULL)) - #define CGAL_Min_ellipse_2_precondition_msg(EX,MSG) \ - ((EX) ? ((void)0) : cgal_precondition_fail( #EX , __FILE__, __LINE__, MSG)) - #else - #define CGAL_Min_ellipse_2_precondition(EX) ((void)0) - #define CGAL_Min_ellipse_2_precondition_msg(EX,MSG) ((void)0) - #endif // CGAL_CHECK_PRECONDITIONS - - #ifdef CGAL_CHECK_POSTCONDITIONS - #define CGAL_Min_ellipse_2_postcondition(EX) \ - ((EX) ? ((void)0) : cgal_postcondition_fail( #EX , __FILE__, __LINE__, NULL)) - #define CGAL_Min_ellipse_2_postcondition_msg(EX,MSG) \ - ((EX) ? ((void)0) : cgal_postcondition_fail( #EX , __FILE__, __LINE__, MSG)) - #else - #define CGAL_Min_ellipse_2_postcondition(EX) ((void)0) - #define CGAL_Min_ellipse_2_postcondition_msg(EX,MSG) ((void)0) - #endif // CGAL_CHECK_POSTCONDITIONS - - - // workaround for new C++-style casts - // ---------------------------------- - #if (__SUNPRO_CC) - #define static_cast(type,expr) (type)( expr) - #define const_cast(type,expr) (type)( expr) - #define reinterpret_cast(type,expr) (type)( expr) - #define dynamic_cast(type,expr) (type)( expr) - #else - #define static_cast(type,expr) static_cast< type>( expr) - #define const_cast(type,expr) const_cast< type>( expr) - #define reinterpret_cast(type,expr) reinterpret_cast< type>( expr) - #define dynamic_cast(type,expr) dynamic_cast< type>( expr) - #endif // (__SUNPRO_CC) - - - // Class declaration - // ================= - template < class R > - class CGAL_Min_ellipse_2; - - // class CGAL_Bbox_2; - - // Class interface - // =============== - // includes - #ifndef CGAL_POINT_2_H - #include - #endif - #include - - @ - - @ - - // Class definition - // ================ - // includes - // -------- - #ifndef CGAL_PREDICATES_ON_POINTS_2_H - #include - #endif - #ifndef CGAL_UTILS_H - #include - #endif - #include - #include - - @ - - // specialization does not exist yet - // --------------------------------- - // #if ( defined( CGAL_INTEGER_H) && defined( CGAL_HOMOGENEOUS_H)) - // #include - // #endif - - // Conic class definition - @ - - #endif // CGAL_MIN_ELLIPSE_2_H - - @ -@end - -@i file_header.awlib - -\begin{thebibliography}{Wel} -\bibitem{GS} -B.~G{\"a}rtner and S.~Sch{\"o}nherr. -\newblock Smallest enclosing ellipses -- fast end exact. -\newblock Manuscript, 1997 - -\bibitem{Wel} -E.~Welzl. -\newblock Smallest enclosing disks (balls and ellipsoids). -\newblock In H.~Maurer, editor, {\em New Results and New Trends in Computer - Science}, volume 555 of {\em Lecture Notes in Computer Science}, pages - 359--370. Springer-Verlag, 1991. -\end{thebibliography} - diff --git a/Packages/Random_numbers/web/Random.aw b/Packages/Random_numbers/web/Random.aw index c9f9161f00c..3b9a7587e8f 100644 --- a/Packages/Random_numbers/web/Random.aw +++ b/Packages/Random_numbers/web/Random.aw @@ -2,7 +2,7 @@ @! The CGAL Project @! Implementation: Random Numbers Generator @! ---------------------------------------------------------------------------- -@! file : Kernel/web/Random.aw +@! file : web/Random/Random.aw @! author: Sven Schönherr (sven@inf.fu-berlin.de) @! ---------------------------------------------------------------------------- @! $Revision$ @@ -74,7 +74,7 @@ created in Section~4. \renewcommand{\ccEndFont}{} \ccSetThreeColumns{CGAL_Random}{random.restore_seed( Seed seed)}{} \ccPropagateThreeToTwoColumns -\input{../spec/Random.tex} +\input{../spec/Random/Random.tex} @! ============================================================================ @! Implementation @@ -361,8 +361,8 @@ numbers. \clearpage \section{Files} -@file = @begin - @("include/CGAL/Random.h") +@file = @begin + @("include/CGAL/Random/Random.h") #ifndef CGAL_RANDOM_H #define CGAL_RANDOM_H @@ -398,7 +398,7 @@ numbers. @ @end -@file = @begin +@file = @begin @("src/Random.C") #include @@ -418,8 +418,8 @@ numbers. @ @end -@file = @begin - @("test/test_Random.C") +@file = @begin + @("test/Random/test_Random.C") #include #include @@ -433,7 +433,7 @@ numbers. @ @end -@i file_header.awlib +@i file_header.awi @macro (1) many = @begin @("Random Numbers Generator",@1,"Random",