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: 00015 // $Id: 00016 // 00017 // 00018 // Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il> 00019 // Ophir Setter <ophir.setter@cs.tau.ac.il> 00020 // Guy Zucker <guyzucke@post.tau.ac.il> 00021 00022 00023 #ifndef CGAL_GPS_ON_SURFACE_BASE_2_H 00024 #define CGAL_GPS_ON_SURFACE_BASE_2_H 00025 00026 #include <CGAL/basic.h> 00027 #include <CGAL/Object.h> 00028 #include <CGAL/enum.h> 00029 #include <CGAL/iterator.h> 00030 #include <CGAL/Arrangement_on_surface_2.h> 00031 #include <CGAL/Arrangement_2/Arr_traits_adaptor_2.h> 00032 00033 #include <CGAL/Arr_overlay_2.h> 00034 #include <CGAL/Boolean_set_operations_2/Gps_do_intersect_functor.h> 00035 #include <CGAL/Boolean_set_operations_2/Gps_intersection_functor.h> 00036 #include <CGAL/Boolean_set_operations_2/Gps_join_functor.h> 00037 #include <CGAL/Boolean_set_operations_2/Gps_difference_functor.h> 00038 #include <CGAL/Boolean_set_operations_2/Gps_sym_diff_functor.h> 00039 #include <CGAL/Boolean_set_operations_2/Gps_merge.h> 00040 #include <CGAL/Boolean_set_operations_2/Gps_polygon_simplifier.h> 00041 #include <CGAL/Boolean_set_operations_2/Ccb_curve_iterator.h> 00042 00054 CGAL_BEGIN_NAMESPACE 00055 00056 namespace Boolean_set_operation_2_internal 00057 { 00058 struct NoValidationPolicy 00059 { 00064 template <class Polygon, class Traits> 00065 inline static void is_valid(const Polygon&, Traits&) {} 00066 }; 00067 } 00068 00070 00076 template <class Traits_, class TopTraits_, 00077 class ValidationPolicy = 00078 Boolean_set_operation_2_internal::NoValidationPolicy> 00079 class Gps_on_surface_base_2 00080 { 00081 public: 00082 typedef Traits_ Traits_2; 00083 typedef TopTraits_ Topology_traits; 00084 typedef typename Traits_2::Polygon_2 Polygon_2; 00085 typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; 00086 typedef CGAL::Arrangement_on_surface_2<Traits_2, Topology_traits> 00087 Arrangement_on_surface_2; 00088 typedef typename Arrangement_on_surface_2::Size Size; 00089 00090 private: 00091 typedef Arrangement_on_surface_2 Aos_2; 00092 00093 typedef Gps_on_surface_base_2 < 00094 Traits_2, Topology_traits, ValidationPolicy> Self; 00095 typedef typename Traits_2::Point_2 Point_2; 00096 typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; 00097 00098 typedef typename Polygon_with_holes_2::Hole_const_iterator 00099 GP_Holes_const_iterator; 00100 typedef typename Traits_2::Curve_const_iterator Curve_const_iterator; 00101 typedef typename Traits_2::Compare_endpoints_xy_2 00102 Compare_endpoints_xy_2; 00103 typedef typename Traits_2::Construct_opposite_2 Construct_opposite_2; 00104 00105 typedef typename Aos_2::Face_const_iterator Face_const_iterator; 00106 typedef typename Aos_2::Halfedge_const_iterator Halfedge_const_iterator; 00107 typedef typename Aos_2::Vertex_const_iterator Vertex_const_iterator; 00108 typedef typename Aos_2::Edge_const_iterator Edge_const_iterator; 00109 typedef typename Aos_2::Outer_ccb_const_iterator Outer_ccb_const_iterator; 00110 typedef typename Aos_2::Inner_ccb_const_iterator Inner_ccb_const_iterator; 00111 typedef typename Aos_2::Ccb_halfedge_const_circulator 00112 Ccb_halfedge_const_circulator; 00113 typedef typename Aos_2::Face_iterator Face_iterator; 00114 typedef typename Aos_2::Halfedge_iterator Halfedge_iterator; 00115 typedef typename Aos_2::Vertex_iterator Vertex_iterator; 00116 typedef typename Aos_2::Edge_iterator Edge_iterator; 00117 typedef typename Aos_2::Outer_ccb_iterator Outer_ccb_iterator; 00118 typedef typename Aos_2::Inner_ccb_iterator Inner_ccb_iterator; 00119 typedef typename Aos_2::Ccb_halfedge_circulator Ccb_halfedge_circulator; 00120 typedef typename Aos_2::Face_handle Face_handle; 00121 typedef typename Aos_2::Halfedge_handle Halfedge_handle; 00122 typedef typename Aos_2::Vertex_handle Vertex_handle; 00123 00124 typedef typename Aos_2::Face_const_handle Face_const_handle; 00125 typedef typename Aos_2::Halfedge_const_handle Halfedge_const_handle; 00126 typedef typename Aos_2::Vertex_const_handle Vertex_const_handle; 00127 00128 typedef typename Aos_2::Halfedge_around_vertex_const_circulator 00129 Halfedge_around_vertex_const_circulator; 00130 00131 typedef std::pair<Aos_2 *, 00132 std::vector<Vertex_handle> *> Arr_entry; 00133 00134 typedef typename Arrangement_on_surface_2:: 00135 Topology_traits::Default_point_location_strategy Point_location; 00136 00137 protected: 00138 00139 // Traits* should be removed and only m_traits should be used. 00140 // If you, who reads this text, have time, replace m_traits 00141 // with m_traits_adaptor and try to do something about m_traits_owner. 00142 Traits_2* m_traits; 00143 CGAL::Arr_traits_adaptor_2<Traits_2> m_traits_adaptor; 00144 bool m_traits_owner; 00145 00146 // the underlying arrangement 00147 Aos_2* m_arr; 00148 00149 00150 public: 00151 00152 // default costructor 00153 Gps_on_surface_base_2() : m_traits(new Traits_2()), 00154 m_traits_adaptor(*m_traits), 00155 m_traits_owner(true), 00156 m_arr(new Aos_2(m_traits)) 00157 {} 00158 00159 00160 // constructor with traits object 00161 Gps_on_surface_base_2(Traits_2& tr) : m_traits(&tr), 00162 m_traits_adaptor(*m_traits), 00163 m_traits_owner(false), 00164 m_arr(new Aos_2(m_traits)) 00165 {} 00166 00167 00168 Gps_on_surface_base_2(const Self& ps) : 00169 m_traits(new Traits_2(*(ps.m_traits))), 00170 m_traits_adaptor(*m_traits), 00171 m_traits_owner(true), 00172 m_arr(new Aos_2(*(ps.m_arr))) 00173 {} 00174 00175 00176 Gps_on_surface_base_2& operator=(const Self& ps) 00177 { 00178 if (this == &ps) 00179 return (*this); 00180 00181 if (m_traits_owner) 00182 delete m_traits; 00183 delete m_arr; 00184 m_traits = new Traits_2(*(ps.m_traits)); 00185 m_traits_adaptor = CGAL::Arr_traits_adaptor_2<Traits_2>(*m_traits); 00186 m_traits_owner = true; 00187 m_arr = new Aos_2(*(ps.m_arr)); 00188 return (*this); 00189 } 00190 00191 00192 explicit Gps_on_surface_base_2(const Polygon_2& pgn) : 00193 m_traits(new Traits_2()), 00194 m_traits_adaptor(*m_traits), 00195 m_traits_owner(true), 00196 m_arr(new Aos_2(m_traits)) 00197 { 00198 ValidationPolicy::is_valid(pgn, *m_traits); 00199 _insert(pgn, *m_arr); 00200 } 00201 00202 explicit Gps_on_surface_base_2(const Polygon_with_holes_2& pgn_with_holes): 00203 m_traits(new Traits_2()), 00204 m_traits_adaptor(*m_traits), 00205 m_traits_owner(true), 00206 m_arr(new Aos_2(m_traits)) 00207 { 00208 ValidationPolicy::is_valid(pgn_with_holes,*m_traits); 00209 _insert(pgn_with_holes, *m_arr); 00210 } 00211 00212 protected: 00213 Gps_on_surface_base_2(Aos_2* arr) : m_traits(new Traits_2()), 00214 m_traits_adaptor(*m_traits), 00215 m_traits_owner(true), 00216 m_arr(arr) 00217 {} 00218 00219 public: 00220 //destructor 00221 virtual ~Gps_on_surface_base_2() 00222 { 00223 delete m_arr; 00224 00225 if (m_traits_owner) 00226 delete m_traits; 00227 } 00228 00229 void simplify(const Polygon_2& pgn, Polygon_with_holes_2& res) 00230 { 00231 typedef Gps_polygon_simplifier<Aos_2> Simplifier; 00232 00233 Aos_2* arr = new Aos_2(); 00234 00235 Simplifier simp(*arr, *m_traits); 00236 simp.simplify(pgn); 00237 _remove_redundant_edges(arr); 00238 Self gps(arr); 00239 gps._reset_faces(); 00240 00241 typedef Oneset_iterator<Polygon_with_holes_2> OutputItr; 00242 OutputItr oi (res); 00243 gps.polygons_with_holes(oi); 00244 } 00245 00246 // insert a simple polygon 00247 void insert(const Polygon_2& pgn) 00248 { 00249 ValidationPolicy::is_valid(pgn, *m_traits); 00250 _insert(pgn, *m_arr); 00251 } 00252 00253 // insert a polygon with holes 00254 void insert(const Polygon_with_holes_2& pgn_with_holes) 00255 { 00256 ValidationPolicy::is_valid(pgn_with_holes, *m_traits); 00257 _insert(pgn_with_holes, *m_arr); 00258 } 00259 00260 // insert a range of polygons that can be either simple polygons 00261 // or polygons with holes 00262 // precondition: the polygons are disjoint and simple 00263 template <class PolygonIterator> 00264 void insert(PolygonIterator pgn_begin, PolygonIterator pgn_end); 00265 00266 00267 // insert two ranges of : the first one for simple polygons, 00268 // the second one for polygons with holes 00269 // precondition: the first range is disjoint simple polygons 00270 // the second range is disjoint polygons with holes 00271 template <class PolygonIterator, class PolygonWithHolesIterator> 00272 void insert(PolygonIterator pgn_begin, PolygonIterator pgn_end, 00273 PolygonWithHolesIterator pgn_with_holes_begin, 00274 PolygonWithHolesIterator pgn_with_holes_end); 00275 00276 // test for intersection with a simple polygon 00277 bool do_intersect(const Polygon_2 &pgn) const 00278 { 00279 ValidationPolicy::is_valid(pgn,*m_traits); 00280 Self other(pgn); 00281 return (do_intersect(other)); 00282 } 00283 00284 // test for intersection with a polygon with holes 00285 bool do_intersect(const Polygon_with_holes_2& pgn_with_holes) const 00286 { 00287 ValidationPolicy::is_valid(pgn_with_holes, *m_traits); 00288 Self other(pgn_with_holes); 00289 return (do_intersect(other)); 00290 } 00291 00292 //test for intersection with another Gps_on_surface_base_2 object 00293 bool do_intersect(const Self& other) const 00294 { 00295 if (this->is_empty() || other.is_empty()) 00296 return false; 00297 00298 if (this->is_plane() || other.is_plane()) 00299 return true; 00300 00301 Aos_2 res_arr; 00302 00303 Gps_do_intersect_functor<Aos_2> func; 00304 overlay(*m_arr, *(other.m_arr), res_arr, func); 00305 return func.found_reg_intersection(); 00306 } 00307 00308 template <class InputIterator> 00309 bool do_intersect(InputIterator begin, InputIterator end) 00310 { 00311 Self other(*this); 00312 other.intersection(begin, end); 00313 return (other.is_empty()); 00314 } 00315 00316 template <class InputIterator1, class InputIterator2> 00317 bool do_intersect(InputIterator1 begin1, InputIterator1 end1, 00318 InputIterator2 begin2, InputIterator2 end2) 00319 { 00320 Self other(*this); 00321 other.intersection(begin1, end1, begin2, end2); 00322 return (other.is_empty()); 00323 } 00324 00325 00326 // intersection with a simple polygon 00327 void intersection(const Polygon_2& pgn) 00328 { 00329 ValidationPolicy::is_valid(pgn, *m_traits); 00330 _intersection(pgn); 00331 } 00332 00333 // intersection with a polygon with holes 00334 void intersection(const Polygon_with_holes_2& pgn) 00335 { 00336 ValidationPolicy::is_valid(pgn, *m_traits); 00337 _intersection(pgn); 00338 } 00339 00340 //intersection with another Gps_on_surface_base_2 object 00341 void intersection(const Self& other) 00342 { 00343 _intersection(other); 00344 } 00345 00346 void intersection(const Self& gps1, const Self& gps2) 00347 { 00348 this->clear(); 00349 _intersection(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); 00350 } 00351 00352 00353 // join with a simple polygon 00354 void join(const Polygon_2& pgn) 00355 { 00356 ValidationPolicy::is_valid(pgn, *m_traits); 00357 _join(pgn); 00358 } 00359 00360 // join with a polygon with holes 00361 void join(const Polygon_with_holes_2& pgn) 00362 { 00363 ValidationPolicy::is_valid(pgn, *m_traits); 00364 _join(pgn); 00365 } 00366 00367 //join with another Gps_on_surface_base_2 object 00368 void join(const Self& other) 00369 { 00370 _join(other); 00371 } 00372 00373 void join(const Self& gps1, const Self& gps2) 00374 { 00375 this->clear(); 00376 _join(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); 00377 } 00378 00379 // difference with a simple polygon 00380 void difference (const Polygon_2& pgn) 00381 { 00382 ValidationPolicy::is_valid(pgn, *m_traits); 00383 _difference(pgn); 00384 } 00385 00386 // difference with a polygon with holes 00387 void difference (const Polygon_with_holes_2& pgn) 00388 { 00389 ValidationPolicy::is_valid(pgn, *m_traits); 00390 _difference(pgn); 00391 } 00392 00393 //difference with another Gps_on_surface_base_2 object 00394 void difference (const Self& other) 00395 { 00396 _difference(other); 00397 } 00398 00399 void difference(const Self& gps1, const Self& gps2) 00400 { 00401 this->clear(); 00402 _difference(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); 00403 } 00404 00405 00406 // symmetric_difference with a simple polygon 00407 void symmetric_difference(const Polygon_2& pgn) 00408 { 00409 ValidationPolicy::is_valid(pgn, *m_traits); 00410 _symmetric_difference(pgn); 00411 } 00412 00413 // symmetric_difference with a polygon with holes 00414 void symmetric_difference(const Polygon_with_holes_2& pgn) 00415 { 00416 ValidationPolicy::is_valid(pgn, *m_traits); 00417 _symmetric_difference(pgn); 00418 } 00419 00420 //symmetric_difference with another Gps_on_surface_base_2 object 00421 void symmetric_difference(const Self& other) 00422 { 00423 _symmetric_difference(other); 00424 } 00425 00426 void symmetric_difference(const Self& gps1, const Self& gps2) 00427 { 00428 this->clear(); 00429 _symmetric_difference(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); 00430 } 00431 00432 00433 void complement() 00434 { 00435 this->_complement(m_arr); 00436 } 00437 00438 void complement(const Self& other) 00439 { 00440 *(this->m_arr) = *(other.m_arr); 00441 this->complement(); 00442 } 00443 00444 void fix_curves_direction() 00445 { 00446 _fix_curves_direction(*m_arr); 00447 } 00448 00449 Size number_of_polygons_with_holes() const; 00450 00451 Traits_2& traits() 00452 { 00453 return *m_traits; 00454 } 00455 00456 const Traits_2& traits() const 00457 { 00458 return *m_traits; 00459 } 00460 00461 bool is_empty() const 00462 { 00463 // We have to check that all the faces of an empty arrangement are not 00464 // conained in the polygon set (there can be several faces in an empty 00465 // arrangement, dependant on the topology traits. 00466 // The point is that if the arrangement is "empty" (meaning that no curve 00467 // or point were inserted and that it is in its original state) then 00468 // all the faces (created by the topology traits) should have the same 00469 // result for contained() --- from Boolean operations point of view there 00470 // can not be an empty arrangement which has serveral faces with different 00471 // attributes. 00472 return (m_arr->is_empty() && !m_arr->faces_begin()->contained()); 00473 } 00474 00475 bool is_plane() const 00476 { 00477 // Same comment as in "is_empty" above, just with adjustments. 00478 return (m_arr->is_empty() && m_arr->faces_begin()->contained()); 00479 } 00480 00481 void clear() 00482 { 00483 m_arr->clear(); 00484 } 00485 00486 00487 Oriented_side oriented_side(const Point_2& q) const 00488 { 00489 Point_location pl(*m_arr); 00490 00491 Object obj = pl.locate(q); 00492 Face_const_iterator f; 00493 if (CGAL::assign(f, obj)) 00494 { 00495 if (f->contained()) 00496 return ON_POSITIVE_SIDE; 00497 00498 return ON_NEGATIVE_SIDE ; 00499 } 00500 return ON_ORIENTED_BOUNDARY ; 00501 } 00502 00503 Oriented_side oriented_side(const Polygon_2& pgn) const 00504 { 00505 ValidationPolicy::is_valid(pgn, *m_traits); 00506 Self other(pgn); 00507 return (oriented_side(other)); 00508 } 00509 00510 Oriented_side oriented_side(const Polygon_with_holes_2& pgn) const 00511 { 00512 ValidationPolicy::is_valid(pgn, *m_traits); 00513 Self other(pgn); 00514 return (oriented_side(other)); 00515 } 00516 00517 Oriented_side oriented_side(const Self& other) const 00518 { 00519 if (this->is_empty() || other.is_empty()) 00520 return ON_NEGATIVE_SIDE; 00521 00522 if (this->is_plane() || other.is_plane()) 00523 return ON_POSITIVE_SIDE; 00524 00525 Aos_2 res_arr; 00526 00527 Gps_do_intersect_functor<Aos_2> func; 00528 overlay(*m_arr, *(other.m_arr), res_arr, func); 00529 if (func.found_reg_intersection()) 00530 return ON_POSITIVE_SIDE; 00531 00532 if (func.found_boundary_intersection()) 00533 return ON_ORIENTED_BOUNDARY; 00534 00535 return ON_NEGATIVE_SIDE; 00536 } 00537 00538 00539 // returns the location of the query point 00540 bool locate(const Point_2& q, Polygon_with_holes_2& pgn) const; 00541 00545 const Aos_2& arrangement() const 00546 { 00547 return *m_arr; 00548 } 00549 00553 Aos_2& arrangement() 00554 { 00555 return *m_arr; 00556 } 00557 00559 bool is_valid() const 00560 { 00561 if (!CGAL::is_valid(*m_arr)) 00562 return false; 00563 00564 Compare_endpoints_xy_2 cmp_endpoints = 00565 m_traits->compare_endpoints_xy_2_object(); 00566 Construct_opposite_2 ctr_opp = m_traits->construct_opposite_2_object(); 00567 00568 for (Edge_const_iterator eci = m_arr->edges_begin(); 00569 eci != m_arr->edges_end(); 00570 ++eci) 00571 { 00572 Halfedge_const_handle he = eci; 00573 if (he->face() == he->twin()->face()) 00574 { 00575 return false; 00576 } 00577 if (he->face()->contained() == he->twin()->face()->contained()) 00578 { 00579 return false; 00580 } 00581 00582 const X_monotone_curve_2& cv = he->curve(); 00583 const bool is_cont = he->face()->contained(); 00584 const Comparison_result he_res = 00585 ((Arr_halfedge_direction)he->direction() == ARR_LEFT_TO_RIGHT) ? 00586 SMALLER : LARGER; 00587 const bool has_same_dir = (cmp_endpoints(cv) == he_res); 00588 00589 if ((is_cont && !has_same_dir) || (!is_cont && has_same_dir)) 00590 return false; 00591 } 00592 return true; 00593 } 00594 00595 // get the simple polygons, takes O(n) 00596 template <class OutputIterator> 00597 OutputIterator polygons_with_holes(OutputIterator out) const; 00598 00599 // join a range of polygons 00600 template <class InputIterator> 00601 void join(InputIterator begin, InputIterator end, unsigned int k = 5) 00602 { 00603 typename std::iterator_traits<InputIterator>::value_type pgn; 00604 this->join(begin, end, pgn, k); 00605 this->remove_redundant_edges(); 00606 this->_reset_faces(); 00607 } 00608 00609 // join range of simple polygons 00610 // 5 is the magic number in which we switch to a sweep-based algorithm 00611 // instead of a D&C algorithm. This point should be further studies, as 00612 // it is hard to believe that this is the best value for all applications. 00613 template <class InputIterator> 00614 inline void join(InputIterator begin, 00615 InputIterator end, 00616 Polygon_2&, 00617 unsigned int k=5) 00618 { 00619 std::vector<Arr_entry> arr_vec (std::distance(begin, end) + 1); 00620 00621 arr_vec[0].first = this->m_arr; 00622 unsigned int i = 1; 00623 for (InputIterator itr = begin; itr!=end; ++itr, ++i) 00624 { 00625 arr_vec[i].first = new Aos_2(m_traits); 00626 _insert(*itr, *(arr_vec[i].first)); 00627 } 00628 00629 Join_merge<Aos_2> join_merge; 00630 _build_sorted_vertices_vectors (arr_vec); 00631 _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, join_merge); 00632 00633 //the result arrangement is at index 0 00634 this->m_arr = arr_vec[0].first; 00635 delete arr_vec[0].second; 00636 } 00637 00638 //join range of polygons with holes (see previous comment about k=5). 00639 template <class InputIterator> 00640 inline void join(InputIterator begin, InputIterator end, 00641 Polygon_with_holes_2&, unsigned int k=5) 00642 { 00643 std::vector<Arr_entry> arr_vec (std::distance(begin, end) + 1); 00644 arr_vec[0].first = this->m_arr; 00645 00646 unsigned int i = 1; 00647 for (InputIterator itr = begin; itr!=end; ++itr, ++i) 00648 { 00649 arr_vec[i].first = new Aos_2(m_traits); 00650 _insert(*itr, *(arr_vec[i].first)); 00651 } 00652 00653 Join_merge<Aos_2> join_merge; 00654 _build_sorted_vertices_vectors (arr_vec); 00655 _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, join_merge); 00656 00657 //the result arrangement is at index 0 00658 this->m_arr = arr_vec[0].first; 00659 delete arr_vec[0].second; 00660 } 00661 00662 // (see previous comment about k=5). 00663 template <class InputIterator1, class InputIterator2> 00664 inline void join(InputIterator1 begin1, InputIterator1 end1, 00665 InputIterator2 begin2, InputIterator2 end2, 00666 unsigned int k=5) 00667 { 00668 std::vector<Arr_entry> arr_vec (std::distance(begin1, end1)+ 00669 std::distance(begin2, end2)+1); 00670 00671 arr_vec[0].first = this->m_arr; 00672 unsigned int i = 1; 00673 00674 for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i) 00675 { 00676 arr_vec[i].first = new Aos_2(m_traits); 00677 _insert(*itr1, *(arr_vec[i].first)); 00678 } 00679 00680 for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i) 00681 { 00682 arr_vec[i].first = new Aos_2(m_traits); 00683 _insert(*itr2, *(arr_vec[i].first)); 00684 } 00685 00686 Join_merge<Aos_2> join_merge; 00687 _build_sorted_vertices_vectors (arr_vec); 00688 _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, join_merge); 00689 00690 //the result arrangement is at index 0 00691 this->m_arr = arr_vec[0].first; 00692 delete arr_vec[0].second; 00693 this->remove_redundant_edges(); 00694 this->_reset_faces(); 00695 } 00696 00697 00698 // intersect range of polygins (see previous comment about k=5). 00699 template <class InputIterator> 00700 inline void intersection(InputIterator begin, InputIterator end, 00701 unsigned int k=5) 00702 { 00703 typename std::iterator_traits<InputIterator>::value_type pgn; 00704 this->intersection(begin, end, pgn, k); 00705 this->remove_redundant_edges(); 00706 this->_reset_faces(); 00707 } 00708 00709 00710 // intersect range of simple polygons 00711 template <class InputIterator> 00712 inline void intersection(InputIterator begin, InputIterator end, 00713 Polygon_2&, unsigned int k) 00714 { 00715 std::vector<Arr_entry> arr_vec (std::distance(begin, end) + 1); 00716 arr_vec[0].first = this->m_arr; 00717 unsigned int i = 1; 00718 00719 for (InputIterator itr = begin; itr!=end; ++itr, ++i) 00720 { 00721 ValidationPolicy::is_valid((*itr), *m_traits); 00722 arr_vec[i].first = new Aos_2(m_traits); 00723 _insert(*itr, *(arr_vec[i].first)); 00724 } 00725 00726 Intersection_merge<Aos_2> intersection_merge; 00727 _build_sorted_vertices_vectors (arr_vec); 00728 _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, intersection_merge); 00729 00730 //the result arrangement is at index 0 00731 this->m_arr = arr_vec[0].first; 00732 delete arr_vec[0].second; 00733 } 00734 00735 //intersect range of polygons with holes 00736 template <class InputIterator> 00737 inline void intersection(InputIterator begin, InputIterator end, 00738 Polygon_with_holes_2&, unsigned int k) 00739 { 00740 std::vector<Arr_entry> arr_vec (std::distance(begin, end) + 1); 00741 arr_vec[0].first = this->m_arr; 00742 unsigned int i = 1; 00743 00744 for (InputIterator itr = begin; itr!=end; ++itr, ++i) 00745 { 00746 ValidationPolicy::is_valid((*itr), *m_traits); 00747 arr_vec[i].first = new Aos_2(m_traits); 00748 _insert(*itr, *(arr_vec[i].first)); 00749 } 00750 00751 Intersection_merge<Aos_2> intersection_merge; 00752 _build_sorted_vertices_vectors (arr_vec); 00753 _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, intersection_merge); 00754 00755 //the result arrangement is at index 0 00756 this->m_arr = arr_vec[0].first; 00757 delete arr_vec[0].second; 00758 } 00759 00760 00761 template <class InputIterator1, class InputIterator2> 00762 inline void intersection(InputIterator1 begin1, InputIterator1 end1, 00763 InputIterator2 begin2, InputIterator2 end2, 00764 unsigned int k=5) 00765 { 00766 std::vector<Arr_entry> arr_vec (std::distance(begin1, end1)+ 00767 std::distance(begin2, end2)+1); 00768 arr_vec[0].first = this->m_arr; 00769 unsigned int i = 1; 00770 00771 for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i) 00772 { 00773 ValidationPolicy::is_valid(*itr1, *m_traits); 00774 arr_vec[i].first = new Aos_2(m_traits); 00775 _insert(*itr1, *(arr_vec[i].first)); 00776 } 00777 00778 for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i) 00779 { 00780 ValidationPolicy::is_valid(*itr2,*m_traits); 00781 arr_vec[i].first = new Aos_2(m_traits); 00782 _insert(*itr2, *(arr_vec[i].first)); 00783 } 00784 00785 Intersection_merge<Aos_2> intersection_merge; 00786 _build_sorted_vertices_vectors (arr_vec); 00787 _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, intersection_merge); 00788 00789 //the result arrangement is at index 0 00790 this->m_arr = arr_vec[0].first; 00791 delete arr_vec[0].second; 00792 this->remove_redundant_edges(); 00793 this->_reset_faces(); 00794 } 00795 00796 00797 00798 // symmetric_difference of a range of polygons (similar to xor) 00799 // (see previous comment about k=5). 00800 template <class InputIterator> 00801 inline void symmetric_difference(InputIterator begin, InputIterator end, 00802 unsigned int k=5) 00803 { 00804 typename std::iterator_traits<InputIterator>::value_type pgn; 00805 this->symmetric_difference(begin, end, pgn, k); 00806 this->remove_redundant_edges(); 00807 this->_reset_faces(); 00808 } 00809 00810 00811 // intersect range of simple polygons (see previous comment about k=5). 00812 template <class InputIterator> 00813 inline void symmetric_difference(InputIterator begin, InputIterator end, 00814 Polygon_2&, unsigned int k=5) 00815 { 00816 std::vector<Arr_entry> arr_vec (std::distance(begin, end) + 1); 00817 arr_vec[0].first = this->m_arr; 00818 unsigned int i = 1; 00819 00820 for (InputIterator itr = begin; itr!=end; ++itr, ++i) 00821 { 00822 ValidationPolicy::is_valid(*itr,*m_traits); 00823 arr_vec[i].first = new Aos_2(m_traits); 00824 _insert(*itr, *(arr_vec[i].first)); 00825 } 00826 00827 Xor_merge<Aos_2> xor_merge; 00828 _build_sorted_vertices_vectors (arr_vec); 00829 _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, xor_merge); 00830 00831 //the result arrangement is at index 0 00832 this->m_arr = arr_vec[0].first; 00833 delete arr_vec[0].second; 00834 } 00835 00836 //intersect range of polygons with holes (see previous comment about k=5). 00837 template <class InputIterator> 00838 inline void symmetric_difference(InputIterator begin, InputIterator end, 00839 Polygon_with_holes_2&, unsigned int k=5) 00840 { 00841 std::vector<Arr_entry> arr_vec (std::distance(begin, end) + 1); 00842 arr_vec[0].first = this->m_arr; 00843 unsigned int i = 1; 00844 00845 for (InputIterator itr = begin; itr!=end; ++itr, ++i) 00846 { 00847 ValidationPolicy::is_valid(*itr,*m_traits); 00848 arr_vec[i].first = new Aos_2(m_traits); 00849 _insert(*itr, *(arr_vec[i].first)); 00850 } 00851 00852 Xor_merge<Aos_2> xor_merge; 00853 _build_sorted_vertices_vectors (arr_vec); 00854 _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, xor_merge); 00855 00856 //the result arrangement is at index 0 00857 this->m_arr = arr_vec[0].first; 00858 delete arr_vec[0].second; 00859 } 00860 00861 // (see previous comment about k=5). 00862 template <class InputIterator1, class InputIterator2> 00863 inline void symmetric_difference(InputIterator1 begin1, InputIterator1 end1, 00864 InputIterator2 begin2, InputIterator2 end2, 00865 unsigned int k=5) 00866 { 00867 std::vector<Arr_entry> arr_vec (std::distance(begin1, end1)+ 00868 std::distance(begin2, end2)+1); 00869 arr_vec[0].first = this->m_arr; 00870 unsigned int i = 1; 00871 00872 for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i) 00873 { 00874 ValidationPolicy::is_valid(*itr1, *m_traits); 00875 arr_vec[i].first = new Aos_2(m_traits); 00876 _insert(*itr1, *(arr_vec[i].first)); 00877 } 00878 00879 for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i) 00880 { 00881 ValidationPolicy::is_valid(*itr2, *m_traits); 00882 arr_vec[i].first = new Aos_2(m_traits); 00883 _insert(*itr2, *(arr_vec[i].first)); 00884 } 00885 00886 Xor_merge<Aos_2> xor_merge; 00887 _build_sorted_vertices_vectors (arr_vec); 00888 _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, xor_merge); 00889 00890 //the result arrangement is at index 0 00891 this->m_arr = arr_vec[0].first; 00892 delete arr_vec[0].second; 00893 this->remove_redundant_edges(); 00894 this->_reset_faces(); 00895 } 00896 00897 static void construct_polygon(Ccb_halfedge_const_circulator ccb, 00898 Polygon_2 & pgn, Traits_2 * tr); 00899 00900 bool is_hole_of_face(Face_const_handle f, Halfedge_const_handle he) const; 00901 00902 Ccb_halfedge_const_circulator 00903 get_boundary_of_polygon(Face_const_iterator f) const; 00904 00905 void remove_redundant_edges() 00906 { 00907 this->_remove_redundant_edges(m_arr); 00908 } 00909 00910 protected: 00911 00912 void _remove_redundant_edges(Aos_2* arr) 00913 { 00914 for (Edge_iterator itr = arr->edges_begin(); itr != arr->edges_end(); ) 00915 { 00916 Halfedge_handle he = itr; 00917 if (he->face()->contained() == he->twin()->face()->contained()) 00918 { 00919 Edge_iterator next = itr; 00920 ++next; 00921 arr->remove_edge(he); 00922 itr = next; 00923 } 00924 else 00925 ++itr; 00926 } 00927 } 00928 00929 class Less_vertex_handle 00930 { 00931 typename Traits_2::Compare_xy_2 comp_xy; 00932 00933 public: 00934 00935 Less_vertex_handle (const typename Traits_2::Compare_xy_2& cmp) : 00936 comp_xy (cmp) 00937 {} 00938 00939 bool operator() (Vertex_handle v1, Vertex_handle v2) const 00940 { 00941 return (comp_xy (v1->point(), v2->point()) == SMALLER); 00942 } 00943 }; 00944 00945 00946 void _complement(Aos_2* arr) 00947 { 00948 for (Face_iterator fit = arr->faces_begin(); 00949 fit != arr->faces_end(); 00950 ++fit) 00951 { 00952 fit->set_contained(!fit->contained()); 00953 } 00954 00955 Construct_opposite_2 ctr_opp = m_traits->construct_opposite_2_object(); 00956 for (Edge_iterator eit = arr->edges_begin(); 00957 eit != arr->edges_end(); 00958 ++eit) 00959 { 00960 Halfedge_handle he = eit; 00961 const X_monotone_curve_2& cv = he->curve(); 00962 arr->modify_edge(he, ctr_opp(cv)); 00963 } 00964 } 00965 00966 //fix the directions of the curves (given correct marked face) 00967 // it should be called mostly after symmetric_difference. 00968 void _fix_curves_direction(Aos_2& arr) 00969 { 00970 Compare_endpoints_xy_2 cmp_endpoints = 00971 m_traits->compare_endpoints_xy_2_object(); 00972 Construct_opposite_2 ctr_opp = m_traits->construct_opposite_2_object(); 00973 00974 for (Edge_iterator eit = arr.edges_begin(); 00975 eit != arr.edges_end(); 00976 ++eit) 00977 { 00978 Halfedge_handle he = eit; 00979 const X_monotone_curve_2& cv = he->curve(); 00980 const bool is_cont = he->face()->contained(); 00981 const Comparison_result he_res = 00982 ((Arr_halfedge_direction)he->direction() == ARR_LEFT_TO_RIGHT) ? 00983 SMALLER : LARGER; 00984 const bool has_same_dir = (cmp_endpoints(cv) == he_res); 00985 00986 if ((is_cont && !has_same_dir) || (!is_cont && has_same_dir)) 00987 arr.modify_edge(he, ctr_opp(cv)); 00988 } 00989 } 00990 00991 void _build_sorted_vertices_vectors (std::vector<Arr_entry>& arr_vec) 00992 { 00993 Less_vertex_handle comp (m_traits->compare_xy_2_object()); 00994 Aos_2 *p_arr; 00995 Vertex_iterator vit; 00996 const std::size_t n = arr_vec.size(); 00997 std::size_t i, j; 00998 00999 for (i = 0; i < n; i++) 01000 { 01001 // Allocate a vector of handles to all vertices in the current 01002 // arrangement. 01003 p_arr = arr_vec[i].first; 01004 arr_vec[i].second = new std::vector<Vertex_handle>; 01005 arr_vec[i].second->resize (p_arr->number_of_vertices()); 01006 01007 for (j = 0, vit = p_arr->vertices_begin(); 01008 vit != p_arr->vertices_end(); 01009 j++, ++vit) 01010 { 01011 (*(arr_vec[i].second))[j] = vit; 01012 } 01013 01014 // Sort the vector. 01015 std::sort (arr_vec[i].second->begin(), arr_vec[i].second->end(), comp); 01016 } 01017 } 01018 01019 template <class Merge> 01020 void _divide_and_conquer (unsigned int lower, unsigned int upper, 01021 std::vector<Arr_entry>& arr_vec, 01022 unsigned int k, Merge merge_func) 01023 { 01024 if ((upper - lower) < k) 01025 { 01026 merge_func(lower, upper, 1, arr_vec); 01027 return; 01028 } 01029 01030 unsigned int sub_size = ((upper - lower + 1) / k); 01031 unsigned int i = 0; 01032 unsigned int curr_lower = lower; 01033 01034 for (; i<k-1; ++i, curr_lower += sub_size ) 01035 { 01036 _divide_and_conquer(curr_lower, curr_lower + sub_size-1, arr_vec, k, 01037 merge_func); 01038 } 01039 _divide_and_conquer (curr_lower, upper,arr_vec, k, merge_func); 01040 merge_func (lower, curr_lower, sub_size ,arr_vec); 01041 01042 return; 01043 } 01044 01045 // mark all faces as non-visited 01046 void _reset_faces() const 01047 { 01048 _reset_faces(m_arr); 01049 } 01050 01051 void _reset_faces(Aos_2* arr) const 01052 { 01053 Face_const_iterator fit = arr->faces_begin(); 01054 for ( ; fit != arr->faces_end(); ++fit) 01055 { 01056 fit->set_visited(false); 01057 } 01058 } 01059 01060 01061 void _insert(const Polygon_2& pgn, Aos_2& arr); 01062 01063 // The function below is public because are_holes_and_boundary_pairwise_disjoint 01064 // of Gps_polygon_validation is using it. 01065 // I have tried to define it as friend function, but with no success (probably 01066 // did something wrong with templates and friend.) Besides, it was like this 01067 // before I touched it, so I did not have the energy. 01068 public: 01069 void _insert(const Polygon_with_holes_2& pgn, Aos_2& arr); 01070 01071 protected: 01072 template<class PolygonIter> 01073 void _insert(PolygonIter p_begin, PolygonIter p_end, Polygon_2& pgn); 01074 01075 template<class PolygonIter> 01076 void _insert(PolygonIter p_begin, PolygonIter p_end, 01077 Polygon_with_holes_2& pgn); 01078 01079 template <class OutputIterator> 01080 void _construct_curves(const Polygon_2& pgn, OutputIterator oi); 01081 01082 template <class OutputIterator> 01083 void _construct_curves(const Polygon_with_holes_2& pgn, OutputIterator oi); 01084 01085 01086 bool _is_empty(const Polygon_2& pgn) const 01087 { 01088 const std::pair<Curve_const_iterator, Curve_const_iterator>& itr_pair = 01089 m_traits->construct_curves_2_object()(pgn); 01090 return (itr_pair.first == itr_pair.second); 01091 } 01092 01093 bool _is_empty(const Polygon_with_holes_2& ) const 01094 { 01095 return (false); 01096 } 01097 01098 bool _is_plane(const Polygon_2& ) const 01099 { 01100 return (false); 01101 } 01102 01103 bool _is_plane(const Polygon_with_holes_2& pgn) const 01104 { 01105 //typedef typename Traits_2::Is_unbounded Is_unbounded; 01106 bool unbounded = m_traits->construct_is_unbounded_object()(pgn); 01107 std::pair<GP_Holes_const_iterator, 01108 GP_Holes_const_iterator> pair = 01109 m_traits->construct_holes_object()(pgn); 01110 return (unbounded && (pair.first == pair.second)); 01111 //used to return 01112 // (pgn.is_unbounded() && (pgn.holes_begin() == pgn.holes_end())) 01113 } 01114 01115 void _intersection(const Aos_2& arr) 01116 { 01117 Aos_2* res_arr = new Aos_2(m_traits); 01118 Gps_intersection_functor<Aos_2> func; 01119 overlay(*m_arr, arr, *res_arr, func); 01120 delete m_arr; // delete the previous arrangement 01121 01122 m_arr = res_arr; 01123 remove_redundant_edges(); 01124 } 01125 01126 void _intersection(const Aos_2& arr1, 01127 const Aos_2& arr2, 01128 Aos_2& res) 01129 { 01130 Gps_intersection_functor<Aos_2> func; 01131 overlay(arr1, arr2, res, func); 01132 _remove_redundant_edges(&res); 01133 01134 } 01135 01136 template <class Polygon_> 01137 void _intersection(const Polygon_& pgn) 01138 { 01139 if (_is_empty(pgn)) 01140 this->clear(); 01141 if (_is_plane(pgn)) return; 01142 if (this->is_empty()) return; 01143 if (this->is_plane()) 01144 { 01145 Aos_2* arr = new Aos_2(m_traits); 01146 _insert(pgn, *arr); 01147 delete (this->m_arr); 01148 this->m_arr = arr; 01149 return; 01150 } 01151 01152 Aos_2 second_arr; 01153 _insert(pgn, second_arr); 01154 _intersection(second_arr); 01155 } 01156 01157 void _intersection(const Self& other) 01158 { 01159 if (other.is_empty()) 01160 { 01161 m_arr->clear(); 01162 return; 01163 } 01164 if (other.is_plane()) return; 01165 if (this->is_empty()) return; 01166 if (this->is_plane()) 01167 { 01168 *(this->m_arr) = *(other.m_arr); 01169 return; 01170 } 01171 01172 _intersection(*(other.m_arr)); 01173 } 01174 01175 void _join(const Aos_2& arr) 01176 { 01177 Aos_2* res_arr = new Aos_2(m_traits); 01178 Gps_join_functor<Aos_2> func; 01179 overlay(*m_arr, arr, *res_arr, func); 01180 delete m_arr; // delete the previous arrangement 01181 01182 m_arr = res_arr; 01183 remove_redundant_edges(); 01184 } 01185 01186 void _join(const Aos_2& arr1, const Aos_2& arr2, 01187 Aos_2& res) 01188 { 01189 Gps_join_functor<Aos_2> func; 01190 overlay(arr1, arr2, res, func); 01191 _remove_redundant_edges(&res); 01192 01193 } 01194 01195 template <class Polygon_> 01196 void _join(const Polygon_& pgn) 01197 { 01198 if (_is_empty(pgn)) return; 01199 if (_is_plane(pgn)) 01200 { 01201 this->clear(); 01202 01203 // Even in an empty arrangement there can be several faces 01204 // (because of the topology traits). 01205 for (Face_iterator fit = this->m_arr->faces_begin(); 01206 fit != this->m_arr->faces_end(); ++fit) 01207 fit->set_contained(true); 01208 return; 01209 } 01210 if (this->is_empty()) 01211 { 01212 Aos_2* arr = new Aos_2(m_traits); 01213 _insert(pgn, *arr); 01214 delete (this->m_arr); 01215 this->m_arr = arr; 01216 return; 01217 } 01218 if (this->is_plane()) return; 01219 01220 Aos_2 second_arr; 01221 _insert(pgn, second_arr); 01222 _join(second_arr); 01223 } 01224 01225 01226 void _join(const Self& other) 01227 { 01228 if (other.is_empty()) return; 01229 if (other.is_plane()) 01230 { 01231 this->clear(); 01232 01233 // Even in an empty arrangement there can be several faces 01234 // (because of the topology traits). 01235 for (Face_iterator fit = this->m_arr->faces_begin(); 01236 fit != this->m_arr->faces_end(); ++fit) 01237 fit->set_contained(true); 01238 return; 01239 } 01240 if (this->is_empty()) 01241 { 01242 *(this->m_arr) = *(other.m_arr); 01243 return; 01244 } 01245 if (this->is_plane()) return; 01246 _join(*(other.m_arr)); 01247 } 01248 01249 void _difference(const Aos_2& arr) 01250 { 01251 Aos_2* res_arr = new Aos_2(m_traits); 01252 Gps_difference_functor<Aos_2> func; 01253 overlay(*m_arr, arr, *res_arr, func); 01254 delete m_arr; // delete the previous arrangement 01255 01256 m_arr = res_arr; 01257 remove_redundant_edges(); 01258 fix_curves_direction(); 01259 } 01260 01261 void _difference(const Aos_2& arr1, const Aos_2& arr2, 01262 Aos_2& res) 01263 { 01264 Gps_difference_functor<Aos_2> func; 01265 overlay(arr1, arr2, res, func); 01266 _remove_redundant_edges(&res); 01267 _fix_curves_direction(res); 01268 01269 } 01270 01271 template <class Polygon_> 01272 void _difference(const Polygon_& pgn) 01273 { 01274 if (_is_empty(pgn)) return; 01275 if (_is_plane(pgn)) 01276 { 01277 this->clear(); 01278 return; 01279 } 01280 if (this->is_empty()) return; 01281 if (this->is_plane()) 01282 { 01283 Aos_2* arr = new Aos_2(m_traits); 01284 _insert(pgn, *arr); 01285 delete (this->m_arr); 01286 this->m_arr = arr; 01287 this->complement(); 01288 return; 01289 } 01290 01291 Aos_2 second_arr; 01292 _insert(pgn, second_arr); 01293 _difference(second_arr); 01294 } 01295 01296 01297 void _difference(const Self& other) 01298 { 01299 if (other.is_empty()) return; 01300 if (other.is_plane()) 01301 { 01302 this->clear(); 01303 return; 01304 } 01305 if (this->is_empty()) return; 01306 if (this->is_plane()) 01307 { 01308 *(this->m_arr) = *(other.m_arr); 01309 this->complement(); 01310 return; 01311 } 01312 01313 _difference(*(other.m_arr)); 01314 } 01315 01316 void _symmetric_difference(const Aos_2& arr) 01317 { 01318 Aos_2* res_arr = new Aos_2(m_traits); 01319 Gps_sym_diff_functor<Aos_2> func; 01320 overlay(*m_arr, arr, *res_arr, func); 01321 delete m_arr; // delete the previous arrangement 01322 01323 m_arr = res_arr; 01324 remove_redundant_edges(); 01325 fix_curves_direction(); 01326 } 01327 01328 void _symmetric_difference(const Aos_2& arr1, 01329 const Aos_2& arr2, 01330 Aos_2& res) 01331 { 01332 Gps_sym_diff_functor<Aos_2> func; 01333 overlay(arr1, arr2, res, func); 01334 _remove_redundant_edges(&res); 01335 _fix_curves_direction(res); 01336 } 01337 01338 template <class Polygon_> 01339 void _symmetric_difference(const Polygon_& pgn) 01340 { 01341 if (_is_empty(pgn)) return; 01342 01343 if (_is_plane(pgn)) 01344 { 01345 this->complement(); 01346 return; 01347 } 01348 if (this->is_empty()) 01349 { 01350 Aos_2* arr = new Aos_2(m_traits); 01351 _insert(pgn, *arr); 01352 delete (this->m_arr); 01353 this->m_arr = arr; 01354 return; 01355 } 01356 01357 if (this->is_plane()) 01358 { 01359 Aos_2* arr = new Aos_2(m_traits); 01360 _insert(pgn, *arr); 01361 delete (this->m_arr); 01362 this->m_arr = arr; 01363 this->complement(); 01364 return; 01365 } 01366 01367 Aos_2 second_arr; 01368 _insert(pgn, second_arr); 01369 _symmetric_difference(second_arr); 01370 } 01371 01372 01373 void _symmetric_difference(const Self& other) 01374 { 01375 if (other.is_empty()) return; 01376 01377 if (other.is_plane()) 01378 { 01379 this->complement(); 01380 return; 01381 } 01382 if (this->is_empty()) 01383 { 01384 *(this->m_arr) = *(other.m_arr); 01385 return; 01386 } 01387 01388 if (this->is_plane()) 01389 { 01390 *(this->m_arr) = *(other.m_arr); 01391 this->complement(); 01392 return; 01393 } 01394 01395 _symmetric_difference(*(other.m_arr)); 01396 } 01397 01398 }; 01399 01400 #include <CGAL/Boolean_set_operations_2/Gps_on_surface_base_2_impl.h> 01401 01402 CGAL_END_NAMESPACE 01403 01404 #endif // CGAL_GPS_ON_SURFACE_BASE_2_H