// ====================================================================== // // 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 ) // // ====================================================================== #ifndef CGAL_ARR_CIRCLES_REAL_TRAITS_H #define CGAL_ARR_CIRCLES_REAL_TRAITS_H #include #include #include #include CGAL_BEGIN_NAMESPACE template class Arr_circles_real_traits; template class Circ_Curve { public: typedef Cartesian 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; private: Circle c; Point_2 s,t; //source, target }; // DEBUG // template // ::std::ostream& operator << // (::std::ostream& os,const Circ_Curve& 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 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 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 // and 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); // and 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& 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 ¢er(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::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::iterator lit; typename std::list::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 > 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