BWAPI
|
00001 // Copyright (c) 2006 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_geodesic_arc_on_sphere_traits_2.h $ 00015 // $Id: Arr_geodesic_arc_on_sphere_traits_2.h 49924 2009-06-16 07:14:42Z efif $ 00016 // 00017 // 00018 // Author(s) : Efi Fogel <efif@post.tau.ac.il> 00019 00020 #ifndef CGAL_ARR_GEODESIC_ARC_ON_SPHERE_TRAITS_2_H 00021 #define CGAL_ARR_GEODESIC_ARC_ON_SPHERE_TRAITS_2_H 00022 00023 // #define CGAL_FULL_X_MONOTONE_GEODESIC_ARC_ON_SPHERE_IS_SUPPORTED 1 00024 00030 #include <fstream> 00031 00032 #include <CGAL/config.h> 00033 #include <CGAL/tags.h> 00034 #include <CGAL/intersections.h> 00035 #include <CGAL/Arr_tags.h> 00036 #include <CGAL/Arr_enums.h> 00037 00038 CGAL_BEGIN_NAMESPACE 00039 00040 #define CGAL_X_MINUS_1_Y_0 0 00041 #define CGAL_X_MINUS_8_Y_6 1 00042 #define CGAL_X_MINUS_11_Y_7 2 00043 00044 #ifndef CGAL_IDENTIFICATION_XY 00045 #define CGAL_IDENTIFICATION_XY CGAL_X_MINUS_1_Y_0 00046 #endif 00047 00048 template <typename Kernel> class Arr_x_monotone_geodesic_arc_on_sphere_3; 00049 template <typename Kernel> class Arr_geodesic_arc_on_sphere_3; 00050 template <typename Kernel> class Arr_extended_direction_3; 00051 00056 template <typename T_Kernel> 00057 class Arr_geodesic_arc_on_sphere_traits_2 : public T_Kernel { 00058 friend class Arr_x_monotone_geodesic_arc_on_sphere_3<T_Kernel>; 00059 friend class Arr_geodesic_arc_on_sphere_3<T_Kernel>; 00060 friend class Arr_extended_direction_3<T_Kernel>; 00061 00062 public: 00063 typedef T_Kernel Kernel; 00064 00065 // Category tags: 00066 typedef Tag_true Has_left_category; 00067 typedef Tag_true Has_merge_category; 00068 00069 typedef Arr_identified_side_tag Arr_left_side_tag; 00070 typedef Arr_contracted_side_tag Arr_bottom_side_tag; 00071 typedef Arr_contracted_side_tag Arr_top_side_tag; 00072 typedef Arr_identified_side_tag Arr_right_side_tag; 00073 00075 Arr_geodesic_arc_on_sphere_traits_2(){} 00076 00077 protected: 00078 typedef typename Kernel::FT FT; 00079 00080 typedef typename Kernel::Direction_3 Direction_3; 00081 typedef typename Kernel::Vector_3 Vector_3; 00082 typedef typename Kernel::Direction_2 Direction_2; 00083 typedef typename Kernel::Vector_2 Vector_2; 00084 00088 inline static const Direction_3 & pos_pole() 00089 { 00090 static const Direction_3 d(0, 0, 1); 00091 return d; 00092 } 00093 00097 inline static const Direction_3 & neg_pole() 00098 { 00099 static const Direction_3 d(0, 0, -1); 00100 return d; 00101 } 00102 00108 inline static const Direction_2 & identification_xy() 00109 { 00110 #if (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_1_Y_0) 00111 static const Direction_2 d(-1, 0); 00112 #elif (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_8_Y_6) 00113 static const Direction_2 d(-8, 6); 00114 #elif (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_11_Y_7) 00115 static const Direction_2 d(-11, 7); 00116 #else 00117 #error CGAL_IDENTIFICATION_XY is not defined 00118 #endif 00119 return d; 00120 } 00121 00127 inline static const Direction_3 & identification_normal() 00128 { 00129 #if (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_1_Y_0) 00130 static const Direction_3 d(0, 1, 0); 00131 #elif (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_8_Y_6) 00132 static const Direction_3 d(6, 8, 0); 00133 #elif (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_11_Y_7) 00134 static const Direction_3 d(7, 11, 0); 00135 #else 00136 #error CGAL_IDENTIFICATION_XY is not defined 00137 #endif 00138 return d; 00139 } 00140 00144 inline static const Direction_2 & neg_x_2() 00145 { 00146 static const Direction_2 d(-1, 0); 00147 return d; 00148 } 00149 00153 inline static const Direction_2 & neg_y_2() 00154 { 00155 static const Direction_2 d(0, -1); 00156 return d; 00157 } 00158 00163 inline static Sign x_sign(Direction_3 d) { return CGAL::sign(d.dx()); } 00164 00169 inline static Sign y_sign(Direction_3 d) { return CGAL::sign(d.dy()); } 00170 00175 inline static Sign z_sign(Direction_3 d) { return CGAL::sign(d.dz()); } 00176 00177 typedef Direction_2 (*Project)(const Direction_3 & d) ; 00178 00183 inline static Direction_2 project_xy(const Direction_3 & d) 00184 { return Direction_2(d.dx(), d.dy()); } 00185 00190 inline static Direction_2 project_yz(const Direction_3 & d) 00191 { return Direction_2(d.dy(), d.dz()); } 00192 00197 inline static Direction_2 project_xz(const Direction_3 & d) 00198 { return Direction_2(d.dx(), d.dz()); } 00199 00205 inline Oriented_side oriented_side(const Direction_3 & normal, 00206 const Direction_3 dir) const 00207 { 00208 FT dot = normal.vector() * dir.vector(); 00209 return CGAL::sign(dot); 00210 } 00211 00217 static inline Orientation orientation(const Direction_2 & d1, 00218 const Direction_2 & d2) 00219 { 00220 Kernel kernel; 00221 return kernel.orientation_2_object()(d1.vector(), d2.vector()); 00222 } 00223 00231 inline bool has_on(const Direction_3 & normal, const Direction_3 & dir) const 00232 { 00233 FT dot = normal.vector() * dir.vector(); 00234 return CGAL::sign(dot) == ZERO; 00235 } 00236 00237 public: 00245 inline Comparison_result compare_y(const Direction_3 & d1, 00246 const Direction_3 & d2) const 00247 { 00248 Vector_3 v1 = d1.vector(); 00249 Vector_3 v2 = d2.vector(); 00250 00251 FT dot_p1 = v1.z(); 00252 FT dot_p2 = v2.z(); 00253 00254 Sign s1 = CGAL::sign(dot_p1); 00255 Sign s2 = CGAL::sign(dot_p2); 00256 00257 if (s1 != s2) { 00258 if (s1 == NEGATIVE) return SMALLER; 00259 if (s1 == POSITIVE) return LARGER; 00260 if (s2 == NEGATIVE) return LARGER; 00261 if (s2 == POSITIVE) return SMALLER; 00262 } 00263 if (s1 == ZERO) return EQUAL; 00264 00265 FT norm1 = v1 * v1; 00266 FT norm2 = v2 * v2; 00267 00268 return (s1 == POSITIVE) ? 00269 compare(dot_p1 * dot_p1 * norm2, dot_p2 * dot_p2 * norm1) : 00270 compare(dot_p2 * dot_p2 * norm1, dot_p1 * dot_p1 * norm2); 00271 } 00272 00280 inline Comparison_result compare_x(const Direction_2 & d1, 00281 const Direction_2 & d2) const 00282 { 00283 const Kernel * kernel = this; 00284 if (kernel->equal_2_object()(d1, d2)) return EQUAL; 00285 const Direction_2 & d = identification_xy(); 00286 return (kernel->counterclockwise_in_between_2_object()(d, d1, d2)) ? 00287 LARGER : SMALLER; 00288 } 00289 00299 inline Comparison_result compare_x(const Direction_3 & d1, 00300 const Direction_3 & d2) const 00301 { 00302 // Compare the projections onto the xy plane: 00303 Direction_2 d1_2 = project_xy(d1); 00304 Direction_2 d2_2 = project_xy(d2); 00305 return compare_x(d1_2, d2_2); 00306 } 00307 00319 inline Comparison_result compare_xy(const Direction_3 & d1, 00320 const Direction_3 & d2) const 00321 { 00322 Comparison_result res = compare_x(d1, d2); 00323 if (res == EQUAL) return compare_y(d1, d2); 00324 return res; 00325 } 00326 00327 public: 00328 // Traits objects 00329 typedef Arr_extended_direction_3<Kernel> Point_2; 00330 typedef Arr_x_monotone_geodesic_arc_on_sphere_3<Kernel> X_monotone_curve_2; 00331 typedef Arr_geodesic_arc_on_sphere_3<Kernel> Curve_2; 00332 typedef unsigned int Multiplicity; 00333 00334 public: 00336 00337 00339 class Compare_x_2 { 00340 protected: 00341 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 00342 00344 const Traits * m_traits; 00345 00349 Compare_x_2(const Traits * traits) : m_traits(traits) {} 00350 00351 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 00352 00353 public: 00363 Comparison_result operator()(const Point_2 & p1, const Point_2 & p2) const 00364 { 00365 CGAL_precondition(p1.is_no_boundary()); 00366 CGAL_precondition(p2.is_no_boundary()); 00367 00368 return m_traits->compare_x(p1, p2); 00369 } 00370 }; 00371 00373 Compare_x_2 compare_x_2_object() const { return Compare_x_2(this); } 00374 00378 class Compare_xy_2 { 00379 protected: 00380 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 00381 00383 const Traits * m_traits; 00384 00388 Compare_xy_2(const Traits * traits) : m_traits(traits) {} 00389 00390 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 00391 00392 public: 00404 Comparison_result operator()(const Point_2 & p1, const Point_2 & p2) const 00405 { 00406 CGAL_precondition(p1.is_no_boundary()); 00407 CGAL_precondition(p2.is_no_boundary()); 00408 00409 return m_traits->compare_xy(p1, p2); 00410 } 00411 }; 00412 00414 Compare_xy_2 compare_xy_2_object() const { return Compare_xy_2(this); } 00415 00417 class Construct_min_vertex_2 { 00418 public: 00423 const Point_2 & operator()(const X_monotone_curve_2 & xc) const 00424 { return xc.left(); } 00425 }; 00426 00428 Construct_min_vertex_2 construct_min_vertex_2_object() const 00429 { return Construct_min_vertex_2(); } 00430 00432 class Construct_max_vertex_2 { 00433 public: 00438 const Point_2 & operator()(const X_monotone_curve_2 & xc) const 00439 { return xc.right(); } 00440 }; 00441 00443 Construct_max_vertex_2 construct_max_vertex_2_object() const 00444 { return Construct_max_vertex_2(); } 00445 00447 class Is_vertical_2 { 00448 public: 00454 bool operator()(const X_monotone_curve_2 & xc) const 00455 { 00456 CGAL_precondition(!xc.is_degenerate()); 00457 return xc.is_vertical(); 00458 } 00459 }; 00460 00462 Is_vertical_2 is_vertical_2_object() const { return Is_vertical_2(); } 00463 00467 class Compare_y_at_x_2 { 00468 protected: 00469 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 00470 00472 const Traits * m_traits; 00473 00477 Compare_y_at_x_2(const Traits * traits) : m_traits(traits) {} 00478 00479 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 00480 00481 public: 00491 Comparison_result operator()(const Point_2 & p, 00492 const X_monotone_curve_2 & xc) const 00493 { 00494 CGAL_precondition(!p.is_min_boundary() && !p.is_max_boundary()); 00495 CGAL_precondition(xc.is_in_x_range(p)); 00496 00497 if (xc.is_vertical()) { 00498 // Compare the point with the left endpoint. If smaller, return SMALLER. 00499 // Otherwise, if EQUAL, return EQUAL. 00500 // Otherwise, compare with the right endpoint. If larger, return LARGER. 00501 // Otherwise, return EQUAL: 00502 if (!xc.left().is_min_boundary()) { 00503 Comparison_result cr = m_traits->compare_y(p, xc.left()); 00504 if (cr != LARGER) return cr; 00505 } 00506 if (xc.right().is_max_boundary()) return EQUAL; 00507 Comparison_result cr = m_traits->compare_y(p, xc.right()); 00508 return (cr == LARGER) ? LARGER : EQUAL; 00509 } 00510 00511 // Compare the point to the underlying plane of xc: 00512 Oriented_side os = m_traits->oriented_side(xc.normal(), p); 00513 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 00514 (xc.is_directed_right()) ? 00515 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER) : 00516 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER); 00517 } 00518 }; 00519 00521 Compare_y_at_x_2 compare_y_at_x_2_object() const 00522 { return Compare_y_at_x_2(this); } 00523 00527 class Compare_y_at_x_left_2 { 00528 protected: 00529 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 00530 00532 const Traits * m_traits; 00533 00537 Compare_y_at_x_left_2(const Traits * traits) : m_traits(traits) {} 00538 00539 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 00540 00541 public: 00553 Comparison_result operator()(const X_monotone_curve_2 & xc1, 00554 const X_monotone_curve_2 & xc2, 00555 const Point_2 & p) const 00556 { 00557 CGAL_precondition(!xc1.is_degenerate()); 00558 CGAL_precondition(!xc2.is_degenerate()); 00559 CGAL_precondition(p == xc1.right()); 00560 CGAL_precondition(p == xc2.right()); 00561 00562 // If Both arcs are vertical, they overlap: 00563 if (xc1.is_vertical() && xc2.is_vertical()) return EQUAL; 00564 if (xc1.is_vertical()) return SMALLER; 00565 if (xc2.is_vertical()) return LARGER; 00566 00567 // Non of the arc is verticel. Thus, non of the endpoints coincide with 00568 // a pole. 00569 // Compare the y-coord. at the x-coord of the most right left-endpoint. 00570 const Point_2 & l1 = xc1.left(); 00571 const Point_2 & l2 = xc2.left(); 00572 if (!l1.is_no_boundary()) { 00573 // use l2 and xc1: 00574 Oriented_side os = m_traits->oriented_side(xc1.normal(), l2); 00575 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 00576 (xc1.is_directed_right()) ? 00577 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER) : 00578 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER); 00579 } 00580 if (!l2.is_no_boundary()) { 00581 // use l1 and xc2: 00582 Oriented_side os = m_traits->oriented_side(xc2.normal(), l1); 00583 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 00584 (xc2.is_directed_right()) ? 00585 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER) : 00586 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER); 00587 } 00588 00589 if (m_traits->compare_xy(l1, l2) == SMALLER) { 00590 // use l2 and xc1: 00591 Oriented_side os = m_traits->oriented_side(xc1.normal(), l2); 00592 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 00593 (xc1.is_directed_right()) ? 00594 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER) : 00595 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER); 00596 } 00597 // use l1 and xc2: 00598 Oriented_side os = m_traits->oriented_side(xc2.normal(), l1); 00599 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 00600 (xc2.is_directed_right()) ? 00601 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER) : 00602 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER); 00603 } 00604 }; 00605 00607 Compare_y_at_x_left_2 compare_y_at_x_left_2_object() const 00608 { return Compare_y_at_x_left_2(this); } 00609 00613 class Compare_y_at_x_right_2 { 00614 protected: 00615 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 00616 00618 const Traits * m_traits; 00619 00623 Compare_y_at_x_right_2(const Traits * traits) : m_traits(traits) {} 00624 00625 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 00626 00627 public: 00639 Comparison_result operator()(const X_monotone_curve_2 & xc1, 00640 const X_monotone_curve_2 & xc2, 00641 const Point_2 &) const 00642 { 00643 CGAL_precondition(!xc1.is_degenerate()); 00644 CGAL_precondition(!xc2.is_degenerate()); 00645 00646 // CGAL_precondition(p == xc1.left()); 00647 // CGAL_precondition(p == xc2.left()); 00648 00649 // If Both arcs are vertical, they overlap: 00650 if (xc1.is_vertical() && xc2.is_vertical()) return EQUAL; 00651 if (xc1.is_vertical()) return LARGER; 00652 if (xc2.is_vertical()) return SMALLER; 00653 00654 // Non of the arcs is verticel. Thus, non of the endpoints coincide with 00655 // a pole. 00656 // Compare the y-coord. at the x-coord of the most left right-endpoint. 00657 const Point_2 & r1 = xc1.right(); 00658 const Point_2 & r2 = xc2.right(); 00659 if (!r1.is_no_boundary()) { 00660 // use r2 and xc1: 00661 Oriented_side os = m_traits->oriented_side(xc1.normal(), r2); 00662 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 00663 (xc1.is_directed_right()) ? 00664 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER) : 00665 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER); 00666 } 00667 if (!r2.is_no_boundary()) { 00668 // use r1 and xc2: 00669 Oriented_side os = m_traits->oriented_side(xc2.normal(), r1); 00670 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 00671 (xc2.is_directed_right()) ? 00672 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER) : 00673 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER); 00674 } 00675 if (m_traits->compare_xy(r1, r2) == LARGER) { 00676 // use r2 and xc1: 00677 Oriented_side os = m_traits->oriented_side(xc1.normal(), r2); 00678 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 00679 (xc1.is_directed_right()) ? 00680 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER) : 00681 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER); 00682 } 00683 // use r1 and xc2: 00684 Oriented_side os = m_traits->oriented_side(xc2.normal(), r1); 00685 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 00686 (xc2.is_directed_right()) ? 00687 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER) : 00688 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER); 00689 } 00690 }; 00691 00693 Compare_y_at_x_right_2 compare_y_at_x_right_2_object() const 00694 { return Compare_y_at_x_right_2(this); } 00695 00699 class Equal_2 { 00700 protected: 00701 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 00702 00704 const Traits * m_traits; 00705 00709 Equal_2(const Traits * traits) : m_traits(traits) {} 00710 00711 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 00712 00713 public: 00720 bool operator()(const X_monotone_curve_2 & xc1, 00721 const X_monotone_curve_2 & xc2) const 00722 { 00723 const Kernel * kernel = m_traits; 00724 typename Kernel::Equal_3 equal_3 = kernel->equal_3_object(); 00725 if (xc1.is_full() || xc2.is_full()) { 00726 return (xc1.is_full() && xc2.is_full() && 00727 equal_3(xc1.left(), xc2.left())); 00728 } 00729 00730 return (equal_3(xc1.left(), xc2.left()) && 00731 equal_3(xc1.right(), xc2.right())); 00732 } 00733 00739 bool operator()(const Point_2 & p1, const Point_2 & p2) const 00740 { 00741 const Kernel * kernel = m_traits; 00742 return kernel->equal_3_object()(p1, p2); 00743 } 00744 }; 00745 00747 Equal_2 equal_2_object() const { return Equal_2(this); } 00749 00751 00752 00756 class Parameter_space_in_x_2 { 00757 public: 00776 Arr_parameter_space operator()(const X_monotone_curve_2 & xcv, 00777 Arr_curve_end ce) const 00778 { 00779 if (xcv.is_vertical()) { 00780 CGAL_precondition(!xcv.is_on_boundary()); 00781 return ARR_INTERIOR; 00782 } 00783 00784 return (ce == ARR_MIN_END) ? 00785 ((xcv.left().is_no_boundary()) ? ARR_INTERIOR : ARR_LEFT_BOUNDARY) : 00786 ((xcv.right().is_no_boundary()) ? ARR_INTERIOR : ARR_RIGHT_BOUNDARY); 00787 } 00788 00794 Arr_parameter_space operator()(const Point_2 p) const 00795 { 00801 return (p.is_mid_boundary()) ? ARR_LEFT_BOUNDARY : ARR_INTERIOR; 00802 } 00803 }; 00804 00806 Parameter_space_in_x_2 parameter_space_in_x_2_object() const 00807 { return Parameter_space_in_x_2(); } 00808 00812 class Parameter_space_in_y_2 { 00813 public: 00832 Arr_parameter_space operator()(const X_monotone_curve_2 & xcv, 00833 Arr_curve_end ce) const 00834 { 00835 return (ce == ARR_MIN_END) ? 00836 ((xcv.left().is_min_boundary()) ? ARR_BOTTOM_BOUNDARY: ARR_INTERIOR) : 00837 ((xcv.right().is_max_boundary()) ? ARR_TOP_BOUNDARY : ARR_INTERIOR); 00838 } 00839 00846 Arr_parameter_space operator()(const Point_2 p) const 00847 { 00848 return 00849 (p.is_min_boundary()) ? ARR_BOTTOM_BOUNDARY : 00850 (p.is_max_boundary()) ? ARR_TOP_BOUNDARY : ARR_INTERIOR; 00851 } 00852 }; 00853 00855 Parameter_space_in_y_2 parameter_space_in_y_2_object() const 00856 { return Parameter_space_in_y_2(); } 00857 00861 class Compare_x_near_boundary_2 { 00862 protected: 00863 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 00864 00866 const Traits * m_traits; 00867 00871 Compare_x_near_boundary_2(const Traits * traits) : m_traits(traits) {} 00872 00873 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 00874 00875 public: 00891 Comparison_result operator()(const Point_2 & point, 00892 const X_monotone_curve_2 & xcv, 00893 Arr_curve_end ce) const 00894 { 00895 CGAL_precondition(point.is_no_boundary()); 00896 CGAL_precondition_code 00897 (const Point_2 & p2 = (ce == ARR_MIN_END) ? xcv.left() : xcv.right();); 00898 CGAL_precondition(!p2.is_no_boundary()); 00899 00900 if (xcv.is_vertical()) { 00901 CGAL_precondition(!xcv.is_on_boundary()); 00902 00903 /* The following is replaced by the precondition above. 00904 * If xc coincides with the discontinuity arc, all its points are 00905 * assumed to be smaller than non-boundary points: 00906 * if (xcv.is_on_boundary()) return LARGER; 00907 */ 00908 00909 // xcv is vertical, but does not coincide with the discontinuity arc. 00910 // Obtain the direction contained in the underlying plane, which is 00911 // also on the xy-plane: 00912 Direction_3 normal = xcv.normal(); 00913 Direction_2 q = (xcv.is_directed_right()) ? 00914 Direction_2(-(normal.dy()), normal.dx()) : 00915 Direction_2(normal.dy(), -(normal.dx())); 00916 Direction_2 p = Traits::project_xy(point); 00917 return m_traits->compare_x(p, q); 00918 } 00919 00920 // xcv is not a vertical sphercial_arc: 00921 return (ce == ARR_MIN_END) ? LARGER : SMALLER; 00922 } 00923 00943 Comparison_result operator()(const X_monotone_curve_2 & xcv1, 00944 Arr_curve_end ce1, 00945 const X_monotone_curve_2 & xcv2, 00946 Arr_curve_end ce2) const 00947 { 00948 CGAL_precondition_code 00949 (const Point_2 & p1 = (ce1 == ARR_MIN_END) ? xcv1.left() : xcv1.right();); 00950 CGAL_precondition(!p1.is_no_boundary()); 00951 CGAL_precondition_code 00952 (const Point_2 & p2 = (ce2 == ARR_MIN_END) ? xcv2.left() : xcv2.right();); 00953 CGAL_precondition(!p2.is_no_boundary()); 00954 00955 if (xcv1.is_vertical() && xcv2.is_vertical()) { 00956 CGAL_precondition(!xcv1.is_on_boundary()); 00957 CGAL_precondition(!xcv2.is_on_boundary()); 00958 00959 /* The following is replaced by the code above 00960 * if (xcv1.is_on_boundary() && xcv2.is_on_boundary()) return EQUAL; 00961 * if (xcv1.is_on_boundary()) return SMALLER; 00962 * if (xcv2.is_on_boundary()) return LARGER; 00963 */ 00964 00965 // Non of the arcs coincide with the discontinuity arc: 00966 // Obtain the directions contained in the underlying planes, which are 00967 // also on the xy-plane: 00968 Direction_3 normal1 = xcv1.normal(); 00969 Direction_2 p = (xcv1.is_directed_right()) ? 00970 Direction_2(-(normal1.dy()), normal1.dx()) : 00971 Direction_2(normal1.dy(), -(normal1.dx())); 00972 Direction_3 normal2 = xcv2.normal(); 00973 Direction_2 q = (xcv2.is_directed_right()) ? 00974 Direction_2(-(normal2.dy()), normal2.dx()) : 00975 Direction_2(normal2.dy(), -(normal2.dx())); 00976 return m_traits->compare_x(p, q); 00977 } 00978 if (xcv1.is_vertical()) { 00979 CGAL_precondition(!xcv1.is_on_boundary()); 00980 /* The following is replaced by the code above 00981 * if (xcv1.is_on_boundary()) return SMALLER; 00982 */ 00983 return (ce2 == ARR_MAX_END) ? SMALLER : LARGER; 00984 } 00985 if (xcv2.is_vertical()) { 00986 CGAL_precondition(!xcv2.is_on_boundary()); 00987 /* The following is replaced by the code above 00988 * if (xcv2.is_on_boundary()) return LARGER; 00989 */ 00990 return (ce1 == ARR_MAX_END) ? LARGER : SMALLER; 00991 } 00992 // Non of the arcs are vertical: 00993 if (ce1 == ce2) return EQUAL; 00994 if (ce1 == ARR_MIN_END) return SMALLER; 00995 return LARGER; 00996 } 00997 }; 00998 01000 Compare_x_near_boundary_2 compare_x_near_boundary_2_object() const 01001 { return Compare_x_near_boundary_2(this); } 01002 01003 01007 class Compare_y_near_boundary_2 { 01008 protected: 01009 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01010 01012 const Traits * m_traits; 01013 01017 Compare_y_near_boundary_2(const Traits * traits) : m_traits(traits) {} 01018 01019 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 01020 01021 public: 01032 Comparison_result operator()(const X_monotone_curve_2 & xcv1, 01033 const X_monotone_curve_2 & xcv2, 01034 Arr_curve_end ce) const 01035 { 01036 CGAL_precondition(!xcv1.is_degenerate()); 01037 CGAL_precondition(!xcv2.is_degenerate()); 01038 01039 const Point_2 & l1 = xcv1.left(); 01040 const Point_2 & r1 = xcv1.right(); 01041 const Point_2 & l2 = xcv2.left(); 01042 const Point_2 & r2 = xcv2.right(); 01043 01044 // If xcv1 is vertical, xcv1 coincides with the discontinuity arc: 01045 if (xcv1.is_vertical()) { 01046 CGAL_precondition(!l1.is_no_boundary()); 01047 CGAL_precondition(!r1.is_no_boundary()); 01048 } 01049 01050 // If xcv2 is vertical, xcv2 coincides with the discontinuity arc: 01051 if (xcv2.is_vertical()) { 01052 CGAL_precondition(!l2.is_no_boundary()); 01053 CGAL_precondition(!r2.is_no_boundary()); 01054 } 01055 01056 if (ce == ARR_MIN_END) { 01057 // Handle the south pole. It has the smallest y coords: 01058 if (l1.is_min_boundary()) 01059 return (l2.is_min_boundary()) ? EQUAL : SMALLER; 01060 if (l2.is_min_boundary()) return LARGER; 01061 01062 // None of xcv1 and xcv2 endpoints coincide with a pole: 01063 Comparison_result cr = m_traits->compare_y(l1, l2); 01064 if (cr != EQUAL) return cr; 01065 01066 // If Both arcs are vertical, they overlap: 01067 if (xcv1.is_vertical() && xcv2.is_vertical()) return EQUAL; 01068 if (xcv1.is_vertical()) return LARGER; 01069 if (xcv2.is_vertical()) return SMALLER; 01070 01071 // Non of the arcs is verticel. Thus, non of the endpoints coincide 01072 // with a pole. 01073 // Compare the y-coord. at the x-coord of the most left right-endpoint. 01074 CGAL_assertion(r1.is_no_boundary()); 01075 CGAL_assertion(r2.is_no_boundary()); 01076 01077 if (m_traits->compare_xy(r1, r2) == LARGER) { 01078 // use r2 and xcv1: 01079 Oriented_side os = 01080 m_traits->oriented_side(xcv1.normal(), r2); 01081 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 01082 (xcv1.is_directed_right()) ? 01083 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER) : 01084 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER); 01085 } 01086 // use r1 and xcv2: 01087 Oriented_side os = m_traits->oriented_side(xcv2.normal(), r1); 01088 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 01089 (xcv2.is_directed_right()) ? 01090 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER) : 01091 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER); 01092 } 01093 01094 // ce == ARR_MAX_END 01095 01096 // Handle the north pole. It has the largest y coords: 01097 if (r1.is_max_boundary()) return (r2.is_max_boundary()) ? EQUAL : LARGER; 01098 if (r2.is_max_boundary()) return SMALLER; 01099 01100 // None of xcv1 and xcv2 endpoints coincide with a pole: 01101 Direction_2 r1_xy = Traits::project_xy(r1); 01102 Comparison_result cr = m_traits->compare_y(r1, r2); 01103 if (cr != EQUAL) return cr; 01104 01105 // If Both arcs are vertical, they overlap: 01106 if (xcv1.is_vertical() && xcv2.is_vertical()) return EQUAL; 01107 if (xcv1.is_vertical()) return LARGER; 01108 if (xcv2.is_vertical()) return SMALLER; 01109 01110 // Compare to the left: 01111 Direction_2 p_r1 = Traits::project_xy(r1); 01112 cr = m_traits->compare_y(r1, r2); 01113 if (cr != EQUAL) return cr; 01114 01115 // Non of the arcs is verticel. Thus, non of the endpoints coincide with 01116 // a pole. 01117 // Compare the y-coord. at the x-coord of the most right left-endpoint. 01118 CGAL_assertion(l1.is_no_boundary()); 01119 CGAL_assertion(l2.is_no_boundary()); 01120 01121 if (m_traits->compare_xy(l1, l2) == SMALLER) { 01122 // use l2 and xcv1: 01123 Oriented_side os = m_traits->oriented_side(xcv1.normal(), l2); 01124 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 01125 (xcv1.is_directed_right()) ? 01126 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER) : 01127 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER); 01128 } 01129 // use l1 and xcv2: 01130 Oriented_side os = m_traits->oriented_side(xcv2.normal(), l1); 01131 return (os == ON_ORIENTED_BOUNDARY) ? EQUAL : 01132 (xcv2.is_directed_right()) ? 01133 ((os == ON_NEGATIVE_SIDE) ? SMALLER : LARGER) : 01134 ((os == ON_NEGATIVE_SIDE) ? LARGER : SMALLER); 01135 } 01136 }; 01137 01139 Compare_y_near_boundary_2 compare_y_near_boundary_2_object() const 01140 { return Compare_y_near_boundary_2(this); } 01141 01145 class Is_on_x_identification_2 { 01146 protected: 01147 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01148 01149 public: 01155 bool operator()(const Point_2 & p) const 01156 { 01157 CGAL_error_msg("There is no horizontal identification arc!"); 01158 return false; 01159 } 01160 01167 bool operator()(const X_monotone_curve_2 & xcv) const 01168 { 01169 CGAL_error_msg("There is no horizontal identification arc!"); 01170 return false; 01171 } 01172 }; 01173 01175 Is_on_x_identification_2 is_on_x_identification_2_object() const 01176 { return Is_on_x_identification_2(); } 01177 01181 class Is_on_y_identification_2 { 01182 protected: 01183 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01184 01186 const Traits * m_traits; 01187 01191 Is_on_y_identification_2(const Traits * traits) : m_traits(traits) {} 01192 01193 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 01194 01195 public: 01201 bool operator()(const Point_2 & p) const { return p.is_mid_boundary(); } 01202 01209 bool operator()(const X_monotone_curve_2 & xcv) const 01210 { return xcv.is_on_boundary(); } 01211 }; 01212 01214 Is_on_y_identification_2 is_on_y_identification_2_object() const 01215 { return Is_on_y_identification_2(this); } 01216 01221 class Compare_x_on_boundary_2 { 01222 public: 01229 Comparison_result operator()(const Point_2 & p1, const Point_2 & p2) const 01230 { 01231 CGAL_error_msg("There is no horizontal identification arc!"); 01232 return SMALLER; 01233 } 01234 }; 01235 01237 Compare_x_on_boundary_2 compare_x_on_boundary_2_object() const 01238 { return Compare_x_on_boundary_2(); } 01239 01243 class Compare_y_on_boundary_2 { 01244 protected: 01245 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01246 01248 const Traits * m_traits; 01249 01253 Compare_y_on_boundary_2(const Traits * traits) : m_traits(traits) {} 01254 01255 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 01256 01257 public: 01268 Comparison_result operator()(const Point_2 & p1, const Point_2 & p2) const 01269 { 01270 CGAL_precondition(!p1.is_no_boundary()); 01271 CGAL_precondition(!p2.is_no_boundary()); 01272 return m_traits->compare_y(p1, p2); 01273 } 01274 }; 01275 01277 Compare_y_on_boundary_2 compare_y_on_boundary_2_object() const 01278 { return Compare_y_on_boundary_2(this); } 01280 01282 01283 01287 class Make_x_monotone_2 { 01288 protected: 01289 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01290 01292 const Traits * m_traits; 01293 01297 Make_x_monotone_2(const Traits * traits) : m_traits(traits) {} 01298 01299 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 01300 01301 public: 01311 template<typename OutputIterator> 01312 OutputIterator operator()(const Curve_2 & c, OutputIterator oi) const 01313 { 01314 if (c.is_degenerate()) { 01315 // The spherical_arc is a degenerate point - wrap it with an object: 01316 *oi++ = make_object(c.right()); 01317 return oi; 01318 } 01319 01320 if (c.is_x_monotone()) { 01321 // The spherical arc is monotone - wrap it with an object: 01322 // *oi++ = make_object(X_monotone_curve_2(c)); 01323 const X_monotone_curve_2 * xc = &c; 01324 *oi++ = make_object(*xc); 01325 return oi; 01326 } 01327 01328 if (c.is_full()) { 01329 // The spherical arc is full 01330 if (c.is_vertical()) { 01331 // The arc is vertical => divide it into 2 half arcs; 01332 const Direction_3 & np = m_traits->neg_pole(); 01333 const Direction_3 & pp = m_traits->pos_pole(); 01334 X_monotone_curve_2 xc1(np, pp, c.normal(), true, true); 01335 X_monotone_curve_2 xc2(pp, np, c.normal(), true, false); 01336 *oi++ = make_object(xc1); 01337 *oi++ = make_object(xc2); 01338 return oi; 01339 } 01340 #if defined(CGAL_FULL_X_MONOTONE_GEODESIC_ARC_ON_SPHERE_IS_SUPPORTED) 01341 // The arc is not vertical => break it at the discontinuity arc: 01342 const X_monotone_curve_2 xc(c.normal()); 01343 *oi++ = make_object(xc); 01344 #else 01345 // Full x-monotone arcs are not supported! 01346 // Split the arc at the intersection point with the complement of the 01347 // discontinuity arc: 01348 Direction_3 normal = c.normal(); 01349 bool directed_right = Traits::x_sign(normal) == POSITIVE; 01350 Direction_3 d1(-(normal.dz()), 0, normal.dx()); 01351 Direction_3 d2(normal.dz(), 0, -(normal.dx())); 01352 X_monotone_curve_2 xc1(d1, d2, normal, false, directed_right); 01353 X_monotone_curve_2 xc2(d2, d1, normal, false, directed_right); 01354 *oi++ = make_object(xc1); 01355 *oi++ = make_object(xc2); 01356 #endif 01357 return oi; 01358 } 01359 01360 const Point_2 & source = c.source(); 01361 const Point_2 & target = c.target(); 01362 const Direction_3 & normal = c.normal(); 01363 01364 if (c.is_vertical()) { 01365 /* If one of the endpoints coincide with a pole, divide the arc at 01366 * the opposite pole: 01367 */ 01368 const Direction_3 & np = m_traits->neg_pole(); 01369 const Direction_3 & pp = m_traits->pos_pole(); 01370 if (source.is_min_boundary() || target.is_min_boundary()) { 01371 X_monotone_curve_2 xc1(source, pp, normal, true, true); 01372 X_monotone_curve_2 xc2(pp, target, normal, true, false); 01373 *oi++ = make_object(xc1); 01374 *oi++ = make_object(xc2); 01375 return oi; 01376 } 01377 01378 if (source.is_max_boundary() || target.is_max_boundary()) { 01379 X_monotone_curve_2 xc1(source, np, normal, true, false); 01380 X_monotone_curve_2 xc2(np, target, normal, true, true); 01381 *oi++ = make_object(xc1); 01382 *oi++ = make_object(xc2); 01383 return oi; 01384 } 01385 01386 // None of the enpoints coincide with a pole. 01387 bool s_is_positive, t_is_positive, plane_is_positive; 01388 CGAL::Sign xsign = Traits::x_sign(normal); 01389 if (xsign == ZERO) { 01390 s_is_positive = Traits::x_sign(source) == POSITIVE; 01391 t_is_positive = Traits::x_sign(target) == POSITIVE; 01392 plane_is_positive = Traits::y_sign(normal) == NEGATIVE; 01393 } else { 01394 s_is_positive = Traits::y_sign(source) == POSITIVE; 01395 t_is_positive = Traits::y_sign(target) == POSITIVE; 01396 plane_is_positive = xsign == POSITIVE; 01397 } 01398 bool ccw = ((plane_is_positive && s_is_positive) || 01399 (!plane_is_positive && !s_is_positive)); 01400 const Point_2 & pole1 = (ccw) ? pp : np; 01401 X_monotone_curve_2 xc1(source, pole1, normal, true, ccw); 01402 *oi++ = make_object(xc1); 01403 if (s_is_positive != t_is_positive) { 01404 // Construct 1 more arc: 01405 X_monotone_curve_2 xc2(pole1, target, normal, true, !ccw); 01406 *oi++ = make_object(xc2); 01407 return oi; 01408 } 01409 // Construct 2 more arcs: 01410 const Point_2 & pole2 = (ccw) ? np : pp; 01411 X_monotone_curve_2 xc2(pole1, pole2, normal, true, !ccw); 01412 *oi++ = make_object(xc2); 01413 X_monotone_curve_2 xc3(pole2, target, normal, true, ccw); 01414 *oi++ = make_object(xc3); 01415 return oi; 01416 } 01417 01418 // The curve is not vertical, (none of the enpoints coincide with a pole) 01419 #if (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_1_Y_0) 01420 Direction_3 dp = (CGAL::sign(normal.dz()) == POSITIVE) ? 01421 Direction_3(-(normal.dz()), 0, normal.dx()) : 01422 Direction_3(normal.dz(), 0, -(normal.dx())); 01423 #else 01424 const Direction_2 & xy = Traits::identification_xy(); 01425 FT x = xy.dx(); 01426 FT y = xy.dy(); 01427 FT z((xy.dx() * normal.dx() + xy.dy() * normal.dy()) / -(normal.dz())); 01428 Direction_3 dp(x, y, z); 01429 #endif 01430 Point_2 p(dp, Point_2::MID_BOUNDARY_LOC); 01431 Direction_2 s = Traits::project_xy(source); 01432 Direction_2 t = Traits::project_xy(target); 01433 const Direction_2 & d = Traits::identification_xy(); 01434 const Kernel * kernel = m_traits; 01435 bool directed_right = 01436 kernel->counterclockwise_in_between_2_object()(d, s, t); 01437 01438 X_monotone_curve_2 xc1(source, p, normal, false, directed_right); 01439 X_monotone_curve_2 xc2(p, target, normal, false, directed_right); 01440 *oi++ = make_object(xc1); 01441 *oi++ = make_object(xc2); 01442 return oi; 01443 } 01444 }; 01445 01447 Make_x_monotone_2 make_x_monotone_2_object() const 01448 { return Make_x_monotone_2(this); } 01449 01451 class Split_2 { 01452 protected: 01453 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01454 01456 const Traits * m_traits; 01457 01461 Split_2(const Traits * traits) : m_traits(traits) {} 01462 01463 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 01464 01465 public: 01476 void operator()(const X_monotone_curve_2 & xc, const Point_2 & p, 01477 X_monotone_curve_2 & xc1, X_monotone_curve_2 & xc2) const 01478 { 01479 CGAL_precondition(!xc.is_degenerate()); 01480 const Point_2 & source = xc.source(); 01481 const Point_2 & target = xc.target(); 01482 CGAL_precondition_code(const Kernel * kernel = m_traits); 01483 CGAL_precondition_code 01484 (typename Kernel::Equal_3 equal_3 = kernel->equal_3_object()); 01485 CGAL_precondition(!equal_3(p, source)); 01486 CGAL_precondition(!equal_3(p, target)); 01487 01488 xc1.normal(xc.normal()); 01489 xc1.set_is_vertical(xc.is_vertical()); 01490 xc1.set_is_degenerate(false); 01491 xc1.set_is_empty(false); 01492 01493 xc2.normal(xc.normal()); 01494 xc2.set_is_vertical(xc.is_vertical()); 01495 xc2.set_is_empty(false); 01496 01497 if (xc.is_directed_right()) { 01498 xc1.set_source(source); 01499 xc1.set_target(p); 01500 xc1.set_is_directed_right(true); 01501 xc2.set_source(p); 01502 xc2.set_target(target); 01503 xc2.set_is_directed_right(true); 01504 } else { 01505 xc1.set_source(p); 01506 xc1.set_target(target); 01507 xc1.set_is_directed_right(false); 01508 xc2.set_source(source); 01509 xc2.set_target(p); 01510 xc2.set_is_directed_right(false); 01511 } 01512 } 01513 }; 01514 01516 Split_2 split_2_object() const { return Split_2(this); } 01517 01519 class Clockwise_in_between_2 { 01520 protected: 01521 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01522 01524 const Traits * m_traits; 01525 01529 Clockwise_in_between_2(const Traits * traits) : m_traits(traits) {} 01530 01531 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 01532 01533 public: 01534 bool operator()(const Direction_2 & d, 01535 const Direction_2 & d1, const Direction_2 & d2) const 01536 { 01537 const Kernel * kernel = m_traits; 01538 return kernel->counterclockwise_in_between_2_object()(d, d2, d1); 01539 } 01540 }; 01541 01543 Clockwise_in_between_2 clockwise_in_between_2_object() const 01544 { return Clockwise_in_between_2(this); } 01545 01547 class Intersect_2 { 01548 private: 01549 01562 template <typename In_between, typename OutputIterator> 01563 OutputIterator compute_intersection(const Point_2 & l1_3, 01564 const Point_2 r1_3, 01565 const Point_2 & l2_3, 01566 const Point_2 r2_3, 01567 const Direction_3 & normal, 01568 bool vertical, 01569 const Direction_2 & start, 01570 const In_between & in_between, 01571 Project project, 01572 OutputIterator oi) const 01573 { 01574 typedef std::pair<Point_2,unsigned int> Point_2_pair; 01575 const Kernel * kernel = m_traits; 01576 typename Kernel::Equal_2 equal = kernel->equal_2_object(); 01577 01578 Direction_2 l1 = project(l1_3); 01579 Direction_2 r1 = project(r1_3); 01580 Direction_2 l2 = project(l2_3); 01581 Direction_2 r2 = project(r2_3); 01582 01583 if (equal(l1, l2)) { 01584 const Point_2 & trg = (in_between(r1, l2, r2)) ? r1_3 : r2_3; 01585 X_monotone_curve_2 xc(l1_3, trg, normal, vertical, true); 01586 *oi++ = make_object(xc); 01587 return oi; 01588 } 01589 01590 bool l1_eq_start = equal(l1, start); 01591 bool l2_eq_start = equal(l2, start); 01592 01593 if (l1_eq_start || (!l2_eq_start && in_between(l1, start, l2))) { 01594 // The following applies only to full circles: 01595 if (l1_eq_start && equal(r2, start)) 01596 *oi++ = make_object(Point_2_pair(r2_3, 1)); 01597 if (in_between(r1, l1, l2)) return oi; // no intersection 01598 if (equal(r1, l2)) { 01599 *oi++ = make_object(Point_2_pair(r1_3, 1)); 01600 return oi; 01601 } 01602 const Point_2 & trg = (in_between(r1, l2, r2)) ? r1_3 : r2_3; 01603 X_monotone_curve_2 xc(l2_3, trg, normal, vertical, true); 01604 *oi++ = make_object(xc); 01605 return oi; 01606 } 01607 CGAL_assertion(l2_eq_start || in_between(l2, start, l1)); 01608 // The following applies only to full circles: 01609 if (l2_eq_start && equal(r1, start)) 01610 *oi++ = make_object(Point_2_pair(r1_3, 1)); 01611 if (in_between(r2, l2, l1)) return oi; // no intersection 01612 if (equal(r2, l1)) { 01613 *oi++ = make_object(Point_2_pair(r2_3, 1)); 01614 return oi; 01615 } 01616 const Point_2 & trg = (in_between(r1, l2, r2)) ? r1_3 : r2_3; 01617 X_monotone_curve_2 xc(l1_3, trg, normal, vertical, true); 01618 *oi++ = make_object(xc); 01619 return oi; 01620 } 01621 01628 bool is_in_between(const Point_2 & point, 01629 const X_monotone_curve_2 & xc) const 01630 { 01631 const Kernel * kernel = m_traits; 01632 CGAL_precondition(m_traits->has_on(xc.normal(), point)); 01633 01634 const Point_2 & left = xc.left(); 01635 const Point_2 & right = xc.right(); 01636 01637 // Handle the poles: 01638 if (point.is_max_boundary()) return (right.is_max_boundary()); 01639 if (point.is_min_boundary()) return (left.is_min_boundary()); 01640 01641 if (xc.is_vertical()) { 01642 // Compare the x coordinates. If they are not equal, return false: 01643 Direction_3 normal = xc.normal(); 01644 bool plane_is_positive, p_is_positive; 01645 CGAL::Sign xsign = Traits::x_sign(normal); 01646 if (xsign == ZERO) { 01647 plane_is_positive = Traits::y_sign(normal) == NEGATIVE; 01648 p_is_positive = Traits::x_sign(point) == POSITIVE; 01649 } else { 01650 plane_is_positive = xsign == POSITIVE; 01651 p_is_positive = Traits::y_sign(point) == POSITIVE; 01652 } 01653 01654 bool xc_is_positive = ((plane_is_positive && xc.is_directed_right()) || 01655 (!plane_is_positive && !xc.is_directed_right())); 01656 01657 if ((xc_is_positive && !p_is_positive) || 01658 (!xc_is_positive && p_is_positive)) 01659 return false; 01660 01661 // Compare the y-coords: 01662 return (((left.is_min_boundary()) || 01663 (m_traits->compare_y(point, left) != SMALLER)) && 01664 ((right.is_max_boundary()) || 01665 (m_traits->compare_y(point, right) != LARGER))); 01666 } 01667 01668 // The arc is not vertical. Compare the projections onto the xy-plane: 01669 typename Kernel::Equal_2 equal_2 = kernel->equal_2_object(); 01670 Direction_2 p = Traits::project_xy(point); 01671 Direction_2 r = Traits::project_xy(right); 01672 if (equal_2(p, r)) return true; 01673 Direction_2 l = Traits::project_xy(left); 01674 if (equal_2(p, l)) return true; 01675 return kernel->counterclockwise_in_between_2_object()(p, l, r); 01676 } 01677 01678 protected: 01679 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01680 01682 const Traits * m_traits; 01683 01687 Intersect_2(const Traits * traits) : m_traits(traits) {} 01688 01689 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 01690 01691 public: 01701 template<typename OutputIterator> 01702 OutputIterator operator()(const X_monotone_curve_2 & xc1, 01703 const X_monotone_curve_2 & xc2, 01704 OutputIterator oi) const 01705 { 01706 CGAL_precondition(!xc1.is_degenerate()); 01707 CGAL_precondition(!xc2.is_degenerate()); 01708 01709 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01710 typedef typename Kernel::Equal_2 Equal_2; 01711 typedef typename Kernel::Counterclockwise_in_between_2 01712 Counterclockwise_in_between_2; 01713 typedef typename Traits::Clockwise_in_between_2 01714 Clockwise_in_between_2; 01715 typedef typename Kernel::Equal_3 Equal_3; 01716 01717 typedef std::pair<Point_2,unsigned int> Point_2_pair; 01718 const Kernel * kernel = m_traits; 01719 01720 Equal_3 equal_3 = kernel->equal_3_object(); 01721 const Direction_3 & normal1 = xc1.normal(); 01722 const Direction_3 & normal2 = xc2.normal(); 01723 01724 Direction_3 opposite_normal1 = 01725 kernel->construct_opposite_direction_3_object()(normal1); 01726 01727 if (equal_3(normal1, normal2) || equal_3(opposite_normal1, normal2)) { 01728 // The underlying planes are the same 01729 Equal_2 equal = kernel->equal_2_object(); 01730 Counterclockwise_in_between_2 ccib = 01731 kernel->counterclockwise_in_between_2_object(); 01732 typename Traits::Clockwise_in_between_2 cib = 01733 m_traits->clockwise_in_between_2_object(); 01734 01735 if (xc1.is_vertical()) { 01736 // Both arcs are vertical 01737 bool res = kernel->equal_3_object()(normal1, normal2); 01738 if ((!res && (xc1.is_directed_right() == xc2.is_directed_right())) || 01739 (res && (xc1.is_directed_right() != xc2.is_directed_right()))) 01740 { 01741 if (xc1.left().is_min_boundary() && xc2.left().is_min_boundary()) 01742 *oi++ = make_object(Point_2_pair(xc1.left(), 1)); 01743 if (xc1.right().is_max_boundary() && xc2.right().is_max_boundary()) 01744 *oi++ = make_object(Point_2_pair(xc1.right(), 1)); 01745 return oi; 01746 } 01747 01751 if (xc1.left().is_min_boundary() && xc1.right().is_max_boundary()) { 01752 *oi++ = make_object(xc2); 01753 return oi; 01754 } 01755 if (xc2.left().is_min_boundary() && xc2.right().is_max_boundary()) { 01756 *oi++ = make_object(xc1); 01757 return oi; 01758 } 01763 const Point_2 & point = 01764 xc1.left().is_min_boundary() ? xc1.right() : xc1.left(); 01765 01766 CGAL::Sign xsign = Traits::x_sign(normal1); 01767 bool xz_plane = xsign == ZERO; 01768 Project project = 01769 (xz_plane) ? Traits::project_xz : Traits::project_yz; 01770 01771 Direction_3 normal = (xc1.is_directed_right()) ? 01772 normal1 : opposite_normal1; 01773 01774 bool p_x_is_positive = Traits::x_sign(point) == POSITIVE; 01775 bool p_y_is_positive = Traits::y_sign(point) == POSITIVE; 01776 01777 if ((xz_plane && p_x_is_positive) || (!xz_plane && p_y_is_positive)) { 01778 // The endpoints reside in the positive x-halfspace: 01779 return compute_intersection(xc1.left(), xc1.right(), 01780 xc2.left(), xc2.right(), 01781 normal, true, Traits::neg_y_2(), 01782 ccib, project, oi); 01783 } 01784 // The endpoints reside in the negative x-halfspace: 01785 return compute_intersection(xc1.left(), xc1.right(), 01786 xc2.left(), xc2.right(), 01787 normal, true, Traits::neg_y_2(), 01788 cib, project, oi); 01789 } 01790 01791 // The arcs are not vertical: 01792 bool plane_is_positive = (Traits::z_sign(normal1) == POSITIVE); 01793 Direction_3 normal = 01794 (plane_is_positive) ? normal1 : opposite_normal1; 01795 return compute_intersection(xc1.left(), xc1.right(), 01796 xc2.left(), xc2.right(), 01797 normal, false, Traits::identification_xy(), 01798 ccib, Traits::project_xy, oi); 01799 } 01800 01801 Vector_3 v = 01802 kernel-> 01803 construct_cross_product_vector_3_object()(xc1.normal().vector(), 01804 xc2.normal().vector()); 01805 01806 // Determine which one of the two directions: 01807 Point_2 ed(v.direction()); 01808 if (is_in_between(ed, xc1) && is_in_between(ed, xc2)) { 01809 *oi++ = make_object(Point_2_pair(ed, 1)); 01810 return oi; 01811 } 01812 01813 Vector_3 vo(kernel->construct_opposite_vector_3_object()(v)); 01814 Point_2 edo(vo.direction()); 01815 if (is_in_between(edo, xc1) && is_in_between(edo, xc2)) { 01816 *oi++ = make_object(Point_2_pair(edo, 1)); 01817 return oi; 01818 } 01819 return oi; 01820 } 01821 }; 01822 01824 Intersect_2 intersect_2_object() const { return Intersect_2(this); } 01825 01827 class Are_mergeable_2 { 01828 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01829 01831 const Traits * m_traits; 01832 01836 Are_mergeable_2(const Traits * traits) : m_traits(traits) {} 01837 01838 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 01839 01840 public: 01849 bool operator()(const X_monotone_curve_2 & xc1, 01850 const X_monotone_curve_2 & xc2) const 01851 { 01853 return false; 01854 01855 if (xc1.is_empty() || xc2.is_empty()) return true; 01856 if (xc1.is_full() && xc2.is_full()) return false; 01857 01858 const Kernel * kernel = m_traits; 01859 typename Kernel::Equal_3 equal = kernel->equal_3_object(); 01860 01861 if (xc1.is_degenerate() && xc2.is_degenerate()) 01862 return equal(xc1.left(), xc2.left()); 01863 if (xc1.is_full() && xc2.is_degenerate()) 01864 return xc1.has_on(xc2.left()); 01865 if (xc2.is_full() && xc1.is_degenerate()) 01866 return xc2.has_on(xc1.left()); 01867 01868 const Direction_3 & normal1 = xc1.normal(); 01869 const Direction_3 & normal2 = xc2.normal(); 01870 Direction_3 opposite_normal1 = 01871 kernel->construct_opposite_direction_3_object()(normal1); 01872 if (!equal(normal1, normal2) && !equal(opposite_normal1, normal2)) 01873 return false; 01874 01875 bool eq1 = equal(xc1.right(), xc2.left()); 01876 bool eq2 = equal(xc1.left(), xc2.right()); 01877 01878 #if defined(CGAL_FULL_X_MONOTONE_GEODESIC_ARC_ON_SPHERE_IS_SUPPORTED) 01879 if (eq1 && eq2) return true; 01880 #else 01881 if (eq1 && eq2) return false; 01882 #endif 01883 01884 if (eq1 && xc2.left().is_no_boundary()) return true; 01885 if (eq2 && xc1.left().is_no_boundary()) return true; 01886 return false; 01887 } 01888 }; 01889 01891 Are_mergeable_2 are_mergeable_2_object() const 01892 { return Are_mergeable_2(this); } 01893 01895 class Merge_2 { 01896 protected: 01897 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 01898 01900 const Traits * m_traits; 01901 01905 Merge_2(const Traits * traits) : m_traits(traits) {} 01906 01907 friend class Arr_geodesic_arc_on_sphere_traits_2<Kernel>; 01908 01909 public: 01918 void operator()(const X_monotone_curve_2 & xc1, 01919 const X_monotone_curve_2 & xc2, 01920 X_monotone_curve_2 & xc) const 01921 { 01922 CGAL_precondition (m_traits->are_mergeable_2_object()(xc1, xc2) == true); 01923 01924 if (xc1.is_degenerate() || xc1.is_empty()) { 01925 xc = xc2; 01926 return; 01927 } 01928 01929 if (xc2.is_degenerate() || xc2.is_empty()) { 01930 xc = xc1; 01931 return; 01932 } 01933 01934 const Kernel * kernel = m_traits; 01935 typename Kernel::Equal_3 equal = kernel->equal_3_object(); 01936 01937 xc.set_is_degenerate(false); 01938 xc.set_is_empty(false); 01939 xc.set_is_vertical(xc1.is_vertical()); 01940 01941 bool eq1 = equal(xc1.right(), xc2.left()); 01942 01943 #if defined(CGAL_FULL_X_MONOTONE_GEODESIC_ARC_ON_SPHERE_IS_SUPPORTED) 01944 bool eq2 = equal(xc1.left(), xc2.right()); 01945 if (eq1 && eq2) { 01946 const Point_2 & p = 01947 xc1.source().is_mid_boundary() ? xc1.source() : xc1.target(); 01948 xc.set_source(p); 01949 xc.set_target(p); 01950 xc.normal(xc1.normal()); 01951 xc.set_is_full(true); 01952 } 01953 #endif 01954 01955 if (xc1.is_directed_right() || xc2.is_directed_right()) { 01956 xc.normal(xc1.is_directed_right() ? 01957 xc1.normal() : xc2.normal()); 01958 xc.set_is_directed_right(true); 01959 01960 if (eq1) { 01961 xc.set_source(xc1.left()); 01962 xc.set_target(xc2.right()); 01963 } else { 01964 CGAL_assertion(equal(xc1.left(), xc2.right())); 01965 xc.set_source(xc2.left()); 01966 xc.set_target(xc1.right()); 01967 } 01968 } else { 01969 xc.normal(xc1.normal()); 01970 xc.set_is_directed_right(false); 01971 01972 if (eq1) { 01973 xc.set_source(xc2.right()); 01974 xc.set_target(xc1.left()); 01975 } else { 01976 CGAL_assertion(equal(xc1.left(), xc2.right())); 01977 xc.set_source(xc1.right()); 01978 xc.set_target(xc2.left()); 01979 } 01980 } 01981 } 01982 }; 01983 01985 Merge_2 merge_2_object() const { return Merge_2(this); } 01987 01989 01990 typedef double Approximate_number_type; 01991 01992 class Approximate_2 { 01993 public: 01994 02002 Approximate_number_type operator()(const Point_2 & p, int i) const 02003 { 02004 CGAL_precondition(i == 0 || i == 1); 02005 return (i == 0) ? CGAL::to_double(p.x()) : CGAL::to_double(p.y()); 02006 } 02007 }; 02008 02010 Approximate_2 approximate_2_object() const { return Approximate_2(); } 02011 02012 class Construct_x_monotone_curve_2 { 02013 public: 02014 02021 X_monotone_curve_2 operator()(const Point_2 & p, const Point_2 & q) const 02022 { return X_monotone_curve_2(p, q); } 02023 }; 02024 02026 Construct_x_monotone_curve_2 construct_x_monotone_curve_2_object() const 02027 { return Construct_x_monotone_curve_2(); } 02029 02030 02032 02033 02034 class Compare_endpoints_xy_2 { 02035 public: 02036 02044 Comparison_result operator()(const X_monotone_curve_2 & xc) 02045 { return (xc.is_directed_right()) ? SMALLER : LARGER; } 02046 }; 02047 02049 Compare_endpoints_xy_2 compare_endpoints_xy_2_object() const 02050 { return Compare_endpoints_xy_2(); } 02051 02052 class Construct_opposite_2 { 02053 public: 02058 X_monotone_curve_2 operator()(const X_monotone_curve_2 & xc) 02059 { return xc.opposite(); } 02060 }; 02061 02063 Construct_opposite_2 construct_opposite_2_object() const 02064 { return Construct_opposite_2(); } 02066 02067 #if 0 02068 02069 template <typename OutputStream> 02070 friend OutputStream & operator<<(OutputStream & os, const Point_2 & p) 02071 { 02072 CGAL::To_double<typename Kernel::FT> todouble; 02073 os << static_cast<float>(todouble(p.dx())) << ", " 02074 << static_cast<float>(todouble(p.dy())) << ", " 02075 << static_cast<float>(todouble(p.dz())); 02076 return os; 02077 } 02078 02080 template <typename OutputStream> 02081 friend OutputStream & operator<<(OutputStream & os, 02082 const X_monotone_curve_2 & xc) 02083 { 02084 os << "(" << xc.left() << "), (" << xc.right() << ")"; 02085 return os; 02086 } 02087 02089 template <typename InputStream> 02090 friend InputStream & operator>>(InputStream & is, X_monotone_curve_2 & arc) 02091 { 02092 std::cerr << "Not implemented yet!" << std::endl; 02093 return is; 02094 } 02095 #endif 02096 }; 02097 02103 template <typename Kernel> 02104 class Arr_extended_direction_3 : public Kernel::Direction_3 { 02105 public: 02106 typedef typename Kernel::FT FT; 02107 typedef typename Kernel::Direction_3 Direction_3; 02108 02110 enum Location_type { 02111 NO_BOUNDARY_LOC, 02112 MIN_BOUNDARY_LOC, 02113 MID_BOUNDARY_LOC, 02114 MAX_BOUNDARY_LOC 02115 }; 02116 02117 private: 02118 typedef typename Kernel::Direction_2 Direction_2; 02119 02121 Location_type m_location; 02122 02123 inline Sign x_sign(Direction_3 d) const { return CGAL::sign(d.dx()); } 02124 02125 inline Sign y_sign(Direction_3 d) const { return CGAL::sign(d.dy()); } 02126 02127 inline Sign z_sign(Direction_3 d) const { return CGAL::sign(d.dz()); } 02128 02129 public: 02131 Arr_extended_direction_3() : 02132 Direction_3(0, 0, 1), 02133 m_location(MAX_BOUNDARY_LOC) 02134 {} 02135 02137 Arr_extended_direction_3(const Direction_3 & dir, Location_type location) : 02138 Direction_3(dir), 02139 m_location(location) 02140 {} 02141 02147 Arr_extended_direction_3(const FT & x, const FT & y, const FT & z) : 02148 Direction_3(x, y, z) 02149 { init(Direction_3(x, y, z)); } 02150 02154 Arr_extended_direction_3(const Direction_3 & dir) : Direction_3(dir) 02155 { init(dir); } 02156 02160 void init(const Direction_3 & dir) 02161 { 02162 #if (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_1_Y_0) 02163 if (y_sign(dir) != ZERO) { 02164 m_location = NO_BOUNDARY_LOC; 02165 return; 02166 } 02167 CGAL::Sign signx = x_sign(dir); 02168 m_location = 02169 (signx == POSITIVE) ? NO_BOUNDARY_LOC : 02170 ((signx == NEGATIVE) ? MID_BOUNDARY_LOC : 02171 ((z_sign(dir) == NEGATIVE) ? MIN_BOUNDARY_LOC : MAX_BOUNDARY_LOC)); 02172 #else 02173 if ((x_sign(dir) == ZERO) && (y_sign(dir) == ZERO)) { 02174 m_location = 02175 (z_sign(dir) == NEGATIVE) ? MIN_BOUNDARY_LOC : MAX_BOUNDARY_LOC; 02176 return; 02177 } 02178 02179 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 02180 Direction_2 dir_xy = Traits::project_xy(dir); 02181 Kernel kernel; 02182 typename Kernel::Equal_2 equal_2 = kernel.equal_2_object(); 02183 const Direction_2 & xy = Traits::identification_xy(); 02184 m_location = equal_2(dir_xy, xy) ? MID_BOUNDARY_LOC : NO_BOUNDARY_LOC; 02185 #endif 02186 } 02187 02189 Arr_extended_direction_3(const Arr_extended_direction_3 & ed) : 02190 Direction_3(static_cast<const Direction_3&>(ed)) 02191 { 02192 m_location = ed.discontinuity_type(); 02193 } 02194 02196 Arr_extended_direction_3 & operator=(const Arr_extended_direction_3 & ed) 02197 { 02198 *(static_cast<Direction_3*>(this)) = static_cast<const Direction_3&>(ed); 02199 m_location = ed.discontinuity_type(); 02200 return (*this); 02201 } 02202 02204 Location_type discontinuity_type() const 02205 { return m_location; } 02206 02207 bool is_no_boundary() const { return (m_location == NO_BOUNDARY_LOC); } 02208 02209 bool is_min_boundary() const { return (m_location == MIN_BOUNDARY_LOC); } 02210 02211 bool is_mid_boundary() const { return (m_location == MID_BOUNDARY_LOC); } 02212 02213 bool is_max_boundary() const { return (m_location == MAX_BOUNDARY_LOC); } 02214 }; 02215 02224 template <typename T_Kernel> 02225 class Arr_x_monotone_geodesic_arc_on_sphere_3 { 02226 protected: 02227 typedef T_Kernel Kernel; 02228 02229 typedef typename Kernel::Plane_3 Plane_3; 02230 typedef typename Kernel::Vector_3 Vector_3; 02231 typedef typename Kernel::Direction_2 Direction_2; 02232 typedef typename Kernel::Direction_3 Direction_3; 02233 02234 // For some reason compilation under Windows fails without the qualifier 02235 typedef CGAL::Arr_extended_direction_3<Kernel> Arr_extended_direction_3; 02236 02238 Arr_extended_direction_3 m_source; 02239 02241 Arr_extended_direction_3 m_target; 02242 02244 Direction_3 m_normal; 02245 02247 bool m_is_vertical; 02248 02250 bool m_is_directed_right; 02251 02253 bool m_is_full; 02254 02255 /* The arc is degenerate - it consists of a single point */ 02256 bool m_is_degenerate; 02257 02259 bool m_is_empty; 02260 02261 inline Sign x_sign(Direction_3 d) const { return CGAL::sign(d.dx()); } 02262 02263 inline Sign y_sign(Direction_3 d) const { return CGAL::sign(d.dy()); } 02264 02265 inline Sign z_sign(Direction_3 d) const { return CGAL::sign(d.dz()); } 02266 02271 inline Direction_3 construct_normal_3(const Direction_3 & d1, 02272 const Direction_3 & d2) const 02273 { 02274 Kernel kernel; 02275 Vector_3 v = kernel.construct_cross_product_vector_3_object()(d1.vector(), 02276 d2.vector()); 02277 return v.direction(); 02278 } 02279 02280 public: 02282 Arr_x_monotone_geodesic_arc_on_sphere_3() : 02283 m_is_vertical(false), 02284 m_is_directed_right(false), 02285 m_is_full(false), 02286 m_is_degenerate(false), 02287 m_is_empty(true) 02288 {} 02289 02299 Arr_x_monotone_geodesic_arc_on_sphere_3 02300 (const Arr_extended_direction_3 & src, 02301 const Arr_extended_direction_3 & trg, 02302 const Direction_3 & normal, 02303 bool is_vertical, bool is_directed_right, 02304 bool is_full = false, bool is_degenerate = false, bool is_empty = false) : 02305 m_source(src), 02306 m_target(trg), 02307 m_normal(normal), 02308 m_is_vertical(is_vertical), 02309 m_is_directed_right(is_directed_right), 02310 m_is_full(is_full), 02311 m_is_degenerate(is_degenerate), 02312 m_is_empty(is_empty) 02313 {} 02314 02318 Arr_x_monotone_geodesic_arc_on_sphere_3 02319 (const Arr_x_monotone_geodesic_arc_on_sphere_3 & other) 02320 { 02321 m_source = other.m_source; 02322 m_target = other.m_target; 02323 m_normal = other.m_normal; 02324 m_is_vertical = other.m_is_vertical; 02325 m_is_directed_right = other.m_is_directed_right; 02326 m_is_full = other.m_is_full; 02327 m_is_degenerate = other.m_is_degenerate; 02328 m_is_empty = other.m_is_empty; 02329 } 02330 02332 Arr_x_monotone_geodesic_arc_on_sphere_3 & operator= 02333 (const Arr_x_monotone_geodesic_arc_on_sphere_3 & other) 02334 { 02335 m_source = other.m_source; 02336 m_target = other.m_target; 02337 m_normal = other.m_normal; 02338 m_is_vertical = other.m_is_vertical; 02339 m_is_directed_right = other.m_is_directed_right; 02340 m_is_full = other.m_is_full; 02341 m_is_degenerate = other.m_is_degenerate; 02342 m_is_empty = other.m_is_empty; 02343 return (*this); 02344 } 02345 02360 Arr_x_monotone_geodesic_arc_on_sphere_3 02361 (const Arr_extended_direction_3 & source, 02362 const Arr_extended_direction_3 & target) : 02363 m_source(source), 02364 m_target(target), 02365 m_is_full(false), 02366 m_is_degenerate(false), 02367 m_is_empty(false) 02368 { 02369 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 02370 02371 Kernel kernel; 02372 CGAL_precondition(!kernel.equal_3_object()(source, target)); 02373 CGAL_precondition(!kernel.equal_3_object() 02374 (kernel.construct_opposite_direction_3_object()(source), 02375 target)); 02376 m_normal = construct_normal_3(source, target); 02377 02378 // Check whether any one of the endpoint coincide with a pole: 02379 if (source.is_max_boundary()) { 02380 set_is_vertical(true); 02381 set_is_directed_right(false); 02382 return; 02383 } 02384 if (source.is_min_boundary()) { 02385 set_is_vertical(true); 02386 set_is_directed_right(true); 02387 return; 02388 } 02389 if (target.is_max_boundary()) { 02390 set_is_vertical(true); 02391 set_is_directed_right(true); 02392 return; 02393 } 02394 if (target.is_min_boundary()) { 02395 set_is_vertical(true); 02396 set_is_directed_right(false); 02397 return; 02398 } 02399 02400 // None of the enpoints coincide with a pole: 02401 typename Kernel::Equal_2 equal_2 = kernel.equal_2_object(); 02402 Direction_2 s = Traits::project_xy(source); 02403 Direction_2 t = Traits::project_xy(target); 02404 02405 Orientation orient = Traits::orientation(s, t); 02406 if (orient == COLLINEAR) { 02407 set_is_vertical(true); 02408 const Direction_2 & nx = Traits::neg_x_2(); 02409 if (Traits::orientation(nx, s) == COLLINEAR) { 02410 // Project onto xz plane: 02411 s = Traits::project_xz(source); 02412 t = Traits::project_xz(target); 02413 const Direction_2 & ny = Traits::neg_y_2(); 02414 Orientation orient1 = Traits::orientation(ny, s); 02415 CGAL_assertion_code(Orientation orient2 = Traits::orientation(ny, t)); 02416 CGAL_assertion(orient1 == orient2); 02417 orient = Traits::orientation(s, t); 02418 CGAL_assertion(orient != COLLINEAR); 02419 if (orient1 == LEFT_TURN) { 02420 set_is_directed_right(orient == LEFT_TURN); 02421 return; 02422 } 02423 set_is_directed_right(orient == RIGHT_TURN); 02424 return; 02425 } 02426 // Project onto yz plane: 02427 s = Traits::project_yz(source); 02428 t = Traits::project_yz(target); 02429 const Direction_2 & ny = Traits::neg_y_2(); 02430 Orientation orient1 = Traits::orientation(ny, s); 02431 CGAL_assertion_code(Orientation orient2 = Traits::orientation(ny, t)); 02432 CGAL_assertion(orient1 == orient2); 02433 if (orient1 == LEFT_TURN) { 02434 orient = Traits::orientation(s, t); 02435 CGAL_assertion(orient != COLLINEAR); 02436 set_is_directed_right(orient == LEFT_TURN); 02437 return; 02438 } 02439 orient = Traits::orientation(s, t); 02440 CGAL_assertion(orient != COLLINEAR); 02441 set_is_directed_right(orient == RIGHT_TURN); 02442 return; 02443 } 02444 02445 // The arc is not vertical! 02446 set_is_vertical(false); 02447 set_is_directed_right(orient == LEFT_TURN); 02448 set_is_full(kernel.equal_3_object()(source, target)); 02449 } 02450 02455 Arr_x_monotone_geodesic_arc_on_sphere_3(const Direction_3 & normal) : 02456 m_normal(normal), 02457 m_is_vertical(false), 02458 m_is_directed_right(z_sign(normal) == POSITIVE), 02459 m_is_full(true), 02460 m_is_degenerate(false), 02461 m_is_empty(false) 02462 { 02463 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 02464 typedef typename Kernel::FT FT; 02465 02466 CGAL_precondition(z_sign(normal) != ZERO); 02467 02468 #if (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_1_Y_0) 02469 Direction_3 d = (CGAL::sign(normal.dz()) == POSITIVE) ? 02470 Direction_3(-(normal.dz()), 0, normal.dx()) : 02471 Direction_3(normal.dz(), 0, -(normal.dx())); 02472 #else 02473 const Direction_2 & xy = Traits::identification_xy(); 02474 FT x = xy.dx(); 02475 FT y = xy.dy(); 02476 FT z((xy.dx() * normal.dx() + xy.dy() * normal.dy()) / -(normal.dz())); 02477 Direction_3 d(x, y, z); 02478 #endif 02479 m_source = m_target = 02480 Arr_extended_direction_3(d, Arr_extended_direction_3::MID_BOUNDARY_LOC); 02481 } 02482 02488 Arr_x_monotone_geodesic_arc_on_sphere_3 02489 (const Arr_extended_direction_3 & point, 02490 const Direction_3 & normal) : 02491 m_source(point), 02492 m_target(point), 02493 m_normal(normal), 02494 m_is_vertical(false), 02495 m_is_directed_right(z_sign(normal) == POSITIVE), 02496 m_is_full(true), 02497 m_is_degenerate(false), 02498 m_is_empty(false) 02499 { 02500 CGAL_precondition(has_on(point)); 02501 CGAL_precondition(z_sign(normal) != ZERO); 02502 #if !defined(CGAL_FULL_X_MONOTONE_GEODESIC_ARC_ON_SPHERE_IS_SUPPORTED) 02503 CGAL_error_msg( "Full x-monotone arcs are not supported!"); 02504 #endif 02505 } 02506 02515 Arr_x_monotone_geodesic_arc_on_sphere_3 02516 (const Arr_extended_direction_3 & source, 02517 const Arr_extended_direction_3 & target, 02518 const Direction_3 & normal) : 02519 m_source(source), 02520 m_target(target), 02521 m_normal(normal), 02522 m_is_full(false), 02523 m_is_degenerate(false), 02524 m_is_empty(false) 02525 { 02526 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 02527 02528 CGAL_precondition(has_on(source)); 02529 CGAL_precondition(has_on(target)); 02530 02531 // Check whether any one of the endpoint coincide with a pole: 02532 if (source.is_max_boundary()) { 02533 set_is_vertical(true); 02534 set_is_directed_right(false); 02535 return; 02536 } 02537 if (source.is_min_boundary()) { 02538 set_is_vertical(true); 02539 set_is_directed_right(true); 02540 return; 02541 } 02542 if (target.is_max_boundary()) { 02543 set_is_vertical(true); 02544 set_is_directed_right(true); 02545 return; 02546 } 02547 if (target.is_min_boundary()) { 02548 set_is_vertical(true); 02549 set_is_directed_right(false); 02550 return; 02551 } 02552 02553 if (z_sign(normal) == ZERO) { 02554 set_is_vertical(true); 02555 bool s_is_positive, plane_is_positive; 02556 CGAL::Sign xsign = x_sign(normal); 02557 if (xsign == ZERO) { 02558 s_is_positive = x_sign(source) == POSITIVE; 02559 plane_is_positive = y_sign(normal) == NEGATIVE; 02560 } else { 02561 s_is_positive = y_sign(source) == POSITIVE; 02562 plane_is_positive = xsign == POSITIVE; 02563 } 02564 bool ccw = ((plane_is_positive && s_is_positive) || 02565 (!plane_is_positive && !s_is_positive)); 02566 set_is_directed_right(ccw); 02567 return; 02568 } 02569 02570 // The arc is not vertical! 02571 set_is_vertical(false); 02572 set_is_directed_right(z_sign(normal) == POSITIVE); 02573 } 02574 02578 void set_source(const Direction_3 & p) { m_source = p; } 02579 02583 void set_target(const Direction_3 & p) { m_target = p; } 02584 02588 void normal(const Direction_3 & normal) { m_normal = normal; } 02589 02590 void set_is_vertical(bool flag) { m_is_vertical = flag; } 02591 void set_is_directed_right(bool flag) { m_is_directed_right = flag; } 02592 void set_is_full(bool flag) { m_is_full = flag; } 02593 void set_is_degenerate(bool flag) { m_is_degenerate = flag; } 02594 void set_is_empty(bool flag) { m_is_empty = flag; } 02595 02597 const Arr_extended_direction_3 & source() const { return m_source; } 02598 02600 const Arr_extended_direction_3 & target() const { return m_target; } 02601 02603 const Direction_3 & normal() const { return m_normal; } 02604 02606 const Arr_extended_direction_3 & left() const 02607 { return (m_is_directed_right ? m_source : m_target); } 02608 02610 const Arr_extended_direction_3 & right() const 02611 { return (m_is_directed_right ? m_target : m_source); } 02612 02614 bool is_vertical() const { return m_is_vertical; } 02615 02619 bool is_directed_right() const { return m_is_directed_right; } 02620 02622 bool is_full() const { return m_is_full; } 02623 02625 bool is_degenerate() const { return m_is_degenerate; } 02626 02628 bool is_empty() const { return m_is_empty; } 02629 02631 bool is_on_boundary() const 02632 { 02633 /* If the curve is not vertical and non of its endpoints lie on the 02634 * boundary, the arc itself cannot lie on the identification arc. 02635 */ 02636 if (m_source.is_no_boundary() || m_target.is_no_boundary() || 02637 !is_vertical()) 02638 return false; 02639 02643 if (m_source.is_mid_boundary() || m_target.is_mid_boundary()) 02644 return true; 02645 02646 /* Both endpoints lie on opposite poles respectively. If the normal 02647 * coincides with the normal of the plane that contains the identification 02648 * arc, the arc lies on the identification arc. 02649 */ 02650 #if (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_1_Y_0) 02651 return ((x_sign(m_normal) == ZERO) && 02652 (((y_sign(m_normal) == NEGATIVE) && !is_directed_right()) || 02653 ((y_sign(m_normal) == POSITIVE) && is_directed_right()))); 02654 #else 02655 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 02656 02657 const Direction_3 & iden_normal = Traits::identification_normal(); 02658 const Direction_2 iden_normal_xy = Traits::project_xy(iden_normal); 02659 Direction_2 normal_xy = Traits::project_xy(m_normal); 02660 Kernel kernel; 02661 if (is_directed_right()) { 02662 return kernel.equal_2_object()(normal_xy, iden_normal_xy); 02663 } else { 02664 Direction_2 opposite_normal_xy = 02665 kernel.construct_opposite_direction_2_object()(normal_xy); 02666 return kernel.equal_2_object()(opposite_normal_xy, iden_normal_xy); 02667 } 02668 #endif 02669 } 02670 02678 bool is_in_x_range(const Arr_extended_direction_3 & point) const 02679 { 02680 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 02681 02682 CGAL_precondition(!point.is_min_boundary()); 02683 CGAL_precondition(!point.is_max_boundary()); 02684 02685 Direction_2 p = Traits::project_xy(point); 02686 if (is_vertical()) { 02687 Direction_2 q = (is_directed_right()) ? 02688 Direction_2(-(m_normal.dy()), m_normal.dx()) : 02689 Direction_2(m_normal.dy(), -(m_normal.dx())); 02690 Kernel kernel; 02691 return kernel.equal_2_object()(p, q); 02692 } 02693 02694 // The curve is not vertical: 02695 Direction_2 r = Traits::project_xy(right()); 02696 Kernel kernel; 02697 if (kernel.equal_2_object()(p, r)) return true; 02698 Direction_2 l = Traits::project_xy(left()); 02699 if (kernel.equal_2_object()(p, l)) return true; 02700 return kernel.counterclockwise_in_between_2_object()(p, l, r); 02701 } 02702 02703 #if 0 02704 02705 Bbox_2 bbox() const 02706 { 02707 Kernel kernel; 02708 Segment_2 seg = kernel.construct_spherical_arc_2_object()(this->m_source, 02709 this->m_target); 02710 return kernel.construct_bbox_2_object()(seg); 02711 } 02712 #endif 02713 02715 Arr_x_monotone_geodesic_arc_on_sphere_3 opposite() const 02716 { 02717 Arr_x_monotone_geodesic_arc_on_sphere_3 opp; 02718 opp.m_source = this->m_target; 02719 opp.m_target = this->m_source; 02720 opp.m_normal = this->m_normal; 02721 opp.m_is_directed_right = !(this->is_directed_right()); 02722 opp.m_is_vertical = this->is_vertical(); 02723 opp.m_is_full = this->is_full(); 02724 opp.m_is_degenerate = this->is_degenerate(); 02725 opp.m_is_empty = this->is_empty(); 02726 return opp; 02727 } 02728 02735 inline bool has_on(const Direction_3 & dir) const 02736 { 02737 typename Kernel::FT dot = normal().vector() * dir.vector(); 02738 return CGAL::sign(dot) == ZERO; 02739 } 02740 }; 02741 02750 template <typename T_Kernel> 02751 class Arr_geodesic_arc_on_sphere_3 : 02752 public Arr_x_monotone_geodesic_arc_on_sphere_3<T_Kernel> { 02753 protected: 02754 typedef T_Kernel Kernel; 02755 typedef Arr_x_monotone_geodesic_arc_on_sphere_3<Kernel> Base; 02756 02757 typedef typename Base::Plane_3 Plane_3; 02758 typedef typename Base::Direction_3 Direction_3; 02759 typedef typename Base::Direction_2 Direction_2; 02760 02761 // For some reason compilation under Windows fails without the qualifier 02762 typedef CGAL::Arr_extended_direction_3<Kernel> Arr_extended_direction_3; 02763 02765 bool m_is_x_monotone; 02766 02767 public: 02769 Arr_geodesic_arc_on_sphere_3() : Base(), m_is_x_monotone(true) {} 02770 02774 Arr_geodesic_arc_on_sphere_3 02775 (const Arr_geodesic_arc_on_sphere_3 & other) : Base(other) 02776 { 02777 m_is_x_monotone = other.m_is_x_monotone; 02778 } 02779 02793 Arr_geodesic_arc_on_sphere_3(const Arr_extended_direction_3 & src, 02794 const Arr_extended_direction_3 & trg, 02795 const Direction_3 & normal, 02796 bool is_x_monotone, bool is_vertical, 02797 bool is_directed_right, 02798 bool is_full = false, 02799 bool is_degenerate = false, 02800 bool is_empty = false) : 02801 Base(src, trg, normal, 02802 is_vertical, is_directed_right, is_full, is_degenerate, is_empty), 02803 m_is_x_monotone(is_x_monotone) 02804 { 02805 CGAL_precondition(this->has_on(src)); 02806 CGAL_precondition(this->has_on(trg)); 02807 } 02808 02823 Arr_geodesic_arc_on_sphere_3(const Arr_extended_direction_3 & source, 02824 const Arr_extended_direction_3 & target) 02825 { 02826 this->set_source(source); 02827 this->set_target(target); 02828 this->set_is_full(false); 02829 this->set_is_degenerate(false); 02830 this->set_is_empty(false); 02831 02832 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 02833 typedef typename Kernel::Direction_2 Direction_2; 02834 typedef typename Kernel::Direction_3 Direction_3; 02835 02836 Kernel kernel; 02837 CGAL_precondition(!kernel.equal_3_object()(source, target)); 02838 CGAL_precondition(!kernel.equal_3_object() 02839 (kernel.construct_opposite_direction_3_object()(source), 02840 target)); 02841 this->m_normal = this->construct_normal_3(source, target); 02842 02843 // Check whether one of the endpoints coincides with a pole: */ 02844 if (source.is_max_boundary()) { 02845 this->set_is_vertical(true); 02846 this->set_is_directed_right(false); 02847 set_is_x_monotone(true); 02848 return; 02849 } 02850 if (source.is_min_boundary()) { 02851 this->set_is_vertical(true); 02852 this->set_is_directed_right(true); 02853 set_is_x_monotone(true); 02854 return; 02855 } 02856 if (target.is_max_boundary()) { 02857 this->set_is_vertical(true); 02858 this->set_is_directed_right(true); 02859 set_is_x_monotone(true); 02860 return; 02861 } 02862 if (target.is_min_boundary()) { 02863 this->set_is_vertical(true); 02864 this->set_is_directed_right(false); 02865 set_is_x_monotone(true); 02866 return; 02867 } 02868 02869 // None of the enpoints coincide with a pole: 02870 Direction_3 normal = this->m_normal; 02871 if (z_sign(normal) == ZERO) { 02872 // The arc is vertical 02873 this->set_is_vertical(true); 02874 bool s_is_positive, t_is_positive, plane_is_positive; 02875 CGAL::Sign xsign = x_sign(normal); 02876 if (xsign == ZERO) { 02877 s_is_positive = x_sign(source) == POSITIVE; 02878 t_is_positive = x_sign(target) == POSITIVE; 02879 plane_is_positive = y_sign(normal) == NEGATIVE; 02880 } else { 02881 s_is_positive = y_sign(source) == POSITIVE; 02882 t_is_positive = y_sign(target) == POSITIVE; 02883 plane_is_positive = xsign == POSITIVE; 02884 } 02885 set_is_x_monotone(s_is_positive == t_is_positive); 02886 bool ccw = ((plane_is_positive && s_is_positive) || 02887 (!plane_is_positive && !s_is_positive)); 02888 this->set_is_directed_right(ccw); 02889 return; 02890 } 02891 02892 // The arc is not vertical! 02893 this->set_is_vertical(false); 02894 Direction_2 s = Traits::project_xy(source); 02895 Direction_2 t = Traits::project_xy(target); 02896 Orientation orient = Traits::orientation(s, t); 02897 02898 const Direction_2 & d = Traits::identification_xy(); 02899 if (orient == LEFT_TURN) { 02900 this->set_is_directed_right(true); 02901 set_is_x_monotone(!kernel.counterclockwise_in_between_2_object()(d, s, t)); 02902 return; 02903 } 02904 02905 // (orient == RIGHT_TURN) 02906 this->set_is_directed_right(false); 02907 set_is_x_monotone(!kernel.counterclockwise_in_between_2_object()(d, t, s)); 02908 return; 02909 } 02910 02919 Arr_geodesic_arc_on_sphere_3(const Arr_extended_direction_3 & source, 02920 const Arr_extended_direction_3 & target, 02921 const Direction_3 & normal) 02922 { 02923 Kernel kernel; 02924 02925 this->set_source(source); 02926 this->set_target(target); 02927 this->normal(normal); 02928 this->set_is_degenerate(false); 02929 this->set_is_empty(false); 02930 02931 typedef Arr_geodesic_arc_on_sphere_traits_2<Kernel> Traits; 02932 02933 CGAL_precondition(this->has_on(source)); 02934 CGAL_precondition(this->has_on(target)); 02935 02936 if (z_sign(normal) == ZERO) { 02937 this->set_is_vertical(true); 02938 02939 // Check whether both endpoint coincide with the poles: 02940 if (source.is_min_boundary() && target.is_max_boundary()) { 02941 // Both endpoints coincide with the 2 poles respectively. 02942 this->set_is_directed_right(true); 02943 this->set_is_full(false); 02944 set_is_x_monotone(true); 02945 return; 02946 } 02947 02948 if (source.is_max_boundary() && target.is_min_boundary()) { 02949 // Both endpoints coincide with the 2 poles respectively. 02950 this->set_is_directed_right(false); 02951 this->set_is_full(false); 02952 set_is_x_monotone(true); 02953 return; 02954 } 02955 02956 CGAL::Sign xsign = x_sign(normal); 02957 bool xz_plane = xsign == ZERO; 02958 bool s_is_positive, t_is_positive, plane_is_positive; 02959 if (xz_plane) { 02960 s_is_positive = x_sign(source) == POSITIVE; 02961 t_is_positive = x_sign(target) == POSITIVE; 02962 plane_is_positive = y_sign(normal) == NEGATIVE; 02963 } else { 02964 s_is_positive = y_sign(source) == POSITIVE; 02965 t_is_positive = y_sign(target) == POSITIVE; 02966 plane_is_positive = xsign == POSITIVE; 02967 } 02968 02969 // Process degenerate cases: 02970 if (source.is_min_boundary()) { 02971 this->set_is_directed_right(true); 02972 set_is_x_monotone((plane_is_positive && t_is_positive) || 02973 (!plane_is_positive && !t_is_positive)); 02974 return; 02975 } 02976 if (source.is_max_boundary()) { 02977 this->set_is_directed_right(false); 02978 set_is_x_monotone((plane_is_positive && !t_is_positive) || 02979 (!plane_is_positive && t_is_positive)); 02980 return; 02981 } 02982 if (target.is_min_boundary()) { 02983 this->set_is_directed_right(false); 02984 set_is_x_monotone((plane_is_positive && !s_is_positive) || 02985 (!plane_is_positive && s_is_positive)); 02986 return; 02987 } 02988 if (target.is_max_boundary()) { 02989 this->set_is_directed_right(true); 02990 set_is_x_monotone((plane_is_positive && s_is_positive) || 02991 (!plane_is_positive && !s_is_positive)); 02992 return; 02993 } 02994 if (s_is_positive != t_is_positive) { 02995 set_is_x_monotone(false); 02996 return; 02997 } 02998 02999 /* Non of the endpoints coincide with a pole. 03000 * The projections of both endpoints lie on the same hemi-circle. 03001 * Thus, either the arc is x-monotone, or it includes both poles. 03002 * This means that it is sufficient to check whether one pole lies 03003 * on the arc in order to determine x-monotonicity 03004 */ 03005 03006 typename Traits::Project project = 03007 (xz_plane) ? Traits::project_xz : Traits::project_yz; 03008 Direction_2 s = project(source); 03009 Direction_2 t = project(target); 03010 const Direction_2 & ny = Traits::neg_y_2(); 03011 typename Kernel::Counterclockwise_in_between_2 ccib = 03012 kernel.counterclockwise_in_between_2_object(); 03013 set_is_x_monotone((plane_is_positive && !ccib(ny, s, t)) || 03014 (!plane_is_positive && !ccib(ny, t, s))); 03015 03016 bool ccw = ((plane_is_positive && s_is_positive) || 03017 (!plane_is_positive && !s_is_positive)); 03018 this->set_is_directed_right(ccw); 03019 return; 03020 } 03021 03022 // The arc is not vertical! 03023 this->set_is_vertical(false); 03024 this->set_is_directed_right(z_sign(normal) == POSITIVE); 03025 const Direction_2 & d = Traits::identification_xy(); 03026 Direction_2 s = Traits::project_xy(source); 03027 Direction_2 t = Traits::project_xy(target); 03028 typename Kernel::Counterclockwise_in_between_2 ccib = 03029 kernel.counterclockwise_in_between_2_object(); 03030 bool plane_is_positive = (z_sign(normal) == POSITIVE); 03031 set_is_x_monotone((plane_is_positive && !ccib(d, s, t)) || 03032 (!plane_is_positive && !ccib(d, t, s))); 03033 } 03034 03038 Arr_geodesic_arc_on_sphere_3(const Direction_3 & normal) 03039 { 03040 this->normal(normal); 03041 this->set_is_vertical(CGAL::sign(normal.dz()) == ZERO); 03042 this->set_is_directed_right(true); 03043 this->set_is_full(true); 03044 this->set_is_degenerate(false); 03045 this->set_is_empty(false); 03046 set_is_x_monotone(false); 03047 } 03048 03052 bool is_x_monotone() const { return m_is_x_monotone; } 03053 03057 void set_is_x_monotone(bool flag) { m_is_x_monotone = flag; } 03058 }; 03059 03061 template <typename Kernel, typename OutputStream> 03062 OutputStream & operator<<(OutputStream & os, 03063 const Arr_extended_direction_3<Kernel> & ed) 03064 { 03065 CGAL::To_double<typename Kernel::FT> todouble; 03066 #if defined(CGAL_ARR_GEODESIC_ARC_ON_SPHERE_DETAILS) 03067 os << "("; 03068 #endif 03069 #if 0 03070 os << ed.dx() << ", " << ed.dy() << ", " << ed.dz(); 03071 #else 03072 os << static_cast<float>(todouble(ed.dx())) << ", " 03073 << static_cast<float>(todouble(ed.dy())) << ", " 03074 << static_cast<float>(todouble(ed.dz())); 03075 #endif 03076 #if defined(CGAL_ARR_GEODESIC_ARC_ON_SPHERE_DETAILS) 03077 os << ")" 03078 << ", " 03079 << 03080 (ed.is_min_boundary() ? "min" : 03081 ed.is_max_boundary() ? "max" : 03082 ed.is_mid_boundary() ? "dis" : "reg"); 03083 #endif 03084 return os; 03085 } 03086 03088 template <typename Kernel, typename OutputStream> 03089 OutputStream & 03090 operator<<(OutputStream & os, 03091 const Arr_x_monotone_geodesic_arc_on_sphere_3<Kernel> & arc) 03092 { 03093 #if defined(CGAL_ARR_GEODESIC_ARC_ON_SPHERE_DETAILS) 03094 os << "("; 03095 #endif 03096 os << "(" << arc.source() << "), (" << arc.target() << ")"; 03097 #if defined(CGAL_ARR_GEODESIC_ARC_ON_SPHERE_DETAILS) 03098 os << "(" 03099 << ", " << (arc.is_vertical() ? " |" : "!|") 03100 << ", " << (arc.is_directed_right() ? "=>" : "<=") 03101 << ", " << (arc.is_full() ? "o" : "/"); 03102 #endif 03103 return os; 03104 } 03105 03107 template <typename Kernel, typename InputStream> 03108 InputStream & 03109 operator>>(InputStream & is, 03110 const Arr_x_monotone_geodesic_arc_on_sphere_3<Kernel> & arc) 03111 { 03112 std::cerr << "Not implemented yet!" << std::endl; 03113 return is; 03114 } 03115 03116 CGAL_END_NAMESPACE 03117 03118 #endif