// Copyright (c) 1997-2001 // ETH Zurich (Switzerland). All rights reserved. // // This file is part of CGAL (www.cgal.org). // // $URL: https://github.com/CGAL/cgal/blob/v5.1/Bounding_volumes/include/CGAL/Min_circle_2.h $ // $Id: Min_circle_2.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // // // Author(s) : Sven Schoenherr , Bernd Gaertner #ifndef CGAL_MIN_CIRCLE_2_H #define CGAL_MIN_CIRCLE_2_H #include // includes # include # include # include # include # include # include # include namespace CGAL { // Class declaration // ================= template < class Traits_ > class Min_circle_2; // Class interface // =============== template < class Traits_ > class Min_circle_2 { public: // types typedef Traits_ Traits; typedef typename Traits_::Point Point; typedef typename Traits_::Circle Circle; typedef typename std::list::const_iterator Point_iterator; typedef const Point * Support_point_iterator; /************************************************************************** WORKAROUND: Some compilers are unable to match member functions defined outside the class template. Therefore, all member functions are implemented in the class interface. // creation template < class InputIterator > Min_circle_2( InputIterator first, InputIterator last, bool randomize = false, Random& random = get_default_random(), const Traits& traits = Traits()); Min_circle_2( const Traits& traits = Traits()); Min_circle_2( const Point& p, const Traits& traits = Traits()); Min_circle_2( Point p, Point q, const Traits& traits = Traits()); Min_circle_2( const Point& p1, const Point& p2, const Point& p3, const Traits& traits = Traits()); ~Min_circle_2( ); // access functions int number_of_points ( ) const; int number_of_support_points( ) const; Point_iterator points_begin( ) const; Point_iterator points_end ( ) const; Support_point_iterator support_points_begin( ) const; Support_point_iterator support_points_end ( ) const; const Point& support_point( int i) const; const Circle& circle( ) const; // predicates Bounded_side bounded_side( const Point& p) const; bool has_on_bounded_side ( const Point& p) const; bool has_on_boundary ( const Point& p) const; bool has_on_unbounded_side ( const Point& p) const; bool is_empty ( ) const; bool is_degenerate( ) const; // modifiers void insert( const Point& p); void insert( const Point* first, const Point* last ); void insert( std::list::const_iterator first, std::list::const_iterator last ); void insert( std::istream_iterator first, std::istream_iterator last ); void clear( ); // validity check bool is_valid( bool verbose = false, int level = 0) const; // miscellaneous const Traits& traits( ) const; **************************************************************************/ private: // private data members Traits tco; // traits class object std::list points; // doubly linked list of points std::size_t n_support_points; // number of support points Point* support_points; // array of support points // copying and assignment not allowed! Min_circle_2( const Min_circle_2&); Min_circle_2& operator = ( const Min_circle_2&); // ============================================================================ // Class implementation // ==================== public: // Access functions and predicates // ------------------------------- // #points and #support points inline std::size_t number_of_points( ) const { return( points.size()); } inline std::size_t number_of_support_points( ) const { return( n_support_points); } // is_... predicates inline bool is_empty( ) const { return( number_of_support_points() == 0); } inline bool is_degenerate( ) const { return( number_of_support_points() < 2); } // access to points and support points inline Point_iterator points_begin( ) const { return( points.begin()); } inline Point_iterator points_end( ) const { return( points.end()); } inline Support_point_iterator support_points_begin( ) const { return( support_points); } inline Support_point_iterator support_points_end( ) const { return( support_points+n_support_points); } // random access for support points inline const Point& support_point( std::size_t i) const { CGAL_optimisation_precondition(i < number_of_support_points()); return( support_points[ i]); } // circle inline const Circle& circle( ) const { return( tco.circle); } // in-circle test predicates inline CGAL::Bounded_side bounded_side( const Point& p) const { return( tco.circle.bounded_side( p)); } inline bool has_on_bounded_side( const Point& p) const { return( tco.circle.has_on_bounded_side( p)); } inline bool has_on_boundary( const Point& p) const { return( tco.circle.has_on_boundary( p)); } inline bool has_on_unbounded_side( const Point& p) const { return( tco.circle.has_on_unbounded_side( p)); } private: // Private member functions // ------------------------ // compute_circle inline void compute_circle( ) { switch ( n_support_points) { case 3: tco.circle.set( support_points[ 0], support_points[ 1], support_points[ 2]); break; case 2: tco.circle.set( support_points[ 0], support_points[ 1]); break; case 1: tco.circle.set( support_points[ 0]); break; case 0: tco.circle.set( ); break; default: CGAL_optimisation_assertion( n_support_points <= 3 ); } } void mc( const Point_iterator& last, std::size_t n_sp) { // compute circle through support points n_support_points = n_sp; compute_circle(); if ( n_sp == 3) return; // test first n points typename std::list::iterator point_iter = points.begin(); for ( ; last != point_iter; ) { const Point& p = *point_iter; // p not in current circle? if ( has_on_unbounded_side( p)) { // recursive call with p as additional support point support_points[ n_sp] = p; mc( point_iter, n_sp+1); // move current point to front points.splice( points.begin(), points, point_iter++); } else ++point_iter; } } public: // Constructors // ------------ // STL-like constructor (member template) template < class InputIterator > Min_circle_2( InputIterator first, InputIterator last, bool randomize #if !defined(_MSC_VER) || _MSC_VER > 1300 = false #endif , Random& random = get_default_random(), const Traits& traits = Traits()) : tco( traits) { // allocate support points' array support_points = new Point[ 3]; // range of points not empty? if ( first != last) { // store points if ( randomize) { // shuffle points at random std::vector v( first, last); CGAL::cpp98::random_shuffle( v.begin(), v.end(), random); std::copy( v.begin(), v.end(), std::back_inserter( points)); } else std::copy( first, last, std::back_inserter( points)); } // compute mc mc( points.end(), 0); } // default constructor inline Min_circle_2( const Traits& traits = Traits()) : tco( traits), n_support_points( 0) { // allocate support points' array support_points = new Point[ 3]; // initialize circle tco.circle.set(); CGAL_optimisation_postcondition( is_empty()); } // constructor for one point inline Min_circle_2( const Point& p, const Traits& traits = Traits()) : tco( traits), points( 1, p), n_support_points( 1) { // allocate support points' array support_points = new Point[ 3]; // initialize circle support_points[ 0] = p; tco.circle.set( p); CGAL_optimisation_postcondition( is_degenerate()); } // constructor for two points // This was const Point& but then Intel 7.0/.net2003 messes it up // with the constructor taking an iterator range inline Min_circle_2( Point p1, Point p2, const Traits& traits = Traits()) : tco( traits) { // allocate support points' array support_points = new Point[ 3]; // store points points.push_back( p1); points.push_back( p2); // compute mc mc( points.end(), 0); } // constructor for three points inline Min_circle_2( const Point& p1, const Point& p2, const Point& p3, const Traits& traits = Traits()) : tco( traits) { // allocate support points' array support_points = new Point[ 3]; // store points points.push_back( p1); points.push_back( p2); points.push_back( p3); // compute mc mc( points.end(), 0); } // Destructor // ---------- inline ~Min_circle_2( ) { // free support points' array delete[] support_points; } // Modifiers // --------- void insert( const Point& p) { // p not in current circle? if ( has_on_unbounded_side( p)) { // p new support point support_points[ 0] = p; // recompute mc mc( points.end(), 1); // store p as the first point in list points.push_front( p); } else // append p to the end of the list points.push_back( p); } template < class InputIterator > void insert( InputIterator first, InputIterator last) { for ( ; first != last; ++first) insert( *first); } void clear( ) { points.erase( points.begin(), points.end()); n_support_points = 0; tco.circle.set(); } // Validity check // -------------- bool is_valid( bool verbose = false, int level = 0) const { using namespace std; CGAL::Verbose_ostream verr( verbose); verr << endl; verr << "CGAL::Min_circle_2::" << endl; verr << "is_valid( true, " << level << "):" << endl; verr << " |P| = " << number_of_points() << ", |S| = " << number_of_support_points() << endl; // containment check (a) verr << " a) containment check..." << flush; Point_iterator point_iter; for ( point_iter = points_begin(); point_iter != points_end(); ++point_iter) if ( has_on_unbounded_side( *point_iter)) return( CGAL::_optimisation_is_valid_fail( verr, "circle does not contain all points")); verr << "passed." << endl; // support set checks (b)+(c) verr << " b)+c) support set checks..." << flush; switch( number_of_support_points()) { case 0: if ( ! is_empty()) return( CGAL::_optimisation_is_valid_fail( verr, "P is nonempty, \ but there are no support points.")); break; case 1: if ( ( circle().center() != support_point( 0) ) || ( ! CGAL_NTS is_zero( circle().squared_radius())) ) return( CGAL::_optimisation_is_valid_fail( verr, "circle differs from the circle \ spanned by its single support point.")); break; case 2: { const Point& p = support_point( 0), q = support_point( 1); // p equals q? if ( p == q) return( CGAL::_optimisation_is_valid_fail( verr, "the two support points are equal.")); // segment(p,q) is not diameter? if ( ( ! has_on_boundary( p) ) || ( ! has_on_boundary( q) ) || ( tco.orientation( p, q, circle().center()) != CGAL::COLLINEAR) ) return( CGAL::_optimisation_is_valid_fail( verr, "circle does not have its \ two support points as diameter.")); } break; case 3: { const Point& p = support_point( 0), q = support_point( 1), r = support_point( 2); // p, q, r not pairwise distinct? if ( ( p == q) || ( q == r) || ( r == p)) return( CGAL::_optimisation_is_valid_fail( verr, "at least two of the three \ support points are equal.")); // p, q, r collinear? if ( tco.orientation( p, q, r) == CGAL::COLLINEAR) return( CGAL::_optimisation_is_valid_fail( verr, "the three support points are collinear.")); // current circle not equal the unique circle through p,q,r ? Circle c = circle(); c.set( p, q, r); if ( circle() != c) return( CGAL::_optimisation_is_valid_fail( verr, "circle is not the unique circle \ through its three support points.")); // circle's center on boundary of triangle(p,q,r)? const Point& center = circle().center(); CGAL::Orientation o_pqz = tco.orientation( p, q, center); CGAL::Orientation o_qrz = tco.orientation( q, r, center); CGAL::Orientation o_rpz = tco.orientation( r, p, center); if ( ( o_pqz == CGAL::COLLINEAR) || ( o_qrz == CGAL::COLLINEAR) || ( o_rpz == CGAL::COLLINEAR) ) return( CGAL::_optimisation_is_valid_fail( verr, "one of the three support points is redundant.")); // circle's center not inside triangle(p,q,r)? if ( ( o_pqz != o_qrz) || ( o_qrz != o_rpz) || ( o_rpz != o_pqz)) return( CGAL::_optimisation_is_valid_fail( verr, "circle's center is not in the \ convex hull of its three support points.")); } break; default: return( CGAL::_optimisation_is_valid_fail( verr, "illegal number of support points, \ not between 0 and 3.")); }; verr << "passed." << endl; verr << " object is valid!" << endl; return( true); } // Miscellaneous // ------------- inline const Traits& traits( ) const { return( tco); } }; // Function declarations // ===================== // I/O // --- template < class Traits_ > std::ostream& operator << ( std::ostream& os, const Min_circle_2& mc); template < class Traits_ > std::istream& operator >> ( std::istream& is, Min_circle_2& mc); } //namespace CGAL #include #endif // CGAL_MIN_CIRCLE_2_H // ===== EOF ==================================================================