BWAPI
SPAR/AIModule/BWTA/vendors/CGAL/CGAL/Arr_geometry_traits/Conic_arc_2.h
Go to the documentation of this file.
00001 // Copyright (c) 2005  Tel-Aviv University (Israel).
00002 // All rights reserved.
00003 //
00004 // This file is part of CGAL (www.cgal.org); you may redistribute it under
00005 // the terms of the Q Public License version 1.0.
00006 // See the file LICENSE.QPL distributed with CGAL.
00007 //
00008 // Licensees holding a valid commercial license may use this file in
00009 // accordance with the commercial license agreement provided with the software.
00010 //
00011 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00012 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00013 //
00014 // $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Arrangement_on_surface_2/include/CGAL/Arr_geometry_traits/Conic_arc_2.h $
00015 // $Id: Conic_arc_2.h 48716 2009-04-08 11:40:21Z spion $
00016 // 
00017 //
00018 // Author(s)     : Ron Wein <wein@post.tau.ac.il>
00019 
00020 #ifndef CGAL_CONIC_ARC_2_H
00021 #define CGAL_CONIC_ARC_2_H
00022 
00027 #include <CGAL/Arr_geometry_traits/Conic_point_2.h>
00028 #include <CGAL/Arr_geometry_traits/Conic_intersections_2.h>
00029 #include <CGAL/Bbox_2.h>
00030 
00031 #include <ostream>
00032 
00033 CGAL_BEGIN_NAMESPACE
00034 
00035 
00051 template <class Rat_kernel_, class Alg_kernel_, class Nt_traits_>
00052 class _Conic_arc_2
00053 {
00054 public:
00055 
00056   typedef Rat_kernel_                                      Rat_kernel;
00057   typedef Alg_kernel_                                      Alg_kernel;
00058   typedef Nt_traits_                                       Nt_traits;
00059 
00060   typedef _Conic_arc_2<Rat_kernel, Alg_kernel, Nt_traits>  Self;
00061  
00062   typedef typename Rat_kernel::FT                          Rational;
00063   typedef typename Rat_kernel::Point_2                     Rat_point_2;
00064   typedef typename Rat_kernel::Segment_2                   Rat_segment_2;
00065   typedef typename Rat_kernel::Circle_2                    Rat_circle_2;
00066 
00067   typedef typename Nt_traits::Integer                      Integer;
00068 
00069   typedef typename Alg_kernel::FT                          Algebraic;
00070   typedef typename Alg_kernel::Point_2                     Point_2;
00071   typedef _Conic_point_2<Alg_kernel>                       Conic_point_2;
00072 
00073 protected:
00074 
00075   Integer        _r;       //
00076   Integer        _s;       // The coefficients of the supporting conic curve:
00077   Integer        _t;       //
00078   Integer        _u;       //
00079   Integer        _v;       //   r*x^2 + s*y^2 + t*xy + u*x + v*y +w = 0 .
00080   Integer        _w;       //
00081 
00082   Orientation    _orient;  // The orientation of the conic.
00083 
00084   // Bit masks for the _info field.
00085   enum
00086   {
00087     IS_VALID = 1,
00088     IS_FULL_CONIC = 2
00089   };
00090 
00091   int            _info;    // Does the arc represent a full conic curve.
00092   Conic_point_2  _source;  // The source of the arc (if not a full curve).
00093   Conic_point_2  _target;  // The target of the arc (if not a full curve).
00094 
00103   struct Extra_data
00104   {
00105     Algebraic     a;
00106     Algebraic     b;
00107     Algebraic     c;
00108     Sign          side;
00109   };
00110 
00111   Extra_data    *_extra_data_P;  // The extra data stored with the arc
00112                                  // (may be NULL).
00113 
00114 public:
00115 
00117 
00118 
00122   _Conic_arc_2 () :
00123     _r(0), _s(0), _t(0), _u(0), _v(0), _w(0),
00124     _orient (COLLINEAR),
00125     _info (0),
00126     _extra_data_P (NULL)
00127   {}
00128 
00133   _Conic_arc_2 (const Self& arc) :
00134     _r(arc._r), _s(arc._s), _t(arc._t), _u(arc._u), _v(arc._v), _w(arc._w),
00135     _orient (arc._orient),
00136     _info (arc._info),
00137     _source(arc._source),
00138     _target(arc._target)
00139   {
00140     if (arc._extra_data_P != NULL)
00141       _extra_data_P = new Extra_data (*(arc._extra_data_P));
00142     else
00143       _extra_data_P = NULL;
00144   }
00145 
00151   _Conic_arc_2 (const Rational& r, const Rational& s, const Rational& t,
00152                 const Rational& u, const Rational& v, const Rational& w) :
00153     _extra_data_P (NULL)
00154   {
00155     // Make sure the given curve is an ellipse (4rs - t^2 should be positive).
00156     CGAL_precondition (CGAL::sign (4*r*s - t*t) == POSITIVE);
00157 
00158     // Set the arc to be the full conic (and compute the orientation).
00159     Rational    rat_coeffs [6];
00160 
00161     rat_coeffs[0] = r;
00162     rat_coeffs[1] = s;
00163     rat_coeffs[2] = t;
00164     rat_coeffs[3] = u;
00165     rat_coeffs[4] = v;
00166     rat_coeffs[5] = w;
00167 
00168     _set_full (rat_coeffs, true);
00169   }
00170 
00180   _Conic_arc_2 (const Rational& r, const Rational& s, const Rational& t,
00181                 const Rational& u, const Rational& v, const Rational& w,
00182                 const Orientation& orient,
00183                 const Point_2& source, const Point_2& target) :
00184     _orient (orient),
00185     _source (source),
00186     _target (target),
00187     _extra_data_P (NULL)
00188   {
00189     // Make sure that the source and the taget are not the same.
00190     CGAL_precondition (Alg_kernel().compare_xy_2_object() (source,
00191                                                            target) != EQUAL);
00192 
00193     // Set the arc properties (no need to compute the orientation).
00194     Rational    rat_coeffs [6];
00195 
00196     rat_coeffs[0] = r;
00197     rat_coeffs[1] = s;
00198     rat_coeffs[2] = t;
00199     rat_coeffs[3] = u;
00200     rat_coeffs[4] = v;
00201     rat_coeffs[5] = w;
00202 
00203     _set (rat_coeffs);
00204   }
00205 
00210   _Conic_arc_2 (const Rat_segment_2& seg) :
00211     _orient (COLLINEAR),
00212     _extra_data_P (NULL)
00213   {
00214     // Set the source and target.
00215     Rat_kernel        ker;
00216     Rat_point_2       source = ker.construct_vertex_2_object() (seg, 0); 
00217     Rat_point_2       target = ker.construct_vertex_2_object() (seg, 1); 
00218     Rational          x1 = source.x();
00219     Rational          y1 = source.y();
00220     Rational          x2 = target.x();
00221     Rational          y2 = target.y();
00222     Nt_traits         nt_traits;
00223 
00224     _source = Point_2 (nt_traits.convert (x1), nt_traits.convert (y1));
00225     _target = Point_2 (nt_traits.convert (x2), nt_traits.convert (y2));
00226  
00227     // Make sure that the source and the taget are not the same.
00228     CGAL_precondition (Alg_kernel().compare_xy_2_object() (_source,
00229                                                            _target) != EQUAL);
00230 
00231     // The supporting conic is r=s=t=0, and u*x + v*y + w = 0 should hold
00232     // for both the source (x1,y1) and the target (x2, y2).
00233     const Rational    _zero (0);
00234     const Rational    _one (1);
00235     Rational          rat_coeffs [6];
00236 
00237     rat_coeffs[0] = _zero;
00238     rat_coeffs[1] = _zero;
00239     rat_coeffs[2] = _zero;
00240 
00241     if (CGAL::compare (x1, x2) == EQUAL)
00242     {
00243       // The supporting conic is a vertical line, of the form x = CONST.
00244       rat_coeffs[3] = _one;
00245       rat_coeffs[4] = _zero;
00246       rat_coeffs[5] = -x1;
00247     }
00248     else
00249     {
00250       // The supporting line is A*x + B*y + C = 0, where:
00251       //
00252       //  A = y2 - y1,    B = x1 - x2,    C = x2*y1 - x1*y2 
00253       //
00254       rat_coeffs[3] = y2 - y1;
00255       rat_coeffs[4] = x1 - x2;
00256       rat_coeffs[5] = x2*y1 - x1*y2;
00257     }
00258 
00259     // Set the arc properties (no need to compute the orientation).
00260     _set (rat_coeffs);
00261   }
00262 
00267   _Conic_arc_2 (const Rat_circle_2& circ) :
00268     _orient (CLOCKWISE),
00269     _extra_data_P (NULL)
00270   {
00271     // Get the circle properties.
00272     Rat_kernel        ker;
00273     Rat_point_2       center = ker.construct_center_2_object() (circ); 
00274     Rational          x0 = center.x();
00275     Rational          y0 = center.y();
00276     Rational          R_sqr = ker.compute_squared_radius_2_object() (circ); 
00277 
00278     // Produce the correponding conic: if the circle center is (x0,y0)
00279     // and its squared radius is R^2, that its equation is:
00280     //   x^2 + y^2 - 2*x0*x - 2*y0*y + (x0^2 + y0^2 - R^2) = 0
00281     // Note that this equation describes a curve with a negative (clockwise) 
00282     // orientation.
00283     const Rational    _zero (0);
00284     const Rational    _one (1);
00285     const Rational    _minus_two (-2);
00286     Rational          rat_coeffs [6];
00287 
00288     rat_coeffs[0] = _one;
00289     rat_coeffs[1] = _one;
00290     rat_coeffs[2] = _zero;
00291     rat_coeffs[3] = _minus_two*x0;
00292     rat_coeffs[4] = _minus_two*y0;
00293     rat_coeffs[5] = x0*x0 + y0*y0 - R_sqr;
00294 
00295     // Set the arc to be the full conic (no need to compute the orientation).
00296     _set_full (rat_coeffs, false);
00297   }
00298 
00308   _Conic_arc_2 (const Rat_circle_2& circ,
00309                 const Orientation& orient,
00310                 const Point_2& source, const Point_2& target) :
00311     _orient(orient),
00312     _source(source),
00313     _target(target),
00314     _extra_data_P (NULL)
00315   {
00316     // Make sure that the source and the taget are not the same.
00317     CGAL_precondition (Alg_kernel().compare_xy_2_object() (source,
00318                                                            target) != EQUAL);
00319     CGAL_precondition (orient != COLLINEAR);
00320 
00321     // Get the circle properties.
00322     Rat_kernel        ker;
00323     Rat_point_2       center = ker.construct_center_2_object() (circ);
00324     Rational          x0 = center.x();
00325     Rational          y0 = center.y();
00326     Rational          R_sqr = ker.compute_squared_radius_2_object() (circ); 
00327 
00328     // Produce the correponding conic: if the circle center is (x0,y0)
00329     // and it squared radius is R^2, that its equation is:
00330     //   x^2 + y^2 - 2*x0*x - 2*y0*y + (x0^2 + y0^2 - R^2) = 0
00331     // Since this equation describes a curve with a negative (clockwise) 
00332     // orientation, we multiply it by -1 if necessary to obtain a positive
00333     // (counterclockwise) orientation.
00334     const Rational    _zero (0);
00335     Rational          rat_coeffs[6];
00336 
00337     if (_orient == COUNTERCLOCKWISE)
00338     {
00339       const Rational  _minus_one (-1);
00340       const Rational  _two (2);
00341 
00342       rat_coeffs[0] = _minus_one;
00343       rat_coeffs[1] = _minus_one;
00344       rat_coeffs[2] = _zero;
00345       rat_coeffs[3] = _two*x0;
00346       rat_coeffs[4] = _two*y0;
00347       rat_coeffs[5] = R_sqr - x0*x0 - y0*y0;
00348     }
00349     else
00350     {
00351       const Rational    _one (1);
00352       const Rational    _minus_two (-2);
00353 
00354       rat_coeffs[0] = _one;
00355       rat_coeffs[1] = _one;
00356       rat_coeffs[2] = _zero;
00357       rat_coeffs[3] = _minus_two*x0;
00358       rat_coeffs[4] = _minus_two*y0;
00359       rat_coeffs[5] = x0*x0 + y0*y0 - R_sqr;
00360     }
00361 
00362     // Set the arc properties (no need to compute the orientation).
00363     _set (rat_coeffs);
00364   }
00365 
00373   _Conic_arc_2 (const Rat_point_2& p1,
00374                 const Rat_point_2& p2,
00375                 const Rat_point_2& p3):
00376     _extra_data_P (NULL)
00377   {
00378     // Set the source and target.
00379     Rational          x1 = p1.x();
00380     Rational          y1 = p1.y();
00381     Rational          x2 = p2.x();
00382     Rational          y2 = p2.y();
00383     Rational          x3 = p3.x();
00384     Rational          y3 = p3.y();
00385     Nt_traits         nt_traits;
00386 
00387     _source = Point_2 (nt_traits.convert (x1), nt_traits.convert (y1));
00388     _target = Point_2 (nt_traits.convert (x3), nt_traits.convert (y3));
00389  
00390     // Make sure that the source and the taget are not the same.
00391     CGAL_precondition (Alg_kernel().compare_xy_2_object() (_source,
00392                                                            _target) != EQUAL);
00393 
00394     // Compute the lines: A1*x + B1*y + C1 = 0,
00395     //               and: A2*x + B2*y + C2 = 0,
00396     // where:
00397     const Rational  _two  = 2;
00398 
00399     const Rational  A1 = _two*(x1 - x2);
00400     const Rational  B1 = _two*(y1 - y2);
00401     const Rational  C1 = y2*y2 - y1*y1 + x2*x2 - x1*x1;
00402 
00403     const Rational  A2 = _two*(x2 - x3);
00404     const Rational  B2 = _two*(y2 - y3);
00405     const Rational  C2 = y3*y3 - y2*y2 + x3*x3 - x2*x2;
00406 
00407     // Compute the coordinates of the intersection point between the
00408     // two lines, given by (Nx / D, Ny / D), where:
00409     const Rational  Nx = B1*C2 - B2*C1;
00410     const Rational  Ny = A2*C1 - A1*C2;
00411     const Rational  D = A1*B2 - A2*B1;
00412 
00413     // Make sure the three points are not collinear.
00414     const bool  points_collinear = (CGAL::sign (D) == ZERO);
00415 
00416     if (points_collinear)
00417     {
00418       _info = 0;           // Inavlid arc.
00419       return;
00420     }
00421 
00422     // The equation of the underlying circle is given by:
00423     Rational          rat_coeffs[6];
00424     
00425     rat_coeffs[0] = D*D;
00426     rat_coeffs[1] = D*D;
00427     rat_coeffs[2] = 0;
00428     rat_coeffs[3] = -_two*D*Nx;
00429     rat_coeffs[4] = -_two*D*Ny;
00430     rat_coeffs[5] = 
00431       Nx*Nx + Ny*Ny - ((D*x2 - Nx)*(D*x2 - Nx) + (D*y2 - Ny)*(D*y2 - Ny));
00432 
00433     // Determine the orientation: If the mid-point forms a left-turn with
00434     // the source and the target points, the orientation is positive (going
00435     // counterclockwise).
00436     // Otherwise, it is negative (going clockwise).
00437     Alg_kernel                         ker;
00438     typename Alg_kernel::Orientation_2 orient_f = ker.orientation_2_object();
00439 
00440 
00441     Point_2  p_mid = Point_2 (nt_traits.convert (x2), nt_traits.convert (y2));
00442  
00443     if (orient_f(_source, p_mid, _target) == LEFT_TURN)
00444       _orient = COUNTERCLOCKWISE;
00445     else
00446       _orient = CLOCKWISE;
00447 
00448     // Set the arc properties (no need to compute the orientation).
00449     _set (rat_coeffs);
00450   }
00451 
00460   _Conic_arc_2 (const Rat_point_2& p1,
00461                 const Rat_point_2& p2,
00462                 const Rat_point_2& p3,
00463                 const Rat_point_2& p4,
00464                 const Rat_point_2& p5) :
00465     _extra_data_P(NULL)
00466   {
00467     // Make sure that no three points are collinear.
00468     Rat_kernel                         ker;
00469     typename Rat_kernel::Orientation_2 orient_f = ker.orientation_2_object();
00470     const bool                         point_collinear =
00471       (orient_f (p1, p2, p3) == COLLINEAR ||
00472        orient_f (p1, p2, p4) == COLLINEAR ||
00473        orient_f (p1, p2, p5) == COLLINEAR ||
00474        orient_f (p1, p3, p4) == COLLINEAR ||
00475        orient_f (p1, p3, p5) == COLLINEAR ||
00476        orient_f (p1, p4, p5) == COLLINEAR ||
00477        orient_f (p2, p3, p4) == COLLINEAR ||
00478        orient_f (p2, p3, p5) == COLLINEAR ||
00479        orient_f (p2, p4, p5) == COLLINEAR ||
00480        orient_f (p3, p4, p5) == COLLINEAR);
00481 
00482     if (point_collinear)
00483     {
00484       _info = 0;           // Inavlid arc.
00485       return;
00486     }
00487 
00488     // Set the source and target.
00489     Rational          x1 = p1.x();
00490     Rational          y1 = p1.y();
00491     Rational          x5 = p5.x();
00492     Rational          y5 = p5.y();
00493     Nt_traits         nt_traits;
00494 
00495     _source = Point_2 (nt_traits.convert (x1), nt_traits.convert (y1));
00496     _target = Point_2 (nt_traits.convert (x5), nt_traits.convert (y5));
00497 
00498     // Set a conic curve that passes through the five given point.
00499     typename Rat_kernel::Conic_2   temp_conic;
00500     Rational                       rat_coeffs [6];
00501 
00502     temp_conic.set (p1, p2, p3, p4, p5);
00503 
00504     // Get the conic coefficients.
00505     rat_coeffs[0] = temp_conic.r();
00506     rat_coeffs[1] = temp_conic.s();
00507     rat_coeffs[2] = temp_conic.t();
00508     rat_coeffs[3] = temp_conic.u();
00509     rat_coeffs[4] = temp_conic.v();
00510     rat_coeffs[5] = temp_conic.w();
00511 
00512     // Determine the orientation: If one of the midpoints forms a left-turn
00513     // with the source and the target points, the orientation is positive
00514     // (going counterclockwise).
00515     // Otherwise, it is negative (going clockwise).
00516     const Orientation                  turn = orient_f(p1, p2, p5);
00517 
00518     if (turn == LEFT_TURN)
00519     {
00520       _orient = COUNTERCLOCKWISE;
00521       CGAL_precondition (orient_f(p1, p3, p5) == LEFT_TURN &&
00522                          orient_f(p1, p4, p5) == LEFT_TURN);
00523     }
00524     else
00525     {
00526       _orient = CLOCKWISE;
00527       CGAL_precondition (orient_f(p1, p3, p5) != LEFT_TURN &&
00528                          orient_f(p1, p4, p5) != LEFT_TURN);
00529     }
00530 
00531     // Set the arc properties (no need to compute the orientation).
00532     _set (rat_coeffs);
00533 
00534     // Make sure that all midpoints are strictly between the
00535     // source and the target.
00536     Point_2  mp2 = Point_2 (nt_traits.convert (p2.x()),
00537                             nt_traits.convert (p2.y()));
00538     Point_2  mp3 = Point_2 (nt_traits.convert (p3.x()),
00539                             nt_traits.convert (p3.y()));
00540     Point_2  mp4 = Point_2 (nt_traits.convert (p4.x()),
00541                             nt_traits.convert (p4.y()));
00542     
00543     if (! _is_strictly_between_endpoints (mp2) ||
00544         ! _is_strictly_between_endpoints (mp3) ||
00545         ! _is_strictly_between_endpoints (mp4))
00546     {
00547       _info = 0;               // Inalvid arc.
00548     }
00549   }
00550 
00562   _Conic_arc_2 (const Rational& r, const Rational& s, const Rational& t,
00563                 const Rational& u, const Rational& v, const Rational& w,
00564                 const Orientation& orient,
00565                 const Point_2& app_source,
00566                 const Rational& r_1, const Rational& s_1, const Rational& t_1,
00567                 const Rational& u_1, const Rational& v_1, const Rational& w_1,
00568                 const Point_2& app_target,
00569                 const Rational& r_2, const Rational& s_2, const Rational& t_2,
00570                 const Rational& u_2, const Rational& v_2, const Rational& w_2):
00571     _orient(orient),
00572     _extra_data_P(NULL)
00573   {
00574     // Create the integer coefficients of the base conic.
00575     Rational          rat_coeffs [6];
00576     Nt_traits         nt_traits;
00577     Integer           base_coeffs[6];
00578     int               deg_base;
00579 
00580     rat_coeffs[0] = r;
00581     rat_coeffs[1] = s;
00582     rat_coeffs[2] = t;
00583     rat_coeffs[3] = u;
00584     rat_coeffs[4] = v;
00585     rat_coeffs[5] = w;
00586 
00587     nt_traits.convert_coefficients (rat_coeffs, rat_coeffs + 6,
00588                                     base_coeffs);
00589 
00590     if (CGAL::sign (base_coeffs[0]) == ZERO &&
00591         CGAL::sign (base_coeffs[1]) == ZERO &&
00592         CGAL::sign (base_coeffs[2]) == ZERO)
00593     {
00594       deg_base = 1;
00595     }
00596     else
00597     {
00598       deg_base = 2;
00599     }
00600 
00601     // Compute the endpoints.
00602     Rational          aux_rat_coeffs [6];
00603     Integer           aux_coeffs[6];
00604     int               deg_aux;
00605     Algebraic         xs[4];
00606     int               n_xs;
00607     Algebraic         ys[4];
00608     int               n_ys;
00609     int               i, j;
00610     Algebraic         val;
00611     bool              found;
00612     double            dx, dy;
00613     double            curr_dist;
00614     double            min_dist = -1;
00615     int               k;
00616 
00617     for (k = 1; k <= 2; k++)
00618     {
00619       // Get the integer coefficients of the k'th auxiliary conic curve.
00620       aux_rat_coeffs[0] = (k == 1) ? r_1 : r_2;
00621       aux_rat_coeffs[1] = (k == 1) ? s_1 : s_2;
00622       aux_rat_coeffs[2] = (k == 1) ? t_1 : t_2;
00623       aux_rat_coeffs[3] = (k == 1) ? u_1 : u_2;
00624       aux_rat_coeffs[4] = (k == 1) ? v_1 : v_2;
00625       aux_rat_coeffs[5] = (k == 1) ? w_1 : w_2;
00626 
00627       nt_traits.convert_coefficients (aux_rat_coeffs, aux_rat_coeffs + 6,
00628                                       aux_coeffs);
00629 
00630       if (CGAL::sign (aux_coeffs[0]) == ZERO &&
00631           CGAL::sign (aux_coeffs[1]) == ZERO &&
00632           CGAL::sign (aux_coeffs[2]) == ZERO)
00633       {
00634         deg_aux = 1;
00635       }
00636       else
00637       {
00638         deg_aux = 2;
00639       }
00640 
00641       // Compute the x- and y-coordinates of intersection points of the base
00642       // conic and the k'th auxiliary conic.
00643       n_xs = _compute_resultant_roots (nt_traits,
00644                                        base_coeffs[0], base_coeffs[1],
00645                                        base_coeffs[2],
00646                                        base_coeffs[3], base_coeffs[4],
00647                                        base_coeffs[5],
00648                                        deg_base,
00649                                        aux_coeffs[0], aux_coeffs[1],
00650                                        aux_coeffs[2],
00651                                        aux_coeffs[3], aux_coeffs[4],
00652                                        aux_coeffs[5],
00653                                        deg_aux,
00654                                        xs);
00655 
00656       n_ys = _compute_resultant_roots (nt_traits,
00657                                        base_coeffs[1], base_coeffs[0],
00658                                        base_coeffs[2],
00659                                        base_coeffs[4], base_coeffs[3],
00660                                        base_coeffs[5],
00661                                        deg_base,
00662                                        aux_coeffs[1], aux_coeffs[0],
00663                                        aux_coeffs[2],
00664                                        aux_coeffs[4], aux_coeffs[3],
00665                                        aux_coeffs[5],
00666                                        deg_aux,
00667                                        ys);
00668 
00669       // Find the intersection point which is nearest the given approximation
00670       // and set it as the endpoint.
00671       found = false;
00672       for (i = 0; i < n_xs; i++)
00673       {
00674         for (j = 0; j < n_ys; j++)
00675         {
00676           // Check if the point (xs[i], ys[j]) lies on both conics.
00677           val = nt_traits.convert(base_coeffs[0]) * xs[i]*xs[i] +
00678                 nt_traits.convert(base_coeffs[1]) * ys[j]*ys[j] +
00679                 nt_traits.convert(base_coeffs[2]) * xs[i]*ys[j] +
00680                 nt_traits.convert(base_coeffs[3]) * xs[i] +
00681                 nt_traits.convert(base_coeffs[4]) * ys[j] +
00682                 nt_traits.convert(base_coeffs[5]);
00683 
00684           if (CGAL::sign (val) != ZERO)
00685             continue;
00686 
00687           val = nt_traits.convert(aux_coeffs[0]) * xs[i]*xs[i] +
00688                 nt_traits.convert(aux_coeffs[1]) * ys[j]*ys[j] +
00689                 nt_traits.convert(aux_coeffs[2]) * xs[i]*ys[j] +
00690                 nt_traits.convert(aux_coeffs[3]) * xs[i] +
00691                 nt_traits.convert(aux_coeffs[4]) * ys[j] +
00692                 nt_traits.convert(aux_coeffs[5]);
00693           
00694           if (CGAL::sign (val) == ZERO)
00695           {
00696             // Compute the distance of (xs[i], ys[j]) from the approximated
00697             // endpoint.
00698             if (k == 1)
00699             {
00700               dx = CGAL::to_double (xs[i] - app_source.x());
00701               dy = CGAL::to_double (ys[j] - app_source.y());
00702             }
00703             else
00704             {
00705               dx = CGAL::to_double (xs[i] - app_target.x());
00706               dy = CGAL::to_double (ys[j] - app_target.y());
00707             }
00708 
00709             curr_dist = dx*dx + dy*dy;
00710 
00711             // Update the endpoint if (xs[i], ys[j]) is the nearest pair so
00712             // far.
00713             if (! found || curr_dist < min_dist)
00714             {
00715               if (k == 1)
00716                 _source = Point_2 (xs[i], ys[j]);
00717               else
00718                 _target = Point_2 (xs[i], ys[j]);
00719 
00720               min_dist = curr_dist;
00721               found = true;
00722             }
00723           }
00724         }
00725       }
00726 
00727       if (! found)
00728       {
00729         _info = 0;           // Invalid arc.
00730         return;
00731       }
00732     }
00733  
00734     // Make sure that the source and the target are not the same.
00735     if (Alg_kernel().compare_xy_2_object() (_source,
00736                                             _target) == EQUAL)
00737     {
00738       _info = 0;      // Invalid arc.
00739       return;
00740     }
00741 
00742     // Set the arc properties (no need to compute the orientation).
00743     _set (rat_coeffs);
00744   }
00745 
00749   virtual ~_Conic_arc_2 ()
00750   {
00751     if (_extra_data_P != NULL)
00752       delete _extra_data_P;
00753   }
00754 
00759   const Self& operator= (const Self& arc)
00760   {
00761     if (this == &arc)
00762       return (*this);
00763 
00764     // Free any existing data.
00765     if (_extra_data_P != NULL)
00766       delete _extra_data_P;
00767 
00768     // Copy the arc's attributes.
00769     _r = arc._r;
00770     _s = arc._s;
00771     _t = arc._t;
00772     _u = arc._u;
00773     _v = arc._v;
00774     _w = arc._w;
00775 
00776     _orient = arc._orient;
00777     _info = arc._info;
00778     _source = arc._source;
00779     _target = arc._target;
00780 
00781     // Duplicate the extra data, if necessary.
00782     if (arc._extra_data_P != NULL)
00783       _extra_data_P = new Extra_data (*(arc._extra_data_P));
00784     else
00785       _extra_data_P = NULL;
00786 
00787     return (*this);
00788   }
00790 
00792 
00793 
00797   bool is_valid () const
00798   {
00799     return ((_info & IS_VALID) != 0);
00800   }
00801 
00805   const Integer& r () const {return (_r);}
00806   const Integer& s () const {return (_s);}
00807   const Integer& t () const {return (_t);}
00808   const Integer& u () const {return (_u);}
00809   const Integer& v () const {return (_v);}
00810   const Integer& w () const {return (_w);}
00811 
00815   bool is_x_monotone () const
00816   {
00817     // Check if the arc contains no vertical tangency points.
00818     Point_2      vtan_ps[2];
00819     return (vertical_tangency_points (vtan_ps) == 0);
00820   }
00821 
00825   bool is_y_monotone () const
00826   {
00827     // Check if the arc contains no horizontal tangency points.
00828     Point_2      htan_ps[2];
00829     return (horizontal_tangency_points (htan_ps) == 0);
00830   }
00831 
00835   bool is_full_conic () const
00836   {
00837     return ((_info & IS_FULL_CONIC) != 0);
00838   }
00839 
00845   const Point_2& source () const
00846   {
00847     CGAL_precondition (! is_full_conic());
00848 
00849     return (_source);
00850   }
00851 
00857   const Point_2& target () const
00858   {
00859     CGAL_precondition (! is_full_conic());
00860 
00861     return (_target);
00862   }
00863 
00868   Orientation orientation () const
00869   {
00870     return (_orient);
00871   }
00872 
00877   Bbox_2 bbox () const
00878   {
00879     CGAL_precondition (is_valid());
00880 
00881     double    x_min = 0, y_min = 0;
00882     double    x_max = 0, y_max = 0;
00883 
00884     if (is_full_conic())
00885     {
00886       // In case of a full conic (an ellipse or a circle), compute the
00887       // horizontal and vertical tangency points and use them to bound the arc.
00888       Point_2   tan_ps[2];
00889       int       n_tan_ps;
00890 
00891       n_tan_ps = vertical_tangency_points (tan_ps);
00892       CGAL_assertion (n_tan_ps == 2);
00893 
00894       if (CGAL::to_double(tan_ps[0].x()) < CGAL::to_double(tan_ps[1].x()))
00895       {
00896         x_min = CGAL::to_double(tan_ps[0].x());
00897         x_max = CGAL::to_double(tan_ps[1].x());
00898       }
00899       else
00900       {
00901         x_min = CGAL::to_double(tan_ps[1].x());
00902         x_max = CGAL::to_double(tan_ps[0].x());
00903       }
00904 
00905       n_tan_ps = horizontal_tangency_points (tan_ps);
00906       CGAL_assertion (n_tan_ps == 2);
00907 
00908       if (CGAL::to_double(tan_ps[0].y()) < CGAL::to_double(tan_ps[1].y()))
00909       {
00910         y_min = CGAL::to_double(tan_ps[0].y());
00911         y_max = CGAL::to_double(tan_ps[1].y());
00912       }
00913       else
00914       {
00915         y_min = CGAL::to_double(tan_ps[1].y());
00916         y_max = CGAL::to_double(tan_ps[0].y());
00917       }
00918     }
00919     else
00920     {
00921       // Use the source and target to initialize the exterme points.
00922       bool   source_left = 
00923         CGAL::to_double(_source.x()) < CGAL::to_double(_target.x());
00924       x_min = source_left ?
00925         CGAL::to_double(_source.x()) : CGAL::to_double(_target.x());
00926       x_max = source_left ?
00927         CGAL::to_double(_target.x()) : CGAL::to_double(_source.x());
00928       
00929       bool   source_down = 
00930         CGAL::to_double(_source.y()) < CGAL::to_double(_target.y());
00931       y_min = source_down ?
00932         CGAL::to_double(_source.y()) : CGAL::to_double(_target.y());
00933       y_max = source_down ?
00934         CGAL::to_double(_target.y()) : CGAL::to_double(_source.y());
00935 
00936       // Go over the vertical tangency points and try to update the x-points.
00937       Point_2    tan_ps[2];
00938       int        n_tan_ps;
00939       int        i;
00940 
00941       n_tan_ps = vertical_tangency_points (tan_ps);
00942       for (i = 0; i < n_tan_ps; i++)
00943       {
00944         if (CGAL::to_double(tan_ps[i].x()) < x_min)
00945           x_min = CGAL::to_double(tan_ps[i].x());
00946         if (CGAL::to_double(tan_ps[i].x()) > x_max)
00947           x_max = CGAL::to_double(tan_ps[i].x());
00948       }
00949 
00950       // Go over the horizontal tangency points and try to update the y-points.
00951       n_tan_ps = horizontal_tangency_points (tan_ps);
00952       for (i = 0; i < n_tan_ps; i++)
00953       {
00954         if (CGAL::to_double(tan_ps[i].y()) < y_min)
00955           y_min = CGAL::to_double(tan_ps[i].y());
00956         if (CGAL::to_double(tan_ps[i].y()) > y_max)
00957           y_max = CGAL::to_double(tan_ps[i].y());
00958       }
00959     }
00960 
00961     // Return the resulting bounding box.
00962     return (Bbox_2 (x_min, y_min, x_max, y_max));
00963   }
00965 
00967 
00968 
00975   void set_source (const Point_2& ps)
00976   {
00977     CGAL_precondition (! is_full_conic());
00978     CGAL_precondition (_is_on_supporting_conic (ps));
00979     CGAL_precondition (Alg_kernel().orientation_2_object()
00980                        (_source, ps, _target) == _orient ||
00981                        Alg_kernel().orientation_2_object()
00982                        (ps, _source, _target) == _orient);
00983 
00984     _source = ps;
00985     return;
00986   }
00987 
00994   void set_target (const Point_2& pt)
00995   {
00996     CGAL_precondition (! is_full_conic());
00997     CGAL_precondition (_is_on_supporting_conic (pt));
00998     CGAL_precondition (Alg_kernel().orientation_2_object()
00999                        (_source, pt, _target) == _orient ||
01000                        Alg_kernel().orientation_2_object()
01001                        (_source, _target, pt) == _orient);
01002 
01003     _target = pt;
01004     return;
01005   }
01006 
01008 
01010 
01011 
01018   int vertical_tangency_points (Point_2* vpts) const
01019   {
01020     // No vertical tangency points for line segments:
01021     if (_orient == COLLINEAR)
01022       return (0);
01023 
01024     // Calculate the vertical tangency points of the supporting conic.
01025     Point_2 ps[2];
01026     int     n;
01027 
01028     n = _conic_vertical_tangency_points (ps);
01029 
01030     // Return only the points that are contained in the arc interior.
01031     int    m = 0;
01032     
01033     for (int i = 0; i < n; i++)
01034     {
01035       if (is_full_conic() || _is_strictly_between_endpoints(ps[i]))
01036       {
01037         vpts[m] = ps[i];
01038         m++;
01039       }
01040     }
01041 
01042     // Return the number of vertical tangency points found.
01043     CGAL_assertion (m <= 2);
01044     return (m);
01045   }
01046 
01053   int horizontal_tangency_points (Point_2* hpts) const
01054   {
01055     // No horizontal tangency points for line segments:
01056     if (_orient == COLLINEAR)
01057       return (0);
01058 
01059     // Calculate the horizontal tangency points of the conic.
01060     Point_2    ps[2];
01061     int        n;
01062 
01063     n = _conic_horizontal_tangency_points (ps);
01064 
01065     // Return only the points that are contained in the arc interior.
01066     int    m = 0;
01067     
01068     for (int i = 0; i < n; i++)
01069     {
01070       if (is_full_conic() || _is_strictly_between_endpoints(ps[i]))
01071       {
01072         hpts[m] = ps[i];
01073         m++;
01074       }
01075     }
01076 
01077     // Return the number of horizontal tangency points found.
01078     CGAL_assertion (m <= 2);
01079     return (m);
01080   }
01081 
01089   int points_at_x (const Point_2& p,
01090                        Point_2 *ps) const
01091   {
01092     // Get the y coordinates of the points on the conic.
01093     Algebraic    ys[2];
01094     int          n;
01095 
01096     n = _conic_get_y_coordinates (p.x(), ys);
01097     
01098     // Find all the points that are contained in the arc.
01099     int   m = 0;
01100     
01101     for (int i = 0; i < n; i++)
01102     {
01103       ps[m] = Point_2 (p.x(), ys[i]);
01104 
01105       if (is_full_conic() || _is_between_endpoints(ps[m]))
01106         m++;
01107     }
01108 
01109     // Return the number of points on the arc.
01110     CGAL_assertion (m <= 2);
01111     return (m);
01112   }
01113 
01121   int points_at_y (const Point_2& p,
01122                        Point_2 *ps) const
01123   {
01124     // Get the y coordinates of the points on the conic.
01125     Algebraic    xs[2];
01126     int          n;
01127 
01128     n = _conic_get_x_coordinates (p.y(), xs);
01129     
01130     // Find all the points that are contained in the arc.
01131     int   m = 0;
01132     
01133     for (int i = 0; i < n; i++)
01134     {
01135       ps[m] = Point_2 (xs[i], p.y());
01136 
01137       if (is_full_conic() || _is_between_endpoints(ps[m]))
01138         m++;
01139     }
01140 
01141     // Return the number of points on the arc.
01142     CGAL_assertion (m <= 2);
01143     return (m);
01144   }
01146 
01147 private:
01148 
01150 
01151 
01157   void _set (const Rational* rat_coeffs)
01158   {
01159     _info = IS_VALID;
01160 
01161     // Convert the coefficients vector to an equivalent vector of integer
01162     // coefficients.
01163     Nt_traits         nt_traits;
01164     Integer           int_coeffs[6];
01165 
01166     nt_traits.convert_coefficients (rat_coeffs, rat_coeffs + 6,
01167                                     int_coeffs);
01168 
01169     // Check the orientation of conic curve, and negate the conic coefficients
01170     // if its given orientation.
01171     typename Rat_kernel::Conic_2   temp_conic (rat_coeffs[0], rat_coeffs[1],
01172                                                rat_coeffs[2], rat_coeffs[3],
01173                                                rat_coeffs[4], rat_coeffs[5]);
01174 
01175     if (_orient == temp_conic.orientation())
01176     {
01177       _r = int_coeffs[0];
01178       _s = int_coeffs[1];
01179       _t = int_coeffs[2];
01180       _u = int_coeffs[3];
01181       _v = int_coeffs[4];
01182       _w = int_coeffs[5];
01183     }
01184     else
01185     {
01186       _r = -int_coeffs[0];
01187       _s = -int_coeffs[1];
01188       _t = -int_coeffs[2];
01189       _u = -int_coeffs[3];
01190       _v = -int_coeffs[4];
01191       _w = -int_coeffs[5];
01192     }
01193 
01194     // Make sure both endpoint lie on the supporting conic.
01195     if (! _is_on_supporting_conic (_source) ||
01196         ! _is_on_supporting_conic (_target))
01197     {
01198       _info = 0;          // Invalid arc.
01199       return;
01200     }
01201 
01202     _extra_data_P = NULL;
01203 
01204     // Check whether we have a degree 2 curve.
01205     if ((CGAL::sign (_r) != ZERO ||
01206          CGAL::sign (_s) != ZERO ||
01207          CGAL::sign (_t) != ZERO))
01208     {
01209       if (_orient == COLLINEAR)
01210       {
01211         // We have a segment of a line pair with rational coefficients.
01212         // Compose the equation of the underlying line
01213         // (with algebraic coefficients).
01214         const Algebraic        x1 = _source.x(), y1 = _source.y();
01215         const Algebraic        x2 = _target.x(), y2 = _target.y();
01216         
01217         // The supporting line is A*x + B*y + C = 0, where:
01218         //
01219         //  A = y2 - y1,    B = x1 - x2,    C = x2*y1 - x1*y2 
01220         //
01221         // We use the extra dat field to store the equation of this line.
01222         _extra_data_P = new Extra_data;
01223         _extra_data_P->a = y2 - y1;
01224         _extra_data_P->b = x1 - x2;
01225         _extra_data_P->c = x2*y1 - x1*y2;
01226         _extra_data_P->side = ZERO;
01227 
01228         // Make sure the midpoint is on the line pair (thus making sure that
01229         // the two points are not taken from different lines).
01230         Alg_kernel       ker;
01231         Point_2          p_mid = ker.construct_midpoint_2_object() (_source,
01232                                                                     _target);
01233         
01234         if (CGAL::sign ((nt_traits.convert(_r)*p_mid.x() + 
01235                          nt_traits.convert(_t)*p_mid.y() + 
01236                          nt_traits.convert(_u)) * p_mid.x() +
01237                         (nt_traits.convert(_s)*p_mid.y() +
01238                          nt_traits.convert(_v)) * p_mid.y() +
01239                         nt_traits.convert(_w)) != ZERO)
01240         {
01241           _info = 0;          // Invalid arc.
01242           return;
01243         }
01244       }
01245       else 
01246       {
01247         // The sign of (4rs - t^2) detetmines the conic type:
01248         // - if it is possitive, the conic is an ellipse,
01249         // - if it is negative, the conic is a hyperbola,
01250         // - if it is zero, the conic is a parabola.
01251         CGAL::Sign   sign_conic = CGAL::sign (4*_r*_s - _t*_t);
01252 
01253         if (sign_conic == NEGATIVE)
01254           // Build the extra hyperbolic data
01255           _build_hyperbolic_arc_data ();
01256 
01257         if (sign_conic != POSITIVE)
01258         {
01259           // In case of a non-degenerate parabola or a hyperbola, make sure 
01260           // the arc is not infinite.
01261           Alg_kernel       ker;
01262           Point_2          p_mid = ker.construct_midpoint_2_object() (_source,
01263                                                                       _target);
01264           Point_2          ps[2];
01265 
01266           bool  finite_at_x = (points_at_x(p_mid, ps) > 0);
01267           bool  finite_at_y = (points_at_y(p_mid, ps) > 0);
01268       
01269           if (! finite_at_x && ! finite_at_y)
01270           {
01271             _info = 0;          // Invalid arc.
01272             return;
01273           }
01274         }
01275       }
01276     }
01277 
01278     // Mark that this arc valid and is not a full conic curve.
01279     _info = IS_VALID;
01280 
01281     return;
01282   }
01283 
01291   void _set_full (const Rational* rat_coeffs,
01292                   const bool& comp_orient)
01293   {
01294     // Convert the coefficients vector to an equivalent vector of integer
01295     // coefficients.
01296     Nt_traits         nt_traits;
01297     Integer           int_coeffs[6];
01298 
01299     nt_traits.convert_coefficients (rat_coeffs, rat_coeffs + 6,
01300                                     int_coeffs);
01301 
01302     // Check the orientation of conic curve, and negate the conic coefficients
01303     // if its given orientation.
01304     typename Rat_kernel::Conic_2   temp_conic (rat_coeffs[0], rat_coeffs[1],
01305                                                rat_coeffs[2], rat_coeffs[3],
01306                                                rat_coeffs[4], rat_coeffs[5]);
01307     const Orientation              temp_orient = temp_conic.orientation();
01308 
01309     if (comp_orient)
01310       _orient = temp_orient;
01311 
01312     if (_orient == temp_orient)
01313     {
01314       _r = int_coeffs[0];
01315       _s = int_coeffs[1];
01316       _t = int_coeffs[2];
01317       _u = int_coeffs[3];
01318       _v = int_coeffs[4];
01319       _w = int_coeffs[5];
01320     }
01321     else
01322     {
01323       _r = -int_coeffs[0];
01324       _s = -int_coeffs[1];
01325       _t = -int_coeffs[2];
01326       _u = -int_coeffs[3];
01327       _v = -int_coeffs[4];
01328       _w = -int_coeffs[5];
01329     }
01330 
01331     // Make sure the conic is a non-degenerate ellipse:
01332     // The coefficients should satisfy (4rs - t^2) > 0.
01333     const bool  is_ellipse = (CGAL::sign (4*_r*_s - _t*_t) == POSITIVE);
01334     CGAL_assertion (is_ellipse);
01335 
01336     // We do not have to store any extra data with the arc.
01337     _extra_data_P = NULL;
01338 
01339     // Mark that this arc is a full conic curve.
01340     if (is_ellipse)
01341       _info = IS_VALID | IS_FULL_CONIC;
01342     else
01343       _info = 0;
01344 
01345     return;
01346   }
01347 
01352   void _build_hyperbolic_arc_data ()
01353   {
01354     // Let phi be the rotation angle of the conic from its canonic form.
01355     // We can write:
01356     // 
01357     //                          t
01358     //  sin(2*phi) = -----------------------
01359     //                sqrt((r - s)^2 + t^2)
01360     // 
01361     //                        r - s
01362     //  cos(2*phi) = -----------------------
01363     //                sqrt((r - s)^2 + t^2)
01364     //
01365     Nt_traits        nt_traits;
01366     const int        or_fact = (_orient == CLOCKWISE) ? -1 : 1;
01367     const Algebraic  r = nt_traits.convert (or_fact * _r);
01368     const Algebraic  s = nt_traits.convert (or_fact * _s);
01369     const Algebraic  t = nt_traits.convert (or_fact * _t);
01370     const Algebraic  cos_2phi = (r - s) / nt_traits.sqrt((r-s)*(r-s) + t*t);
01371     const Algebraic  _zero = 0;
01372     const Algebraic  _one = 1;
01373     const Algebraic  _two = 2;
01374     Algebraic        sin_phi;
01375     Algebraic        cos_phi;
01376 
01377     // Calculate sin(phi) and cos(phi) according to the half-angle formulae:
01378     // 
01379     //  sin(phi)^2 = 0.5 * (1 - cos(2*phi))
01380     //  cos(phi)^2 = 0.5 * (1 + cos(2*phi))
01381     Sign             sign_t = CGAL::sign (t);
01382 
01383     if (sign_t == ZERO)
01384     {
01385       // sin(2*phi) == 0, so phi = 0 or phi = PI/2
01386       if (CGAL::sign (cos_2phi) == POSITIVE)
01387       {
01388         // phi = 0.
01389         sin_phi = _zero;
01390         cos_phi = _one;
01391       }
01392       else
01393       {
01394         // phi = PI.
01395         sin_phi = _zero;
01396         cos_phi = -_one;
01397       }
01398     }
01399     else if (sign_t == POSITIVE)
01400     {
01401       // sin(2*phi) > 0 so 0 < phi < PI/2.
01402       sin_phi = nt_traits.sqrt((_one + cos_2phi) / _two);
01403       cos_phi = nt_traits.sqrt((_one - cos_2phi) / _two);
01404     }
01405     else
01406     {
01407       // sin(2*phi) < 0 so PI/2 < phi < PI.
01408       sin_phi = nt_traits.sqrt((_one + cos_2phi) / _two);
01409       cos_phi = -nt_traits.sqrt((_one - cos_2phi) / _two);
01410     }
01411            
01412     // Calculate the center (x0, y0) of the conic, given by the formulae:
01413     //
01414     //        t*v - 2*s*u                t*u - 2*r*v
01415     //  x0 = -------------   ,     y0 = -------------
01416     //        4*r*s - t^2                4*r*s - t^2
01417     //
01418     // The denominator (4*r*s - t^2) must be negative for hyperbolas.
01419     const Algebraic  u = nt_traits.convert (or_fact * _u);
01420     const Algebraic  v = nt_traits.convert (or_fact * _v);
01421     const Algebraic  det = 4*r*s - t*t;
01422     Algebraic        x0, y0;
01423 
01424     CGAL_assertion (CGAL::sign (det) == NEGATIVE);
01425     
01426     x0 = (t*v - _two*s*u) / det;
01427     y0 = (t*u - _two*r*v) / det;
01428    
01429     // The axis separating the two branches of the hyperbola is now given by:
01430     // 
01431     //  cos(phi)*x + sin(phi)*y - (cos(phi)*x0 + sin(phi)*y0) = 0
01432     //
01433     // We store the equation of this line in the extra data structure and also
01434     // the sign (side of half-plane) our arc occupies with respect to the line.
01435     _extra_data_P = new Extra_data;
01436 
01437     _extra_data_P->a = cos_phi;
01438     _extra_data_P->b = sin_phi;
01439     _extra_data_P->c = - (cos_phi*x0 + sin_phi*y0);
01440 
01441     // Make sure that the two endpoints are located on the same branch
01442     // of the hyperbola.
01443     _extra_data_P->side = _sign_of_extra_data (_source.x(), _source.y());
01444 
01445     CGAL_assertion (_extra_data_P->side != ZERO);
01446     CGAL_assertion (_extra_data_P->side == _sign_of_extra_data(_target.x(),
01447                                                               _target.y()));
01448 
01449     return;
01450   }
01452 
01453 protected:
01454 
01456 
01457 
01465   Sign _sign_of_extra_data (const Algebraic& px,
01466                             const Algebraic& py) const
01467   {
01468     CGAL_assertion (_extra_data_P != NULL);
01469 
01470     if (_extra_data_P == NULL)
01471       return (ZERO);
01472 
01473     Algebraic         val = (_extra_data_P->a*px + _extra_data_P->b*py + 
01474                              _extra_data_P->c);
01475 
01476     return (CGAL::sign (val));
01477   }
01478 
01484   bool _is_on_supporting_conic (const Point_2& p) const
01485   {
01486     // Check whether p satisfies the conic equation.
01487     // The point must satisfy: r*x^2 + s*y^2 + t*xy + u*x + v*y + w = 0.
01488     Nt_traits        nt_traits;
01489     const Algebraic  val = (nt_traits.convert(_r)*p.x() + 
01490                             nt_traits.convert(_t)*p.y() +
01491                             nt_traits.convert(_u)) * p.x() +
01492                            (nt_traits.convert(_s)*p.y() + 
01493                             nt_traits.convert(_v)) * p.y() +
01494                            nt_traits.convert(_w);
01495 
01496     return (CGAL::sign (val) == ZERO);
01497   }
01498  
01506   bool _is_between_endpoints (const Point_2& p) const
01507   {
01508     CGAL_precondition (! is_full_conic());
01509 
01510     // Check if p is one of the endpoints.
01511     Alg_kernel                         ker;
01512 
01513     if (ker.equal_2_object() (p, _source) || 
01514         ker.equal_2_object() (p, _target))
01515     {
01516       return (true);
01517     }
01518     else
01519     {
01520       return (_is_strictly_between_endpoints(p));
01521     }
01522   }
01523 
01532   bool _is_strictly_between_endpoints (const Point_2& p) const
01533   {
01534     // In case this is a full conic, any point on its boundary is between
01535     // its end points.
01536     if (is_full_conic())
01537       return (true);
01538 
01539     // Check if we have extra data available.
01540     if (_extra_data_P != NULL)
01541     {
01542       if (_extra_data_P->side != ZERO)
01543       {
01544         // In case of a hyperbolic arc, make sure the point is located on the
01545         // same branch as the arc.
01546         if (_sign_of_extra_data(p.x(), p.y()) != _extra_data_P->side)
01547           return (false);
01548       }
01549       else
01550       {
01551         // In case we have a segment of a line pair, make sure that p really
01552         // satisfies the equation of the line.
01553         if (_sign_of_extra_data(p.x(), p.y()) != ZERO)
01554           return (false);
01555       }
01556     }
01557 
01558     // Act according to the conic degree.
01559     Alg_kernel                         ker;
01560 
01561     if (_orient == COLLINEAR)
01562     {
01563       Comparison_result  res1;
01564       Comparison_result  res2;
01565 
01566       if (ker.compare_x_2_object() (_source, _target) == EQUAL)
01567       {
01568         // In case of a vertical segment - just check whether the y coordinate
01569         // of p is between those of the source's and of the target's.
01570         res1 = ker.compare_y_2_object() (p, _source);
01571         res2 = ker.compare_y_2_object() (p, _target);
01572       }
01573       else
01574       {
01575         // Otherwise, since the segment is x-monotone, just check whether the
01576         // x coordinate of p is between those of the source's and of the 
01577         // target's.
01578         res1 = ker.compare_x_2_object() (p, _source);
01579         res2 = ker.compare_x_2_object() (p, _target);
01580       }
01581 
01582       // If p is not in the (open) x-range (or y-range) of the segment, it
01583       // cannot be contained in the segment.
01584       if (res1 == EQUAL || res2 == EQUAL || res1 == res2)
01585         return (false);
01586 
01587       // Perform an orientation test: This is crucial for segment of line
01588       // pairs, as we want to make sure that p lies on the same line as the
01589       // source and the target.
01590       return (ker.orientation_2_object()(_source, p, _target) == COLLINEAR);
01591     }
01592     else
01593     {
01594       // In case of a conic of degree 2, make a decision based on the conic's
01595       // orientation and whether (source,p,target) is a right or a left turn.
01596       if (_orient == COUNTERCLOCKWISE)
01597         return (ker.orientation_2_object()(_source, p, _target) == LEFT_TURN);
01598       else
01599         return (ker.orientation_2_object()(_source, p, _target) == RIGHT_TURN);
01600     }
01601   }
01602   
01609   int _conic_vertical_tangency_points (Point_2* ps) const
01610   {
01611     // In case the base conic is of degree 1 (and not 2), the arc has no
01612     // vertical tangency points.
01613     if (CGAL::sign (_s) == ZERO)
01614       return (0);
01615 
01616     // We are interested in the x coordinates where the quadratic equation:
01617     //  s*y^2 + (t*x + v)*y + (r*x^2 + u*x + w) = 0
01618     // has a single solution (obviously if s = 0, there are no such points).
01619     // We therefore demand that the discriminant of this equation is zero:
01620     //  (t*x + v)^2 - 4*s*(r*x^2 + u*x + w) = 0
01621     const Integer _two = 2;
01622     const Integer _four = 4;
01623     Algebraic     xs[2];
01624     Algebraic    *xs_end;
01625     int           n_xs;
01626     Nt_traits     nt_traits;
01627     
01628     xs_end = nt_traits.solve_quadratic_equation (_t*_t - _four*_r*_s,
01629                                                  _two*_t*_v - _four*_s*_u,
01630                                                  _v*_v - _four*_s*_w,
01631                                                  xs);
01632     n_xs = xs_end - xs;
01633 
01634     // Find the y-coordinates of the vertical tangency points.
01635     Algebraic     ys[2];
01636     Algebraic    *ys_end;
01637     int           n_ys;
01638 
01639     if (CGAL::sign (_t) == ZERO)
01640     {
01641       // The two vertical tangency points have the same y coordinate:
01642       ys[0] = nt_traits.convert (-_v) /nt_traits.convert (_two*_s);
01643       n_ys = 1;
01644     }
01645     else
01646     {
01647       ys_end =
01648         nt_traits.solve_quadratic_equation (_four*_r*_s*_s - _s*_t*_t,
01649                                             _four*_r*_s*_v - _two*_s*_t*_u,
01650                                             _r*_v*_v - _t*_u*_v + _t*_t*_w,
01651                                             ys);
01652       n_ys = ys_end - ys;
01653     }
01654 
01655     // Pair the x and y coordinates and obtain the vertical tangency points.
01656     int   n = 0;
01657     int   i, j;
01658 
01659     for (i = 0; i < n_xs; i++)
01660     {
01661       if (n_ys == 1)
01662       {
01663         ps[n] = Point_2 (xs[i], ys[0]);
01664         n++;
01665       }
01666       else
01667       {
01668         for (j = 0; j < n_ys; j++)
01669         {
01670           if (CGAL::compare (ys[j], 
01671                              -(nt_traits.convert(_t) * xs[i] + 
01672                                nt_traits.convert(_v)) /
01673                              nt_traits.convert(_two*_s)) == EQUAL)
01674           {
01675             ps[n] = Point_2 (xs[i], ys[j]);
01676             n++;
01677             break;
01678           }
01679         }
01680       }
01681     }
01682 
01683     CGAL_assertion (n <= 2);
01684     return (n);
01685   }
01686 
01693   int _conic_horizontal_tangency_points (Point_2* ps) const
01694   {
01695     const Integer _zero = 0;
01696 
01697     // In case the base conic is of degree 1 (and not 2), the arc has no
01698     // vertical tangency points.
01699     if (CGAL::sign (_r) == ZERO)
01700       return (0);
01701 
01702     // We are interested in the y coordinates were the quadratic equation:
01703     //  r*x^2 + (t*y + u)*x + (s*y^2 + v*y + w) = 0
01704     // has a single solution (obviously if r = 0, there are no such points).
01705     // We therefore demand that the discriminant of this equation is zero:
01706     //  (t*y + u)^2 - 4*r*(s*y^2 + v*y + w) = 0
01707     const Integer _two = 2;
01708     const Integer _four = 4;
01709     int           n;
01710     Algebraic     ys[2];
01711     Algebraic    *ys_end;
01712     Nt_traits     nt_traits;
01713 
01714     ys_end = nt_traits.solve_quadratic_equation (_t*_t - _four*_r*_s,
01715                                                  _two*_t*_u - _four*_r*_v,
01716                                                  _u*_u - _four*_r*_w,
01717                                                  ys);
01718     n = ys_end - ys;
01719 
01720     // Compute the x coordinates and construct the horizontal tangency points.
01721     Algebraic     x;
01722     int           i;
01723 
01724     for (i = 0; i < n; i++)
01725     {
01726       // Having computed y, x is the simgle solution to the quadratic equation
01727       // above, and since its discriminant is 0, x is simply given by:
01728       x = -(nt_traits.convert(_t)*ys[i] + nt_traits.convert(_u)) / 
01729         nt_traits.convert(_two*_r);
01730 
01731       ps[i] = Point_2 (x, ys[i]);
01732     }
01733       
01734     CGAL_assertion (n <= 2);
01735     return (n);
01736   }
01737 
01745   int _conic_get_y_coordinates (const Algebraic& x,
01746                                 Algebraic *ys) const
01747   {
01748     // Solve the quadratic equation for a given x and find the y values:
01749     //  s*y^2 + (t*x + v)*y + (r*x^2 + u*x + w) = 0
01750     Nt_traits     nt_traits;
01751     Algebraic     A = nt_traits.convert(_s);
01752     Algebraic     B = nt_traits.convert(_t)*x + nt_traits.convert(_v);
01753     Algebraic     C = (nt_traits.convert(_r)*x + 
01754                        nt_traits.convert(_u))*x + nt_traits.convert(_w);
01755 
01756     return (_solve_quadratic_equation (A, B, C, ys[0], ys[1]));
01757   }
01758 
01766   int _conic_get_x_coordinates (const Algebraic& y,
01767                                 Algebraic *xs) const
01768   {
01769     // Solve the quadratic equation for a given y and find the x values:
01770     //  r*x^2 + (t*y + u)*x + (s*y^2 + v*y + w) = 0
01771     Nt_traits     nt_traits;
01772     Algebraic     A = nt_traits.convert(_r);
01773     Algebraic     B = nt_traits.convert(_t)*y + nt_traits.convert(_u);
01774     Algebraic     C = (nt_traits.convert(_s)*y + 
01775                        nt_traits.convert(_v))*y + nt_traits.convert(_w);
01776 
01777     return (_solve_quadratic_equation (A, B, C, xs[0], xs[1]));
01778   }
01779 
01786   int _solve_quadratic_equation (const Algebraic& A,
01787                                  const Algebraic& B,
01788                                  const Algebraic& C,
01789                                  Algebraic& x_minus, Algebraic& x_plus) const
01790   {
01791     // Check if we actually have a linear equation.
01792     if (CGAL::sign(A) == ZERO)
01793     {
01794       if (CGAL::sign(B) == ZERO)
01795         return (0);
01796 
01797       x_minus = x_plus = -C / B;
01798       return (1);
01799     }
01800 
01801     // Compute the discriminant and act according to its sign.
01802     const Algebraic  disc = B*B - 4*A*C;
01803     Sign             sign_disc = CGAL::sign (disc);
01804 
01805     if (sign_disc == NEGATIVE)
01806     {
01807       // No real-valued solutions:
01808       return (0);
01809     }
01810     else if (sign_disc == ZERO)
01811     {
01812       // One distinct solution:
01813       x_minus = x_plus = -B / (2*A);
01814       return (1);
01815     }
01816 
01817     // Compute the two distinct solutions:
01818     Algebraic     _2A = 2*A;
01819     Nt_traits     nt_traits;
01820     Algebraic     sqrt_disc = nt_traits.sqrt (disc);
01821 
01822     x_minus = -(B + sqrt_disc) / _2A;
01823     x_plus = (sqrt_disc - B) / _2A;
01824     return (2);
01825   }
01827 
01828 };
01829 
01833 template <class Rat_kernel, class Alg_kernel, class Nt_traits>
01834 std::ostream& 
01835 operator<< (std::ostream& os, 
01836             const _Conic_arc_2<Rat_kernel, Alg_kernel, Nt_traits> & arc)
01837 {
01838   os << "{" << CGAL::to_double(arc.r()) << "*x^2 + "
01839      << CGAL::to_double(arc.s()) << "*y^2 + "
01840      << CGAL::to_double(arc.t()) << "*xy + " 
01841      << CGAL::to_double(arc.u()) << "*x + "
01842      << CGAL::to_double(arc.v()) << "*y + "
01843      << CGAL::to_double(arc.w()) << "}";
01844 
01845   if (arc.is_full_conic())
01846   {
01847     os << " - Full curve";
01848   }
01849   else
01850   {
01851     os << " : (" << CGAL::to_double(arc.source().x()) << "," 
01852        << CGAL::to_double(arc.source().y()) << ") ";
01853 
01854     if (arc.orientation() == CLOCKWISE)
01855       os << "--cw-->";
01856     else if (arc.orientation() == COUNTERCLOCKWISE)
01857       os << "--ccw-->";
01858     else
01859       os << "--l-->";
01860 
01861     os << " (" << CGAL::to_double(arc.target().x()) << "," 
01862        << CGAL::to_double(arc.target().y()) << ")";
01863   }
01864 
01865   return (os);
01866 }
01867 
01868 CGAL_END_NAMESPACE
01869 
01870 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines