dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/Min_circle_2.h

586 lines
17 KiB
C++

// 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 <sven@inf.ethz.ch>, Bernd Gaertner
#ifndef CGAL_MIN_CIRCLE_2_H
#define CGAL_MIN_CIRCLE_2_H
#include <CGAL/license/Bounding_volumes.h>
// includes
# include <CGAL/Optimisation/basic.h>
# include <CGAL/Random.h>
# include <CGAL/algorithm.h>
# include <list>
# include <vector>
# include <algorithm>
# include <iostream>
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<Point>::const_iterator Point_iterator;
typedef const Point * Support_point_iterator;
/**************************************************************************
WORKAROUND: Some compilers are unable to match member functions defined
outside the class template. Therefore, all member functions are implemented
in the class interface.
// creation
template < class InputIterator >
Min_circle_2( InputIterator first,
InputIterator last,
bool randomize = false,
Random& random = 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<Point>::const_iterator first,
std::list<Point>::const_iterator last );
void insert( std::istream_iterator<Point,std::ptrdiff_t> first,
std::istream_iterator<Point,std::ptrdiff_t> last );
void clear( );
// validity check
bool is_valid( bool verbose = false, int level = 0) const;
// miscellaneous
const Traits& traits( ) const;
**************************************************************************/
private:
// private data members
Traits tco; // traits class object
std::list<Point> 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<Traits_>&);
Min_circle_2<Traits_>&
operator = ( const Min_circle_2<Traits_>&);
// ============================================================================
// 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<Point>::iterator point_iter = points.begin();
for ( ; last != point_iter; ) {
const Point& p = *point_iter;
// p not in current circle?
if ( has_on_unbounded_side( p)) {
// recursive call with p as additional support point
support_points[ n_sp] = p;
mc( point_iter, n_sp+1);
// move current point to front
points.splice( points.begin(), points, point_iter++); }
else
++point_iter; }
}
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<Point> 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<Traits>::" << 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<Traits_>& mc);
template < class Traits_ >
std::istream&
operator >> ( std::istream& is, Min_circle_2<Traits_>& mc);
} //namespace CGAL
#include <CGAL/Min_circle_2/Min_circle_2_impl.h>
#endif // CGAL_MIN_CIRCLE_2_H
// ===== EOF ==================================================================