cgal/Packages/Arrangement/include/CGAL/Arr_circles_real_traits.h

898 lines
27 KiB
C++

// ======================================================================
//
// Copyright (c) 1999 The CGAL Consortium
//
// This software and related documentation is part of an INTERNAL release
// of the Computational Geometry Algorithms Library (CGAL). It is not
// intended for general use.
//
// ----------------------------------------------------------------------
//
// release :
// release_date : 1999, October 13
//
// file : include/CGAL/Arr_circles_real_traits.h
// package : arr (1.03)
// author(s) : Iddo Hanniel
// coordinator : Tel-Aviv University (Dan Halperin <halperin@math.tau.ac.il>)
//
// ======================================================================
#ifndef CGAL_ARR_CIRCLES_REAL_TRAITS_H
#define CGAL_ARR_CIRCLES_REAL_TRAITS_H
#include <CGAL/basic.h>
#include <list>
#include <CGAL/Cartesian.h>
#include <CGAL/tags.h>
CGAL_BEGIN_NAMESPACE
template <class NT> class Arr_circles_real_traits;
template <class NT>
class Circ_Curve {
public:
typedef Cartesian<NT> Kernel;
typedef typename Kernel::Point_2 Point_2;
typedef typename Kernel::Circle_2 Circle_2;
// Obsolete, for backward compatibility
typedef Kernel R;
typedef Point_2 Point;
typedef Circle_2 Circle;
Circ_Curve(const NT& x, const NT& y, const NT& r2) :
c(Point_2(x,y),r2), s(x-CGAL::sqrt(r2),y), t(x-CGAL::sqrt(r2),y)
{}
Circ_Curve(const NT& x, const NT& y, const NT& r2,
const Point_2& src , const Point_2& trgt) :
c(Point_2(x,y),r2), s(src), t(trgt)
{
CGAL_precondition(c.has_on_boundary(src));
CGAL_precondition(c.has_on_boundary(trgt));
}
//a ctr with cgal_circle
Circ_Curve(const Circle& _c) : c(_c),
s(_c.center().x()-CGAL::sqrt(c.squared_radius()), _c.center().y()),
t(_c.center().x()-CGAL::sqrt(c.squared_radius()), _c.center().y()) {}
Circ_Curve(const Circle& _c, const Point_2& src, const Point_2& trgt) :
c(_c), s(src), t(trgt)
{
CGAL_precondition(c.has_on_boundary(src));
CGAL_precondition(c.has_on_boundary(trgt));
}
Circ_Curve () {}
Circ_Curve (const Circ_Curve& cv) : c(cv.c),s(cv.s),t(cv.t)
{}
Circ_Curve& operator=(const Circ_Curve& cv) {
c=cv.c; s=cv.s; t=cv.t;
return *this;
}
//Public member functions for the users
const Circle& circle() const {return c;}
const Point_2& source() const {return s;}
const Point_2& target() const {return t;}
bool is_x_monotone() const {
if (s==t)
return false; //closed circle
int point_position = (CGAL_NTS compare(s.y(),c.center().y())) *
(CGAL_NTS compare(t.y(),c.center().y()));
if (point_position < 0)
return false; //one above and one below
if (orientation(s,c.center(),t)!=(c.orientation()) )
return true; //if the same orientation or on diameter (==COLLINEAR)
return false;
}
friend class Arr_circles_real_traits<NT>;
private:
Circle c;
Point_2 s,t; //source, target
};
// DEBUG
// template <class NT>
// ::std::ostream& operator <<
// (::std::ostream& os,const Circ_Curve<NT>& cv) {
// os << "Curve:\n" ;
// os << "s: " << cv.source() << std::endl;
// os << "t: " << cv.target() << std::endl;
// os << "circle: " << cv.circle() << std::endl;
// return os;
// }
// DEBUG
template <class _NT>
class Arr_circles_real_traits {
public:
// Categories:
typedef Tag_false Has_left_category;
typedef _NT NT;
//the difference between Curve and X_curve is semantical only,
// NOT syntactical
typedef Circ_Curve<NT> Curve_2;
typedef Curve_2 X_curve_2;
// using typename to please compiler (e.g., CC with IRIX64 on mips)
typedef typename Curve_2::Kernel Kernel;
typedef typename Curve_2::Point_2 Point_2;
typedef typename Curve_2::Circle_2 Circle_2;
typedef typename Kernel::Vector_2 Vector_2;
// Obsolete, for backward compatibility
typedef Kernel R;
typedef Point_2 Point;
typedef Curve_2 Curve;
typedef X_curve_2 X_curve;
typedef Circle_2 Circle;
typedef Vector_2 Vector;
Arr_circles_real_traits() {}
Comparison_result compare_x(const Point_2& p0, const Point_2& p1) const {
return _compare_value(p0.x(),p1.x());
}
Comparison_result compare_xy(const Point_2& p0, const Point_2& p1) const {
Comparison_result x_res = _compare_value(p0.x(),p1.x());
if (x_res != EQUAL)
return (x_res);
return _compare_value(p0.y(),p1.y());
}
//no vertical segments :
bool curve_is_vertical(const X_curve_2&) const {return false;}
bool curve_is_in_x_range(const X_curve_2& cv, const Point_2& p) const {
CGAL_precondition(is_x_monotone(cv));
return (compare_x(p,cv.s) * compare_x(p,cv.t)) <=0 ;
}
Comparison_result curve_compare_at_x(const X_curve_2& cv1,
const X_curve_2& cv2,
const Point_2& p) const {
CGAL_assertion(is_x_monotone(cv1));
CGAL_assertion(is_x_monotone(cv2));
CGAL_precondition(curve_is_in_x_range(cv1, p));
CGAL_precondition(curve_is_in_x_range(cv2, p));
Point_2 p1 = curve_calc_point(cv1,p);
Point_2 p2 = curve_calc_point(cv2,p);
return _compare_value(p1.y(),p2.y());
}
Comparison_result curve_compare_at_x_left(const X_curve_2& cva,
const X_curve_2& cvb,
const Point_2& p) const {
CGAL_assertion(is_x_monotone(cva));
CGAL_assertion(is_x_monotone(cvb));
// Both curves is must be defined at p and to its left.
CGAL_precondition(curve_is_in_x_range(cva, p));
CGAL_precondition ((compare_x(curve_source(cva),p) == SMALLER) ||
(compare_x(curve_target(cva),p) == SMALLER));
CGAL_precondition(curve_is_in_x_range(cvb, p));
CGAL_precondition ((compare_x(curve_source(cvb),p) == SMALLER) ||
(compare_x(curve_target(cvb),p) == SMALLER));
// Compare the two curves at x(p).
CGAL_precondition (curve_compare_at_x(cva, cvb, p) == EQUAL);
//otherwise
// <cv1> and <cv2> meet at a point with the same x-coordinate as p
// compare their derivatives
Point_2 q=curve_calc_point(cva,p);
X_curve_2 cv1(cva),cv2(cvb);
if (compare_x(curve_source(cv1),q) == SMALLER)
cv1 = curve_flip(cva);
if (compare_x(curve_source(cv2),q) == SMALLER)
cv2 = curve_flip(cvb);
Vector d1=derivative_vec(cv1,q);
Vector d2=derivative_vec(cv2,q);
if ((_compare_value(d1[0],0)==EQUAL)||
(_compare_value(d2[0],0)==EQUAL) ) { //one or both are infinite
if (CGAL_NTS is_negative(d1[1]*d2[1])) {
return _compare_value(d1[1],d2[1]) ;
}
else {
if (_compare_value(d1[0],0)!=EQUAL) //d2 is vertical
return _compare_value(0,d2[1]);
if (_compare_value(d2[0],0)!=EQUAL) //d1 is vertical
return _compare_value(d1[1],0);
//otherwise both are vertical
//and they share a tangent at q
//compare the norm of tangent vector (==second derivative)
if (CGAL_NTS is_negative(compare_x(cv1.s,cv1.t) *
cv1.c.orientation()) ) {
//curves are on lower part of circle (if d2 has greater value then
//it is below d1 and return LARGER)
return
_compare_value(d2[0]*d2[0]+d2[1]*d2[1], d1[0]*d1[0]+d1[1]*d1[1]);
}
else { //upper part of circle(if d1 has greater value then
//it is above d2 and return LARGER)
return
_compare_value(d1[0]*d1[0]+d1[1]*d1[1], d2[0]*d2[0]+d2[1]*d2[1]);
}
}
}
//in any other case both derivatives are finite and to the left of q
// return _compare_value(derivative(cv2,q), derivative(cv1,q));
Comparison_result ccr=_compare_value(d2[1]/d2[0], d1[1]/d1[0] );
if (ccr!=EQUAL)
return ccr;
else {
//they share a common tangent
//compare the second derivative (norm of vectors) - needs checking
//check if we are above or below
bool cv1_is_on_lower=(compare_x(cv1.s,cv1.t) * cv1.c.orientation() < 0);
bool cv2_is_on_lower=(compare_x(cv2.s,cv2.t) * cv2.c.orientation() < 0);
if (cv1_is_on_lower != cv2_is_on_lower) {
//one is from above one from below
if (cv1_is_on_lower) return LARGER;
else
return SMALLER;
}
//otherwise both are on upper or both on lower
if (cv1_is_on_lower) {
//curves are on lower part of circle (if |d2| has greater value then
//it is below d1 and return LARGER)
return
_compare_value(d2[0]*d2[0]+d2[1]*d2[1], d1[0]*d1[0]+d1[1]*d1[1]);
}
else { //upper part of circle(if |d1| has greater value then
//it is above d2 and return LARGER)
return
_compare_value(d1[0]*d1[0]+d1[1]*d1[1], d2[0]*d2[0]+d2[1]*d2[1]);
}
}
}
Comparison_result curve_compare_at_x_right(const X_curve_2& cva,
const X_curve_2& cvb,
const Point_2& p) const {
CGAL_assertion(is_x_monotone(cva));
CGAL_assertion(is_x_monotone(cvb));
// Both curves is must be defined at p and to its right.
CGAL_precondition(curve_is_in_x_range(cva, p));
CGAL_precondition ((compare_x(curve_source(cva),p) == LARGER) ||
(compare_x(curve_target(cva),p) == LARGER));
CGAL_precondition(curve_is_in_x_range(cvb, p));
CGAL_precondition ((compare_x(curve_source(cvb),p) == LARGER) ||
(compare_x(curve_target(cvb),p) == LARGER));
// Compare the two curves at x(p).
CGAL_precondition (curve_compare_at_x(cva, cvb, p) == EQUAL);
// <cv1> and <cv2> meet at a point with the same x-coordinate as p
// compare their derivatives
//make both curves compared - left to right
Point_2 q=curve_calc_point(cva,p);
X_curve_2 cv1(cva),cv2(cvb);
if (compare_x(curve_source(cv1),q) == LARGER)
cv1 = curve_flip(cva);
if (compare_x(curve_source(cv2),q) == LARGER)
cv2 = curve_flip(cvb);
Vector d1=derivative_vec(cv1,q);
Vector d2=derivative_vec(cv2,q);
if ((_compare_value(d1[0],0)==EQUAL)||
(_compare_value(d2[0],0)==EQUAL) ) { //one or both are vertical
if (CGAL_NTS is_negative(d1[1]*d2[1]) ) {
return _compare_value(d1[1],d2[1]) ;
}
else {
if (_compare_value(d1[0],0)!=EQUAL) //d2 is vertical
return _compare_value(0,d2[1]);
if (_compare_value(d2[0],0)!=EQUAL ) //d1 is vertical
return _compare_value(d1[1],0);
//otherwise they share a tangent at q
//compare the norm of tangent vector (==second derivative)
if (compare_x(cv1.s,cv1.t) * cv1.c.orientation() < 0) {
//curves are on lower part of circle (if |d2| has greater value then
//it is below d1 and return LARGER)
return
_compare_value(d2[0]*d2[0]+d2[1]*d2[1], d1[0]*d1[0]+d1[1]*d1[1]);
}
else { //upper part of circle(if |d1| has greater value then
//it is above d2 and return LARGER)
return
_compare_value(d1[0]*d1[0]+d1[1]*d1[1], d2[0]*d2[0]+d2[1]*d2[1]);
}
}
}
//in other case both derivatives are finite and to the right of q
//return _compare_value(derivative(cv1,q), derivative(cv2,q));
Comparison_result ccr=_compare_value(d1[1]/d1[0], d2[1]/d2[0] );
if (ccr!=EQUAL)
return ccr;
else {
//they share a common tangent
//compare the second derivative (norm of vectors) - needs checking
//check if we are above or below
bool cv1_is_on_lower=(compare_x(cv1.s,cv1.t) * cv1.c.orientation() < 0);
bool cv2_is_on_lower=(compare_x(cv2.s,cv2.t) * cv2.c.orientation() < 0);
if (cv1_is_on_lower != cv2_is_on_lower) {
//one is from above one from below
if (cv1_is_on_lower) return LARGER;
else
return SMALLER;
}
//otherwise both are on upper or on lower
if (cv1_is_on_lower) {
//curves are on lower part of circle (if |d2| has greater value then
//it is below d1 and return LARGER)
return
_compare_value(d2[0]*d2[0]+d2[1]*d2[1], d1[0]*d1[0]+d1[1]*d1[1]);
}
else { //upper part of circle(if |d1| has greater value then
//it is above d2 and return LARGER)
return
_compare_value(d1[0]*d1[0]+d1[1]*d1[1], d2[0]*d2[0]+d2[1]*d2[1]);
}
}
}
Comparison_result curve_get_point_status (const X_curve_2 &cv,
const Point_2& p) const
{
CGAL_precondition(is_x_monotone(cv));
CGAL_precondition(curve_is_in_x_range(cv, p));
return (_compare_value(curve_calc_point(cv, p).y(), p.y()));
}
bool point_is_same(const Point_2 & p, const Point_2 & q) const
{
return is_same(p, q);
}
bool curve_is_same(const X_curve_2& cv1, const X_curve_2& cv2) const {
CGAL_precondition(is_x_monotone(cv1));
CGAL_precondition(is_x_monotone(cv2));
return (is_same( cv1.s,cv2.s) && is_same( cv1.t,cv2.t) &&
( cv1.c.orientation()==cv2.c.orientation()) &&
is_same( cv1.c.center(), cv2.c.center()) &&
_compare_value( cv1.c.squared_radius(),
cv2.c.squared_radius()) == EQUAL);
}
Point_2 curve_source(const X_curve_2& cv) const {
return cv.s;
}
Point_2 curve_target(const X_curve_2& cv) const {
return cv.t;
}
///////////////////////////////////////////////////////
// ARRANGEMENT FUNCS
X_curve_2 curve_flip(const X_curve_2& cv) const {
X_curve_2 xc(cv.c.center().x(),cv.c.center().y(),
cv.c.squared_radius(),cv.t, cv.s);
xc.c=cv.c.opposite();
return xc;
}
bool is_x_monotone(const Curve_2& cv) const {
return cv.is_x_monotone();
}
void make_x_monotone(const Curve_2 & cv, std::list<X_curve_2>& l) const
{
// Require:
// CGAL_precondition( ! is_x_monotone(cv) );
if (is_x_monotone(cv))
{
l.clear();
l.push_back(X_curve(cv));
return;
}
bool switch_orientation = false;
// is cv a closed circle ?
if (cv.s==cv.t) {
// for arrangements of circles this is all that is needed
Point_2 src(cv.c.center().x()-CGAL::sqrt(cv.c.squared_radius()),
cv.c.center().y());
Point_2 trg(cv.c.center().x()+CGAL::sqrt(cv.c.squared_radius()),
cv.c.center().y());
// bug fix, Shai, 12 Feb. 2001
// x-monotone curves did not respect the original orintation
typename Curve_2::Circle circ(cv.circle().center(),
cv.circle().squared_radius(),
cv.circle().orientation());
Curve_2 top_arc(circ, src, trg);
l.push_back(top_arc);
Curve_2 bottom_arc(circ, trg, src);
l.push_back(bottom_arc);
}
else {
//if we get a curve that is not a closed circle - for completeness
// bug fix, Shai, 12 Feb. 2001
// curves that are split to 3 x-monotone sub curves were not handled
// MSVC doesn't like the copy constructor:
// const Point_2 &center(cv.circle().center());
const Point_2 & center = cv.circle().center();
Point_2 mid1, mid2;
NT sq_radius(cv.c.squared_radius());
Curve_2 work_cv;
bool two_cuts = false,
left_cut_is_first = false;
// for simplicity work on CCW curve
if (cv.c.orientation() == CLOCKWISE) {
work_cv = curve_flip(cv);
switch_orientation = true;
}
else {
work_cv = Curve_2(cv);
}
CGAL_assertion(work_cv.circle().orientation() == COUNTERCLOCKWISE);
// MSVC doesn't like the copy constructor:
// const Point_2 &src(work_cv.source()), &trg(work_cv.target());
const Point_2 & src = work_cv.source();
const Point_2 & trg = work_cv.target();
// now we work on a CCW circular curve which is, by precondition
// NOT x-monotone.
// There are four cases, denote the quadrants: II I
// denote s - source, t - target III IV
// In two of them there is ONE spliting point, in the other two
// there are TWO split points.
// First, we check in which scenario we are
if ( _compare_value(src.y(), center.y()) == LARGER ) {
left_cut_is_first = true;
if ( _compare_value(trg.y(), center.y()) == LARGER ) {
// s is in II, t is in I
two_cuts = true;
}
else {
// s is in II, t is in III or IV
}
}
else {
// source is lower then center
if ( _compare_value(trg.y(), center.y()) == SMALLER ) {
// s is in IV, t is in III
two_cuts = true;
}
else {
// s is in IV, t is in I or II
}
}
// Second, we calculate the two or three split points
if ( left_cut_is_first ){
mid1 = Point_2(center.x() - CGAL::sqrt(sq_radius), center.y());
if ( two_cuts ) {
mid2 = Point_2(center.x() + CGAL::sqrt(sq_radius), center.y());;
}
else {
}
}
else {
mid1 = Point_2(center.x() + CGAL::sqrt(sq_radius), center.y());
if ( two_cuts ) {
mid2 = Point_2(center.x() - CGAL::sqrt(sq_radius), center.y());
}
}
// Third, we build the split curves
l.push_back(Curve_2(work_cv.circle(), src, mid1));
if ( two_cuts ) {
l.push_back(Curve_2(work_cv.circle(), mid1, mid2));
l.push_back(Curve_2(work_cv.circle(), mid2, trg));
}
else {
l.push_back(Curve_2(work_cv.circle(), mid1, trg));
}
// If we switched the orientation, we have to switch back
if ( switch_orientation ) {
for (typename std::list<Curve_2>::iterator lit = l.begin();
lit != l.end();
lit++) {
*lit = curve_flip(*lit);
}
}
}
// Ensure:
// There are indeed 2 or 3 split points
CGAL_postcondition(l.size() >= 2 && l.size() <= 3);
// The orientations of the split curves are the same as of cv
CGAL_postcondition_code(
if ( switch_orientation ) l.reverse();
Orientation cv_or = cv.circle().orientation();
typename std::list<Curve_2>::iterator lit;
typename std::list<Curve_2>::iterator next_it; );
// Check consistency of end points
CGAL_postcondition( l.begin()->source() == cv.source() );
CGAL_postcondition_code( lit = l.end(); lit--; );
CGAL_postcondition( lit->target() == cv.target() );
CGAL_postcondition_code(//for all x-monotone parts
for(lit = l.begin();
lit != l.end();
lit++) {
next_it = lit; next_it++; );
CGAL_postcondition( lit->circle().orientation() == cv_or );
// Consistency of split points
CGAL_postcondition( next_it == l.end() ||
lit->target() == next_it->source() );
// Split points are on circle
CGAL_postcondition( cv.circle().has_on_boundary(lit->target()) );
// parts are indeed x-monotone
CGAL_postcondition( is_x_monotone(*lit) );
CGAL_postcondition_code( } ); // end of for
}
void curve_split(const X_curve_2& cv, X_curve_2& c1, X_curve_2& c2,
const Point_2& split_pt) const {
CGAL_precondition(is_x_monotone(cv));
//split curve at split point (x coordinate) into c1 and c2
CGAL_precondition(curve_get_point_status(cv,split_pt)==EQUAL);
CGAL_precondition(compare_x(curve_source(cv),split_pt)!=EQUAL);
CGAL_precondition(compare_x(curve_target(cv),split_pt)!=EQUAL);
c1=cv;
c2=cv;
c1.t=split_pt;
c2.s=split_pt;
}
bool nearest_intersection_to_right(const X_curve_2& c1,
const X_curve_2& c2,
const Point_2& pt,
Point_2& p1,
Point_2& p2) const {
CGAL_precondition(is_x_monotone(c1));
CGAL_precondition(is_x_monotone(c2));
Point_2 rgt,lft;
//case where the arcs are from the same circle
if ( is_same(c1.c.center(),c2.c.center()) &&
_compare_value(c1.c.squared_radius(),c2.c.squared_radius())==EQUAL ) {
//can intersect only at endpoints
Point_2 rightmost1,leftmost1;
if (compare_x(c1.s,c1.t)==LARGER) {
rightmost1=c1.s;leftmost1=c1.t;
}
else {
rightmost1=c1.t;leftmost1=c1.s;
}
Point_2 rightmost2,leftmost2;
if (compare_x(c2.s,c2.t)==LARGER) {
rightmost2=c2.s;leftmost2=c2.t;
}
else {
rightmost2=c2.t;leftmost2=c2.s;
}
bool c1_is_on_lower=(compare_x(c1.s,c1.t) * c1.c.orientation() < 0);
bool c2_is_on_lower=(compare_x(c2.s,c2.t) * c2.c.orientation() < 0);
if (c1_is_on_lower!=c2_is_on_lower) {
//an intersection can occure only at end points
if (is_same(rightmost1,rightmost2)) {
if (compare_x(rightmost1,pt)==LARGER) {
p1=p2=rightmost1;
return true;
}
}
if (is_same(leftmost1,leftmost2)) {
if (compare_x(leftmost1,pt)==LARGER) {
p1=p2=leftmost1;
return true;
}
}
return false;
}
//now we are dealing with two x-curves on the same side of circle
if ( (compare_x(rightmost1,pt) != LARGER) ||
(compare_x(rightmost2,pt) != LARGER) )
return false; //the intersection can't be right of pt
//now, if there is an intersection it has a point right of pt
if ( compare_x(rightmost1,leftmost2)==SMALLER ||
compare_x(rightmost2,leftmost1)==SMALLER ) { //no intersection
return false;
}
//now we know there is an intersection, find p1,p2
//p2 is the leftmost of the 2 rightmost points
if (compare_x(rightmost1,rightmost2)==SMALLER) {
p2=rightmost1;
}
else {
p2=rightmost2;
}
//p1 is the rightmost of the 2 leftmost (if it is right of pt)
if (compare_x(leftmost1,leftmost2)==LARGER) {
p1=leftmost1;
}
else {
p1=leftmost2;
}
if (compare_x(p1,pt)==SMALLER) {
//this assumes pt is on the curve, maybe we
//need to have p1=point_on_curve (pt.x())...?
p1=pt;
}
return true;
} //end of case where arcs come fromsame circle
Point_2 first;
Point_2 last;
circle_intersection(c1.c,c2.c,&first,&last);
if (compare_x(first,last)==SMALLER) {
rgt=first;
lft=last;
}
else {
rgt=last;
lft=first;
}
if (compare_x(rgt,pt)==LARGER) {
if (curve_is_in_x_range(c1, rgt) &&
(curve_get_point_status(c1, rgt) == EQUAL) &&
curve_is_in_x_range(c2, rgt) &&
(curve_get_point_status(c2, rgt) == EQUAL) )
{
p1=p2=rgt;
return true;
}
}
if (compare_x(lft,pt)==LARGER) {
if (curve_is_in_x_range(c1, lft) &&
(curve_get_point_status(c1,lft) == EQUAL) &&
curve_is_in_x_range(c2, lft) &&
(curve_get_point_status(c2,lft) == EQUAL) )
{
p1=p2=lft;
return true;
}
}
//can be done differently (the check first)
return false;
}
Point_2 point_reflect_in_x_and_y (const Point_2& pt) const
{
// use hx(), hy(), hw() in order to support both Homogeneous and Cartesian
Point_2 reflected_pt( -pt.hx(), -pt.hy(), pt.hw());
return reflected_pt;
}
X_curve_2 curve_reflect_in_x_and_y (const X_curve_2& cv) const
{
Circle circ( point_reflect_in_x_and_y (cv.circle().center()),
cv.circle().squared_radius(),
//reflection in two axes means no change in orientation
cv.circle().orientation());
// CGAL::opposite( cv.circle().orientation()));
X_curve_2 reflected_cv( circ,
point_reflect_in_x_and_y (cv.source()),
point_reflect_in_x_and_y (cv.target()));
return reflected_cv;
}
//currently we assume that no two circles overlap (might change in future)
bool curves_overlap(const X_curve_2& c1, const X_curve_2& c2) const {
CGAL_precondition(is_x_monotone(c1));
CGAL_precondition(is_x_monotone(c2));
//case where the arcs are from the same circle (otherwise return false)
if ( is_same(c1.c.center(),c2.c.center()) &&
_compare_value(c1.c.squared_radius(),c2.c.squared_radius())==EQUAL ) {
bool c1_is_on_lower=(compare_x(c1.s,c1.t) * c1.c.orientation() < 0);
bool c2_is_on_lower=(compare_x(c2.s,c2.t) * c2.c.orientation() < 0);
if (c1_is_on_lower!=c2_is_on_lower)
return false;
//check overlaps of x-monotone curves
Point_2 leftmost1,rightmost1;
if (compare_x(c1.s,c1.t)==SMALLER) {
leftmost1=c1.s; rightmost1=c1.t;
}
else {
leftmost1=c1.t; rightmost1=c1.s;
}
Point_2 leftmost2,rightmost2;
if (compare_x(c2.s,c2.t)==SMALLER) {
leftmost2=c2.s; rightmost2=c2.t;
}
else {
leftmost2=c2.t; rightmost2=c2.s;
}
if ( compare_x(rightmost1,leftmost2)!=LARGER ||
compare_x(rightmost2,leftmost1)!=LARGER ) { //no overlap
return false;
}
else {
return true;
}
}
return false; //circles don't overlap
}
////////////////////////////////////////////////////////////////////
// PRIVATE FUNCS
private:
Comparison_result _compare_value (const NT& a, const NT& b) const {
return CGAL_NTS compare(a,b);
}
//calculates the point on the X_curve_2 with the same x coordinate as p
Point_2 curve_calc_point(const X_curve_2& cv, const Point_2& p) const {
//simple cases
if (compare_x(cv.s,p)==EQUAL)
return cv.s;
if (compare_x(cv.t,p)==EQUAL)
return cv.t;
NT px(p.x());
NT sqr = (CGAL::sqrt(cv.c.squared_radius() -
(px-cv.c.center().x())*(px-cv.c.center().x()) ));
Point_2 lst1_first(px,cv.c.center().y() + sqr);
Point_2 lst1_last(px,cv.c.center().y() - sqr);
Point_2 p1;
if (compare_x(cv.s,cv.t) * cv.c.orientation() < 0) { //lower part of circle
if (_compare_value(lst1_first.y(),lst1_last.y()) == LARGER)
p1=lst1_last;
else
p1=lst1_first;
}
else { //upper part of circle
if (_compare_value(lst1_first.y(),lst1_last.y()) == LARGER)
p1=lst1_first;
else
p1=lst1_last;
}
return p1;
}
Vector derivative_vec(const X_curve_2& cv, const Point_2& p) const {
if (cv.c.orientation()==COUNTERCLOCKWISE) { //ccw - (-y,x)
return Vector((cv.c.center().y()-p.y()), (p.x()-cv.c.center().x()));
}
else
return Vector((p.y()-cv.c.center().y()), (cv.c.center().x())-p.x());
}
bool is_same(const Point_2 &p1, const Point_2 &p2) const
{
return (compare_xy(p1, p2) == EQUAL);
}
bool circle_intersection(const Circle& ca, const Circle& cb,
Point_2* p1, Point_2* p2) const {
//function checks if the circles ca,cb intersect,
//if they don't - returns false
//if they do p1,p2 will hold the intersection points
NT l2=squared_distance(ca.center(),cb.center());
NT l=CGAL::sqrt(l2);
NT ra=CGAL::sqrt(ca.squared_radius());
NT rb=CGAL::sqrt(cb.squared_radius());
if ( (_compare_value(l, ra+rb) == LARGER) ||
(_compare_value(ra, l+rb) == LARGER) ||
(_compare_value(rb, l+ra) == LARGER) )
return false;
//x is the distance on the segment-of-centers from ca.center()
//y is the distance from the segment-of-centers to the intersection point
NT x = (ca.squared_radius()-cb.squared_radius()+l2) / NT(2*l);
NT y = CGAL::sqrt(ca.squared_radius() - x*x);
//debug
Vector v_ab=cb.center()-ca.center();
//Vector_2<Cartesian<NT> > v_ab=cb.center()-ca.center();
v_ab = v_ab/(CGAL::sqrt(v_ab.x()*v_ab.x()+v_ab.y()*v_ab.y())); //normalize
Vector v_ab_perp(-v_ab.y(),v_ab.x());
*p1 = ca.center() + x*v_ab + y*v_ab_perp;
*p2 = ca.center() + x*v_ab - y*v_ab_perp;
return true;
}
};
CGAL_END_NAMESPACE
#endif