BWAPI
SPAR/AIModule/BWTA/vendors/CGAL/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines