mirror of https://github.com/CGAL/cgal
414 lines
12 KiB
C++
414 lines
12 KiB
C++
// Copyright (c) 2003-2006 INRIA Sophia-Antipolis (France).
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org); you may redistribute it under
|
|
// the terms of the Q Public License version 1.0.
|
|
// See the file LICENSE.QPL distributed with CGAL.
|
|
//
|
|
// Licensees holding a valid commercial license may use this file in
|
|
// accordance with the commercial license agreement provided with the software.
|
|
//
|
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// $URL$
|
|
// $Id$
|
|
//
|
|
// Author(s) : Monique Teillaud, Sylvain Pion
|
|
|
|
// Partially supported by the IST Programme of the EU as a Shared-cost
|
|
// RTD (FET Open) Project under Contract No IST-2000-26473
|
|
// (ECG - Effective Computational Geometry for Curves and Surfaces)
|
|
// and a STREP (FET Open) Project under Contract No IST-006413
|
|
// (ACS -- Algorithms for Complex Shapes)
|
|
|
|
#ifndef CGAL_CURVED_KERNEL_CIRCULAR_ARC_2_H
|
|
#define CGAL_CURVED_KERNEL_CIRCULAR_ARC_2_H
|
|
|
|
#include <CGAL/global_functions_on_circular_arcs_2.h>
|
|
#include <CGAL/Curved_kernel/internal_functions_on_circular_arc_2.h> // temporarily
|
|
#include <CGAL/intersections.h>
|
|
#include <CGAL/Simple_cartesian.h>
|
|
|
|
namespace CGAL {
|
|
namespace CGALi {
|
|
|
|
template <class CK >
|
|
class Circular_arc_2
|
|
{
|
|
typedef typename CK::FT FT;
|
|
typedef typename CK::RT RT;
|
|
typedef typename CK::Point_2 Point_2;
|
|
typedef typename CK::Line_2 Line_2;
|
|
typedef typename CK::Circle_2 Circle_2;
|
|
typedef typename CK::Circular_arc_point_2 Circular_arc_point_2;
|
|
typedef typename CK::Root_of_2 Root_of_2;
|
|
|
|
public:
|
|
|
|
Circular_arc_2() {}
|
|
|
|
Circular_arc_2(const Circle_2 &c)
|
|
: _support(c), Cache_minmax('s'), Cache_full('y')
|
|
{
|
|
|
|
_begin = _end =
|
|
CircularFunctors::x_extremal_point<CK>(supporting_circle(),true);
|
|
|
|
}
|
|
|
|
Circular_arc_2(const Circle_2 &support,
|
|
const Line_2 &l1, bool b1,
|
|
const Line_2 &l2, bool b2)
|
|
: Cache_minmax('n'), Cache_full('n')
|
|
{
|
|
Point_2 center1 (support.center().x() + l1.a()/2,
|
|
support.center().y() + l1.b()/2);
|
|
|
|
FT sqr1 = support.squared_radius() + l1.c()
|
|
- CGAL::square(support.center().x())
|
|
- CGAL::square(support.center().y())
|
|
+ CGAL::square(center1.x())
|
|
+ CGAL::square(center1.y());
|
|
|
|
Circle_2 c1 (center1, sqr1);
|
|
|
|
Point_2 center2 (support.center().x() + l2.a()/2,
|
|
support.center().y() + l2.b()/2);
|
|
|
|
FT sqr2 = support.squared_radius() + l2.c()
|
|
- CGAL::square(support.center().x())
|
|
- CGAL::square(support.center().y())
|
|
+ CGAL::square(center2.x())
|
|
+ CGAL::square(center2.y());
|
|
|
|
Circle_2 c2 (center2, sqr2);
|
|
|
|
*this = Circular_arc_2(support, c1, b1, c2, b2);
|
|
|
|
CGAL_kernel_assertion(do_intersect(support, c1));
|
|
CGAL_kernel_assertion(do_intersect(support, c2));
|
|
}
|
|
|
|
|
|
Circular_arc_2(const Circle_2 &c,
|
|
const Circle_2 &c1, const bool b_1,
|
|
const Circle_2 &c2, const bool b_2)
|
|
: _support(c) , Cache_minmax('n'), Cache_full('n')
|
|
{
|
|
if (c1 != c2) {
|
|
_begin = CGAL::circle_intersect<CK>(c, c1, b_1);
|
|
_end = CGAL::circle_intersect<CK>(c, c2, b_2);
|
|
}
|
|
else{
|
|
typedef std::vector<CGAL::Object > solutions_container;
|
|
|
|
solutions_container solutions;
|
|
CGAL::intersect_2<CK>( c, c1, std::back_inserter(solutions) );
|
|
typename solutions_container::iterator it = solutions.begin();
|
|
|
|
CGAL_kernel_precondition( it != solutions.end() );
|
|
// the circles intersect
|
|
|
|
const std::pair<typename CK::Circular_arc_point_2, unsigned> *result;
|
|
result = CGAL::object_cast<
|
|
std::pair<typename CK::Circular_arc_point_2, unsigned> > (&(*it));
|
|
if ( result->second == 2 ){ // double solution
|
|
_begin = result->first;
|
|
_end = result->first;
|
|
}
|
|
else{
|
|
if (b_1)
|
|
_begin = result->first;
|
|
if (b_2)
|
|
_end = result->first;
|
|
if (!(b_1 & b_2)) {
|
|
++it;
|
|
result = CGAL::object_cast<
|
|
std::pair<typename CK::Circular_arc_point_2, unsigned> >(&(*it));
|
|
if (!b_1)
|
|
_begin = result->first;
|
|
if (!b_2)
|
|
_end = result->first;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// IS THIS CONSTRUCTOR USED ?
|
|
// constructs a circular arc that is the arc included in A
|
|
// having same (b) endpoint as A (true == _begin, false == _end)
|
|
// but whose (!b) endpoint is the intersection of A with ccut given
|
|
// by b_cut
|
|
Circular_arc_2(const Circular_arc_2 &A, const bool b,
|
|
const Circle_2 &ccut, const bool b_cut)
|
|
: _support(A.supporting_circle()), Cache_minmax('n'), Cache_full('n')
|
|
{
|
|
CGAL_kernel_precondition(A.is_x_monotone());
|
|
CGAL_kernel_precondition(do_intersect(A.supporting_circle(), ccut));
|
|
|
|
Circular_arc_point_2 new_p =
|
|
CGAL::circle_intersect<CK>(A.supporting_circle(), ccut, b_cut);
|
|
|
|
// CGAL_kernel_assertion(point_in_range(A, new_p));
|
|
CGAL_kernel_assertion
|
|
(A.on_upper_part() == (CGAL::compare(new_p.y(), A.center().y()) >= 0));
|
|
|
|
if (b) {
|
|
_begin = A._begin;
|
|
_end = new_p;
|
|
}
|
|
else {
|
|
_begin = new_p;
|
|
_end = A._end;
|
|
}
|
|
}
|
|
|
|
// Constructs an arc supported by Circle_2(begin, middle, end),
|
|
// with _begin == begin, _end == end.
|
|
// (middle is not necessarily on the arc)
|
|
Circular_arc_2(const Point_2 &begin,
|
|
const Point_2 &middle,
|
|
const Point_2 &end)
|
|
: Cache_minmax('n'), Cache_full('n')
|
|
{
|
|
CGAL_kernel_precondition(!CGAL::collinear(begin, middle, end));
|
|
|
|
Circle_2 c (begin, middle, end);
|
|
Line_2 l1 (begin, middle);
|
|
Line_2 l2 (middle, end);
|
|
*this = Circular_arc_2(c,
|
|
l1, compare_xy(begin, middle) < 0,
|
|
l2, compare_xy(end, middle) < 0);
|
|
}
|
|
|
|
Circular_arc_2(const Circle_2 &support,
|
|
const Circular_arc_point_2 &source,
|
|
const Circular_arc_point_2 &target)
|
|
: _begin(source), _end(target), _support(support),
|
|
Cache_minmax('n'), Cache_full('n')
|
|
{
|
|
// We cannot enable these preconditions for now, since the
|
|
// Lazy_curved_kernel
|
|
// calls it on the Interval kernel without try/catch protection
|
|
// through the Curved_kernel_converter.
|
|
// CGAL_kernel_exactness_precondition(CK().has_on_2_object()(support, source));
|
|
// CGAL_kernel_exactness_precondition(CK().has_on_2_object()(support, target));
|
|
}
|
|
|
|
Circular_arc_2(const Point_2 &begin,
|
|
const Point_2 &end,
|
|
const FT &bulge)
|
|
: _begin(begin), _end(end), Cache_minmax('n'), Cache_full('n')
|
|
{
|
|
const FT sqr_bulge = CGAL::square(bulge);
|
|
const FT common = (FT(1) - sqr_bulge) / (FT(4)*bulge);
|
|
const FT x_coord = (begin.x() + end.x())/FT(2)
|
|
+ common*(begin.y() - end.y());
|
|
const FT y_coord = (begin.y() + end.y())/FT(2)
|
|
+ common*(end.x() - begin.x());
|
|
|
|
const FT sqr_rad = squared_distance(begin, end)
|
|
* (FT(1)/sqr_bulge + FT(2) + sqr_bulge) / FT(16);
|
|
|
|
_support = Circle_2(Point_2(x_coord, y_coord), sqr_rad);
|
|
}
|
|
|
|
private:
|
|
// The arc goes from _begin to _end in the positive order
|
|
// If _begin == _end, then it's the full circle
|
|
Circular_arc_point_2 _begin, _end;
|
|
Circle_2 _support;
|
|
|
|
public:
|
|
mutable char Cache_minmax;
|
|
mutable char Cache_full;
|
|
// to remember if the arc was constructed from a full circle
|
|
|
|
const Circular_arc_point_2 & left() const
|
|
{
|
|
CGAL_kernel_precondition(is_x_monotone());
|
|
CGAL_kernel_precondition(on_upper_part() ? compare_xy(_end,_begin)<0
|
|
: compare_xy(_begin,_end)<0);
|
|
if (Cache_minmax == 's')
|
|
return _end;
|
|
if (Cache_minmax == 't')
|
|
return _begin;
|
|
if (on_upper_part()) {
|
|
Cache_minmax = 's';
|
|
return _end;
|
|
}
|
|
Cache_minmax = 't';
|
|
return _begin;
|
|
}
|
|
|
|
const Circular_arc_point_2 & right() const
|
|
{
|
|
CGAL_kernel_precondition(is_x_monotone());
|
|
CGAL_kernel_precondition(on_upper_part() ? compare_xy(_end,_begin)<0
|
|
: compare_xy(_begin,_end)<0);
|
|
if (Cache_minmax == 's')
|
|
return _begin;
|
|
if (Cache_minmax == 't')
|
|
return _end;
|
|
if (on_upper_part()) {
|
|
Cache_minmax = 's';
|
|
return _begin;
|
|
}
|
|
Cache_minmax = 't';
|
|
return _end;
|
|
}
|
|
|
|
const Circular_arc_point_2 & source() const
|
|
{
|
|
return _begin;
|
|
}
|
|
|
|
const Circular_arc_point_2 & target() const
|
|
{
|
|
return _end;
|
|
}
|
|
|
|
bool is_x_monotone() const
|
|
{
|
|
if (Cache_full == 'y' )
|
|
return false;
|
|
|
|
int cmp_begin = CGAL::compare(_begin.y(), center().y());
|
|
int cmp_end = CGAL::compare(_end.y(), center().y());
|
|
|
|
// XXX : be careful, this may be surprising if the return value
|
|
// is not -1/1 but some random int...
|
|
|
|
if (cmp_begin == opposite(cmp_end) && cmp_begin != 0)
|
|
return false;
|
|
|
|
int cmp_x = compare_x(_begin, _end);
|
|
|
|
// Is the arc on the upper part ?
|
|
if (cmp_begin > 0 || cmp_end > 0)
|
|
return cmp_x > 0;
|
|
|
|
// Is the arc on the lower part ?
|
|
if (cmp_begin < 0 || cmp_end < 0)
|
|
return cmp_x < 0;
|
|
|
|
// There remains the case :
|
|
CGAL_kernel_assertion(cmp_begin == 0 && cmp_end == 0);
|
|
|
|
return cmp_x != 0; // full circle or half circle.
|
|
}
|
|
|
|
bool is_y_monotone() const
|
|
{
|
|
int cmp_begin = CGAL::compare(_begin.x(), center().x());
|
|
int cmp_end = CGAL::compare(_end.x(), center().x());
|
|
|
|
// XXX : be careful, this may be surprising if the return value
|
|
// is not -1/1 but some random int...
|
|
if (cmp_begin == opposite(cmp_end) && cmp_begin != 0)
|
|
return false;
|
|
|
|
int cmp_y = compare_y(_begin, _end);
|
|
|
|
// Is the arc on the right part ?
|
|
if (cmp_begin > 0 || cmp_end > 0)
|
|
return cmp_y < 0;
|
|
|
|
// Is the arc on the left part ?
|
|
if (cmp_begin < 0 || cmp_end < 0)
|
|
return cmp_y > 0;
|
|
|
|
// There remains the case :
|
|
assert(cmp_begin == 0 && cmp_end == 0);
|
|
|
|
return cmp_y != 0; // full circle or half circle.
|
|
}
|
|
|
|
bool on_upper_part() const
|
|
// check whether the endpoints are above or below the center
|
|
{
|
|
CGAL_kernel_precondition(is_x_monotone());
|
|
|
|
int begin_y =
|
|
CGAL::compare(_begin.y(), supporting_circle().center().y());
|
|
int end_y =
|
|
CGAL::compare(_end.y(), supporting_circle().center().y());
|
|
|
|
if (begin_y == 0 && end_y == 0)
|
|
return compare_x(_begin, _end) > 0;
|
|
|
|
return begin_y > 0 || end_y > 0;
|
|
}
|
|
|
|
const Circle_2 & supporting_circle() const
|
|
{
|
|
return _support;
|
|
}
|
|
|
|
const Point_2 & center() const
|
|
{
|
|
return supporting_circle().center();
|
|
}
|
|
|
|
const FT & squared_radius() const
|
|
{
|
|
return supporting_circle().squared_radius();
|
|
}
|
|
|
|
Bbox_2 bbox() const
|
|
{
|
|
return CGAL::CircularFunctors::circular_arc_bbox<CK>(*this);
|
|
}
|
|
|
|
};
|
|
|
|
template < typename CK >
|
|
std::ostream &
|
|
operator<<(std::ostream & os, const Circular_arc_2<CK> &a)
|
|
{
|
|
// The output format is :
|
|
// - supporting circle
|
|
// - circle c1
|
|
// - bool b1
|
|
// - circle c2
|
|
// - bool b2
|
|
return os << a.supporting_circle() << " "
|
|
<< a.source() << " "
|
|
<< a.target() << " ";
|
|
}
|
|
|
|
template < typename CK >
|
|
std::istream &
|
|
operator>>(std::istream & is, Circular_arc_2<CK> &a)
|
|
{
|
|
typename CK::Circle_2 s;
|
|
typename CK::Circular_arc_point_2 p1;
|
|
typename CK::Circular_arc_point_2 p2;
|
|
is >> s >> p1 >> p2 ;
|
|
if (is)
|
|
a = Circular_arc_2<CK>(s, p1, p2);
|
|
return is;
|
|
}
|
|
|
|
template < typename CK >
|
|
std::ostream &
|
|
print(std::ostream & os, const Circular_arc_2<CK> &a)
|
|
{
|
|
return os << "Circular_arc_2( " << std::endl
|
|
<< "left : " << a.left() << " , " << std::endl
|
|
<< "right : " << a.right() << " , " << std::endl
|
|
<< "upper part : " << a.on_upper_part() << std::endl
|
|
<< " [[ approximate circle is (x,y,r) : "
|
|
<< CGAL::to_double(a.supporting_circle().center().x()) << " "
|
|
<< CGAL::to_double(a.supporting_circle().center().y()) << " "
|
|
<< std::sqrt(CGAL::to_double(a.supporting_circle()
|
|
.squared_radius()))
|
|
<< " ]]" << std::endl;
|
|
}
|
|
|
|
} // namespace CGALi
|
|
} // namespace CGAL
|
|
|
|
#endif // CGAL_CURVED_KERNEL_CIRCULAR_ARC_2_H
|