BWAPI
|
00001 // Copyright (c) 2008 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 // 00015 // 00016 // Author(s): Baruch Zukerman <baruchzu@post.tau.ac.il> 00017 // Ron Wein <wein@post.tau.ac.il> 00018 // Boris Kozorovitzky <boriskoz@post.tau.ac.il> 00019 // Guy Zucker <guyzucke@post.tau.ac.il> 00020 00021 #ifndef CGAL_GPS_POLYGON_VALIDATION_2_H 00022 #define CGAL_GPS_POLYGON_VALIDATION_2_H 00023 00024 #include <CGAL/Boolean_set_operations_2/Gps_traits_adaptor.h> 00025 #include <CGAL/Boolean_set_operations_2/Gps_default_dcel.h> 00026 #include <CGAL/Boolean_set_operations_2/Gps_on_surface_base_2.h> 00027 00028 #include <CGAL/Arrangement_2/Arr_default_planar_topology.h> 00029 #include <CGAL/Sweep_line_2.h> 00030 #include <CGAL/Sweep_line_2/Sweep_line_event.h> 00031 #include <CGAL/Sweep_line_2/Sweep_line_subcurve.h> 00032 #include <CGAL/Sweep_line_empty_visitor.h> 00033 #include <CGAL/Arr_default_overlay_traits.h> 00034 #include <CGAL/Arr_naive_point_location.h> 00035 00036 00037 #include <iostream> 00038 #include <list> 00039 #include <iterator> 00040 00041 #define CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF \ 00042 typedef Gps_traits_adaptor<Traits_2> Traits_adapter_2; \ 00043 typedef typename Traits_2::Curve_const_iterator \ 00044 Curve_const_iterator; \ 00045 typedef std::pair<Curve_const_iterator,Curve_const_iterator> \ 00046 Cci_pair; \ 00047 typedef typename Traits_2::Construct_curves_2 \ 00048 Construct_curves_2; \ 00049 typedef typename Traits_adapter_2::Construct_vertex_2 \ 00050 Construct_vertex_2; 00051 00052 00053 CGAL_BEGIN_NAMESPACE 00054 00055 /*Arrangement is templated with extended face dcel*/ 00056 template<typename Arrangement_2> 00057 class ValidationOverlayTraits : 00058 public CGAL::Arr_default_overlay_traits<Arrangement_2> 00059 { 00060 public: 00061 typedef CGAL::Arr_default_overlay_traits<Arrangement_2> Base; 00062 typedef typename Base::Face_handle_A Face_handle_A; 00063 typedef typename Base::Face_handle_B Face_handle_B; 00064 typedef typename Base::Face_handle_R Face_handle_R; 00065 00066 typedef typename Arrangement_2::Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator; 00067 typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; 00068 typedef typename Arrangement_2::Face_const_handle Face_const_handle; 00069 typedef typename Arrangement_2::Inner_ccb_const_iterator Inner_ccb_const_iterator; 00070 00071 /*red faces source is the arrangement of holes. The blue faces (face) are caused by the PWH's outer boundary*/ 00072 virtual void create_face(Face_handle_A red_face, Face_handle_B blue_face, Face_handle_R /*r_face*/) { 00073 if ((red_face->contained()==true) && (blue_face->contained()==false)) { 00074 hole_overlap=true; 00075 } 00076 } 00077 00078 public: 00079 ValidationOverlayTraits() : hole_overlap(false) {} 00080 bool getHoleOverlap() { 00081 return hole_overlap; 00082 } 00083 void setHoleOverlap(bool b) { 00084 hole_overlap=b; return; 00085 } 00086 private: 00087 bool hole_overlap; 00088 }; 00089 00090 00095 template <class ArrTraits_> 00096 class Gps_polygon_validation_visitor : 00097 public Sweep_line_empty_visitor<ArrTraits_> 00098 { 00099 private: 00100 00101 typedef ArrTraits_ Traits_2; 00102 typedef Gps_polygon_validation_visitor<Traits_2> Self; 00103 typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; 00104 typedef typename Traits_2::Point_2 Point_2; 00105 00106 typedef Sweep_line_empty_visitor<Traits_2> Base; 00107 typedef typename Base::Event Event; 00108 typedef typename Base::Subcurve Subcurve; 00109 typedef typename Base::Status_line_iterator SL_iterator; 00110 00111 typedef Basic_sweep_line_2<Traits_2, Self> Sweep_line; 00112 00113 public: 00114 00115 Gps_polygon_validation_visitor(bool is_s_simple = true): 00116 m_is_valid(true), 00117 m_is_s_simple(is_s_simple) 00118 {} 00119 00120 00121 template <class XCurveIterator> 00122 void sweep(XCurveIterator begin, XCurveIterator end) 00123 { 00124 //Perform the sweep 00125 reinterpret_cast<Sweep_line*>(this->m_sweep_line)->sweep(begin, end); 00126 } 00127 00128 bool after_handle_event(Event* event,SL_iterator, bool) 00129 { 00130 if(event->is_intersection() || 00131 event->is_weak_intersection() || 00132 event->is_overlap()) 00133 { 00134 m_is_valid = false; 00135 reinterpret_cast<Sweep_line*>(this->m_sweep_line) -> stop_sweep(); 00136 } 00137 else 00138 { 00139 if (m_is_s_simple && 00140 (event->number_of_right_curves() + 00141 event->number_of_left_curves()) != 2) 00142 { 00143 m_is_valid = false; 00144 reinterpret_cast<Sweep_line*>(this->m_sweep_line) -> stop_sweep(); 00145 } 00146 } 00147 00148 return (true); 00149 } 00150 00151 00152 bool is_valid() 00153 { 00154 return m_is_valid; 00155 } 00156 00157 00158 protected: 00159 00160 bool m_is_valid; 00161 bool m_is_s_simple; // is strictly simple 00162 00163 }; 00164 00165 00166 //Traits_2 templates the General_polygon_set_2 Traits. 00167 //These include types for polygon and PWH. 00168 template <typename Traits_2> 00169 bool is_closed_polygon(const typename Traits_2::Polygon_2& pgn, Traits_2 traits) 00170 { 00171 00172 CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF 00173 Cci_pair itr_pair = traits.construct_curves_2_object()(pgn); 00174 Curve_const_iterator begin = itr_pair.first; 00175 Curve_const_iterator end = itr_pair.second; 00176 00177 if (begin == end) 00178 return (true); // An empty polygon is valid. 00179 00180 Traits_adapter_2 traits_adapter; 00181 typename Traits_2::Equal_2 equal_func = traits.equal_2_object(); 00182 Curve_const_iterator curr, next; 00183 Construct_vertex_2 construct_vertex_func; 00184 construct_vertex_func = traits_adapter.construct_vertex_2_object(); 00185 curr = next = begin; 00186 ++next; 00187 00188 if (next == end) 00189 return (false); // A polygon cannot have just a single edge. 00190 00191 while (next != end) 00192 { 00193 // Make sure that the current target equals the next source. 00194 if (equal_func (construct_vertex_func (*curr, 0), 00195 construct_vertex_func (*curr, 1))) 00196 return (false); 00197 00198 if (! equal_func (construct_vertex_func (*curr, 1), 00199 construct_vertex_func (*next, 0))) 00200 return (false); 00201 00202 // Move to the next pair of edges. 00203 curr = next; 00204 ++next; 00205 } 00206 00207 // Make sure that the last target equals the first source. 00208 if (equal_func (construct_vertex_func (*curr, 0), 00209 construct_vertex_func (*curr, 1))) 00210 return (false); 00211 00212 if (! equal_func (construct_vertex_func (*curr, 1), 00213 construct_vertex_func (*begin, 0))) 00214 return (false); 00215 00216 return (true); 00217 } 00218 template <typename Traits_2> 00219 bool is_simple_polygon(const typename Traits_2::Polygon_2& pgn,Traits_2 traits) 00220 {// Previously known as is_strictly_simple 00221 00222 CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF 00223 // Sweep the boundary curves and look for intersections. 00224 typedef Gps_polygon_validation_visitor<Traits_2> Visitor; 00225 typedef Sweep_line_2<Traits_2, Visitor> Sweep_line; 00226 00227 Cci_pair itr_pair = traits.construct_curves_2_object()(pgn); 00228 Visitor visitor; 00229 Sweep_line sweep_line (&traits, &visitor); 00230 00231 visitor.sweep(itr_pair.first, itr_pair.second); 00232 return (visitor.is_valid()); 00233 } 00234 00235 00236 template <typename Traits_2> 00237 bool has_valid_orientation_polygon (const typename Traits_2::Polygon_2& pgn,Traits_2 traits) 00238 { 00239 CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF 00240 00241 Cci_pair itr_pair = traits.construct_curves_2_object()(pgn); 00242 Traits_adapter_2 traits_adapter; 00243 typedef typename Traits_adapter_2::Orientation_2 Check_orientation_2; 00244 00245 if(itr_pair.first == itr_pair.second) 00246 return (true); // empty polygon 00247 00248 return (traits_adapter.orientation_2_object()(itr_pair.first, 00249 itr_pair.second) == COUNTERCLOCKWISE); 00250 } 00251 /* A valid polygon is : 00252 * 1 - Closed or empty polygon 00253 * 2 - Simple (previously known as strictly simple) 00254 * 3 - Counterclockwise oriented 00255 */ 00256 template <typename Traits_2> 00257 bool is_valid_polygon(const typename Traits_2::Polygon_2& pgn,Traits_2 traits) 00258 { 00259 bool closed = is_closed_polygon(pgn,traits); 00260 //CGAL_warning_msg (closed, 00261 // "The polygon's boundary is not closed."); 00262 if (! closed) 00263 return (false); 00264 00265 bool simple = is_simple_polygon(pgn,traits); 00266 //CGAL_warning_msg (simple, 00267 // "The polygon is not simple."); 00268 if (!simple) 00269 return (false); 00270 00271 bool valid_orientation = has_valid_orientation_polygon(pgn,traits); 00272 //CGAL_warning_msg (valid_orientation, 00273 // "The polygon has a wrong orientation."); 00274 if (! valid_orientation) 00275 return (false); 00276 00277 return (true); 00278 } 00279 00280 00281 template <typename Traits_2> 00282 bool is_closed_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) 00283 { 00284 typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; 00285 if(! is_closed_polygon (pgn.outer_boundary(),traits)) 00286 return (false); 00287 00288 typename Polygon_with_holes_2::Hole_const_iterator itr; 00289 00290 for (itr = pgn.holes_begin(); itr != pgn.holes_end(); ++itr) 00291 { 00292 if(! is_closed_polygon (*itr,traits)) 00293 return (false); 00294 } 00295 return (true); 00296 } 00297 00298 //templated point location version 00299 template<class Traits_2, class PointLocation> 00300 bool is_crossover_outer_boundary(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits, PointLocation& pl ) { 00301 CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF 00302 typedef typename Traits_2::Point_2 Point_2; 00303 typedef typename Traits_2::Compare_endpoints_xy_2 Compare_endpoints_xy_2; 00304 typedef typename Traits_2::Construct_min_vertex_2 Construct_min_vertex_2; 00305 typedef typename Traits_2::Construct_max_vertex_2 Construct_max_vertex_2; 00306 typedef CGAL::Gps_default_dcel<Traits_2> Dcel; 00307 00308 // IMPORTATNT! TODO! 00309 // Currently the topology traits is the bounded planar traits. This 00310 // should be replaced with a templated topology traits! 00311 typedef typename Default_planar_topology<Traits_2, Dcel>::Traits 00312 Topology_traits; 00313 typedef CGAL::Gps_on_surface_base_2<Traits_2, Topology_traits> 00314 Polygon_set_2; 00315 typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; 00316 typedef typename Polygon_set_2::Arrangement_on_surface_2 Arrangement_2; 00317 typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; 00318 typedef typename Arrangement_2::Vertex_handle Vertex_handle; 00319 typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; 00320 typedef typename Traits_2::Curve_const_iterator Curve_const_iterator; 00321 00322 typename std::list<Halfedge_handle> he_path; 00323 typename std::list<Halfedge_handle>::iterator he_itr; 00324 //functors used throughout the function 00325 Construct_min_vertex_2 min_functor = traits.construct_min_vertex_2_object(); 00326 Construct_max_vertex_2 max_functor = traits.construct_max_vertex_2_object(); 00327 Compare_endpoints_xy_2 cmp_endpoints = traits.compare_endpoints_xy_2_object(); 00328 00329 Cci_pair itr_pair = traits.construct_curves_2_object()(pgn.outer_boundary()); 00330 Curve_const_iterator begin = itr_pair.first; 00331 Curve_const_iterator end = itr_pair.second; 00332 if (begin == end) 00333 return (true); // An empty polygon is valid. 00334 //handles to consecutive curves 00335 Curve_const_iterator curr, next; 00336 curr = next = begin; 00337 //handles to vertices for insert. one maintains the current curve (already inserted) and next curve's joint vertex. 00338 //the other maintains the next curve's second vertex if it already exists in the arrangement. 00339 Vertex_handle joint_ver, second_ver; 00340 //closed check guarantees polygon has more than 1 curve 00341 ++next; 00342 //halfedge handle whose target is always the joint vertex between next and curr. 00343 Halfedge_handle last_he; 00344 00345 Polygon_set_2 gps(traits); 00346 Arrangement_2 arr = gps.arrangement(); 00347 pl.attach(arr); 00348 00349 //insert first edge lexicographically to arrangement 00350 // compute the joint vertex and insert to the path list a halfedge whose target is the joint vertex 00351 last_he = CGAL::insert_non_intersecting_curve(arr, *curr); 00352 if (cmp_endpoints(*curr) == SMALLER) { //polygon's boundary first curve is in lexicographic direction 00353 joint_ver = last_he->target(); 00354 he_path.push_back(last_he); 00355 } else { //polygon's boundary first curve not lexicographic 00356 joint_ver = last_he->source(); 00357 he_path.push_back(last_he->twin()); 00358 } 00359 00360 /*insert the rest of the curves to the arrangement efficiently the previous closed polygon check guarantees 00361 equal_func (construct_vertex_func (*curr, 1), construct_vertex_func (*next, 0))) */ 00362 while (next != end) { 00363 CGAL::Object obj; 00364 Vertex_const_handle cver; 00365 Point_2 second_point; 00366 if(cmp_endpoints(*next) == SMALLER) { 00367 //next curve's minimum is the joint vertex. Look if it's max exists in the arrangement and insert lexicographically 00368 second_point = max_functor(*next); 00369 obj = pl.locate(second_point); 00370 if (CGAL::assign (cver, obj)) { 00371 //insert where both vertices exist 00372 second_ver = arr.non_const_handle(cver); 00373 last_he = arr.insert_at_vertices( *next, joint_ver, second_ver); 00374 } else //insert from left vertex 00375 last_he = arr.insert_from_left_vertex ( *next,joint_ver) ; 00376 } else { //next curve's maximum vertex is the joint vertex. try to locate the min vertex, and insert from right or from both vertices 00377 second_point = min_functor(*next); 00378 obj = pl.locate(second_point); 00379 if (CGAL::assign (cver, obj)) { 00380 //insert where both vertices exist 00381 second_ver = arr.non_const_handle(cver); 00382 last_he = arr.insert_at_vertices( *next, joint_ver, second_ver); 00383 } else //insert from right vertex 00384 last_he = arr.insert_from_right_vertex ( *next,joint_ver) ; 00385 } 00386 // Move to the next pair of edges. 00387 he_path.push_back(last_he); 00388 joint_ver=last_he->target(); 00389 curr = next; 00390 ++next; 00391 } //end of while 00392 00393 // We created a path of halfedges that circulates the polygon counterclockwise 00394 // The polygon should lay on the left of each of these half edges. 00395 // If the boundary is invalid, the unbounded face should 00396 // be on the left of one of more than one of the halfedges. 00397 // The unbounded face is always to the right of the halfedges. We check if 00398 // all faces that lay on the right of the halfedges are equal (to the 00399 // "unbounded" face). 00400 typename Arrangement_2::Face_handle fh = (*he_path.begin())->twin()->face(); 00401 for (he_itr = he_path.begin(); he_itr != he_path.end(); he_itr++) { 00402 00403 if ((*he_itr)->twin()->face() != fh) 00404 return false; 00405 } 00406 return true; 00407 } 00408 00409 00410 template<typename Traits_2> 00411 bool is_crossover_outer_boundary( 00412 const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits ) { 00413 00414 typedef CGAL::Gps_default_dcel<Traits_2> Dcel; 00415 // IMPORTATNT! TODO! 00416 // Currently the topology traits is the bounded planar traits. This 00417 // should be replaced with a templated topology traits! 00418 typedef typename Default_planar_topology<Traits_2, Dcel>::Traits 00419 Topology_traits; 00420 00421 typedef CGAL::Gps_on_surface_base_2<Traits_2, Topology_traits> 00422 Polygon_set_2; 00423 typedef typename Polygon_set_2::Arrangement_on_surface_2 Arrangement_2; 00424 typedef CGAL::Arr_naive_point_location<Arrangement_2> Naive_pl; 00425 00426 Naive_pl pl; 00427 return is_crossover_outer_boundary(pgn, traits, pl); 00428 } 00429 00430 00431 00432 template <typename Traits_2> 00433 bool is_relatively_simple_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) 00434 {// previously known as Simple 00435 00436 CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF 00437 typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; 00438 typedef Gps_polygon_validation_visitor<Traits_2> Visitor; 00439 typedef Sweep_line_2<Traits_2, Visitor> Sweep_line; 00440 typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; 00441 00442 Construct_curves_2 construct_curves_func = traits.construct_curves_2_object(); 00443 // Construct a container of all outer boundary curves. 00444 Cci_pair itr_pair = construct_curves_func (pgn.outer_boundary()); 00445 std::list<X_monotone_curve_2> outer_curves; 00446 std::copy (itr_pair.first, itr_pair.second, 00447 std::back_inserter(outer_curves)); 00448 //create visitor and sweep to verify outer boundary is relatively simple 00449 Visitor relative_visitor(false); 00450 Sweep_line sweep_line (&traits, &relative_visitor); 00451 relative_visitor.sweep (outer_curves.begin(), outer_curves.end()); 00452 if (!relative_visitor.is_valid()) 00453 return false; 00454 00455 //verify every hole is simple 00456 typename Polygon_with_holes_2::Hole_const_iterator hoit; 00457 std::list<X_monotone_curve_2> hole_curves; 00458 for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit) 00459 { 00460 bool simple_hole = is_simple_polygon(*hoit,traits); 00461 if (!simple_hole) 00462 return false; 00463 } 00464 return true; 00465 } 00466 00467 00468 00469 template <typename Traits_2> 00470 bool has_valid_orientation_polygon_with_holes (const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) 00471 { 00472 CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF 00473 typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; 00474 typedef Gps_polygon_validation_visitor<Traits_2> Visitor; 00475 typedef Sweep_line_2<Traits_2, Visitor> Sweep_line; 00476 typedef typename Traits_adapter_2::Orientation_2 Check_orientation_2; 00477 typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; 00478 00479 Traits_adapter_2 traits_adapter; 00480 00481 Construct_curves_2 construct_curves_func = traits.construct_curves_2_object(); 00482 Check_orientation_2 check_orientation_func = traits_adapter.orientation_2_object();; 00483 // Check the orientation of the outer boundary. 00484 Cci_pair itr_pair = construct_curves_func (pgn.outer_boundary()); 00485 00486 if ((itr_pair.first != itr_pair.second) && 00487 check_orientation_func (itr_pair.first, 00488 itr_pair.second) != COUNTERCLOCKWISE) 00489 { 00490 return (false); 00491 } 00492 00493 // Check the orientation of each of the holes. 00494 typename Polygon_with_holes_2::Hole_const_iterator hoit; 00495 00496 for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit) 00497 { 00498 itr_pair = construct_curves_func (*hoit); 00499 00500 if ((itr_pair.first !=itr_pair.second) && 00501 check_orientation_func (itr_pair.first, 00502 itr_pair.second) != CLOCKWISE) 00503 { 00504 return (false); 00505 } 00506 } 00507 return (true); 00508 } 00509 00510 00511 00512 00513 00514 00515 /*Verify holes do not intersect between themselves as well with the outer boundary 00516 (except intersection on a vertex which is allowed). 00517 00518 This efficient implementation utilizes the general poygon set for aggregated join 00519 operations for N holes which should result in a GPS that contains N independent PWH. 00520 Executing a difference(gps, outer boundary) should result in an empty set if 00521 no holes intersect the boundary. 00522 00523 An iterative use of the difference free function while iterating over the holes 00524 may have an advantage in case there are numerous holes that intersect the boundary 00525 and the iterative loop will be stopped after a small number of iterations. 00526 00527 */ 00528 template <class Traits_2> 00529 bool are_holes_and_boundary_pairwise_disjoint(const typename Traits_2::Polygon_with_holes_2& pwh, Traits_2& traits) 00530 { 00531 CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF 00532 00533 typedef CGAL::Gps_default_dcel<Traits_2> Dcel; 00534 // IMPORTATNT! TODO! 00535 // Currently the topology traits is the bounded planar traits. This 00536 // should be replaced with a templated topology traits! 00537 typedef typename Default_planar_topology<Traits_2, Dcel>::Traits 00538 Topology_traits; 00539 00540 typedef CGAL::Gps_on_surface_base_2<Traits_2, Topology_traits> 00541 Polygon_set_2; 00542 typedef typename Polygon_set_2::Size Size; 00543 typedef typename Traits_2::Polygon_2 Polygon_2; 00544 typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; 00545 typedef typename Polygon_with_holes_2::Hole_const_iterator Hole_const_iterator; 00546 typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; 00547 typedef std::pair<Curve_const_iterator, 00548 Curve_const_iterator> Cci_pair; 00549 typedef typename Traits_2::Construct_curves_2 Construct_curves_2; 00550 typedef typename Traits_2::Construct_general_polygon_with_holes_2 Construct_polygon_with_holes_2; 00551 typedef typename Traits_adapter_2::Construct_vertex_2 00552 Construct_vertex_2; 00553 typedef Gps_polygon_validation_visitor<Traits_2> Visitor; 00554 typedef Sweep_line_2<Traits_2, Visitor> Sweep_line ; 00555 typedef typename Polygon_set_2::Arrangement_on_surface_2 00556 Arrangement_2; 00557 00558 /* Should be perfored more efficeintly than using sweep and than difference().*/ 00559 00560 /*Use sweep to find intersections on the interior of curves (not on vertices) and overlapping edges which are not allowed 00561 (note that 0/1 dimension intersections are not detectes by do_intersect() which only returns the 2D intersection polygon if exists) 00562 Note that using this sweep alone allows for a hole and an edge to share a vertex and intersect 00563 (like illegal input pgn_w_overlap_hole.dat in validation_example)*/ 00564 Hole_const_iterator hoit; 00565 // Construct a container of all boundary curves. 00566 Polygon_2 pgn2 = traits.construct_outer_boundary_object()(pwh); 00567 Construct_curves_2 construct_curves_func; 00568 Cci_pair itr_pair = construct_curves_func(pgn2); 00569 00570 std::list<X_monotone_curve_2> curves; 00571 std::copy (itr_pair.first, itr_pair.second, 00572 std::back_inserter(curves)); 00573 00574 std::pair<Hole_const_iterator, Hole_const_iterator> pair = traits.construct_holes_object()(pwh); 00575 for (hoit = pair.first; hoit!=pair.second; ++hoit) 00576 //for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit) 00577 { 00578 itr_pair = construct_curves_func (*hoit); 00579 std::copy (itr_pair.first, itr_pair.second, 00580 std::back_inserter(curves)); 00581 } 00582 00583 // Perform the sweep and check for curve intersections on the interior. 00584 //Traits_2 traits; moved to top, needed also for boundary. 00585 Visitor visitor(false); 00586 Sweep_line sweep_line (&traits, &visitor); 00587 visitor.sweep (curves.begin(), curves.end()); 00588 if (!visitor.is_valid()) 00589 return false; 00590 00591 Polygon_set_2 gps(traits); 00592 //check for 2D intersections of holes (holes must be disjoint except for vertices) 00593 Size num_of_holes=0; 00594 //functors for creating a pwh needed for inserting pgns into the arrangement quickly 00595 Construct_polygon_with_holes_2 construct_pwh_functor = traits.construct_polygon_with_holes_2_object () ; 00596 for (hoit = pwh.holes_begin(); hoit != pwh.holes_end(); ++hoit) { 00597 Polygon_2 hole(*hoit); 00598 hole.reverse_orientation(); 00599 /*gps.join() and gps.insert()requires that the polyon insrted is valid, and therfore hole 00600 orientation must be reversed*/ 00601 bool intersect = gps.do_intersect(hole); 00602 if (intersect) 00603 return false; 00604 else { 00605 /*to use gps.insert(hole) it is required that the set coponents and the new holes do not intersect. 00606 because the sweep detects shared edges and the do_intersect query detects 2D intersections we can safely use 00607 the insert(pwh) function whose performance is better than the join(pgn)*/ 00608 Polygon_with_holes_2 empty_pwh = construct_pwh_functor(hole); 00609 //traits.Construct_general_polygon_with_holes_2 (hole); 00610 // Polygon_with_holes_2 empty_pwh(hole); 00611 gps.insert(empty_pwh); 00612 num_of_holes++; 00613 } 00614 } 00615 /*not good - doesn't work if intersection at vertices is legal. 00616 Size arr_num_of_holes = gps.number_of_polygons_with_holes(); 00617 if (num_of_holes != arr_num_of_holes) 00618 return false; 00619 */ 00620 //check for intersection of holes with the outer boundary 00621 00622 00623 /*outer boundary can be relatively simple. Execution of 00624 do_intersect(hole, boundary) or difference(hole,boundary) relies on 00625 implementation of General polygon set which has a precondition that requires 00626 valid polygon or PWH to be inserted (not just a simple polygon). 00627 This helper function is utilized after checking for the PWH closure, 00628 relative simplicity and orientation. Therefore it is safe to assume the 00629 outer boundary is valid PWH with no holes. We can't assume it is a valid 00630 (simple) polygon. */ 00631 //Polygon_with_holes_2 boundary(pwh.outer_boundary(), fit, fit); 00632 Polygon_with_holes_2 boundary = construct_pwh_functor (pwh.outer_boundary()); 00633 // Unbounded outer boundaries contain all the holes and the holes were checked 00634 // and are OK. 00635 if (boundary.is_unbounded()) 00636 return true; 00637 00638 /*do_intersect predicate will not suffice as hole can be completely outside 00639 the outer boundary in an (extremely strange) case 00640 The gps now contains all the holes. the difference between the boundary and a union of all 00641 the holes should be the empty set. For performance reasons, we use a customized overlay traits and 00642 perform an arrangement overlay instead of difference */ 00643 ValidationOverlayTraits<Arrangement_2> valOverlayTraits; 00644 valOverlayTraits.setHoleOverlap(false); 00645 Polygon_set_2 gps2(traits); 00646 00647 Arrangement_2 boundary_arr = gps2.arrangement(); 00648 gps2._insert(boundary,boundary_arr); 00649 Arrangement_2 holes_arr = gps.arrangement(); 00650 Arrangement_2 output_arr; 00651 overlay(holes_arr, boundary_arr, output_arr, valOverlayTraits); 00652 if (valOverlayTraits.getHoleOverlap()) 00653 return false; 00654 00655 /*old code that works less efficiently than the new overly traits 00656 gps.validation_difference(boundary); 00657 //if gps is not empty at least one hole intersected the boundary 00658 if (!gps.is_empty()) 00659 return (false); 00660 */ 00661 return (true); 00662 } 00663 00664 /*A valid polygon with holes is : 00665 * 1 - Has empty or closed boundary and all the holes are closed 00666 * 2 - The PWH is relatively simple polygon (holes are simple...) 00667 * 3 - Has it's boundary oriented counterclockwise and the holes oriented clockwise 00668 * 4 - All the segments (boundry and holes) do not cross or intersect in their relative interior 00669 * 5 - The holes are on the interior of the boundary polygon if the boundary is not empty 00670 */ 00671 template <typename Traits_2> 00672 bool is_valid_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) 00673 { 00674 bool closed = is_closed_polygon_with_holes(pgn,traits); 00675 //CGAL_warning_msg (closed, 00676 // "The polygon's boundary or one of it's holes is not closed."); 00677 if (! closed) 00678 return (false); 00679 00680 bool relatively_simple = is_relatively_simple_polygon_with_holes(pgn,traits); 00681 //CGAL_warning_msg (relatively_simple, 00682 // "The polygon is not relatively simple."); 00683 if (! relatively_simple) 00684 return (false); 00685 00686 bool no_cross = is_crossover_outer_boundary(pgn, traits); 00687 //CGAL_warning_msg (no_cross, 00688 // "The polygon has a crossover."); 00689 if (!no_cross) 00690 return (false); 00691 00692 bool valid_orientation = has_valid_orientation_polygon_with_holes(pgn,traits); 00693 //CGAL_warning_msg (valid_orientation, 00694 // "The polygon has a wrong orientation."); 00695 if (! valid_orientation) 00696 return (false); 00697 00698 bool holes_disjoint = are_holes_and_boundary_pairwise_disjoint(pgn,traits); 00699 //CGAL_warning_msg (holes_disjoint, 00700 // "Holes of the PWH intersect amongst themselves or with outer boundary"); 00701 if (! holes_disjoint) 00702 return false; 00703 00704 return (true); 00705 } 00706 00707 template <typename Traits_2> 00708 bool is_valid_unknown_polygon(const typename Traits_2::Polygon_with_holes_2& pgn, 00709 Traits_2& traits) 00710 { 00711 return is_valid_polygon_with_holes(pgn, traits); 00712 } 00713 00714 template <typename Traits_2> 00715 bool is_valid_unknown_polygon(const typename Traits_2::Polygon_2& pgn, 00716 Traits_2& traits) 00717 { 00718 return is_valid_polygon(pgn, traits); 00719 } 00720 00721 CGAL_END_NAMESPACE 00722 00723 #endif 00724 00725