BWAPI
|
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