From 097c3793fde62bb6a69d4d7f6f0b6ecadaf3dcc7 Mon Sep 17 00:00:00 2001 From: Ophir Setter Date: Tue, 17 Feb 2009 16:21:43 +0000 Subject: [PATCH] General_polygon_set_on_surface_2 - first verstion --- .gitattributes | 1 + .../Ccb_curve_iterator.h | 2 +- .../Gps_agg_meta_traits.h | 4 +- .../Boolean_set_operations_2/Gps_agg_op.h | 22 +- .../Gps_agg_op_visitor.h | 2 +- .../Gps_bfs_base_visitor.h | 47 +- .../Gps_bfs_intersection_visitor.h | 41 +- .../Gps_bfs_join_visitor.h | 32 +- .../Gps_bfs_scanner.h | 34 +- .../Gps_bfs_xor_visitor.h | 46 +- .../CGAL/Boolean_set_operations_2/Gps_merge.h | 120 +- .../Gps_polygon_validation.h | 1077 ++++++------- .../CGAL/Boolean_set_operations_2/Gps_utils.h | 379 +++-- .../include/CGAL/General_polygon_set_2.h | 1288 +--------------- .../CGAL/General_polygon_set_on_surface_2.h | 1371 +++++++++++++++++ .../include/CGAL/Polygon_set_2.h | 5 +- .../test_polygon_validation.cpp | 11 +- 17 files changed, 2335 insertions(+), 2147 deletions(-) create mode 100644 Boolean_set_operations_2/include/CGAL/General_polygon_set_on_surface_2.h diff --git a/.gitattributes b/.gitattributes index a22c01f51e4..f51c5f3903f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1173,6 +1173,7 @@ Boolean_set_operations_2/examples/Boolean_set_operations_2/char_g.dat -text Boolean_set_operations_2/examples/Boolean_set_operations_2/char_m.dat -text Boolean_set_operations_2/examples/Boolean_set_operations_2/pgn_holes.dat -text Boolean_set_operations_2/examples/Boolean_set_operations_2/test.dxf -text svneol=unset#application/octet-stream +Boolean_set_operations_2/include/CGAL/General_polygon_set_on_surface_2.h -text Boolean_set_operations_2/test/Boolean_set_operations_2/data/pgn_holes1.dat -text Boolean_set_operations_2/test/Boolean_set_operations_2/data/pgn_holes2.dat -text Boolean_set_operations_2/test/Boolean_set_operations_2/data/pgn_holes3.dat -text diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Ccb_curve_iterator.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Ccb_curve_iterator.h index 2ea2e607e21..5d5e9427b54 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Ccb_curve_iterator.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Ccb_curve_iterator.h @@ -31,7 +31,7 @@ CGAL_BEGIN_NAMESPACE public: typedef Arrangement_ Arrangement; - typedef typename Arrangement::Traits_2 Traits; + typedef typename Arrangement::Geometry_traits_2 Traits; typedef Ccb_curve_iterator Self; typedef typename Arrangement::Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator; diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_meta_traits.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_meta_traits.h index 667326a63a0..216d6d18f12 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_meta_traits.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_meta_traits.h @@ -100,12 +100,12 @@ public: template class Gps_agg_meta_traits : - public Gps_traits_decorator, Point_with_vertex > { typedef Arrangement_ Arrangement; - typedef typename Arrangement::Traits_2 Traits; + typedef typename Arrangement::Geometry_traits_2 Traits; typedef typename Traits::X_monotone_curve_2 Base_X_monotone_curve_2; typedef typename Traits::Point_2 Base_Point_2; diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op.h index fd7c2e29cd7..28330c2c851 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op.h @@ -16,10 +16,22 @@ // // // Author(s) : Baruch Zukerman +// Ophir Setter #ifndef CGAL_GPS_AGG_OP_H #define CGAL_GPS_AGG_OP_H +/*! + \file Gps_agg_op.h + \brief The class Gps_agg_op is responsible for aggregated Boolean set + operations depending on a visitor template parameter. + It uses the sweep-line algorithm from the arrangement packages + to overlay all the polygon sets, and then it uses a BFS that + determines which of the faces is contained in the result using + the visitor. +*/ + + #include #include #include @@ -38,7 +50,7 @@ template class Gps_agg_op { typedef Arrangement_ Arrangement_2; - typedef typename Arrangement_2::Traits_2 Traits_2; + typedef typename Arrangement_2::Geometry_traits_2 Traits_2; typedef typename Traits_2::Curve_const_iterator Curve_const_iterator; typedef Gps_agg_meta_traits Meta_traits; typedef typename Meta_traits::Curve_data Curve_data; @@ -120,8 +132,10 @@ public: for (i = lower; i <= upper; i += jump, ++n_pgn) { + // The BFS scan (after the loop) starts in the reference face, + // so we count the number of polygons that contain the reference face. Arrangement_2* arr = (arr_vec[i]).first; - if (arr->unbounded_face()->contained()) + if (arr->reference_face()->contained()) ++n_inf_pgn; Edge_iterator itr = arr->edges_begin(); @@ -144,9 +158,9 @@ public: lower, upper, jump, arr_vec); - m_faces_hash[m_arr->unbounded_face()] = n_inf_pgn; + m_faces_hash[m_arr->reference_face()] = n_inf_pgn; Bfs_visitor visitor(&m_edges_hash, &m_faces_hash, n_pgn); - visitor.visit_ubf(m_arr->unbounded_face(), n_inf_pgn); + visitor.visit_ubf(m_arr->faces_begin(), n_inf_pgn); Bfs_scanner scanner(visitor); scanner.scan(*m_arr); visitor.after_scan(*m_arr); diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op_visitor.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op_visitor.h index 063066d9a00..1e28fa6a4bd 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op_visitor.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op_visitor.h @@ -119,7 +119,7 @@ private: ((Arr_halfedge_direction)he->direction() == ARR_LEFT_TO_RIGHT) ? SMALLER : LARGER; const Comparison_result cv_dir = - this->m_arr_access.arrangement().traits()-> + this->m_arr_access.arrangement().geometry_traits()-> compare_endpoints_xy_2_object()(cv); if (he_dir == cv_dir) diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_base_visitor.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_base_visitor.h index 3b0bb8c8aef..0d7c00b13f6 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_base_visitor.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_base_visitor.h @@ -16,6 +16,7 @@ // // // Author(s) : Baruch Zukerman +// Ophir Setter #ifndef CGAL_GPS_BPS_BASE_VISITOR_H #define CGAL_GPS_BPS_BASE_VISITOR_H @@ -24,7 +25,14 @@ CGAL_BEGIN_NAMESPACE -template +//! Gps_bfs_base_visitor +/*! This is a base class for all visitors that are responsible for merging + polygon sets. + We use DerivedVisitor for static polymorphism for using contained_criteria + which determines if we should mark the face as contained given the inside + count of the face. +*/ +template class Gps_bfs_base_visitor { typedef Arrangement_ Arrangement; @@ -50,23 +58,38 @@ public: {} - void flip_face(Face_iterator f1, Face_iterator f2, Halfedge_iterator he) + //! discovered_face +/*! discovered_face is called by Gps_bfs_scanner when it reveals a new face + during a BFS scan. In the BFS traversal we are going from old_face to + new_face throught the half-edge he. + \param old_face The face that was already revealed + \param new_face The face that we have just now revealed + \param he The half-edge that is used to traverse between them. +*/ + void discovered_face(Face_iterator old_face, + Face_iterator new_face, + Halfedge_iterator he) { - CGAL_assertion(m_edges_hash->is_defined(he) && - m_edges_hash->is_defined(he->twin()) && - m_faces_hash->is_defined(f1) && - !m_faces_hash->is_defined(f2)); + unsigned int ic = compute_ic(old_face, new_face, he); - // IC of f2 (inside counter) - unsigned int ic_f2 = - (*m_faces_hash)[f1] - (*m_edges_hash)[he] + (*m_edges_hash)[he->twin()]; - (*m_faces_hash)[f2] = ic_f2; + if (static_cast(this)->contained_criteria(ic)) + new_face->set_contained(true); + } + + // mark the unbounded_face (true iff contained) + void visit_ubf(Face_iterator ubf, unsigned int ubf_ic) + { + CGAL_assertion(ubf->number_of_outer_ccbs() == 0); + if(static_cast(this)->contained_criteria(ubf_ic)) + ubf->set_contained(true); } protected: // compute the inside count of a face - unsigned int compute_ic(Face_iterator f1, Face_iterator f2, Halfedge_iterator he) + unsigned int compute_ic(Face_iterator f1, + Face_iterator f2, + Halfedge_iterator he) { CGAL_assertion(m_edges_hash->is_defined(he) && m_edges_hash->is_defined(he->twin()) && @@ -75,7 +98,7 @@ protected: unsigned int ic_f2 = (*m_faces_hash)[f1] - (*m_edges_hash)[he] + (*m_edges_hash)[he->twin()]; (*m_faces_hash)[f2] = ic_f2; - + return (ic_f2); } }; diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_intersection_visitor.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_intersection_visitor.h index c1c19e27088..20252821598 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_intersection_visitor.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_intersection_visitor.h @@ -17,6 +17,9 @@ // // Author(s) : Baruch Zukerman +// Ophir Setter + + #ifndef CGAL_GPS_BFS_INTERSECTION_VISITOR_H #define CGAL_GPS_BFS_INTERSECTION_VISITOR_H @@ -25,12 +28,14 @@ CGAL_BEGIN_NAMESPACE template -class Gps_bfs_intersection_visitor : public Gps_bfs_base_visitor +class Gps_bfs_intersection_visitor : +public Gps_bfs_base_visitor > { typedef Arrangement_ Arrangement; typedef typename Arrangement::Face_iterator Face_iterator; typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; - typedef Gps_bfs_base_visitor Base; + typedef Gps_bfs_intersection_visitor Self; + typedef Gps_bfs_base_visitor Base; typedef typename Base::Edges_hash Edges_hash; typedef typename Base::Faces_hash Faces_hash; @@ -44,33 +49,23 @@ public: {} - void flip_face(Face_iterator f1, Face_iterator f2, Halfedge_iterator he) + //! contained_criteria +/*! contained_criteria is used to the determine if the face which has + inside count should be marked as contained. + \param ic the inner count of the talked-about face. + \return true if the face of ic, otherwise false. +*/ + bool contained_criteria(unsigned int ic) { - unsigned int ic_f2; - ic_f2 = this->compute_ic(f1, f2, he); - (*(this->m_faces_hash))[f2] = ic_f2; - - CGAL_assertion(ic_f2 <= this->m_num_of_polygons); - - // only faces that have inside counter equal to the number of polygons - // which are intersectd, will be marked true (containted) - if(ic_f2 == this->m_num_of_polygons) - f2->set_contained(true); - } - - // mark the unbounded_face (true iff contained) - void visit_ubf(Face_iterator ubf, unsigned int ubf_ic) - { - CGAL_assertion(ubf->is_unbounded()); - if(ubf_ic == this->m_num_of_polygons) - ubf->set_contained(true); + // intersection means that all polygons contain the face. + CGAL_assertion(ic <= this->m_num_of_polygons); + return (ic == this->m_num_of_polygons); } void after_scan(Arrangement&) {} - - }; + CGAL_END_NAMESPACE #endif diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_join_visitor.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_join_visitor.h index 652f6b2715a..9390dd734f1 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_join_visitor.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_join_visitor.h @@ -16,6 +16,7 @@ // // // Author(s) : Baruch Zukerman +// Ophir Setter #ifndef CGAL_GPS_BFS_JOIN_VISITOR_H #define CGAL_GPS_BFS_JOIN_VISITOR_H @@ -25,12 +26,14 @@ CGAL_BEGIN_NAMESPACE template -class Gps_bfs_join_visitor : public Gps_bfs_base_visitor +class Gps_bfs_join_visitor : +public Gps_bfs_base_visitor > { typedef Arrangement_ Arrangement; typedef typename Arrangement::Face_iterator Face_iterator; typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; - typedef Gps_bfs_base_visitor Base; + typedef Gps_bfs_join_visitor Self; + typedef Gps_bfs_base_visitor Base; typedef typename Base::Edges_hash Edges_hash; typedef typename Base::Faces_hash Faces_hash; @@ -40,23 +43,16 @@ public: Base(edges_hash, faces_hash, n_pgn) {} - - void flip_face(Face_iterator f1, Face_iterator f2, Halfedge_iterator he) + //! contained_criteria +/*! contained_criteria is used to the determine if the face which has + inside count should be marked as contained. + \param ic the inner count of the talked-about face. + \return true if the face of ic, otherwise false. +*/ + bool contained_criteria(unsigned int ic) { - unsigned int ic_f2; - ic_f2 = this->compute_ic(f1, f2, he); - (*(this->m_faces_hash))[f2] = ic_f2; - - if(ic_f2 > 0) - f2->set_contained(true); - } - - // mark the unbounded_face - void visit_ubf(Face_iterator ubf, unsigned int ubf_ic) - { - CGAL_assertion(ubf->is_unbounded()); - if(ubf_ic > 0) - ubf->set_contained(true); + // at least one polygon contains the face. + return (ic > 0); } void after_scan(Arrangement&) diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_scanner.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_scanner.h index 4a2f9f79181..980e43af381 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_scanner.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_scanner.h @@ -16,6 +16,7 @@ // // // Author(s) : Baruch Zukerman +// Ophir Setter #ifndef CGAL_GPS_BFS_SCANNER_H #define CGAL_GPS_BFS_SCANNER_H @@ -30,7 +31,7 @@ class Gps_bfs_scanner { typedef Arrangement_ Arrangement; - typedef typename Arrangement::Inner_ccb_iterator Hole_iterator; + typedef typename Arrangement::Inner_ccb_iterator Inner_ccb_iterator; typedef typename Arrangement::Ccb_halfedge_circulator Ccb_halfedge_circulator; typedef typename Arrangement::Face_iterator Face_iterator; @@ -40,7 +41,7 @@ class Gps_bfs_scanner protected: Visitor* m_visitor; - std::queue m_holes; + std::queue m_holes; std::stack m_ccb_stcak; public: @@ -50,15 +51,23 @@ public: void scan(Arrangement& arr) { - Face_iterator ubf = arr.unbounded_face(); - ubf->set_visited(true); - push_to_queue_holes_of_face(ubf); - - while(!m_holes.empty()) + Face_iterator ubf; + for (ubf = arr.faces_begin(); ubf != arr.faces_end(); ++ubf) { - Hole_iterator hole = m_holes.front(); - m_holes.pop(); - scan(*hole); + if (ubf->number_of_outer_ccbs() != 0) + continue; + if (ubf->visited() == true) + continue; + + ubf->set_visited(true); + push_to_queue_holes_of_face(ubf); + + while(!m_holes.empty()) + { + Inner_ccb_iterator hole = m_holes.front(); + m_holes.pop(); + scan(*hole); + } } } @@ -86,7 +95,7 @@ public: { push_to_queue_holes_of_face(he->twin()->face()); new_f->set_visited(true); - m_visitor->flip_face(he->face(), new_f, he); + m_visitor->discovered_face(he->face(), new_f, he); //scan(he->twin()); m_ccb_stcak.push(he->twin()); @@ -99,7 +108,8 @@ public: void push_to_queue_holes_of_face(Face_iterator f) { - for(Hole_iterator hit = f->holes_begin(); hit!= f->holes_end(); ++hit) + for(Inner_ccb_iterator hit = f->inner_ccbs_begin(); + hit!= f->inner_ccbs_end(); ++hit) { m_holes.push(hit); } diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_xor_visitor.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_xor_visitor.h index 0e013d9aadd..f006507b594 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_xor_visitor.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_bfs_xor_visitor.h @@ -16,6 +16,7 @@ // // // Author(s) : Baruch Zukerman +// Ophir Setter #ifndef CGAL_GPS_BFS_XOR_VISITOR_H #define CGAL_GPS_BFS_XOR_VISITOR_H @@ -25,43 +26,45 @@ CGAL_BEGIN_NAMESPACE template -class Gps_bfs_xor_visitor : public Gps_bfs_base_visitor +class Gps_bfs_xor_visitor : +public Gps_bfs_base_visitor > { typedef Arrangement_ Arrangement; typedef typename Arrangement::Face_iterator Face_iterator; typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; - typedef Gps_bfs_base_visitor Base; + typedef Gps_bfs_xor_visitor Self; + typedef Gps_bfs_base_visitor Base; typedef typename Base::Edges_hash Edges_hash; typedef typename Base::Faces_hash Faces_hash; public: - Gps_bfs_xor_visitor(Edges_hash* edges_hash, Faces_hash* faces_hash, unsigned int n_pgn): + Gps_bfs_xor_visitor(Edges_hash* edges_hash, Faces_hash* faces_hash, + unsigned int n_pgn) : Base(edges_hash, faces_hash, n_pgn) {} - - void flip_face(Face_iterator f1, Face_iterator f2, Halfedge_iterator he) + //! contained_criteria +/*! contained_criteria is used to the determine if the face which has + inside count should be marked as contained. + \param ic the inner count of the talked-about face. + \return true if the face of ic, otherwise false. +*/ + bool contained_criteria(unsigned int ic) { - unsigned int ic_f2; - ic_f2 = this->compute_ic(f1, f2, he); - (*(this->m_faces_hash))[f2] = ic_f2; - - if(ic_f2%2) - f2->set_contained(true); - } - - // mark the unbounded_face (true iff contained) - void visit_ubf(Face_iterator ubf, unsigned int ubf_ic) - { - CGAL_assertion(ubf->is_unbounded()); - if(ubf_ic%2) - ubf->set_contained(true); + // xor means odd number of polygons. + return (ic % 2) == 1; } + //! after_scan post-processing after bfs scan. +/*! The function fixes some of the curves, to be in the same direction as the + half-edges. + + \param arr The given arrangment. +*/ void after_scan(Arrangement& arr) { - typedef typename Arrangement::Traits_2 Traits; + typedef typename Arrangement::Geometry_traits_2 Traits; typedef typename Traits::Compare_endpoints_xy_2 Compare_endpoints_xy_2; typedef typename Traits::Construct_opposite_2 Construct_opposite_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; @@ -79,7 +82,8 @@ public: Halfedge_iterator he = eit; const X_monotone_curve_2& cv = he->curve(); const bool is_cont = he->face()->contained(); - const Comparison_result he_res = ((Arr_halfedge_direction)he->direction() == ARR_LEFT_TO_RIGHT) ? + const Comparison_result he_res = + ((Arr_halfedge_direction)he->direction() == ARR_LEFT_TO_RIGHT) ? SMALLER : LARGER; const bool has_same_dir = (cmp_endpoints(cv) == he_res); diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_merge.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_merge.h index 117dc070144..505361536ee 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_merge.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_merge.h @@ -24,15 +24,30 @@ #include #include #include -#include #include CGAL_BEGIN_NAMESPACE -template -class Join_merge +/*! + \file Gps_merge.h + \brief This file contains classes that are responsible for merging + two sets of polygons in the divide-and-conquer algorithm. + The file contains 3 mergers: Join_merge, Intersection_merge and + Xor_merge. Join_merge is used when we want to merge the two sets, + Intersection_merge is used for intersection, and Xor_merge is used + for symmetric difference. +*/ + +//! Base_merge +/*! Base_merge is the base class for all merger classes. + All merges used BFS algorithm with a different visitor when discovering + a new face. + */ +template +class Base_merge { typedef Arrangement_ Arrangement_2; + typedef Visitor_ Visitor; typedef typename Arrangement_2::Vertex_handle Vertex_handle; typedef std::pair *> Arr_entry; @@ -46,12 +61,12 @@ public: if(i==j) return; - typename Arrangement_2::Traits_2* tr = arr_vec[i].first->traits(); + typename Arrangement_2::Geometry_traits_2* tr = + arr_vec[i].first->geometry_traits(); Arrangement_2 *res = new Arrangement_2(tr); std::vector *verts = new std::vector; - Gps_agg_op > - agg_op(*res, *verts, *tr); + Gps_agg_op agg_op(*res, *verts, *tr); agg_op.sweep_arrangements(i, j, jump, arr_vec); for(unsigned int count=i; count<=j; count+=jump) @@ -66,82 +81,33 @@ public: }; - +//! Join_merge +/*! Join_merge is used to join two sets of polygons together in the D&C + algorithm. It is a base merge with a visitor that joins faces. + */ template -class Intersection_merge -{ - typedef Arrangement_ Arrangement_2; - typedef typename Arrangement_2::Vertex_handle Vertex_handle; - typedef std::pair *> Arr_entry; +class Join_merge : public Base_merge > +{}; -public: - void operator()(unsigned int i, - unsigned int j, - unsigned int jump, - std::vector& arr_vec) - { - if(i==j) - return; - - typename Arrangement_2::Traits_2* tr = arr_vec[i].first->traits(); - Arrangement_2 *res = new Arrangement_2 (tr); - std::vector *verts = new std::vector; - - Gps_agg_op > - agg_op(*res, *verts, *tr); - agg_op.sweep_arrangements(i, j, jump, arr_vec); - - for(unsigned int count=i; count<=j; count+=jump) - { - delete (arr_vec[count].first); - delete (arr_vec[count].second); - } - - arr_vec[i].first = res; - arr_vec[i].second = verts; - } -}; +//! Intersection_merge +/*! Intersection_merge is used to merge two sets of polygons creating their + intersection. + */ template -class Xor_merge +class Intersection_merge : public Base_merge > +{}; + +//! Xor_merge +/*! Xor_merge is used to merge two sets of polygons creating their + symmetric difference. + */ +template +class Xor_merge : public Base_merge > { - typedef Arrangement_ Arrangement_2; - typedef typename Arrangement_2::Vertex_handle Vertex_handle; - typedef std::pair *> Arr_entry; - -public: - - // Temporarily defined to see if this avoids a warning on SunPro CC - Xor_merge() - {} - - void operator()(unsigned int i, - unsigned int j, - unsigned int jump, - std::vector& arr_vec) - { - if(i==j) - return; - - typename Arrangement_2::Traits_2* tr = arr_vec[i].first->traits(); - Arrangement_2 *res = new Arrangement_2(tr); - std::vector *verts = new std::vector; - - Gps_agg_op > - agg_op(*res, *verts, *tr); - agg_op.sweep_arrangements(i, j, jump, arr_vec); - - for(unsigned int count=i; count<=j; count+=jump) - { - delete (arr_vec[count].first); - delete (arr_vec[count].second); - } - - arr_vec[i].first = res; - arr_vec[i].second = verts; - } }; CGAL_END_NAMESPACE diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h index 14c08034a75..e602521d182 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_polygon_validation.h @@ -16,7 +16,7 @@ // Author(s): Baruch Zukerman // Ron Wein // Boris Kozorovitzky -// Guy Zucker +// Guy Zucker #ifndef CGAL_GPS_POLYGON_VALIDATION_2_H #define CGAL_GPS_POLYGON_VALIDATION_2_H @@ -33,61 +33,65 @@ #include #include - #include -/*Arrangement is templated with extended face dcel*/ - template - class ValidationOverlayTraits : public CGAL::Arr_default_overlay_traits -{ -public: - typedef CGAL::Arr_default_overlay_traits Base; - typedef typename Base::Face_handle_A Face_handle_A; - typedef typename Base::Face_handle_B Face_handle_B; - typedef typename Base::Face_handle_R Face_handle_R; - - typedef typename Arrangement_2::Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator; - typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement_2::Face_const_handle Face_const_handle; - typedef typename Arrangement_2::Hole_const_iterator Hole_const_iterator; - - /*red faces source is the arrangement of holes. The blue faces (face) are caused by the PWH's outer boundary*/ - virtual void create_face(Face_handle_A red_face, Face_handle_B blue_face, Face_handle_R r_face) { - if ((red_face->contained()==true) && (blue_face->contained()==false)) { - hole_overlap=true; - } - } - -public: - ValidationOverlayTraits() : hole_overlap(false) {} - bool getHoleOverlap() { - return hole_overlap; - } - void setHoleOverlap(bool b) { - hole_overlap=b; return; - } -private: - bool hole_overlap; -}; - +#define CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF \ + typedef Gps_traits_adaptor Traits_adapter_2; \ + typedef typename Traits_2::Curve_const_iterator \ + Curve_const_iterator; \ + typedef std::pair \ + Cci_pair; \ + typedef typename Traits_2::Construct_curves_2 \ + Construct_curves_2; \ + typedef typename Traits_adapter_2::Construct_vertex_2 \ + Construct_vertex_2; + CGAL_BEGIN_NAMESPACE -#define CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF \ - typedef Gps_traits_adaptor Traits_adapter_2;\ - typedef typename Traits_2::Curve_const_iterator Curve_const_iterator;\ - typedef std::pair Cci_pair;\ - typedef typename Traits_2::Construct_curves_2 Construct_curves_2;\ - typedef typename Traits_adapter_2::Construct_vertex_2 Construct_vertex_2; +/*Arrangement is templated with extended face dcel*/ +template +class ValidationOverlayTraits : + public CGAL::Arr_default_overlay_traits +{ +public: + typedef CGAL::Arr_default_overlay_traits Base; + typedef typename Base::Face_handle_A Face_handle_A; + typedef typename Base::Face_handle_B Face_handle_B; + typedef typename Base::Face_handle_R Face_handle_R; + + typedef typename Arrangement_2::Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator; + typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement_2::Face_const_handle Face_const_handle; + typedef typename Arrangement_2::Inner_ccb_const_iterator Inner_ccb_const_iterator; + + /*red faces source is the arrangement of holes. The blue faces (face) are caused by the PWH's outer boundary*/ + virtual void create_face(Face_handle_A red_face, Face_handle_B blue_face, Face_handle_R r_face) { + if ((red_face->contained()==true) && (blue_face->contained()==false)) { + hole_overlap=true; + } + } + +public: + ValidationOverlayTraits() : hole_overlap(false) {} + bool getHoleOverlap() { + return hole_overlap; + } + void setHoleOverlap(bool b) { + hole_overlap=b; return; + } +private: + bool hole_overlap; +}; + - - /*! \class +/*! \class * A visitor used for checking whether the edges of a polygon are * non-intersecting. */ template class Gps_polygon_validation_visitor : - public Sweep_line_empty_visitor + public Sweep_line_empty_visitor { private: @@ -108,44 +112,44 @@ public: Gps_polygon_validation_visitor(bool is_s_simple = true): m_is_valid(true), m_is_s_simple(is_s_simple) - {} + {} template void sweep(XCurveIterator begin, XCurveIterator end) - { - //Perform the sweep - reinterpret_cast(this->m_sweep_line)->sweep(begin, end); - } + { + //Perform the sweep + reinterpret_cast(this->m_sweep_line)->sweep(begin, end); + } bool after_handle_event(Event* event,SL_iterator, bool) - { - if(event->is_intersection() || - event->is_weak_intersection() || - event->is_overlap()) { - m_is_valid = false; - reinterpret_cast(this->m_sweep_line) -> stop_sweep(); - } - else - { - if (m_is_s_simple && - (event->number_of_right_curves() + - event->number_of_left_curves()) != 2) + if(event->is_intersection() || + event->is_weak_intersection() || + event->is_overlap()) { - m_is_valid = false; - reinterpret_cast(this->m_sweep_line) -> stop_sweep(); + m_is_valid = false; + reinterpret_cast(this->m_sweep_line) -> stop_sweep(); + } + else + { + if (m_is_s_simple && + (event->number_of_right_curves() + + event->number_of_left_curves()) != 2) + { + m_is_valid = false; + reinterpret_cast(this->m_sweep_line) -> stop_sweep(); + } } - } - return (true); - } + return (true); + } bool is_valid() - { - return m_is_valid; - } + { + return m_is_valid; + } protected: @@ -158,420 +162,333 @@ protected: //Traits_2 templates the General_polygon_set_2 Traits. //These include types for polygon and PWH. - template - bool is_closed_polygon(const typename Traits_2::Polygon_2& pgn, Traits_2 traits) - { +template +bool is_closed_polygon(const typename Traits_2::Polygon_2& pgn, Traits_2 traits) +{ CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF Cci_pair itr_pair = traits.construct_curves_2_object()(pgn); - Curve_const_iterator begin = itr_pair.first; - Curve_const_iterator end = itr_pair.second; + Curve_const_iterator begin = itr_pair.first; + Curve_const_iterator end = itr_pair.second; - if (begin == end) - return (true); // An empty polygon is valid. + if (begin == end) + return (true); // An empty polygon is valid. - Traits_adapter_2 traits_adapter; - typename Traits_2::Equal_2 equal_func = traits.equal_2_object(); - Curve_const_iterator curr, next; - Construct_vertex_2 construct_vertex_func; - construct_vertex_func = traits_adapter.construct_vertex_2_object(); - curr = next = begin; - ++next; + Traits_adapter_2 traits_adapter; + typename Traits_2::Equal_2 equal_func = traits.equal_2_object(); + Curve_const_iterator curr, next; + Construct_vertex_2 construct_vertex_func; + construct_vertex_func = traits_adapter.construct_vertex_2_object(); + curr = next = begin; + ++next; - if (next == end) - return (false); // A polygon cannot have just a single edge. + if (next == end) + return (false); // A polygon cannot have just a single edge. - while (next != end) - { - // Make sure that the current target equals the next source. - if (equal_func (construct_vertex_func (*curr, 0), - construct_vertex_func (*curr, 1))) - return (false); - - if (! equal_func (construct_vertex_func (*curr, 1), - construct_vertex_func (*next, 0))) - return (false); - - // Move to the next pair of edges. - curr = next; - ++next; - } - - // Make sure that the last target equals the first source. + while (next != end) + { + // Make sure that the current target equals the next source. if (equal_func (construct_vertex_func (*curr, 0), construct_vertex_func (*curr, 1))) return (false); - if (! equal_func (construct_vertex_func (*curr, 1), - construct_vertex_func (*begin, 0))) + if (! equal_func (construct_vertex_func (*curr, 1), + construct_vertex_func (*next, 0))) return (false); - return (true); + // Move to the next pair of edges. + curr = next; + ++next; } - template - bool is_simple_polygon(const typename Traits_2::Polygon_2& pgn,Traits_2 traits) - {// Previously known as is_strictly_simple - CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF + // Make sure that the last target equals the first source. + if (equal_func (construct_vertex_func (*curr, 0), + construct_vertex_func (*curr, 1))) + return (false); + + if (! equal_func (construct_vertex_func (*curr, 1), + construct_vertex_func (*begin, 0))) + return (false); + + return (true); +} +template +bool is_simple_polygon(const typename Traits_2::Polygon_2& pgn,Traits_2 traits) +{// Previously known as is_strictly_simple + + CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF // Sweep the boundary curves and look for intersections. - typedef Gps_polygon_validation_visitor Visitor; - typedef Sweep_line_2 Sweep_line; + typedef Gps_polygon_validation_visitor Visitor; + typedef Sweep_line_2 Sweep_line; - Cci_pair itr_pair = traits.construct_curves_2_object()(pgn); - Visitor visitor; - Sweep_line sweep_line (&traits, &visitor); + Cci_pair itr_pair = traits.construct_curves_2_object()(pgn); + Visitor visitor; + Sweep_line sweep_line (&traits, &visitor); - visitor.sweep(itr_pair.first, itr_pair.second); - return (visitor.is_valid()); - } + visitor.sweep(itr_pair.first, itr_pair.second); + return (visitor.is_valid()); +} - template - bool has_valid_orientation_polygon (const typename Traits_2::Polygon_2& pgn,Traits_2 traits) - { - CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF +template +bool has_valid_orientation_polygon (const typename Traits_2::Polygon_2& pgn,Traits_2 traits) +{ + CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF Cci_pair itr_pair = traits.construct_curves_2_object()(pgn); - Traits_adapter_2 traits_adapter; - typedef typename Traits_adapter_2::Orientation_2 Check_orientation_2; + Traits_adapter_2 traits_adapter; + typedef typename Traits_adapter_2::Orientation_2 Check_orientation_2; - if(itr_pair.first == itr_pair.second) - return (true); // empty polygon + if(itr_pair.first == itr_pair.second) + return (true); // empty polygon - return (traits_adapter.orientation_2_object()(itr_pair.first, - itr_pair.second) == COUNTERCLOCKWISE); - } - /* A valid polygon is : - * 1 - Closed or empty polygon - * 2 - Simple (previously known as strictly simple) - * 3 - Counterclockwise oriented - */ - template - bool is_valid_polygon(const typename Traits_2::Polygon_2& pgn,Traits_2 traits) - { - bool closed = is_closed_polygon(pgn,traits); - CGAL_warning_msg (closed, - "The polygon's boundary is not closed."); - if (! closed) - return (false); + return (traits_adapter.orientation_2_object()(itr_pair.first, + itr_pair.second) == COUNTERCLOCKWISE); +} +/* A valid polygon is : + * 1 - Closed or empty polygon + * 2 - Simple (previously known as strictly simple) + * 3 - Counterclockwise oriented + */ +template +bool is_valid_polygon(const typename Traits_2::Polygon_2& pgn,Traits_2 traits) +{ + bool closed = is_closed_polygon(pgn,traits); + CGAL_warning_msg (closed, + "The polygon's boundary is not closed."); + if (! closed) + return (false); - bool simple = is_simple_polygon(pgn,traits); - CGAL_warning_msg (simple, - "The polygon is not simple."); - if (!simple) - return (false); + bool simple = is_simple_polygon(pgn,traits); + CGAL_warning_msg (simple, + "The polygon is not simple."); + if (!simple) + return (false); - bool valid_orientation = has_valid_orientation_polygon(pgn,traits); - CGAL_warning_msg (valid_orientation, - "The polygon has a wrong orientation."); - if (! valid_orientation) - return (false); + bool valid_orientation = has_valid_orientation_polygon(pgn,traits); + CGAL_warning_msg (valid_orientation, + "The polygon has a wrong orientation."); + if (! valid_orientation) + return (false); - return (true); - } + return (true); +} - template - bool is_closed_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) +template +bool is_closed_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) +{ + typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; + if(! is_closed_polygon (pgn.outer_boundary(),traits)) + return (false); + + typename Polygon_with_holes_2::Hole_const_iterator itr; + + for (itr = pgn.holes_begin(); itr != pgn.holes_end(); ++itr) { - typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; - if(! is_closed_polygon (pgn.outer_boundary(),traits)) + if(! is_closed_polygon (*itr,traits)) return (false); - - typename Polygon_with_holes_2::Hole_const_iterator itr; - - for (itr = pgn.holes_begin(); itr != pgn.holes_end(); ++itr) - { - if(! is_closed_polygon (*itr,traits)) - return (false); - } - return (true); } + return (true); +} - - template - bool is_crossover_outer_boundary(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits ) { - CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF +//templated point location version +template +bool is_crossover_outer_boundary(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits, PointLocation& pl ) { + CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF typedef typename Traits_2::Point_2 Point_2; - typedef typename Traits_2::Compare_endpoints_xy_2 Compare_endpoints_xy_2; - typedef typename Traits_2::Construct_min_vertex_2 Construct_min_vertex_2; - typedef typename Traits_2::Construct_max_vertex_2 Construct_max_vertex_2; - typedef CGAL::Gps_default_dcel dcel; - typedef CGAL::General_polygon_set_2 Polygon_set_2; - typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; - typedef typename Polygon_set_2::Arrangement_2 Arrangement_2; - typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; - typedef typename Arrangement_2::Vertex_handle Vertex_handle; - typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; - typedef typename Traits_2::Curve_const_iterator Curve_const_iterator; - typedef CGAL::Arr_naive_point_location Naive_pl; + typedef typename Traits_2::Compare_endpoints_xy_2 Compare_endpoints_xy_2; + typedef typename Traits_2::Construct_min_vertex_2 Construct_min_vertex_2; + typedef typename Traits_2::Construct_max_vertex_2 Construct_max_vertex_2; + typedef CGAL::Gps_default_dcel dcel; + typedef CGAL::General_polygon_set_2 Polygon_set_2; + typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; + typedef typename Polygon_set_2::Arrangement_2 Arrangement_2; + typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; + typedef typename Arrangement_2::Vertex_handle Vertex_handle; + typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; + typedef typename Traits_2::Curve_const_iterator Curve_const_iterator; - typename std::list he_path; - typename std::list::iterator he_itr; - //functors used throughout the function - Construct_min_vertex_2 min_functor = traits.construct_min_vertex_2_object(); - Construct_max_vertex_2 max_functor = traits.construct_max_vertex_2_object(); - Compare_endpoints_xy_2 cmp_endpoints = traits.compare_endpoints_xy_2_object(); + typename std::list he_path; + typename std::list::iterator he_itr; + //functors used throughout the function + Construct_min_vertex_2 min_functor = traits.construct_min_vertex_2_object(); + Construct_max_vertex_2 max_functor = traits.construct_max_vertex_2_object(); + Compare_endpoints_xy_2 cmp_endpoints = traits.compare_endpoints_xy_2_object(); - Cci_pair itr_pair = traits.construct_curves_2_object()(pgn.outer_boundary()); - Curve_const_iterator begin = itr_pair.first; - Curve_const_iterator end = itr_pair.second; - if (begin == end) - return (true); // An empty polygon is valid. - //handles to consecutive curves - Curve_const_iterator curr, next; - curr = next = begin; - //handles to vertices for insert. one maintains the current curve (already inserted) and next curve's joint vertex. - //the other maintains the next curve's second vertex if it already exists in the arrangement. - Vertex_handle joint_ver, second_ver; - //closed check guarantees polygon has more than 1 curve - ++next; - //halfedge handle whose target is always the joint vertex between next and curr. - Halfedge_handle last_he; + Cci_pair itr_pair = traits.construct_curves_2_object()(pgn.outer_boundary()); + Curve_const_iterator begin = itr_pair.first; + Curve_const_iterator end = itr_pair.second; + if (begin == end) + return (true); // An empty polygon is valid. + //handles to consecutive curves + Curve_const_iterator curr, next; + curr = next = begin; + //handles to vertices for insert. one maintains the current curve (already inserted) and next curve's joint vertex. + //the other maintains the next curve's second vertex if it already exists in the arrangement. + Vertex_handle joint_ver, second_ver; + //closed check guarantees polygon has more than 1 curve + ++next; + //halfedge handle whose target is always the joint vertex between next and curr. + Halfedge_handle last_he; - Polygon_set_2 gps(traits); - Arrangement_2 arr = gps.arrangement(); - Naive_pl pl (arr); - //insert first edge lexicographically to arrangement - // compute the joint vertex and insert to the path list a halfedge whose target is the joint vertex - last_he = CGAL::insert_non_intersecting_curve(arr, *curr); - if (cmp_endpoints(*curr) == SMALLER) { //polygon's boundary first curve is in lexicographic direction - joint_ver = last_he->target(); - he_path.push_back(last_he); - } else { //polygon's boundary first curve not lexicographic - joint_ver = last_he->source(); - he_path.push_back(last_he->twin()); - } + Polygon_set_2 gps(traits); + Arrangement_2 arr = gps.arrangement(); + pl.attach(arr); - /*insert the rest of the curves to the arrangement efficiently the previous closed polygon check guarantees - equal_func (construct_vertex_func (*curr, 1), construct_vertex_func (*next, 0))) */ - while (next != end) { - CGAL::Object obj; - Vertex_const_handle cver; - Point_2 second_point; - if(cmp_endpoints(*next) == SMALLER) { - //next curve's minimum is the joint vertex. Look if it's max exists in the arrangement and insert lexicographically - second_point = max_functor(*next); - obj = pl.locate(second_point); - if (CGAL::assign (cver, obj)) { - //insert where both vertices exist - second_ver = arr.non_const_handle(cver); - last_he = arr.insert_at_vertices( *next, joint_ver, second_ver); - } else //insert from left vertex - last_he = arr.insert_from_left_vertex ( *next,joint_ver) ; - } else { //next curve's maximum vertex is the joint vertex. try to locate the min vertex, and insert from right or from both vertices - second_point = min_functor(*next); - obj = pl.locate(second_point); - if (CGAL::assign (cver, obj)) { - //insert where both vertices exist - second_ver = arr.non_const_handle(cver); - last_he = arr.insert_at_vertices( *next, joint_ver, second_ver); - } else //insert from right vertex - last_he = arr.insert_from_right_vertex ( *next,joint_ver) ; - } - // Move to the next pair of edges. - he_path.push_back(last_he); - joint_ver=last_he->target(); - curr = next; - ++next; - } //end of while - /*We created a path of halfedges that circulates the polygon counterclockwise (curves . The - polygon should ly on the left of each of these half edges. If the boundary is invalid, the unbounded face should - be on the left of one of more than one of the halfedges*/ - typename Arrangement_2::Face_const_handle cfh; - typename Arrangement_2::Face_handle fh; - cfh = arr.unbounded_face(); - fh = arr.non_const_handle(cfh); - for (he_itr = he_path.begin();he_itr != he_path.end();he_itr++) { - Halfedge_handle cur = *he_itr; - if (cur->face() == fh) - return false; - } - return true; + //insert first edge lexicographically to arrangement + // compute the joint vertex and insert to the path list a halfedge whose target is the joint vertex + last_he = CGAL::insert_non_intersecting_curve(arr, *curr); + if (cmp_endpoints(*curr) == SMALLER) { //polygon's boundary first curve is in lexicographic direction + joint_ver = last_he->target(); + he_path.push_back(last_he); + } else { //polygon's boundary first curve not lexicographic + joint_ver = last_he->source(); + he_path.push_back(last_he->twin()); } - - - - //templated point location version - template - bool is_crossover_outer_boundary(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits, const PointLocation& pl ) { - CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF - typedef typename Traits_2::Point_2 Point_2; - typedef typename Traits_2::Compare_endpoints_xy_2 Compare_endpoints_xy_2; - typedef typename Traits_2::Construct_min_vertex_2 Construct_min_vertex_2; - typedef typename Traits_2::Construct_max_vertex_2 Construct_max_vertex_2; - typedef CGAL::Gps_default_dcel dcel; - typedef CGAL::General_polygon_set_2 Polygon_set_2; - typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; - typedef typename Polygon_set_2::Arrangement_2 Arrangement_2; - typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; - typedef typename Arrangement_2::Vertex_handle Vertex_handle; - typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; - typedef typename Traits_2::Curve_const_iterator Curve_const_iterator; - typedef CGAL::Arr_naive_point_location Naive_pl; - - typename std::list he_path; - typename std::list::iterator he_itr; - //functors used throughout the function - Construct_min_vertex_2 min_functor = traits.construct_min_vertex_2_object(); - Construct_max_vertex_2 max_functor = traits.construct_max_vertex_2_object(); - Compare_endpoints_xy_2 cmp_endpoints = traits.compare_endpoints_xy_2_object(); - - Cci_pair itr_pair = traits.construct_curves_2_object()(pgn.outer_boundary()); - Curve_const_iterator begin = itr_pair.first; - Curve_const_iterator end = itr_pair.second; - if (begin == end) - return (true); // An empty polygon is valid. - //handles to consecutive curves - Curve_const_iterator curr, next; - curr = next = begin; - //handles to vertices for insert. one maintains the current curve (already inserted) and next curve's joint vertex. - //the other maintains the next curve's second vertex if it already exists in the arrangement. - Vertex_handle joint_ver, second_ver; - //closed check guarantees polygon has more than 1 curve - ++next; - //halfedge handle whose target is always the joint vertex between next and curr. - Halfedge_handle last_he; - - Polygon_set_2 gps(traits); - Arrangement_2 arr = gps.arrangement(); - //insert first edge lexicographically to arrangement - // compute the joint vertex and insert to the path list a halfedge whose target is the joint vertex - last_he = CGAL::insert_non_intersecting_curve(arr, *curr); - if (cmp_endpoints(*curr) == SMALLER) { //polygon's boundary first curve is in lexicographic direction - joint_ver = last_he->target(); - he_path.push_back(last_he); - } else { //polygon's boundary first curve not lexicographic - joint_ver = last_he->source(); - he_path.push_back(last_he->twin()); - } - - /*insert the rest of the curves to the arrangement efficiently the previous closed polygon check guarantees + /*insert the rest of the curves to the arrangement efficiently the previous closed polygon check guarantees equal_func (construct_vertex_func (*curr, 1), construct_vertex_func (*next, 0))) */ - while (next != end) { - CGAL::Object obj; - Vertex_const_handle cver; - Point_2 second_point; - if(cmp_endpoints(*next) == SMALLER) { + while (next != end) { + CGAL::Object obj; + Vertex_const_handle cver; + Point_2 second_point; + if(cmp_endpoints(*next) == SMALLER) { //next curve's minimum is the joint vertex. Look if it's max exists in the arrangement and insert lexicographically - second_point = max_functor(*next); - obj = pl.locate(second_point); - if (CGAL::assign (cver, obj)) { - //insert where both vertices exist - second_ver = arr.non_const_handle(cver); - last_he = arr.insert_at_vertices( *next, joint_ver, second_ver); - } else //insert from left vertex - last_he = arr.insert_from_left_vertex ( *next,joint_ver) ; - } else { //next curve's maximum vertex is the joint vertex. try to locate the min vertex, and insert from right or from both vertices - second_point = min_functor(*next); - obj = pl.locate(second_point); - if (CGAL::assign (cver, obj)) { - //insert where both vertices exist - second_ver = arr.non_const_handle(cver); - last_he = arr.insert_at_vertices( *next, joint_ver, second_ver); - } else //insert from right vertex - last_he = arr.insert_from_right_vertex ( *next,joint_ver) ; - } - // Move to the next pair of edges. - he_path.push_back(last_he); - joint_ver=last_he->target(); - curr = next; - ++next; - } //end of while - /*We created a path of halfedges that circulates the polygon counterclockwise (curves . The - polygon should ly on the left of each of these half edges. If the boundary is invalid, the unbounded face should - be on the left of one of more than one of the halfedges*/ - typename Arrangement_2::Face_const_handle cfh; - typename Arrangement_2::Face_handle fh; - cfh = arr.unbounded_face(); - fh = arr.non_const_handle(cfh); - for (he_itr = he_path.begin();he_itr != he_path.end();he_itr++) { - Halfedge_handle cur = *he_itr; - if (cur->face() == fh) - return false; + second_point = max_functor(*next); + obj = pl.locate(second_point); + if (CGAL::assign (cver, obj)) { + //insert where both vertices exist + second_ver = arr.non_const_handle(cver); + last_he = arr.insert_at_vertices( *next, joint_ver, second_ver); + } else //insert from left vertex + last_he = arr.insert_from_left_vertex ( *next,joint_ver) ; + } else { //next curve's maximum vertex is the joint vertex. try to locate the min vertex, and insert from right or from both vertices + second_point = min_functor(*next); + obj = pl.locate(second_point); + if (CGAL::assign (cver, obj)) { + //insert where both vertices exist + second_ver = arr.non_const_handle(cver); + last_he = arr.insert_at_vertices( *next, joint_ver, second_ver); + } else //insert from right vertex + last_he = arr.insert_from_right_vertex ( *next,joint_ver) ; } - return true; - } + // Move to the next pair of edges. + he_path.push_back(last_he); + joint_ver=last_he->target(); + curr = next; + ++next; + } //end of while +// We created a path of halfedges that circulates the polygon counterclockwise +// The polygon should lay on the left of each of these half edges. +// If the boundary is invalid, the unbounded face should +// be on the left of one of more than one of the halfedges. +// The unbounded face is always to the right of the halfedges. We check if +// all faces that lay on the right of the halfedges are equal (to the +// "unbounded" face). + typename Arrangement_2::Face_handle fh = (*he_path.begin())->twin()->face(); + for (he_itr = he_path.begin(); he_itr != he_path.end(); he_itr++) { - template - bool is_relatively_simple_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) - {// previously known as Simple - - CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF - typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; - typedef Gps_polygon_validation_visitor Visitor; - typedef Sweep_line_2 Sweep_line; - typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; - - Construct_curves_2 construct_curves_func = traits.construct_curves_2_object(); - // Construct a container of all outer boundary curves. - Cci_pair itr_pair = construct_curves_func (pgn.outer_boundary()); - std::list outer_curves; - std::copy (itr_pair.first, itr_pair.second, - std::back_inserter(outer_curves)); - //create visitor and sweep to verify outer boundary is relatively simple - Visitor relative_visitor(false); - Sweep_line sweep_line (&traits, &relative_visitor); - relative_visitor.sweep (outer_curves.begin(), outer_curves.end()); - if (!relative_visitor.is_valid()) + if ((*he_itr)->twin()->face() != fh) return false; + } + return true; +} + + +template +bool is_crossover_outer_boundary( + const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits ) { + + typedef CGAL::Gps_default_dcel Dcel; + typedef CGAL::General_polygon_set_2 Polygon_set_2; + typedef typename Polygon_set_2::Arrangement_2 Arrangement_2; + typedef CGAL::Arr_naive_point_location Naive_pl; + + Naive_pl pl; + return is_crossover_outer_boundary(pgn, traits, pl); +} + + + +template +bool is_relatively_simple_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) +{// previously known as Simple + + CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF + typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; + typedef Gps_polygon_validation_visitor Visitor; + typedef Sweep_line_2 Sweep_line; + typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; + + Construct_curves_2 construct_curves_func = traits.construct_curves_2_object(); + // Construct a container of all outer boundary curves. + Cci_pair itr_pair = construct_curves_func (pgn.outer_boundary()); + std::list outer_curves; + std::copy (itr_pair.first, itr_pair.second, + std::back_inserter(outer_curves)); + //create visitor and sweep to verify outer boundary is relatively simple + Visitor relative_visitor(false); + Sweep_line sweep_line (&traits, &relative_visitor); + relative_visitor.sweep (outer_curves.begin(), outer_curves.end()); + if (!relative_visitor.is_valid()) + return false; - //verify every hole is simple - typename Polygon_with_holes_2::Hole_const_iterator hoit; - std::list hole_curves; - for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit) - { - bool simple_hole = is_simple_polygon(*hoit,traits); - if (!simple_hole) - return false; - } - return true; + //verify every hole is simple + typename Polygon_with_holes_2::Hole_const_iterator hoit; + std::list hole_curves; + for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit) + { + bool simple_hole = is_simple_polygon(*hoit,traits); + if (!simple_hole) + return false; + } + return true; +} + + + +template +bool has_valid_orientation_polygon_with_holes (const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) +{ + CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF + typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; + typedef Gps_polygon_validation_visitor Visitor; + typedef Sweep_line_2 Sweep_line; + typedef typename Traits_adapter_2::Orientation_2 Check_orientation_2; + typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; + + Traits_adapter_2 traits_adapter; + + Construct_curves_2 construct_curves_func = traits.construct_curves_2_object(); + Check_orientation_2 check_orientation_func = traits_adapter.orientation_2_object();; + // Check the orientation of the outer boundary. + Cci_pair itr_pair = construct_curves_func (pgn.outer_boundary()); + + if ((itr_pair.first != itr_pair.second) && + check_orientation_func (itr_pair.first, + itr_pair.second) != COUNTERCLOCKWISE) + { + return (false); } - - - template - bool has_valid_orientation_polygon_with_holes (const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) + // Check the orientation of each of the holes. + typename Polygon_with_holes_2::Hole_const_iterator hoit; + + for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit) { - CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF - typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; - typedef Gps_polygon_validation_visitor Visitor; - typedef Sweep_line_2 Sweep_line; - typedef typename Traits_adapter_2::Orientation_2 Check_orientation_2; - typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; + itr_pair = construct_curves_func (*hoit); - Traits_adapter_2 traits_adapter; - - Construct_curves_2 construct_curves_func = traits.construct_curves_2_object(); - Check_orientation_2 check_orientation_func = traits_adapter.orientation_2_object();; - // Check the orientation of the outer boundary. - Cci_pair itr_pair = construct_curves_func (pgn.outer_boundary()); - - if ((itr_pair.first != itr_pair.second) && + if ((itr_pair.first !=itr_pair.second) && check_orientation_func (itr_pair.first, - itr_pair.second) != COUNTERCLOCKWISE) + itr_pair.second) != CLOCKWISE) { return (false); } - - // Check the orientation of each of the holes. - typename Polygon_with_holes_2::Hole_const_iterator hoit; - - for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit) - { - itr_pair = construct_curves_func (*hoit); - - if ((itr_pair.first !=itr_pair.second) && - check_orientation_func (itr_pair.first, - itr_pair.second) != CLOCKWISE) - { - return (false); - } - } - return (true); } + return (true); +} @@ -579,194 +496,198 @@ protected: /*Verify holes do not intersect between themselves as well with the outer boundary -(except intersection on a vertex which is allowed). + (except intersection on a vertex which is allowed). -This efficient implementation utilizes the general poygon set for aggregated join -operations for N holes which should result in a GPS that contains N independent PWH. -Executing a difference(gps, outer boundary) should result in an empty set if -no holes intersect the boundary. + This efficient implementation utilizes the general poygon set for aggregated join + operations for N holes which should result in a GPS that contains N independent PWH. + Executing a difference(gps, outer boundary) should result in an empty set if + no holes intersect the boundary. -An iterative use of the difference free function while iterating over the holes -may have an advantage in case there are numerous holes that intersect the boundary -and the iterative loop will be stopped after a small number of iterations. + An iterative use of the difference free function while iterating over the holes + may have an advantage in case there are numerous holes that intersect the boundary + and the iterative loop will be stopped after a small number of iterations. */ - template - bool are_holes_and_boundary_pairwise_disjoint(const typename Traits_2::Polygon_with_holes_2& pwh, Traits_2 traits) - { - CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF +template +bool are_holes_and_boundary_pairwise_disjoint(const typename Traits_2::Polygon_with_holes_2& pwh, Traits_2 traits) +{ + CGAL_GPS_POLYGON_VALIDATION_2_TYPEDEF typedef CGAL::Gps_default_dcel dcel; - typedef CGAL::General_polygon_set_2 Polygon_set_2; - typedef typename Polygon_set_2::Size Size; - typedef typename Traits_2::Polygon_2 Polygon_2; - typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; - typedef typename Polygon_with_holes_2::Hole_const_iterator Hole_const_iterator; - typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; - typedef std::pair Cci_pair; - typedef typename Traits_2::Construct_curves_2 Construct_curves_2; + typedef CGAL::General_polygon_set_2 Polygon_set_2; + typedef typename Polygon_set_2::Size Size; + typedef typename Traits_2::Polygon_2 Polygon_2; + typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; + typedef typename Polygon_with_holes_2::Hole_const_iterator Hole_const_iterator; + typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; + typedef std::pair Cci_pair; + typedef typename Traits_2::Construct_curves_2 Construct_curves_2; - typedef typename Traits_adapter_2::Construct_vertex_2 - Construct_vertex_2; - typedef Gps_polygon_validation_visitor Visitor; - typedef Sweep_line_2 Sweep_line ; - typedef typename Polygon_set_2::Arrangement_2 Arrangement_2; + typedef typename Traits_adapter_2::Construct_vertex_2 + Construct_vertex_2; + typedef Gps_polygon_validation_visitor Visitor; + typedef Sweep_line_2 Sweep_line ; + typedef typename Polygon_set_2::Arrangement_2 Arrangement_2; - /* Should be perfored more efficeintly than using sweep and than difference().*/ + /* Should be perfored more efficeintly than using sweep and than difference().*/ - /*Use sweep to find intersections on the interior of curves (not on vertices) and overlapping edges which are not allowed - (note that 0/1 dimension intersections are not detectes by do_intersect() which only returns the 2D intersection polygon if exists) + /*Use sweep to find intersections on the interior of curves (not on vertices) and overlapping edges which are not allowed + (note that 0/1 dimension intersections are not detectes by do_intersect() which only returns the 2D intersection polygon if exists) Note that using this sweep alone allows for a hole and an edge to share a vertex and intersect - (like illegal input pgn_w_overlap_hole.dat in validation_example)*/ - Hole_const_iterator hoit; - // Construct a container of all boundary curves. - Polygon_2 pgn2 = traits.construct_outer_boundary_object()(pwh); - Construct_curves_2 construct_curves_func; - Cci_pair itr_pair = construct_curves_func(pgn2); + (like illegal input pgn_w_overlap_hole.dat in validation_example)*/ + Hole_const_iterator hoit; + // Construct a container of all boundary curves. + Polygon_2 pgn2 = traits.construct_outer_boundary_object()(pwh); + Construct_curves_2 construct_curves_func; + Cci_pair itr_pair = construct_curves_func(pgn2); - std::list curves; + std::list curves; + std::copy (itr_pair.first, itr_pair.second, + std::back_inserter(curves)); + + std::pair pair = traits.construct_holes_object()(pwh); + for (hoit = pair.first; hoit!=pair.second; ++hoit) + //for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit) + { + itr_pair = construct_curves_func (*hoit); std::copy (itr_pair.first, itr_pair.second, std::back_inserter(curves)); + } - std::pair pair = traits.construct_holes_object()(pwh); - for (hoit = pair.first; hoit!=pair.second; ++hoit) - //for (hoit = pgn.holes_begin(); hoit != pgn.holes_end(); ++hoit) - { - itr_pair = construct_curves_func (*hoit); - std::copy (itr_pair.first, itr_pair.second, - std::back_inserter(curves)); - } - - // Perform the sweep and check for curve intersections on the interior. - //Traits_2 traits; moved to top, needed also for boundary. - Visitor visitor(false); - Sweep_line sweep_line (&traits, &visitor); - visitor.sweep (curves.begin(), curves.end()); - if (!visitor.is_valid()) - return false; + // Perform the sweep and check for curve intersections on the interior. + //Traits_2 traits; moved to top, needed also for boundary. + Visitor visitor(false); + Sweep_line sweep_line (&traits, &visitor); + visitor.sweep (curves.begin(), curves.end()); + if (!visitor.is_valid()) + return false; - Polygon_set_2 gps(traits); - //check for 2D intersections of holes (holes must be disjoint except for vertices) - Size num_of_holes=0; - for (hoit = pwh.holes_begin(); hoit != pwh.holes_end(); ++hoit) { - Polygon_2 hole(*hoit); - hole.reverse_orientation(); - /*gps.join() and gps.insert()requires that the polyon insrted is valid, and therfore hole - orientation must be reversed*/ - bool intersect = gps.do_intersect(hole); - if (intersect) - return false; - else { - /*to use gps.insert(hole) it is required that the set coponents and the new holes do not intersect. - because the sweep detects shared edges and the do_intersect query detects 2D intersections we can safely use - the insert(pwh) function whose performance is better than the join(pgn)*/ - Polygon_with_holes_2 empty_pwh(hole); - gps.insert(empty_pwh); - num_of_holes++; - } - } - /*not good - doesn't work if intersection at vertices is legal. + Polygon_set_2 gps(traits); + //check for 2D intersections of holes (holes must be disjoint except for vertices) + Size num_of_holes=0; + for (hoit = pwh.holes_begin(); hoit != pwh.holes_end(); ++hoit) { + Polygon_2 hole(*hoit); + hole.reverse_orientation(); + /*gps.join() and gps.insert()requires that the polyon insrted is valid, and therfore hole + orientation must be reversed*/ + bool intersect = gps.do_intersect(hole); + if (intersect) + return false; + else { + /*to use gps.insert(hole) it is required that the set coponents and the new holes do not intersect. + because the sweep detects shared edges and the do_intersect query detects 2D intersections we can safely use + the insert(pwh) function whose performance is better than the join(pgn)*/ + Polygon_with_holes_2 empty_pwh(hole); + gps.insert(empty_pwh); + num_of_holes++; + } + } + /*not good - doesn't work if intersection at vertices is legal. Size arr_num_of_holes = gps.number_of_polygons_with_holes(); if (num_of_holes != arr_num_of_holes) - return false; - */ - //check for intersection of holes with the outer boundary - Hole_const_iterator fit; - /*outer boundary can be relatively simple. Execution of + return false; + */ + //check for intersection of holes with the outer boundary + Hole_const_iterator fit; + + /*outer boundary can be relatively simple. Execution of do_intersect(hole, boundary) or difference(hole,boundary) relies on implementation of General polygon set which has a precondition that requires valid polygon or PWH to be inserted (not just a simple polygon). This helper function is utilized after checking for the PWH closure, relative simplicity and orientation. Therefore it is safe to assume the outer boundary is valid PWH with no holes. We can't assume it is a valid - (simple) polygon. */ - Polygon_with_holes_2 boundary(pwh.outer_boundary(), fit, fit); - //unbounded outer boundaries contain all the holes and are OK - if (boundary.is_unbounded()) - return true; - /*do_intersect predicate will not suffice as hole can be completely outside + (simple) polygon. */ + Polygon_with_holes_2 boundary(pwh.outer_boundary(), fit, fit); + + // Unbounded outer boundaries contain all the holes and the holes were checked + // and are OK. + if (boundary.is_unbounded()) + return true; + + /*do_intersect predicate will not suffice as hole can be completely outside the outer boundary in an (extremely strange) case The gps now contains all the holes. the difference between the boundary and a union of all - the holes should be the empty set. For performance reasons, we use a customized overlay traits and - perform an arrangement overlay instead of difference */ - ValidationOverlayTraits valOverlayTraits; - valOverlayTraits.setHoleOverlap(false); - Polygon_set_2 gps2(traits); + the holes should be the empty set. For performance reasons, we use a customized overlay traits and + perform an arrangement overlay instead of difference */ + ValidationOverlayTraits valOverlayTraits; + valOverlayTraits.setHoleOverlap(false); + Polygon_set_2 gps2(traits); - Arrangement_2 boundary_arr = gps2.arrangement(); - gps2._insert(boundary,boundary_arr); - Arrangement_2 holes_arr = gps.arrangement(); - Arrangement_2 output_arr; - overlay(holes_arr, boundary_arr, output_arr, valOverlayTraits); - if (valOverlayTraits.getHoleOverlap()) - return false; + Arrangement_2 boundary_arr = gps2.arrangement(); + gps2._insert(boundary,boundary_arr); + Arrangement_2 holes_arr = gps.arrangement(); + Arrangement_2 output_arr; + overlay(holes_arr, boundary_arr, output_arr, valOverlayTraits); + if (valOverlayTraits.getHoleOverlap()) + return false; - /*old code that works less efficiently than the new overly traits + /*old code that works less efficiently than the new overly traits gps.validation_difference(boundary); //if gps is not empty at least one hole intersected the boundary if (!gps.is_empty()) - return (false); - */ - return (true); - } + return (false); + */ + return (true); +} - /*A valid polygon with holes is : - * 1 - Has empty or closed boundary and all the holes are closed - * 2 - The PWH is relatively simple polygon (holes are simple...) - * 3 - Has it's boundary oriented counterclockwise and the holes oriented clockwise - * 4 - All the segments (boundry and holes) do not cross or intersect in their relative interior - * 5 - The holes are on the interior of the boundary polygon if the boundary is not empty - */ - template - bool is_valid_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) - { - bool closed = is_closed_polygon_with_holes(pgn,traits); - CGAL_warning_msg (closed, - "The polygon's boundary or one of it's holes is not closed."); - if (! closed) - return (false); +/*A valid polygon with holes is : + * 1 - Has empty or closed boundary and all the holes are closed + * 2 - The PWH is relatively simple polygon (holes are simple...) + * 3 - Has it's boundary oriented counterclockwise and the holes oriented clockwise + * 4 - All the segments (boundry and holes) do not cross or intersect in their relative interior + * 5 - The holes are on the interior of the boundary polygon if the boundary is not empty + */ +template +bool is_valid_polygon_with_holes(const typename Traits_2::Polygon_with_holes_2& pgn, Traits_2 traits) +{ + bool closed = is_closed_polygon_with_holes(pgn,traits); + CGAL_warning_msg (closed, + "The polygon's boundary or one of it's holes is not closed."); + if (! closed) + return (false); - bool relatively_simple = is_relatively_simple_polygon_with_holes(pgn,traits); - CGAL_warning_msg (relatively_simple, - "The polygon is not relatively simple."); - if (! relatively_simple) - return (false); + bool relatively_simple = is_relatively_simple_polygon_with_holes(pgn,traits); + CGAL_warning_msg (relatively_simple, + "The polygon is not relatively simple."); + if (! relatively_simple) + return (false); - bool no_cross = is_crossover_outer_boundary(pgn, traits); - CGAL_warning_msg (no_cross, - "The polygon has a crossover."); - if (!no_cross) - return (false); + bool no_cross = is_crossover_outer_boundary(pgn, traits); + CGAL_warning_msg (no_cross, + "The polygon has a crossover."); + if (!no_cross) + return (false); - bool valid_orientation = has_valid_orientation_polygon_with_holes(pgn,traits); - CGAL_warning_msg (valid_orientation, - "The polygon has a wrong orientation."); - if (! valid_orientation) - return (false); + bool valid_orientation = has_valid_orientation_polygon_with_holes(pgn,traits); + CGAL_warning_msg (valid_orientation, + "The polygon has a wrong orientation."); + if (! valid_orientation) + return (false); - bool holes_disjoint = are_holes_and_boundary_pairwise_disjoint(pgn,traits); - CGAL_warning_msg (holes_disjoint, - "Holes of the PWH intersect amongst themselves or with outer boundary"); - if (! holes_disjoint) - return false; + bool holes_disjoint = are_holes_and_boundary_pairwise_disjoint(pgn,traits); + CGAL_warning_msg (holes_disjoint, + "Holes of the PWH intersect amongst themselves or with outer boundary"); + if (! holes_disjoint) + return false; - return (true); - } + return (true); +} - template - bool is_valid_unknown_polygon(const typename Traits_2::Polygon_with_holes_2& pgn, - Traits_2 traits) - { - return is_valid_polygon_with_holes(pgn, traits); - } +template +bool is_valid_unknown_polygon(const typename Traits_2::Polygon_with_holes_2& pgn, + Traits_2 traits) +{ + return is_valid_polygon_with_holes(pgn, traits); +} - template - bool is_valid_unknown_polygon(const typename Traits_2::Polygon_2& pgn, - Traits_2 traits) - { - return is_valid_polygon(pgn, traits); - } +template +bool is_valid_unknown_polygon(const typename Traits_2::Polygon_2& pgn, + Traits_2 traits) +{ + return is_valid_polygon(pgn, traits); +} CGAL_END_NAMESPACE diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_utils.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_utils.h index 3d2f2efa98e..cbe96450d68 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_utils.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_utils.h @@ -17,6 +17,7 @@ // // Author(s) : Baruch Zukerman // Efi Fogel +// Ophir Setter #ifndef CGAL_GPS_UTILS_H #define CGAL_GPS_UTILS_H @@ -30,32 +31,47 @@ #include -template -void General_polygon_set_2:: +template +void General_polygon_set_on_surface_2:: construct_polygon(Ccb_halfedge_const_circulator ccb, Polygon_2 & pgn, Traits_ * tr) { - typedef CGAL::Ccb_curve_iterator Ccb_curve_iterator; + typedef CGAL::Ccb_curve_iterator + Ccb_curve_iterator; Ccb_curve_iterator begin(ccb, false); Ccb_curve_iterator end(ccb, true); tr->construct_polygon_2_object()(begin, end, pgn); } - +// The comments below was written after trying to understand what the visitors +// do. There was no comment by the author of this class. +// This class is used afterwards to extract polygons from the representing +// arrangement. +// This scanner is not the same as the Gps_bfs_scanner. In this file, the +// Gps_bfs_scanner is used with Init_faces_visitor to init the faces of the +// representing arrangement. +// It seems that Gps_bfs_scanner is used for a regular bfs scan on the faces +// of the arrangements, with comparison to Arr_bfs_scanner that cares about +// inner ccbs and outer ccbs (it treats them differently). +// If this is the case, we should unite Gps_bfs_scanner with the regular +// adaptation of arrangement to boost graph. template class Arr_bfs_scanner { public: - typedef typename Arrangement::Traits_2 Gps_traits; - typedef typename Arrangement::Dcel Gps_dcel; + typedef typename Arrangement::Geometry_traits_2 Gps_traits; + typedef typename Arrangement::Topology_traits Gps_top_traits; typedef typename Gps_traits::Polygon_2 Polygon_2; typedef typename Gps_traits::Polygon_with_holes_2 Polygon_with_holes_2; typedef typename Arrangement::Ccb_halfedge_const_circulator Ccb_halfedge_const_circulator; typedef typename Arrangement::Face_const_iterator Face_const_iterator; typedef typename Arrangement::Halfedge_const_iterator Halfedge_const_iterator; - typedef typename Arrangement::Inner_ccb_const_iterator Hole_const_iterator; + typedef typename Arrangement::Outer_ccb_const_iterator + Outer_ccb_const_iterator; + typedef typename Arrangement::Inner_ccb_const_iterator + Inner_ccb_const_iterator; protected: @@ -74,40 +90,47 @@ public: void scan(Arrangement& arr) { - Face_const_iterator ubf = arr.unbounded_face(); - Hole_const_iterator holes_it; + Face_const_iterator ubf; + for (ubf = arr.faces_begin(); ubf != arr.faces_end(); ++ubf) + { + if (ubf->number_of_outer_ccbs() != 0) + continue; + if (ubf->visited()) + continue; + + Inner_ccb_const_iterator holes_it; + if (!ubf->contained()) + { + ubf->set_visited(true); + for (holes_it = ubf->inner_ccbs_begin(); + holes_it != ubf->inner_ccbs_end(); ++holes_it) + { + scan_ccb (*holes_it); + } + } + else + { + // ubf is contained -> unbounded polygon !! + scan_contained_ubf(ubf); + + } + + while(!m_holes_q.empty()) + { + Face_const_iterator top_f = m_holes_q.front(); + m_holes_q.pop(); + top_f->set_visited(true); + for (holes_it = top_f->inner_ccbs_begin(); + holes_it != top_f->inner_ccbs_end(); ++holes_it) + { + scan_ccb(*holes_it); + } + + //scan_uncontained_face(top_f->outer_ccb()); + } + } + Face_const_iterator fit; - - if (!ubf->contained()) - { - ubf->set_visited(true); - for (holes_it = ubf->holes_begin(); - holes_it != ubf->holes_end(); ++holes_it) - { - scan_ccb (*holes_it); - } - } - else - { - // ubf is contained -> unbounded polygon !! - scan_contained_ubf(ubf); - - } - - while(!m_holes_q.empty()) - { - Face_const_iterator top_f = m_holes_q.front(); - m_holes_q.pop(); - top_f->set_visited(true); - for (holes_it = top_f->holes_begin(); - holes_it != top_f->holes_end(); ++holes_it) - { - scan_ccb(*holes_it); - } - - //scan_uncontained_face(top_f->outer_ccb()); - } - for (fit = arr.faces_begin(); fit != arr.faces_end(); ++fit) { fit->set_visited(false); @@ -123,7 +146,7 @@ public: { Polygon_2 pgn_boundary; - General_polygon_set_2:: + General_polygon_set_on_surface_2:: construct_polygon(ccb, pgn_boundary, m_traits); Ccb_halfedge_const_circulator ccb_end = ccb; @@ -135,9 +158,10 @@ public: ++ccb; } while(ccb != ccb_end); - Polygon_with_holes_2 pgn = m_traits->construct_polygon_with_holes_2_object()(pgn_boundary, - m_pgn_holes.begin(), - m_pgn_holes.end()); + Polygon_with_holes_2 pgn = + m_traits->construct_polygon_with_holes_2_object()(pgn_boundary, + m_pgn_holes.begin(), + m_pgn_holes.end()); /*Polygon_with_holes_2 pgn(pgn_boundary, m_pgn_holes.begin(), m_pgn_holes.end());*/ @@ -148,13 +172,14 @@ public: void scan_contained_ubf(Face_const_iterator ubf) { - CGAL_assertion(ubf->is_unbounded() && ubf->contained()); + CGAL_assertion(ubf->number_of_outer_ccbs() == 0 && ubf->contained()); // ubf is contained -> unbounded polygon !! all_incident_faces(ubf); Polygon_2 boundary; - Polygon_with_holes_2 pgn = m_traits->construct_polygon_with_holes_2_object()(boundary, - m_pgn_holes.begin(), - m_pgn_holes.end()); + Polygon_with_holes_2 pgn = + m_traits->construct_polygon_with_holes_2_object()(boundary, + m_pgn_holes.begin(), + m_pgn_holes.end()); /*Polygon_with_holes_2 pgn(boundary, m_pgn_holes.begin(), m_pgn_holes.end());*/ @@ -168,37 +193,46 @@ public: { CGAL_assertion(!f->visited()); f->set_visited(true); - if (!f->is_unbounded()) + if (f->number_of_outer_ccbs() != 0) { if (!f->contained()) { - m_pgn_holes.push_back(Polygon_2()); - General_polygon_set_2:: - construct_polygon(f->outer_ccb(), m_pgn_holes.back(), m_traits); + for (Outer_ccb_const_iterator oci = f->outer_ccbs_begin(); + oci != f->outer_ccbs_end(); ++oci) + { + m_pgn_holes.push_back(Polygon_2()); + General_polygon_set_on_surface_2:: + construct_polygon(*oci, m_pgn_holes.back(), m_traits); + } + m_holes_q.push(f); } - Ccb_halfedge_const_circulator ccb_end = f->outer_ccb(); - Ccb_halfedge_const_circulator ccb_circ = ccb_end; - do - { - //get the current halfedge on the face boundary - Halfedge_const_iterator he = ccb_circ; - Face_const_iterator new_f = he->twin()->face(); - if (!new_f->visited()) - { - all_incident_faces(new_f); + for (Outer_ccb_const_iterator oci = f->outer_ccbs_begin(); + oci != f->outer_ccbs_end(); ++oci) + { + Ccb_halfedge_const_circulator ccb_end = *oci; + Ccb_halfedge_const_circulator ccb_circ = ccb_end; + do + { + //get the current halfedge on the face boundary + Halfedge_const_iterator he = ccb_circ; + Face_const_iterator new_f = he->twin()->face(); + if (!new_f->visited()) + { + all_incident_faces(new_f); + } + ++ccb_circ; } - ++ccb_circ; + while(ccb_circ != ccb_end); } - while(ccb_circ != ccb_end); } if (f->contained()) { - Hole_const_iterator hit; - for(hit = f->holes_begin(); hit != f->holes_end(); ++hit) + Inner_ccb_const_iterator hit; + for(hit = f->inner_ccbs_begin(); hit != f->inner_ccbs_end(); ++hit) { Ccb_halfedge_const_circulator ccb_of_hole = *hit; Halfedge_const_iterator he = ccb_of_hole; @@ -207,11 +241,10 @@ public: CGAL_assertion(!he->twin()->face()->contained()); m_pgn_holes.push_back(Polygon_2()); - General_polygon_set_2:: + General_polygon_set_on_surface_2:: construct_polygon(he->twin()->face()->outer_ccb(), m_pgn_holes.back(), m_traits); m_holes_q.push(he->twin()->face()); - } else { @@ -259,17 +292,34 @@ class Init_faces_visitor public: - void flip_face(Face_iterator f1, Face_iterator f2, Halfedge_iterator /*he*/) + //! discovered_face +/*! discovered_face is called by Gps_bfs_scanner when it reveals a new face + during a BFS scan. It is important to say that I have a strong suspition + that this place is the reason why discovered_face was once called + "flip_face" (WTF?) + \param old_f The face that was already revealed + \param new_f The face that we have just now revealed +*/ + void discovered_face(Face_iterator old_f, + Face_iterator new_f, + Halfedge_iterator /*he*/) { - f2->set_contained(!f1->contained()); + new_f->set_contained(!old_f->contained()); } }; - -template -void General_polygon_set_2:: -_insert(const Polygon_2& pgn, Arrangement_2 & arr) + +//! _insert +/*! The function inserts a polygon into an arrangement, assuming that the + polygon is contained in one face of the arrangement. + \param pgn The polygon to be inserted to the arrangement. pgn must be + completely disjoint from the arrangement + \param arr The arrangement to insert the polygon to. +*/ +template +void General_polygon_set_on_surface_2:: +_insert(const Polygon_2& pgn, Arrangement_on_surface_2 & arr) { - typedef Arr_accessor Arr_accessor; + typedef Arr_accessor Arr_accessor; Arr_accessor accessor(arr); Compare_endpoints_xy_2 cmp_ends = m_traits->compare_endpoints_xy_2_object(); @@ -283,23 +333,29 @@ _insert(const Polygon_2& pgn, Arrangement_2 & arr) Curve_const_iterator curr = itr_pair.first; Curve_const_iterator end = itr_pair.second; - Face_iterator f; - if (arr.is_empty()) + const Arr_parameter_space ps_x = + m_traits_adaptor.parameter_space_in_x_2_object()(*curr, ARR_MIN_END); + const Arr_parameter_space ps_y = + m_traits_adaptor.parameter_space_in_y_2_object()(*curr, ARR_MIN_END); + + Object obj_f; + if ((ps_x == ARR_INTERIOR) && (ps_y == ARR_INTERIOR)) { - f = arr.unbounded_face(); + Point_location pl(arr); + obj_f = pl.locate(m_traits->construct_min_vertex_2_object()(*curr)); } else { - Walk_pl pl(arr); - - Object obj = pl.locate(m_traits->construct_min_vertex_2_object()(*curr)); - - Face_const_iterator const_f; - // pgn must be completely disjoint from the arrangement - CGAL_assertion(CGAL::assign(const_f, obj) && !const_f->contained()); - CGAL::assign(const_f, obj); - f = arr.non_const_handle(const_f); + obj_f = accessor.locate_curve_end(*curr, ARR_MIN_END, ps_x, ps_y); } + + Face_const_handle const_f; + // face should not be contained as the pgn is completly disjoint of the + // arrangement. + CGAL_assertion(CGAL::assign(const_f, obj_f) && !const_f->contained()); + CGAL::assign(const_f, obj_f); + Face_iterator f = arr.non_const_handle(const_f); + Halfedge_handle first_he = arr.insert_in_face_interior(*curr, f); //first_he is directed from left to right (see insert_in_face_interior) @@ -332,8 +388,7 @@ _insert(const Polygon_2& pgn, Arrangement_2 & arr) cmp_ends(*temp), new_face_created); CGAL_assertion(new_face_created); - CGAL_assertion((he->face() != he->twin()->face()) && - (he->face() != arr.unbounded_face())); + CGAL_assertion((he->face() != he->twin()->face())); he->face()->set_contained(true); return; @@ -365,36 +420,36 @@ _insert(const Polygon_2& pgn, Arrangement_2 & arr) cmp_ends(last_cv), new_face_created); CGAL_assertion(new_face_created); - CGAL_assertion((last_he->face() != last_he->twin()->face()) && - (last_he->face() != arr.unbounded_face())); + CGAL_assertion((last_he->face() != last_he->twin()->face())); last_he->face()->set_contained(true); } -template +template template -void General_polygon_set_2:: +void General_polygon_set_on_surface_2:: insert(PolygonIter p_begin, PolygonIter p_end) { typename std::iterator_traits::value_type pgn; - //check validity of all polygons - for( ; p_begin != p_end; ++p_begin) + //check validity of all polygons + for( ; p_begin != p_end; ++p_begin) { - CGAL_precondition(is_valid_unkown_polygon(*p_begin, *m_traits)); + CGAL_precondition(is_valid_unknown_polygon(*p_begin, *m_traits)); } + _insert(p_begin, p_end, pgn); } -template +template template -void General_polygon_set_2:: +void General_polygon_set_on_surface_2:: insert(PolygonIter p_begin, PolygonIter p_end, PolygonWithHolesIter pwh_begin, PolygonWithHolesIter pwh_end) { typedef std::list XCurveList; - typedef Init_faces_visitor My_visitor; - typedef Gps_bfs_scanner Arr_bfs_scanner; + typedef Init_faces_visitor My_visitor; + typedef Gps_bfs_scanner Arr_bfs_scanner; XCurveList xcurve_list; @@ -415,7 +470,14 @@ insert(PolygonIter p_begin, PolygonIter p_end, insert_non_intersecting_curves(*m_arr, xcurve_list.begin(), xcurve_list.end()); if (is_unbounded) - m_arr->unbounded_face()->set_contained(true); + { + for (Face_iterator fit = m_arr->faces_begin(); + fit != m_arr->faces_end(); ++fit) + { + if (fit->number_of_outer_ccbs() == 0) + fit->set_contained(true); + } + } My_visitor v; Arr_bfs_scanner scanner(v); @@ -424,9 +486,9 @@ insert(PolygonIter p_begin, PolygonIter p_end, } //insert a range of simple polygons to the arrangement -template +template template -void General_polygon_set_2:: +void General_polygon_set_on_surface_2:: _insert(PolygonIter p_begin, PolygonIter p_end, Polygon_2 & /*pgn*/) { for(PolygonIter pitr = p_begin; pitr != p_end; ++pitr) @@ -435,14 +497,14 @@ _insert(PolygonIter p_begin, PolygonIter p_end, Polygon_2 & /*pgn*/) } } -template +template template -void General_polygon_set_2:: +void General_polygon_set_on_surface_2:: _insert(PolygonIter p_begin, PolygonIter p_end, Polygon_with_holes_2 & /*pgn*/) { typedef std::list XCurveList; - typedef Init_faces_visitor My_visitor; - typedef Gps_bfs_scanner Arr_bfs_scanner; + typedef Init_faces_visitor My_visitor; + typedef Gps_bfs_scanner Arr_bfs_scanner; XCurveList xcurve_list; bool is_unbounded = false; @@ -456,7 +518,14 @@ _insert(PolygonIter p_begin, PolygonIter p_end, Polygon_with_holes_2 & /*pgn*/) insert_non_intersecting_curves(*m_arr, xcurve_list.begin(), xcurve_list.end()); if (is_unbounded) - m_arr->unbounded_face()->set_contained(true); + { + for (Face_iterator fit = m_arr->faces_begin(); + fit != m_arr->faces_end(); ++fit) + { + if (fit->number_of_outer_ccbs() == 0) + fit->set_contained(true); + } + } My_visitor v; Arr_bfs_scanner scanner(v); @@ -464,18 +533,17 @@ _insert(PolygonIter p_begin, PolygonIter p_end, Polygon_with_holes_2 & /*pgn*/) _reset_faces(m_arr); } - - //insert non-sipmle poloygons with holes (non incident edges may have +//insert non-sipmle poloygons with holes (non incident edges may have // common vertex, but they dont intersect at their interior -template -void General_polygon_set_2:: -_insert(const Polygon_with_holes_2 & pgn, Arrangement_2 & arr) +template +void General_polygon_set_on_surface_2:: +_insert(const Polygon_with_holes_2 & pgn, Arrangement_on_surface_2 & arr) { //not needed gps.insert(PWH) has the precondition // CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); typedef std::list XCurveList; - typedef Init_faces_visitor My_visitor; - typedef Gps_bfs_scanner Arr_bfs_scanner; + typedef Init_faces_visitor My_visitor; + typedef Gps_bfs_scanner Arr_bfs_scanner; XCurveList xcurve_list; _construct_curves(pgn, std::back_inserter(xcurve_list)); @@ -483,7 +551,14 @@ _insert(const Polygon_with_holes_2 & pgn, Arrangement_2 & arr) //if (pgn.is_unbounded()) if (m_traits->construct_is_unbounded_object()(pgn)) - arr.unbounded_face()->set_contained(true); + { + for (Face_iterator fit = arr.faces_begin(); + fit != arr.faces_end(); ++fit) + { + if (fit->number_of_outer_ccbs() == 0) + fit->set_contained(true); + } + } My_visitor v; Arr_bfs_scanner scanner(v); @@ -491,10 +566,10 @@ _insert(const Polygon_with_holes_2 & pgn, Arrangement_2 & arr) _reset_faces(&arr); } -template +template template void -General_polygon_set_2:: +General_polygon_set_on_surface_2:: _construct_curves(const Polygon_2 & pgn, OutputIterator oi) { std::pair +template template -void General_polygon_set_2:: +void General_polygon_set_on_surface_2:: _construct_curves(const Polygon_with_holes_2 & pgn, OutputIterator oi) { //if (!pgn.is_unbounded()) @@ -517,7 +592,8 @@ _construct_curves(const Polygon_with_holes_2 & pgn, OutputIterator oi) m_traits->construct_curves_2_object()(pgn_boundary); std::copy (itr_pair.first, itr_pair.second, oi); } - std::pair hpair = m_traits->construct_holes_object()(pgn); + std::pair hpair = + m_traits->construct_holes_object()(pgn); GP_Holes_const_iterator hit; for (hit = hpair.first; hit != hpair.second; ++hit) { @@ -529,26 +605,26 @@ _construct_curves(const Polygon_with_holes_2 & pgn, OutputIterator oi) } } -template +template template OutputIterator -General_polygon_set_2:: +General_polygon_set_on_surface_2:: polygons_with_holes(OutputIterator out) const { - typedef Arr_bfs_scanner Arr_bfs_scanner; + typedef Arr_bfs_scanner Arr_bfs_scanner; Arr_bfs_scanner scanner(this->m_traits, out); scanner.scan(*(this->m_arr)); return (scanner.output_iterator()); } -template -typename General_polygon_set_2::Size -General_polygon_set_2:: +template +typename General_polygon_set_on_surface_2::Size +General_polygon_set_on_surface_2:: number_of_polygons_with_holes() const { - typedef Arr_bfs_scanner + typedef Arr_bfs_scanner Arr_bfs_scanner; //counting_output_operator CTOR reqires a parameter std::size_t *cc = new size_t(); @@ -557,11 +633,12 @@ number_of_polygons_with_holes() const return (scanner.output_iterator().current_counter()); } -template -bool General_polygon_set_2:: + +template +bool General_polygon_set_on_surface_2:: locate(const Point_2& q, Polygon_with_holes_2& pgn) const { - Walk_pl pl(*m_arr); + Point_location pl(*m_arr); Object obj = pl.locate(q); Face_const_iterator f; @@ -601,7 +678,7 @@ locate(const Point_2& q, Polygon_with_holes_2& pgn) const } typedef Oneset_iterator OutputItr; - typedef Arr_bfs_scanner Arr_bfs_scanner; + typedef Arr_bfs_scanner Arr_bfs_scanner; OutputItr oi (pgn); Arr_bfs_scanner scanner(this->m_traits, oi); @@ -609,10 +686,17 @@ locate(const Point_2& q, Polygon_with_holes_2& pgn) const Ccb_halfedge_const_circulator ccb_of_pgn = get_boundary_of_polygon(f); this->_reset_faces(); - if (ccb_of_pgn == Ccb_halfedge_const_circulator()) // the polygon has no boundary + if (ccb_of_pgn == Ccb_halfedge_const_circulator()) { + // the polygon has no boundary + // f is unbounded - scanner.scan_contained_ubf(m_arr->unbounded_face()); + for (Face_iterator fit = m_arr->faces_begin(); fit != m_arr->faces_end(); + ++fit) + { + if (fit->number_of_outer_ccbs() == 0) + scanner.scan_contained_ubf(fit); + } } else { @@ -626,19 +710,27 @@ locate(const Point_2& q, Polygon_with_holes_2& pgn) const return true; } -template -typename General_polygon_set_2::Ccb_halfedge_const_circulator -General_polygon_set_2:: +template +typename General_polygon_set_on_surface_2::Ccb_halfedge_const_circulator +General_polygon_set_on_surface_2:: get_boundary_of_polygon(Face_const_iterator f) const { CGAL_assertion(!f->visited()); f->set_visited(true); - if (f->is_unbounded()) + if (f->number_of_outer_ccbs() == 0) // (f->is_unbounded()) { return Ccb_halfedge_const_circulator(); } - Ccb_halfedge_const_circulator ccb_end = f->outer_ccb(); + + // We assume that a polygon has only one outer_ccb. This code does not handle + // the case where there are more than 1 outer ccbs. If this is the case, we + // need to devise a method to convert the outer ccbs to inner ccbs so we + // will have only one outer ccb. + if (f->number_of_outer_ccbs() > 1) + CGAL_error_msg("Not implemented yet."); + + Ccb_halfedge_const_circulator ccb_end = *f->outer_ccbs_begin(); Ccb_halfedge_const_circulator ccb_circ = ccb_end; do { @@ -659,12 +751,13 @@ get_boundary_of_polygon(Face_const_iterator f) const } -template -bool General_polygon_set_2:: +template +bool General_polygon_set_on_surface_2:: is_hole_of_face(Face_const_handle f, Halfedge_const_handle he) const { - Hole_const_iterator holes_it; - for (holes_it = f->holes_begin(); holes_it != f->holes_end(); ++holes_it) + Inner_ccb_const_iterator holes_it; + for (holes_it = f->inner_ccbs_begin(); + holes_it != f->inner_ccbs_end(); ++holes_it) { Ccb_halfedge_const_circulator ccb = *holes_it; Ccb_halfedge_const_circulator ccb_end = ccb; diff --git a/Boolean_set_operations_2/include/CGAL/General_polygon_set_2.h b/Boolean_set_operations_2/include/CGAL/General_polygon_set_2.h index 4ebd4875d70..4a48f28b2d3 100644 --- a/Boolean_set_operations_2/include/CGAL/General_polygon_set_2.h +++ b/Boolean_set_operations_2/include/CGAL/General_polygon_set_2.h @@ -22,1296 +22,86 @@ #define CGAL_GENERAL_POLYGON_SET_2_H #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include CGAL_BEGIN_NAMESPACE // General_polygon_set_2 template > -class General_polygon_set_2 +class General_polygon_set_2 : public General_polygon_set_on_surface_2 + ::Traits> { public: typedef Traits_ Traits_2; typedef Dcel_ Dcel; - typedef typename Traits_2::Polygon_2 Polygon_2; - typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; - typedef CGAL::Arrangement_2 Arrangement_2; - typedef std::size_t Size; -private: - typedef General_polygon_set_2 Self; - typedef typename Traits_2::Point_2 Point_2; - typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; - - typedef typename Polygon_with_holes_2::Hole_const_iterator - GP_Holes_const_iterator; - typedef typename Traits_2::Curve_const_iterator Curve_const_iterator; - typedef typename Traits_2::Compare_endpoints_xy_2 - Compare_endpoints_xy_2; - typedef typename Traits_2::Construct_opposite_2 Construct_opposite_2; + typedef General_polygon_set_2< Traits_, Dcel_ > Self; + typedef General_polygon_set_on_surface_2 ::Traits> Base; - typedef typename Arrangement_2::Face_const_iterator Face_const_iterator; - typedef typename Arrangement_2::Halfedge_const_iterator - Halfedge_const_iterator; - typedef typename Arrangement_2::Vertex_const_iterator Vertex_const_iterator; - typedef typename Arrangement_2::Edge_const_iterator Edge_const_iterator; - typedef typename Arrangement_2::Inner_ccb_const_iterator Hole_const_iterator; - typedef typename Arrangement_2::Ccb_halfedge_const_circulator - Ccb_halfedge_const_circulator; - typedef typename Arrangement_2::Face_iterator Face_iterator; - typedef typename Arrangement_2::Halfedge_iterator Halfedge_iterator; - typedef typename Arrangement_2::Vertex_iterator Vertex_iterator; - typedef typename Arrangement_2::Edge_iterator Edge_iterator; - typedef typename Arrangement_2::Inner_ccb_iterator Hole_iterator; - typedef typename Arrangement_2::Ccb_halfedge_circulator - Ccb_halfedge_circulator; - typedef typename Arrangement_2::Face_handle Face_handle; - typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; - typedef typename Arrangement_2::Vertex_handle Vertex_handle; - - typedef typename Arrangement_2::Face_const_handle Face_const_handle; - typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; - - typedef typename Arrangement_2::Halfedge_around_vertex_const_circulator - Halfedge_around_vertex_const_circulator; - - typedef std::pair *> Arr_entry; - typedef Arr_walk_along_line_point_location Walk_pl; + typedef typename Base::Arrangement_on_surface_2 Arrangement_2; protected: - - Traits_2* m_traits; - bool m_traits_owner; - - // the underlying arrangement - Arrangement_2* m_arr; - + typedef typename Base::Polygon_2 Polygon_2; + typedef typename Base::Polygon_with_holes_2 Polygon_with_holes_2; public: // default costructor - General_polygon_set_2() : m_traits(new Traits_2()), - m_traits_owner(true), - m_arr(new Arrangement_2(m_traits)) + General_polygon_set_2() : Base() {} // constructor with traits object - General_polygon_set_2(Traits_2& tr) : m_traits(&tr), - m_traits_owner(false), - m_arr(new Arrangement_2(m_traits)) + General_polygon_set_2(Traits_2& tr) : Base(tr) {} - - General_polygon_set_2(const Self& ps) : - m_traits(new Traits_2(*(ps.m_traits))), - m_traits_owner(true), - m_arr(new Arrangement_2(*(ps.m_arr))) - {} - - - General_polygon_set_2& operator=(const Self& ps) - { - if (this == &ps) - return (*this); - - if (m_traits_owner) - delete m_traits; - delete m_arr; - m_traits = new Traits_2(*(ps.m_traits)); - m_traits_owner = true; - m_arr = new Arrangement_2(*(ps.m_arr)); - return (*this); - } - - explicit General_polygon_set_2(const Polygon_2& pgn) : - m_traits(new Traits_2()), - m_traits_owner(true), - m_arr(new Arrangement_2(m_traits)) - { - CGAL_precondition(is_valid_polygon(pgn, *m_traits)); - _insert(pgn, *m_arr); - } + Base(pgn) + { } explicit General_polygon_set_2(const Polygon_with_holes_2& pgn_with_holes): - m_traits(new Traits_2()), - m_traits_owner(true), - m_arr(new Arrangement_2(m_traits)) - { - CGAL_precondition(is_valid_polygon_with_holes(pgn_with_holes,*m_traits)); - _insert(pgn_with_holes, *m_arr); - } - -private: - General_polygon_set_2(Arrangement_2* arr) : m_traits(new Traits_2()), - m_traits_owner(true), - m_arr(arr) - {} - -public: - //destructor - virtual ~General_polygon_set_2() - { - delete m_arr; - - if (m_traits_owner) - delete m_traits; - } - - void simplify(const Polygon_2& pgn, Polygon_with_holes_2& res) - { - typedef Gps_polygon_simplifier Simplifier; - - Arrangement_2* arr = new Arrangement_2(); - - Simplifier simp(*arr, *m_traits); - simp.simplify(pgn); - _remove_redundant_edges(arr); - Self gps(arr); - gps._reset_faces(); - - typedef Oneset_iterator OutputItr; - OutputItr oi (res); - gps.polygons_with_holes(oi); - } - - // insert a simple polygon - void insert(const Polygon_2& pgn) - { - CGAL_precondition(is_valid_polygon(pgn, *m_traits)); - _insert(pgn, *m_arr); - } - - // insert a polygon with holes - void insert(const Polygon_with_holes_2& pgn_with_holes) - { - CGAL_precondition(is_valid_polygon_with_holes(pgn_with_holes, *m_traits)); - _insert(pgn_with_holes, *m_arr); - } - - // insert a range of polygons that can be either simple polygons - // or polygons with holes - // precondition: the polygons are disjoint and simple - template - void insert(PolygonIterator pgn_begin, PolygonIterator pgn_end); - - - // insert two ranges of : the first one for simple polygons, - // the second one for polygons with holes - // precondition: the first range is disjoint simple polygons - // the second range is disjoint polygons with holes - template - void insert(PolygonIterator pgn_begin, PolygonIterator pgn_end, - PolygonWithHolesIterator pgn_with_holes_begin, - PolygonWithHolesIterator pgn_with_holes_end); - - // test for intersection with a simple polygon - bool do_intersect(const Polygon_2 &pgn) const - { - CGAL_precondition(is_valid_polygon(pgn,*m_traits)); - Self other(pgn); - return (do_intersect(other)); - } - - // test for intersection with a polygon with holes - bool do_intersect(const Polygon_with_holes_2& pgn_with_holes) const - { - CGAL_precondition(is_valid_polygon_with_holes(pgn_with_holes, *m_traits)); - Self other(pgn_with_holes); - return (do_intersect(other)); - } - - //test for intersection with another General_polygon_set_2 object - bool do_intersect(const Self& other) const - { - if (this->is_empty() || other.is_empty()) - return false; - - if (this->is_plane() || other.is_plane()) - return true; - - Arrangement_2 res_arr; - - Gps_do_intersect_functor func; - overlay(*m_arr, *(other.m_arr), res_arr, func); - return func.found_reg_intersection(); - } - - template - bool do_intersect(InputIterator begin, InputIterator end) - { - Self other(*this); - other.intersection(begin, end); - return (other.is_empty()); - } - - template - bool do_intersect(InputIterator1 begin1, InputIterator1 end1, - InputIterator2 begin2, InputIterator2 end2) - { - Self other(*this); - other.intersection(begin1, end1, begin2, end2); - return (other.is_empty()); - } + Base(pgn_with_holes) + { } + // For some reason the below functions (the ones that we call "using" for) + // are hidden by the function in this class and are not found in the parent's + // class (General_polygon_set_on_surface_2) when they are called on an + // object of type General_polygon_set_2. + // Check in the Vandervoorde / Stroustrup books what is the exact reason. + // (There may be a better and more correct solution.) + using Base::intersection; + using Base::join; + using Base::symmetric_difference; - // intersection with a simple polygon - void intersection(const Polygon_2& pgn) + inline void intersection(const Self& ps1, const Self& ps2) { - CGAL_precondition(is_valid_polygon(pgn, *m_traits)); - _intersection(pgn); + Base::intersection(static_cast(ps1), + static_cast(ps2)); } - // intersection with a polygon with holes - void intersection(const Polygon_with_holes_2& pgn) + inline void join(const Self& ps1, const Self& ps2) { - CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); - _intersection(pgn); + Base::join(static_cast(ps1), + static_cast(ps2)); } - //intersection with another General_polygon_set_2 object - void intersection(const Self& other) - { - _intersection(other); - } - - void intersection(const Self& gps1, const Self& gps2) - { - this->clear(); - _intersection(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); - } - - - // join with a simple polygon - void join(const Polygon_2& pgn) + inline void symmetric_difference(const Self& ps1, const Self& ps2) { - CGAL_precondition(is_valid_polygon(pgn, *m_traits)); - _join(pgn); + Base::symmetric_difference(static_cast(ps1), + static_cast(ps2)); } - // join with a polygon with holes - void join(const Polygon_with_holes_2& pgn) - { - CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); - _join(pgn); - } - - //join with another General_polygon_set_2 object - void join(const Self& other) - { - _join(other); - } - - void join(const Self& gps1, const Self& gps2) - { - this->clear(); - _join(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); - } - - // difference with a simple polygon - void difference (const Polygon_2& pgn) - { - CGAL_precondition(is_valid_polygon(pgn, *m_traits)); - _difference(pgn); - } - - // difference with a polygon with holes - void difference (const Polygon_with_holes_2& pgn) - { - CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); - _difference(pgn); - } - - //difference with another General_polygon_set_2 object - void difference (const Self& other) - { - _difference(other); - } - - void difference(const Self& gps1, const Self& gps2) - { - this->clear(); - _difference(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); - } - - - // symmetric_difference with a simple polygon - void symmetric_difference(const Polygon_2& pgn) - { - CGAL_precondition(is_valid_polygon(pgn, *m_traits)); - _symmetric_difference(pgn); - } - - // symmetric_difference with a polygon with holes - void symmetric_difference(const Polygon_with_holes_2& pgn) - { - CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); - _symmetric_difference(pgn); - } - - //symmetric_difference with another General_polygon_set_2 object - void symmetric_difference(const Self& other) - { - _symmetric_difference(other); - } - - void symmetric_difference(const Self& gps1, const Self& gps2) - { - this->clear(); - _symmetric_difference(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); - } - - - void complement() - { - this->_complement(m_arr); - } - - void complement(const Self& other) - { - *(this->m_arr) = *(other.m_arr); - this->complement(); - } - - // TODO: move to private (or prot. area) - void _complement(Arrangement_2* arr) - { - for (Face_iterator fit = arr->faces_begin(); - fit != arr->faces_end(); - ++fit) - { - fit->set_contained(!fit->contained()); - } - - Construct_opposite_2 ctr_opp = m_traits->construct_opposite_2_object(); - for (Edge_iterator eit = arr->edges_begin(); - eit != arr->edges_end(); - ++eit) - { - Halfedge_handle he = eit; - const X_monotone_curve_2& cv = he->curve(); - arr->modify_edge(he, ctr_opp(cv)); - } - } - - //fix the directions of the curves (given correct marked face) - // it should be called mostly after symmetric_difference. - void _fix_curves_direction(Arrangement_2& arr) - { - Compare_endpoints_xy_2 cmp_endpoints = - m_traits->compare_endpoints_xy_2_object(); - Construct_opposite_2 ctr_opp = m_traits->construct_opposite_2_object(); - - for (Edge_iterator eit = arr.edges_begin(); - eit != arr.edges_end(); - ++eit) - { - Halfedge_handle he = eit; - const X_monotone_curve_2& cv = he->curve(); - const bool is_cont = he->face()->contained(); - const Comparison_result he_res = ((Arr_halfedge_direction)he->direction() == ARR_LEFT_TO_RIGHT) ? - SMALLER : LARGER; - const bool has_same_dir = (cmp_endpoints(cv) == he_res); - - if ((is_cont && !has_same_dir) || (!is_cont && has_same_dir)) - arr.modify_edge(he, ctr_opp(cv)); - } - } - - void fix_curves_direction() - { - _fix_curves_direction(*m_arr); - } - - Size number_of_polygons_with_holes() const; - - Traits_2& traits() - { - return *m_traits; - } - - const Traits_2& traits() const - { - return *m_traits; - } - - bool is_empty() const - { - return (m_arr->is_empty() && ! m_arr->unbounded_face()->contained()); - } - - bool is_plane() const - { - return (m_arr->is_empty() && m_arr->unbounded_face()->contained()); - } - - void clear() - { - m_arr->clear(); - } - - - Oriented_side oriented_side(const Point_2& q) const - { - Walk_pl pl(*m_arr); - - Object obj = pl.locate(q); - Face_const_iterator f; - if (CGAL::assign(f, obj)) - { - if (f->contained()) - return ON_POSITIVE_SIDE; - - return ON_NEGATIVE_SIDE ; - } - return ON_ORIENTED_BOUNDARY ; - } - - Oriented_side oriented_side(const Polygon_2& pgn) const - { - CGAL_precondition(is_valid_polygon(pgn, *m_traits)); - Self other(pgn); - return (oriented_side(other)); - } - - Oriented_side oriented_side(const Polygon_with_holes_2& pgn) const - { - CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); - Self other(pgn); - return (oriented_side(other)); - } - - Oriented_side oriented_side(const Self& other) const - { - if (this->is_empty() || other.is_empty()) - return ON_NEGATIVE_SIDE; - - if (this->is_plane() || other.is_plane()) - return ON_POSITIVE_SIDE; - - Arrangement_2 res_arr; - - Gps_do_intersect_functor func; - overlay(*m_arr, *(other.m_arr), res_arr, func); - if (func.found_reg_intersection()) - return ON_POSITIVE_SIDE; - - if (func.found_boundary_intersection()) - return ON_ORIENTED_BOUNDARY; - - return ON_NEGATIVE_SIDE; - } - - - // returns the location of the query point - bool locate(const Point_2& q, Polygon_with_holes_2& pgn) const; - - /*! Obtain a const reference to the underlying arrangement - * \return the underlying arrangement. - */ - const Arrangement_2& arrangement() const - { - return *m_arr; - } - - /*! Obtain a reference to the underlying arrangement - * \return the underlying arrangement. - */ - Arrangement_2 & arrangement() - { - return *m_arr; - } - - /*! */ - bool is_valid() const - { - if (!CGAL::is_valid(*m_arr)) - return false; - - Compare_endpoints_xy_2 cmp_endpoints = - m_traits->compare_endpoints_xy_2_object(); - Construct_opposite_2 ctr_opp = m_traits->construct_opposite_2_object(); - - for (Edge_const_iterator eci = m_arr->edges_begin(); - eci != m_arr->edges_end(); - ++eci) - { - Halfedge_const_handle he = eci; - if (he->face() == he->twin()->face()) - { - return false; - } - if (he->face()->contained() == he->twin()->face()->contained()) - { - return false; - } - - const X_monotone_curve_2& cv = he->curve(); - const bool is_cont = he->face()->contained(); - const Comparison_result he_res = ((Arr_halfedge_direction)he->direction() == ARR_LEFT_TO_RIGHT) ? - SMALLER : LARGER; - const bool has_same_dir = (cmp_endpoints(cv) == he_res); - - if ((is_cont && !has_same_dir) || (!is_cont && has_same_dir)) - return false; - } - return true; - } - - // get the simple polygons, takes O(n) - template - OutputIterator polygons_with_holes(OutputIterator out) const; - - // join a range of polygons - template - void join(InputIterator begin, InputIterator end, unsigned int k = 5) - { - typename std::iterator_traits::value_type pgn; - this->join(begin, end, pgn, k); - this->remove_redundant_edges(); - this->_reset_faces(); - } - - // join range of simple polygons - template - inline void join(InputIterator begin, - InputIterator end, - Polygon_2&, - unsigned int k=5) - { - std::vector arr_vec (std::distance(begin, end) + 1); - - arr_vec[0].first = this->m_arr; - unsigned int i = 1; - for (InputIterator itr = begin; itr!=end; ++itr, ++i) - { - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr, *(arr_vec[i].first)); - } - - Join_merge join_merge; - _build_sorted_vertices_vectors (arr_vec); - _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, join_merge); - - //the result arrangement is at index 0 - this->m_arr = arr_vec[0].first; - delete arr_vec[0].second; - } - - //join range of polygons with holes - template - inline void join(InputIterator begin, InputIterator end, - Polygon_with_holes_2&, unsigned int k=5) - { - std::vector arr_vec (std::distance(begin, end) + 1); - arr_vec[0].first = this->m_arr; - - unsigned int i = 1; - for (InputIterator itr = begin; itr!=end; ++itr, ++i) - { - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr, *(arr_vec[i].first)); - } - - Join_merge join_merge; - _build_sorted_vertices_vectors (arr_vec); - _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, join_merge); - - //the result arrangement is at index 0 - this->m_arr = arr_vec[0].first; - delete arr_vec[0].second; - } - - template - inline void join(InputIterator1 begin1, InputIterator1 end1, - InputIterator2 begin2, InputIterator2 end2, - unsigned int k=5) - { - std::vector arr_vec (std::distance(begin1, end1)+ - std::distance(begin2, end2)+1); - - arr_vec[0].first = this->m_arr; - unsigned int i = 1; - - for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i) - { - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr1, *(arr_vec[i].first)); - } - - for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i) - { - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr2, *(arr_vec[i].first)); - } - - Join_merge join_merge; - _build_sorted_vertices_vectors (arr_vec); - _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, join_merge); - - //the result arrangement is at index 0 - this->m_arr = arr_vec[0].first; - delete arr_vec[0].second; - this->remove_redundant_edges(); - this->_reset_faces(); - } - - - // intersect range of polygins - template - inline void intersection(InputIterator begin, InputIterator end, - unsigned int k=5) - { - typename std::iterator_traits::value_type pgn; - this->intersection(begin, end, pgn, k); - this->remove_redundant_edges(); - this->_reset_faces(); - } - - - // intersect range of simple polygons - template - inline void intersection(InputIterator begin, InputIterator end, - Polygon_2&, unsigned int k) - { - std::vector arr_vec (std::distance(begin, end) + 1); - arr_vec[0].first = this->m_arr; - unsigned int i = 1; - - for (InputIterator itr = begin; itr!=end; ++itr, ++i) - { - CGAL_precondition(is_valid_polygon((*itr), *m_traits)); - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr, *(arr_vec[i].first)); - } - - Intersection_merge intersection_merge; - _build_sorted_vertices_vectors (arr_vec); - _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, intersection_merge); - - //the result arrangement is at index 0 - this->m_arr = arr_vec[0].first; - delete arr_vec[0].second; - } - - //intersect range of polygons with holes - template - inline void intersection(InputIterator begin, InputIterator end, - Polygon_with_holes_2&, unsigned int k) - { - std::vector arr_vec (std::distance(begin, end) + 1); - arr_vec[0].first = this->m_arr; - unsigned int i = 1; - - for (InputIterator itr = begin; itr!=end; ++itr, ++i) - { - CGAL_precondition(is_valid_polygon_with_holes((*itr), *m_traits)); - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr, *(arr_vec[i].first)); - } - - Intersection_merge intersection_merge; - _build_sorted_vertices_vectors (arr_vec); - _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, intersection_merge); - - //the result arrangement is at index 0 - this->m_arr = arr_vec[0].first; - delete arr_vec[0].second; - } - - - template - inline void intersection(InputIterator1 begin1, InputIterator1 end1, - InputIterator2 begin2, InputIterator2 end2, - unsigned int k=5) - { - std::vector arr_vec (std::distance(begin1, end1)+ - std::distance(begin2, end2)+1); - arr_vec[0].first = this->m_arr; - unsigned int i = 1; - - for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i) - { - CGAL_precondition(is_valid_unknown_polygon(*itr1, *m_traits)); - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr1, *(arr_vec[i].first)); - } - - for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i) - { - CGAL_precondition(is_valid_unknown_polygon(*itr2,*m_traits)); - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr2, *(arr_vec[i].first)); - } - - Intersection_merge intersection_merge; - _build_sorted_vertices_vectors (arr_vec); - _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, intersection_merge); - - //the result arrangement is at index 0 - this->m_arr = arr_vec[0].first; - delete arr_vec[0].second; - this->remove_redundant_edges(); - this->_reset_faces(); - } - - - - // symmetric_difference of a range of polygons (similar to xor) - template - inline void symmetric_difference(InputIterator begin, InputIterator end, - unsigned int k=5) - { - typename std::iterator_traits::value_type pgn; - this->symmetric_difference(begin, end, pgn, k); - this->remove_redundant_edges(); - this->_reset_faces(); - } - - - // intersect range of simple polygons - template - inline void symmetric_difference(InputIterator begin, InputIterator end, - Polygon_2&, unsigned int k=5) - { - std::vector arr_vec (std::distance(begin, end) + 1); - arr_vec[0].first = this->m_arr; - unsigned int i = 1; - - for (InputIterator itr = begin; itr!=end; ++itr, ++i) - { - CGAL_precondition(is_valid_polygon(*itr,*m_traits)); - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr, *(arr_vec[i].first)); - } - - Xor_merge xor_merge; - _build_sorted_vertices_vectors (arr_vec); - _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, xor_merge); - - //the result arrangement is at index 0 - this->m_arr = arr_vec[0].first; - delete arr_vec[0].second; - } - - //intersect range of polygons with holes - template - inline void symmetric_difference(InputIterator begin, InputIterator end, - Polygon_with_holes_2&, unsigned int k=5) - { - std::vector arr_vec (std::distance(begin, end) + 1); - arr_vec[0].first = this->m_arr; - unsigned int i = 1; - - for (InputIterator itr = begin; itr!=end; ++itr, ++i) - { - CGAL_precondition(is_valid_polygon_with_holes(*itr,*m_traits)); - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr, *(arr_vec[i].first)); - } - - Xor_merge xor_merge; - _build_sorted_vertices_vectors (arr_vec); - _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, xor_merge); - - //the result arrangement is at index 0 - this->m_arr = arr_vec[0].first; - delete arr_vec[0].second; - } - - - template - inline void symmetric_difference(InputIterator1 begin1, InputIterator1 end1, - InputIterator2 begin2, InputIterator2 end2, - unsigned int k=5) - { - std::vector arr_vec (std::distance(begin1, end1)+ - std::distance(begin2, end2)+1); - arr_vec[0].first = this->m_arr; - unsigned int i = 1; - - for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i) - { - CGAL_precondition(is_valid_unknown_polygon(*itr1, *m_traits)); - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr1, *(arr_vec[i].first)); - } - - for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i) - { - CGAL_precondition(is_valid_unknown_polygon(*itr2,*m_traits)); - arr_vec[i].first = new Arrangement_2(m_traits); - _insert(*itr2, *(arr_vec[i].first)); - } - - Xor_merge xor_merge; - _build_sorted_vertices_vectors (arr_vec); - _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, xor_merge); - - //the result arrangement is at index 0 - this->m_arr = arr_vec[0].first; - delete arr_vec[0].second; - this->remove_redundant_edges(); - this->_reset_faces(); - } - - static void construct_polygon(Ccb_halfedge_const_circulator ccb, - Polygon_2 & pgn, Traits_2 * tr); - - bool is_hole_of_face(Face_const_handle f, Halfedge_const_handle he) const; - - Ccb_halfedge_const_circulator - get_boundary_of_polygon(Face_const_iterator f) const; - - void remove_redundant_edges() - { - this->_remove_redundant_edges(m_arr); - } - - void _remove_redundant_edges(Arrangement_2* arr) - { - for (Edge_iterator itr = arr->edges_begin(); itr != arr->edges_end(); ) - { - Halfedge_handle he = itr; - if (he->face()->contained() == he->twin()->face()->contained()) - { - Edge_iterator next = itr; - ++next; - arr->remove_edge(he); - itr = next; - } - else - ++itr; - } - } - - class Less_vertex_handle - { - typename Traits_2::Compare_xy_2 comp_xy; - - public: - - Less_vertex_handle (const typename Traits_2::Compare_xy_2& cmp) : - comp_xy (cmp) - {} - - bool operator() (Vertex_handle v1, Vertex_handle v2) const - { - return (comp_xy (v1->point(), v2->point()) == SMALLER); - } - }; - - void _build_sorted_vertices_vectors (std::vector& arr_vec) - { - Less_vertex_handle comp (m_traits->compare_xy_2_object()); - Arrangement_2 *p_arr; - Vertex_iterator vit; - const unsigned int n = arr_vec.size(); - unsigned int i, j; - - for (i = 0; i < n; i++) - { - // Allocate a vector of handles to all vertices in the current - // arrangement. - p_arr = arr_vec[i].first; - arr_vec[i].second = new std::vector; - arr_vec[i].second->resize (p_arr->number_of_vertices()); - - for (j = 0, vit = p_arr->vertices_begin(); - vit != p_arr->vertices_end(); - j++, ++vit) - { - (*(arr_vec[i].second))[j] = vit; - } - - // Sort the vector. - std::sort (arr_vec[i].second->begin(), arr_vec[i].second->end(), comp); - } - - return; - } - - template - void _divide_and_conquer (unsigned int lower, unsigned int upper, - std::vector& arr_vec, - unsigned int k, Merge merge_func) - { - if ((upper - lower) < k) - { - merge_func(lower, upper, 1, arr_vec); - return; - } - - unsigned int sub_size = ((upper - lower + 1) / k); - unsigned int i = 0; - unsigned int curr_lower = lower; - - for (; ifaces_begin(); - for ( ; fit != arr->faces_end(); ++fit) - { - fit->set_visited(false); - } - } - - void _insert(const Polygon_2& pgn, Arrangement_2& arr); - - void _insert(const Polygon_with_holes_2& pgn, Arrangement_2& arr); - - template - void _insert(PolygonIter p_begin, PolygonIter p_end, Polygon_2& pgn); - - template - void _insert(PolygonIter p_begin, PolygonIter p_end, - Polygon_with_holes_2& pgn); - - template - void _construct_curves(const Polygon_2& pgn, OutputIterator oi); - - template - void _construct_curves(const Polygon_with_holes_2& pgn, OutputIterator oi); - - - bool _is_empty(const Polygon_2& pgn) const - { - const std::pair& itr_pair = - m_traits->construct_curves_2_object()(pgn); - return (itr_pair.first == itr_pair.second); - } - - bool _is_empty(const Polygon_with_holes_2& ) const - { - return (false); - } - - bool _is_plane(const Polygon_2& ) const - { - return (false); - } - - bool _is_plane(const Polygon_with_holes_2& pgn) const - { - //typedef typename Traits_2::Is_unbounded Is_unbounded; - bool unbounded = m_traits->construct_is_unbounded_object()(pgn); - std::pair pair = m_traits->construct_holes_object()(pgn); - return (unbounded && (pair.first == pair.second)); - //used to return (pgn.is_unbounded() && (pgn.holes_begin() == pgn.holes_end())) - } - - void _intersection(const Arrangement_2& arr) - { - Arrangement_2* res_arr = new Arrangement_2(m_traits); - Gps_intersection_functor func; - overlay(*m_arr, arr, *res_arr, func); - delete m_arr; // delete the previous arrangement - - m_arr = res_arr; - remove_redundant_edges(); - } - - void _intersection(const Arrangement_2& arr1, - const Arrangement_2& arr2, - Arrangement_2& res) - { - Gps_intersection_functor func; - overlay(arr1, arr2, res, func); - _remove_redundant_edges(&res); - - } - - template - void _intersection(const Polygon_& pgn) - { - if (_is_empty(pgn)) - this->clear(); - if (_is_plane(pgn)) return; - if (this->is_empty()) return; - if (this->is_plane()) - { - Arrangement_2* arr = new Arrangement_2(m_traits); - _insert(pgn, *arr); - delete (this->m_arr); - this->m_arr = arr; - return; - } - - Arrangement_2 second_arr; - _insert(pgn, second_arr); - _intersection(second_arr); - } - - void _intersection(const Self& other) - { - if (other.is_empty()) - { - m_arr->clear(); - return; - } - if (other.is_plane()) return; - if (this->is_empty()) return; - if (this->is_plane()) - { - *(this->m_arr) = *(other.m_arr); - return; - } - - _intersection(*(other.m_arr)); - } - - void _join(const Arrangement_2& arr) - { - Arrangement_2* res_arr = new Arrangement_2(m_traits); - Gps_join_functor func; - overlay(*m_arr, arr, *res_arr, func); - delete m_arr; // delete the previous arrangement - - m_arr = res_arr; - remove_redundant_edges(); - } - - void _join(const Arrangement_2& arr1, const Arrangement_2& arr2, - Arrangement_2& res) - { - Gps_join_functor func; - overlay(arr1, arr2, res, func); - _remove_redundant_edges(&res); - - } - - template - void _join(const Polygon_& pgn) - { - if (_is_empty(pgn)) return; - if (_is_plane(pgn)) - { - this->clear(); - this->m_arr->unbounded_face()->set_contained(true); - return; - } - if (this->is_empty()) - { - Arrangement_2* arr = new Arrangement_2(m_traits); - _insert(pgn, *arr); - delete (this->m_arr); - this->m_arr = arr; - return; - } - if (this->is_plane()) return; - - Arrangement_2 second_arr; - _insert(pgn, second_arr); - _join(second_arr); - } - - - void _join(const Self& other) - { - if (other.is_empty()) return; - if (other.is_plane()) - { - this->clear(); - this->m_arr->unbounded_face()->set_contained(true); - return; - } - if (this->is_empty()) - { - *(this->m_arr) = *(other.m_arr); - return; - } - if (this->is_plane()) return; - _join(*(other.m_arr)); - } - - void _difference(const Arrangement_2& arr) - { - Arrangement_2* res_arr = new Arrangement_2(m_traits); - Gps_difference_functor func; - overlay(*m_arr, arr, *res_arr, func); - delete m_arr; // delete the previous arrangement - - m_arr = res_arr; - remove_redundant_edges(); - fix_curves_direction(); - } - - void _difference(const Arrangement_2& arr1, const Arrangement_2& arr2, - Arrangement_2& res) - { - Gps_difference_functor func; - overlay(arr1, arr2, res, func); - _remove_redundant_edges(&res); - _fix_curves_direction(res); - - } - - template - void _difference(const Polygon_& pgn) - { - if (_is_empty(pgn)) return; - if (_is_plane(pgn)) - { - this->clear(); - return; - } - if (this->is_empty()) return; - if (this->is_plane()) - { - Arrangement_2* arr = new Arrangement_2(m_traits); - _insert(pgn, *arr); - delete (this->m_arr); - this->m_arr = arr; - this->complement(); - return; - } - - Arrangement_2 second_arr; - _insert(pgn, second_arr); - _difference(second_arr); - } - - - void _difference(const Self& other) - { - if (other.is_empty()) return; - if (other.is_plane()) - { - this->clear(); - return; - } - if (this->is_empty()) return; - if (this->is_plane()) - { - *(this->m_arr) = *(other.m_arr); - this->complement(); - return; - } - - _difference(*(other.m_arr)); - } - - void _symmetric_difference(const Arrangement_2& arr) - { - Arrangement_2* res_arr = new Arrangement_2(m_traits); - Gps_sym_diff_functor func; - overlay(*m_arr, arr, *res_arr, func); - delete m_arr; // delete the previous arrangement - - m_arr = res_arr; - remove_redundant_edges(); - fix_curves_direction(); - } - - void _symmetric_difference(const Arrangement_2& arr1, - const Arrangement_2& arr2, - Arrangement_2& res) - { - Gps_sym_diff_functor func; - overlay(arr1, arr2, res, func); - _remove_redundant_edges(&res); - _fix_curves_direction(res); - } - - template - void _symmetric_difference(const Polygon_& pgn) - { - if (_is_empty(pgn)) return; - - if (_is_plane(pgn)) - { - this->complement(); - return; - } - if (this->is_empty()) - { - Arrangement_2* arr = new Arrangement_2(m_traits); - _insert(pgn, *arr); - delete (this->m_arr); - this->m_arr = arr; - return; - } - - if (this->is_plane()) - { - Arrangement_2* arr = new Arrangement_2(m_traits); - _insert(pgn, *arr); - delete (this->m_arr); - this->m_arr = arr; - this->complement(); - return; - } - - Arrangement_2 second_arr; - _insert(pgn, second_arr); - _symmetric_difference(second_arr); - } - - - void _symmetric_difference(const Self& other) - { - if (other.is_empty()) return; - - if (other.is_plane()) - { - this->complement(); - return; - } - if (this->is_empty()) - { - *(this->m_arr) = *(other.m_arr); - return; - } - - if (this->is_plane()) - { - *(this->m_arr) = *(other.m_arr); - this->complement(); - return; - } - - _symmetric_difference(*(other.m_arr)); - } - }; -#include - CGAL_END_NAMESPACE #endif diff --git a/Boolean_set_operations_2/include/CGAL/General_polygon_set_on_surface_2.h b/Boolean_set_operations_2/include/CGAL/General_polygon_set_on_surface_2.h new file mode 100644 index 00000000000..7509407bf7e --- /dev/null +++ b/Boolean_set_operations_2/include/CGAL/General_polygon_set_on_surface_2.h @@ -0,0 +1,1371 @@ +// Copyright (c) 2005 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you may redistribute it under +// the terms of the Q Public License version 1.0. +// See the file LICENSE.QPL distributed with CGAL. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: +// $Id: General_polygon_set_2.h 47919 2009-02-05 15:39:55Z guyzucke $ $Date: 2009-02-05 17:39:55 +0200 (Thu, 05 Feb 2009) $ +// +// +// Author(s) : Baruch Zukerman +// Efi Fogel +// Ophir Setter + +#ifndef CGAL_GENERAL_POLYGON_SET_ON_SURFACE_2_H +#define CGAL_GENERAL_POLYGON_SET_ON_SURFACE_2_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CGAL_BEGIN_NAMESPACE + +// General_polygon_set_on_sufrace_2 +template +class General_polygon_set_on_surface_2 +{ +public: + typedef Traits_ Traits_2; + typedef TopTraits_ Topology_traits; + typedef typename Traits_2::Polygon_2 Polygon_2; + typedef typename Traits_2::Polygon_with_holes_2 Polygon_with_holes_2; + typedef CGAL::Arrangement_on_surface_2 + Arrangement_on_surface_2; + typedef typename Arrangement_on_surface_2::Size Size; + +private: + typedef Arrangement_on_surface_2 Aos_2; + + typedef General_polygon_set_on_surface_2 < + Traits_2, Topology_traits> Self; + typedef typename Traits_2::Point_2 Point_2; + typedef typename Traits_2::X_monotone_curve_2 X_monotone_curve_2; + + typedef typename Polygon_with_holes_2::Hole_const_iterator + GP_Holes_const_iterator; + typedef typename Traits_2::Curve_const_iterator Curve_const_iterator; + typedef typename Traits_2::Compare_endpoints_xy_2 + Compare_endpoints_xy_2; + typedef typename Traits_2::Construct_opposite_2 Construct_opposite_2; + + typedef typename Aos_2::Face_const_iterator Face_const_iterator; + typedef typename Aos_2::Halfedge_const_iterator Halfedge_const_iterator; + typedef typename Aos_2::Vertex_const_iterator Vertex_const_iterator; + typedef typename Aos_2::Edge_const_iterator Edge_const_iterator; + typedef typename Aos_2::Outer_ccb_const_iterator Outer_ccb_const_iterator; + typedef typename Aos_2::Inner_ccb_const_iterator Inner_ccb_const_iterator; + typedef typename Aos_2::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + typedef typename Aos_2::Face_iterator Face_iterator; + typedef typename Aos_2::Halfedge_iterator Halfedge_iterator; + typedef typename Aos_2::Vertex_iterator Vertex_iterator; + typedef typename Aos_2::Edge_iterator Edge_iterator; + typedef typename Aos_2::Outer_ccb_iterator Outer_ccb_iterator; + typedef typename Aos_2::Inner_ccb_iterator Inner_ccb_iterator; + typedef typename Aos_2::Ccb_halfedge_circulator Ccb_halfedge_circulator; + typedef typename Aos_2::Face_handle Face_handle; + typedef typename Aos_2::Halfedge_handle Halfedge_handle; + typedef typename Aos_2::Vertex_handle Vertex_handle; + + typedef typename Aos_2::Face_const_handle Face_const_handle; + typedef typename Aos_2::Halfedge_const_handle Halfedge_const_handle; + typedef typename Aos_2::Vertex_const_handle Vertex_const_handle; + + typedef typename Aos_2::Halfedge_around_vertex_const_circulator + Halfedge_around_vertex_const_circulator; + + typedef std::pair *> Arr_entry; + + typedef typename Arrangement_on_surface_2:: + Topology_traits::Default_point_location_strategy Point_location; + +protected: + + // Traits* should be removed and only m_traits should be used. + // If you, who reads this text, have time, replace m_traits + // with m_traits_adaptor and try to do something about m_traits_owner. + Traits_2* m_traits; + CGAL::Arr_traits_adaptor_2 m_traits_adaptor; + bool m_traits_owner; + + // the underlying arrangement + Aos_2* m_arr; + + +public: + + // default costructor + General_polygon_set_on_surface_2() : m_traits(new Traits_2()), + m_traits_adaptor(*m_traits), + m_traits_owner(true), + m_arr(new Aos_2(m_traits)) + {} + + + // constructor with traits object + General_polygon_set_on_surface_2(Traits_2& tr) : m_traits(&tr), + m_traits_adaptor(*m_traits), + m_traits_owner(false), + m_arr(new Aos_2(m_traits)) + {} + + + General_polygon_set_on_surface_2(const Self& ps) : + m_traits(new Traits_2(*(ps.m_traits))), + m_traits_adaptor(*m_traits), + m_traits_owner(true), + m_arr(new Aos_2(*(ps.m_arr))) + {} + + + General_polygon_set_on_surface_2& operator=(const Self& ps) + { + if (this == &ps) + return (*this); + + if (m_traits_owner) + delete m_traits; + delete m_arr; + m_traits = new Traits_2(*(ps.m_traits)); + m_traits_adaptor = CGAL::Arr_traits_adaptor_2(*m_traits); + m_traits_owner = true; + m_arr = new Aos_2(*(ps.m_arr)); + return (*this); + } + + + explicit General_polygon_set_on_surface_2(const Polygon_2& pgn) : + m_traits(new Traits_2()), + m_traits_adaptor(*m_traits), + m_traits_owner(true), + m_arr(new Aos_2(m_traits)) + { + CGAL_precondition(is_valid_polygon(pgn, *m_traits)); + _insert(pgn, *m_arr); + } + + explicit General_polygon_set_on_surface_2(const Polygon_with_holes_2& pgn_with_holes): + m_traits(new Traits_2()), + m_traits_adaptor(*m_traits), + m_traits_owner(true), + m_arr(new Aos_2(m_traits)) + { + CGAL_precondition(is_valid_polygon_with_holes(pgn_with_holes,*m_traits)); + _insert(pgn_with_holes, *m_arr); + } + +private: + General_polygon_set_on_surface_2(Aos_2* arr) : m_traits(new Traits_2()), + m_traits_adaptor(*m_traits), + m_traits_owner(true), + m_arr(arr) + {} + +public: + //destructor + virtual ~General_polygon_set_on_surface_2() + { + delete m_arr; + + if (m_traits_owner) + delete m_traits; + } + + void simplify(const Polygon_2& pgn, Polygon_with_holes_2& res) + { + typedef Gps_polygon_simplifier Simplifier; + + Aos_2* arr = new Aos_2(); + + Simplifier simp(*arr, *m_traits); + simp.simplify(pgn); + _remove_redundant_edges(arr); + Self gps(arr); + gps._reset_faces(); + + typedef Oneset_iterator OutputItr; + OutputItr oi (res); + gps.polygons_with_holes(oi); + } + + // insert a simple polygon + void insert(const Polygon_2& pgn) + { + CGAL_precondition(is_valid_polygon(pgn, *m_traits)); + _insert(pgn, *m_arr); + } + + // insert a polygon with holes + void insert(const Polygon_with_holes_2& pgn_with_holes) + { + CGAL_precondition(is_valid_polygon_with_holes(pgn_with_holes, *m_traits)); + _insert(pgn_with_holes, *m_arr); + } + + // insert a range of polygons that can be either simple polygons + // or polygons with holes + // precondition: the polygons are disjoint and simple + template + void insert(PolygonIterator pgn_begin, PolygonIterator pgn_end); + + + // insert two ranges of : the first one for simple polygons, + // the second one for polygons with holes + // precondition: the first range is disjoint simple polygons + // the second range is disjoint polygons with holes + template + void insert(PolygonIterator pgn_begin, PolygonIterator pgn_end, + PolygonWithHolesIterator pgn_with_holes_begin, + PolygonWithHolesIterator pgn_with_holes_end); + + // test for intersection with a simple polygon + bool do_intersect(const Polygon_2 &pgn) const + { + CGAL_precondition(is_valid_polygon(pgn,*m_traits)); + Self other(pgn); + return (do_intersect(other)); + } + + // test for intersection with a polygon with holes + bool do_intersect(const Polygon_with_holes_2& pgn_with_holes) const + { + CGAL_precondition(is_valid_polygon_with_holes(pgn_with_holes, *m_traits)); + Self other(pgn_with_holes); + return (do_intersect(other)); + } + + //test for intersection with another General_polygon_set_on_surface_2 object + bool do_intersect(const Self& other) const + { + if (this->is_empty() || other.is_empty()) + return false; + + if (this->is_plane() || other.is_plane()) + return true; + + Aos_2 res_arr; + + Gps_do_intersect_functor func; + overlay(*m_arr, *(other.m_arr), res_arr, func); + return func.found_reg_intersection(); + } + + template + bool do_intersect(InputIterator begin, InputIterator end) + { + Self other(*this); + other.intersection(begin, end); + return (other.is_empty()); + } + + template + bool do_intersect(InputIterator1 begin1, InputIterator1 end1, + InputIterator2 begin2, InputIterator2 end2) + { + Self other(*this); + other.intersection(begin1, end1, begin2, end2); + return (other.is_empty()); + } + + + // intersection with a simple polygon + void intersection(const Polygon_2& pgn) + { + CGAL_precondition(is_valid_polygon(pgn, *m_traits)); + _intersection(pgn); + } + + // intersection with a polygon with holes + void intersection(const Polygon_with_holes_2& pgn) + { + CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); + _intersection(pgn); + } + + //intersection with another General_polygon_set_on_surface_2 object + void intersection(const Self& other) + { + _intersection(other); + } + + void intersection(const Self& gps1, const Self& gps2) + { + this->clear(); + _intersection(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); + } + + + // join with a simple polygon + void join(const Polygon_2& pgn) + { + CGAL_precondition(is_valid_polygon(pgn, *m_traits)); + _join(pgn); + } + + // join with a polygon with holes + void join(const Polygon_with_holes_2& pgn) + { + CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); + _join(pgn); + } + + //join with another General_polygon_set_on_surface_2 object + void join(const Self& other) + { + _join(other); + } + + void join(const Self& gps1, const Self& gps2) + { + this->clear(); + _join(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); + } + + // difference with a simple polygon + void difference (const Polygon_2& pgn) + { + CGAL_precondition(is_valid_polygon(pgn, *m_traits)); + _difference(pgn); + } + + // difference with a polygon with holes + void difference (const Polygon_with_holes_2& pgn) + { + CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); + _difference(pgn); + } + + //difference with another General_polygon_set_on_surface_2 object + void difference (const Self& other) + { + _difference(other); + } + + void difference(const Self& gps1, const Self& gps2) + { + this->clear(); + _difference(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); + } + + + // symmetric_difference with a simple polygon + void symmetric_difference(const Polygon_2& pgn) + { + CGAL_precondition(is_valid_polygon(pgn, *m_traits)); + _symmetric_difference(pgn); + } + + // symmetric_difference with a polygon with holes + void symmetric_difference(const Polygon_with_holes_2& pgn) + { + CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); + _symmetric_difference(pgn); + } + + //symmetric_difference with another General_polygon_set_on_surface_2 object + void symmetric_difference(const Self& other) + { + _symmetric_difference(other); + } + + void symmetric_difference(const Self& gps1, const Self& gps2) + { + this->clear(); + _symmetric_difference(*(gps1.m_arr), *(gps2.m_arr), *(this->m_arr)); + } + + + void complement() + { + this->_complement(m_arr); + } + + void complement(const Self& other) + { + *(this->m_arr) = *(other.m_arr); + this->complement(); + } + + void fix_curves_direction() + { + _fix_curves_direction(*m_arr); + } + + Size number_of_polygons_with_holes() const; + + Traits_2& traits() + { + return *m_traits; + } + + const Traits_2& traits() const + { + return *m_traits; + } + + bool is_empty() const + { + // We have to check that all the faces of an empty arrangement are not + // conained in the polygon set (there can be several faces in an empty + // arrangement, dependant on the topology traits. + // The point is that if the arrangement is "empty" (meaning that no curve + // or point were inserted and that it is in its original state) then + // all the faces (created by the topology traits) should have the same + // result for contained() --- from Boolean operations point of view there + // can not be an empty arrangement which has serveral faces with different + // attributes. + return (m_arr->is_empty() && !m_arr->faces_begin()->contained()); + } + + bool is_plane() const + { + // Same comment as in "is_empty" above, just with adjustments. + return (m_arr->is_empty() && m_arr->faces_begin()->contained()); + } + + void clear() + { + m_arr->clear(); + } + + + Oriented_side oriented_side(const Point_2& q) const + { + Point_location pl(*m_arr); + + Object obj = pl.locate(q); + Face_const_iterator f; + if (CGAL::assign(f, obj)) + { + if (f->contained()) + return ON_POSITIVE_SIDE; + + return ON_NEGATIVE_SIDE ; + } + return ON_ORIENTED_BOUNDARY ; + } + + Oriented_side oriented_side(const Polygon_2& pgn) const + { + CGAL_precondition(is_valid_polygon(pgn, *m_traits)); + Self other(pgn); + return (oriented_side(other)); + } + + Oriented_side oriented_side(const Polygon_with_holes_2& pgn) const + { + CGAL_precondition(is_valid_polygon_with_holes(pgn, *m_traits)); + Self other(pgn); + return (oriented_side(other)); + } + + Oriented_side oriented_side(const Self& other) const + { + if (this->is_empty() || other.is_empty()) + return ON_NEGATIVE_SIDE; + + if (this->is_plane() || other.is_plane()) + return ON_POSITIVE_SIDE; + + Aos_2 res_arr; + + Gps_do_intersect_functor func; + overlay(*m_arr, *(other.m_arr), res_arr, func); + if (func.found_reg_intersection()) + return ON_POSITIVE_SIDE; + + if (func.found_boundary_intersection()) + return ON_ORIENTED_BOUNDARY; + + return ON_NEGATIVE_SIDE; + } + + + // returns the location of the query point + bool locate(const Point_2& q, Polygon_with_holes_2& pgn) const; + + /*! Obtain a const reference to the underlying arrangement + * \return the underlying arrangement. + */ + const Aos_2& arrangement() const + { + return *m_arr; + } + + /*! Obtain a reference to the underlying arrangement + * \return the underlying arrangement. + */ + Aos_2& arrangement() + { + return *m_arr; + } + + /*! */ + bool is_valid() const + { + if (!CGAL::is_valid(*m_arr)) + return false; + + Compare_endpoints_xy_2 cmp_endpoints = + m_traits->compare_endpoints_xy_2_object(); + Construct_opposite_2 ctr_opp = m_traits->construct_opposite_2_object(); + + for (Edge_const_iterator eci = m_arr->edges_begin(); + eci != m_arr->edges_end(); + ++eci) + { + Halfedge_const_handle he = eci; + if (he->face() == he->twin()->face()) + { + return false; + } + if (he->face()->contained() == he->twin()->face()->contained()) + { + return false; + } + + const X_monotone_curve_2& cv = he->curve(); + const bool is_cont = he->face()->contained(); + const Comparison_result he_res = + ((Arr_halfedge_direction)he->direction() == ARR_LEFT_TO_RIGHT) ? + SMALLER : LARGER; + const bool has_same_dir = (cmp_endpoints(cv) == he_res); + + if ((is_cont && !has_same_dir) || (!is_cont && has_same_dir)) + return false; + } + return true; + } + + // get the simple polygons, takes O(n) + template + OutputIterator polygons_with_holes(OutputIterator out) const; + + // join a range of polygons + template + void join(InputIterator begin, InputIterator end, unsigned int k = 5) + { + typename std::iterator_traits::value_type pgn; + this->join(begin, end, pgn, k); + this->remove_redundant_edges(); + this->_reset_faces(); + } + + // join range of simple polygons + // 5 is the magic number in which we switch to a sweep-based algorithm + // instead of a D&C algorithm. This point should be further studies, as + // it is hard to believe that this is the best value for all applications. + template + inline void join(InputIterator begin, + InputIterator end, + Polygon_2&, + unsigned int k=5) + { + std::vector arr_vec (std::distance(begin, end) + 1); + + arr_vec[0].first = this->m_arr; + unsigned int i = 1; + for (InputIterator itr = begin; itr!=end; ++itr, ++i) + { + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr, *(arr_vec[i].first)); + } + + Join_merge join_merge; + _build_sorted_vertices_vectors (arr_vec); + _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, join_merge); + + //the result arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + } + + //join range of polygons with holes (see previous comment about k=5). + template + inline void join(InputIterator begin, InputIterator end, + Polygon_with_holes_2&, unsigned int k=5) + { + std::vector arr_vec (std::distance(begin, end) + 1); + arr_vec[0].first = this->m_arr; + + unsigned int i = 1; + for (InputIterator itr = begin; itr!=end; ++itr, ++i) + { + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr, *(arr_vec[i].first)); + } + + Join_merge join_merge; + _build_sorted_vertices_vectors (arr_vec); + _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, join_merge); + + //the result arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + } + + // (see previous comment about k=5). + template + inline void join(InputIterator1 begin1, InputIterator1 end1, + InputIterator2 begin2, InputIterator2 end2, + unsigned int k=5) + { + std::vector arr_vec (std::distance(begin1, end1)+ + std::distance(begin2, end2)+1); + + arr_vec[0].first = this->m_arr; + unsigned int i = 1; + + for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i) + { + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr1, *(arr_vec[i].first)); + } + + for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i) + { + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr2, *(arr_vec[i].first)); + } + + Join_merge join_merge; + _build_sorted_vertices_vectors (arr_vec); + _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, join_merge); + + //the result arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + this->remove_redundant_edges(); + this->_reset_faces(); + } + + + // intersect range of polygins (see previous comment about k=5). + template + inline void intersection(InputIterator begin, InputIterator end, + unsigned int k=5) + { + typename std::iterator_traits::value_type pgn; + this->intersection(begin, end, pgn, k); + this->remove_redundant_edges(); + this->_reset_faces(); + } + + + // intersect range of simple polygons + template + inline void intersection(InputIterator begin, InputIterator end, + Polygon_2&, unsigned int k) + { + std::vector arr_vec (std::distance(begin, end) + 1); + arr_vec[0].first = this->m_arr; + unsigned int i = 1; + + for (InputIterator itr = begin; itr!=end; ++itr, ++i) + { + CGAL_precondition(is_valid_polygon((*itr), *m_traits)); + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr, *(arr_vec[i].first)); + } + + Intersection_merge intersection_merge; + _build_sorted_vertices_vectors (arr_vec); + _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, intersection_merge); + + //the result arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + } + + //intersect range of polygons with holes + template + inline void intersection(InputIterator begin, InputIterator end, + Polygon_with_holes_2&, unsigned int k) + { + std::vector arr_vec (std::distance(begin, end) + 1); + arr_vec[0].first = this->m_arr; + unsigned int i = 1; + + for (InputIterator itr = begin; itr!=end; ++itr, ++i) + { + CGAL_precondition(is_valid_polygon_with_holes((*itr), *m_traits)); + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr, *(arr_vec[i].first)); + } + + Intersection_merge intersection_merge; + _build_sorted_vertices_vectors (arr_vec); + _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, intersection_merge); + + //the result arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + } + + + template + inline void intersection(InputIterator1 begin1, InputIterator1 end1, + InputIterator2 begin2, InputIterator2 end2, + unsigned int k=5) + { + std::vector arr_vec (std::distance(begin1, end1)+ + std::distance(begin2, end2)+1); + arr_vec[0].first = this->m_arr; + unsigned int i = 1; + + for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i) + { + CGAL_precondition(is_valid_unknown_polygon(*itr1, *m_traits)); + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr1, *(arr_vec[i].first)); + } + + for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i) + { + CGAL_precondition(is_valid_unknown_polygon(*itr2,*m_traits)); + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr2, *(arr_vec[i].first)); + } + + Intersection_merge intersection_merge; + _build_sorted_vertices_vectors (arr_vec); + _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, intersection_merge); + + //the result arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + this->remove_redundant_edges(); + this->_reset_faces(); + } + + + + // symmetric_difference of a range of polygons (similar to xor) + // (see previous comment about k=5). + template + inline void symmetric_difference(InputIterator begin, InputIterator end, + unsigned int k=5) + { + typename std::iterator_traits::value_type pgn; + this->symmetric_difference(begin, end, pgn, k); + this->remove_redundant_edges(); + this->_reset_faces(); + } + + + // intersect range of simple polygons (see previous comment about k=5). + template + inline void symmetric_difference(InputIterator begin, InputIterator end, + Polygon_2&, unsigned int k=5) + { + std::vector arr_vec (std::distance(begin, end) + 1); + arr_vec[0].first = this->m_arr; + unsigned int i = 1; + + for (InputIterator itr = begin; itr!=end; ++itr, ++i) + { + CGAL_precondition(is_valid_polygon(*itr,*m_traits)); + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr, *(arr_vec[i].first)); + } + + Xor_merge xor_merge; + _build_sorted_vertices_vectors (arr_vec); + _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, xor_merge); + + //the result arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + } + + //intersect range of polygons with holes (see previous comment about k=5). + template + inline void symmetric_difference(InputIterator begin, InputIterator end, + Polygon_with_holes_2&, unsigned int k=5) + { + std::vector arr_vec (std::distance(begin, end) + 1); + arr_vec[0].first = this->m_arr; + unsigned int i = 1; + + for (InputIterator itr = begin; itr!=end; ++itr, ++i) + { + CGAL_precondition(is_valid_polygon_with_holes(*itr,*m_traits)); + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr, *(arr_vec[i].first)); + } + + Xor_merge xor_merge; + _build_sorted_vertices_vectors (arr_vec); + _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, xor_merge); + + //the result arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + } + + // (see previous comment about k=5). + template + inline void symmetric_difference(InputIterator1 begin1, InputIterator1 end1, + InputIterator2 begin2, InputIterator2 end2, + unsigned int k=5) + { + std::vector arr_vec (std::distance(begin1, end1)+ + std::distance(begin2, end2)+1); + arr_vec[0].first = this->m_arr; + unsigned int i = 1; + + for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i) + { + CGAL_precondition(is_valid_unknown_polygon(*itr1, *m_traits)); + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr1, *(arr_vec[i].first)); + } + + for (InputIterator2 itr2 = begin2; itr2!=end2; ++itr2, ++i) + { + CGAL_precondition(is_valid_unknown_polygon(*itr2,*m_traits)); + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr2, *(arr_vec[i].first)); + } + + Xor_merge xor_merge; + _build_sorted_vertices_vectors (arr_vec); + _divide_and_conquer(0, arr_vec.size()-1, arr_vec, k, xor_merge); + + //the result arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + this->remove_redundant_edges(); + this->_reset_faces(); + } + + static void construct_polygon(Ccb_halfedge_const_circulator ccb, + Polygon_2 & pgn, Traits_2 * tr); + + bool is_hole_of_face(Face_const_handle f, Halfedge_const_handle he) const; + + Ccb_halfedge_const_circulator + get_boundary_of_polygon(Face_const_iterator f) const; + + void remove_redundant_edges() + { + this->_remove_redundant_edges(m_arr); + } + +protected: + + void _remove_redundant_edges(Aos_2* arr) + { + for (Edge_iterator itr = arr->edges_begin(); itr != arr->edges_end(); ) + { + Halfedge_handle he = itr; + if (he->face()->contained() == he->twin()->face()->contained()) + { + Edge_iterator next = itr; + ++next; + arr->remove_edge(he); + itr = next; + } + else + ++itr; + } + } + + class Less_vertex_handle + { + typename Traits_2::Compare_xy_2 comp_xy; + + public: + + Less_vertex_handle (const typename Traits_2::Compare_xy_2& cmp) : + comp_xy (cmp) + {} + + bool operator() (Vertex_handle v1, Vertex_handle v2) const + { + return (comp_xy (v1->point(), v2->point()) == SMALLER); + } + }; + + + void _complement(Aos_2* arr) + { + for (Face_iterator fit = arr->faces_begin(); + fit != arr->faces_end(); + ++fit) + { + fit->set_contained(!fit->contained()); + } + + Construct_opposite_2 ctr_opp = m_traits->construct_opposite_2_object(); + for (Edge_iterator eit = arr->edges_begin(); + eit != arr->edges_end(); + ++eit) + { + Halfedge_handle he = eit; + const X_monotone_curve_2& cv = he->curve(); + arr->modify_edge(he, ctr_opp(cv)); + } + } + + //fix the directions of the curves (given correct marked face) + // it should be called mostly after symmetric_difference. + void _fix_curves_direction(Aos_2& arr) + { + Compare_endpoints_xy_2 cmp_endpoints = + m_traits->compare_endpoints_xy_2_object(); + Construct_opposite_2 ctr_opp = m_traits->construct_opposite_2_object(); + + for (Edge_iterator eit = arr.edges_begin(); + eit != arr.edges_end(); + ++eit) + { + Halfedge_handle he = eit; + const X_monotone_curve_2& cv = he->curve(); + const bool is_cont = he->face()->contained(); + const Comparison_result he_res = + ((Arr_halfedge_direction)he->direction() == ARR_LEFT_TO_RIGHT) ? + SMALLER : LARGER; + const bool has_same_dir = (cmp_endpoints(cv) == he_res); + + if ((is_cont && !has_same_dir) || (!is_cont && has_same_dir)) + arr.modify_edge(he, ctr_opp(cv)); + } + } + + void _build_sorted_vertices_vectors (std::vector& arr_vec) + { + Less_vertex_handle comp (m_traits->compare_xy_2_object()); + Aos_2 *p_arr; + Vertex_iterator vit; + const std::size_t n = arr_vec.size(); + std::size_t i, j; + + for (i = 0; i < n; i++) + { + // Allocate a vector of handles to all vertices in the current + // arrangement. + p_arr = arr_vec[i].first; + arr_vec[i].second = new std::vector; + arr_vec[i].second->resize (p_arr->number_of_vertices()); + + for (j = 0, vit = p_arr->vertices_begin(); + vit != p_arr->vertices_end(); + j++, ++vit) + { + (*(arr_vec[i].second))[j] = vit; + } + + // Sort the vector. + std::sort (arr_vec[i].second->begin(), arr_vec[i].second->end(), comp); + } + } + + template + void _divide_and_conquer (unsigned int lower, unsigned int upper, + std::vector& arr_vec, + unsigned int k, Merge merge_func) + { + if ((upper - lower) < k) + { + merge_func(lower, upper, 1, arr_vec); + return; + } + + unsigned int sub_size = ((upper - lower + 1) / k); + unsigned int i = 0; + unsigned int curr_lower = lower; + + for (; ifaces_begin(); + for ( ; fit != arr->faces_end(); ++fit) + { + fit->set_visited(false); + } + } + + + void _insert(const Polygon_2& pgn, Aos_2& arr); + +// The function below is public because are_holes_and_boundary_pairwise_disjoint +// of Gps_polygon_validation is using it. +// I have tried to define it as friend function, but with no success (probably +// did something wrong with templates and friend.) Besides, it was like this +// before I touched it, so I did not have the energy. +public: + void _insert(const Polygon_with_holes_2& pgn, Aos_2& arr); + +protected: + template + void _insert(PolygonIter p_begin, PolygonIter p_end, Polygon_2& pgn); + + template + void _insert(PolygonIter p_begin, PolygonIter p_end, + Polygon_with_holes_2& pgn); + + template + void _construct_curves(const Polygon_2& pgn, OutputIterator oi); + + template + void _construct_curves(const Polygon_with_holes_2& pgn, OutputIterator oi); + + + bool _is_empty(const Polygon_2& pgn) const + { + const std::pair& itr_pair = + m_traits->construct_curves_2_object()(pgn); + return (itr_pair.first == itr_pair.second); + } + + bool _is_empty(const Polygon_with_holes_2& ) const + { + return (false); + } + + bool _is_plane(const Polygon_2& ) const + { + return (false); + } + + bool _is_plane(const Polygon_with_holes_2& pgn) const + { + //typedef typename Traits_2::Is_unbounded Is_unbounded; + bool unbounded = m_traits->construct_is_unbounded_object()(pgn); + std::pair pair = + m_traits->construct_holes_object()(pgn); + return (unbounded && (pair.first == pair.second)); + //used to return (pgn.is_unbounded() && (pgn.holes_begin() == pgn.holes_end())) + } + + void _intersection(const Aos_2& arr) + { + Aos_2* res_arr = new Aos_2(m_traits); + Gps_intersection_functor func; + overlay(*m_arr, arr, *res_arr, func); + delete m_arr; // delete the previous arrangement + + m_arr = res_arr; + remove_redundant_edges(); + } + + void _intersection(const Aos_2& arr1, + const Aos_2& arr2, + Aos_2& res) + { + Gps_intersection_functor func; + overlay(arr1, arr2, res, func); + _remove_redundant_edges(&res); + + } + + template + void _intersection(const Polygon_& pgn) + { + if (_is_empty(pgn)) + this->clear(); + if (_is_plane(pgn)) return; + if (this->is_empty()) return; + if (this->is_plane()) + { + Aos_2* arr = new Aos_2(m_traits); + _insert(pgn, *arr); + delete (this->m_arr); + this->m_arr = arr; + return; + } + + Aos_2 second_arr; + _insert(pgn, second_arr); + _intersection(second_arr); + } + + void _intersection(const Self& other) + { + if (other.is_empty()) + { + m_arr->clear(); + return; + } + if (other.is_plane()) return; + if (this->is_empty()) return; + if (this->is_plane()) + { + *(this->m_arr) = *(other.m_arr); + return; + } + + _intersection(*(other.m_arr)); + } + + void _join(const Aos_2& arr) + { + Aos_2* res_arr = new Aos_2(m_traits); + Gps_join_functor func; + overlay(*m_arr, arr, *res_arr, func); + delete m_arr; // delete the previous arrangement + + m_arr = res_arr; + remove_redundant_edges(); + } + + void _join(const Aos_2& arr1, const Aos_2& arr2, + Aos_2& res) + { + Gps_join_functor func; + overlay(arr1, arr2, res, func); + _remove_redundant_edges(&res); + + } + + template + void _join(const Polygon_& pgn) + { + if (_is_empty(pgn)) return; + if (_is_plane(pgn)) + { + this->clear(); + + // Even in an empty arrangement there can be several faces + // (because of the topology traits). + for (Face_iterator fit = this->m_arr->faces_begin(); + fit != this->m_arr->faces_end(); ++fit) + fit->set_contained(true); + return; + } + if (this->is_empty()) + { + Aos_2* arr = new Aos_2(m_traits); + _insert(pgn, *arr); + delete (this->m_arr); + this->m_arr = arr; + return; + } + if (this->is_plane()) return; + + Aos_2 second_arr; + _insert(pgn, second_arr); + _join(second_arr); + } + + + void _join(const Self& other) + { + if (other.is_empty()) return; + if (other.is_plane()) + { + this->clear(); + + // Even in an empty arrangement there can be several faces + // (because of the topology traits). + for (Face_iterator fit = this->m_arr->faces_begin(); + fit != this->m_arr->faces_end(); ++fit) + fit->set_contained(true); + return; + } + if (this->is_empty()) + { + *(this->m_arr) = *(other.m_arr); + return; + } + if (this->is_plane()) return; + _join(*(other.m_arr)); + } + + void _difference(const Aos_2& arr) + { + Aos_2* res_arr = new Aos_2(m_traits); + Gps_difference_functor func; + overlay(*m_arr, arr, *res_arr, func); + delete m_arr; // delete the previous arrangement + + m_arr = res_arr; + remove_redundant_edges(); + fix_curves_direction(); + } + + void _difference(const Aos_2& arr1, const Aos_2& arr2, + Aos_2& res) + { + Gps_difference_functor func; + overlay(arr1, arr2, res, func); + _remove_redundant_edges(&res); + _fix_curves_direction(res); + + } + + template + void _difference(const Polygon_& pgn) + { + if (_is_empty(pgn)) return; + if (_is_plane(pgn)) + { + this->clear(); + return; + } + if (this->is_empty()) return; + if (this->is_plane()) + { + Aos_2* arr = new Aos_2(m_traits); + _insert(pgn, *arr); + delete (this->m_arr); + this->m_arr = arr; + this->complement(); + return; + } + + Aos_2 second_arr; + _insert(pgn, second_arr); + _difference(second_arr); + } + + + void _difference(const Self& other) + { + if (other.is_empty()) return; + if (other.is_plane()) + { + this->clear(); + return; + } + if (this->is_empty()) return; + if (this->is_plane()) + { + *(this->m_arr) = *(other.m_arr); + this->complement(); + return; + } + + _difference(*(other.m_arr)); + } + + void _symmetric_difference(const Aos_2& arr) + { + Aos_2* res_arr = new Aos_2(m_traits); + Gps_sym_diff_functor func; + overlay(*m_arr, arr, *res_arr, func); + delete m_arr; // delete the previous arrangement + + m_arr = res_arr; + remove_redundant_edges(); + fix_curves_direction(); + } + + void _symmetric_difference(const Aos_2& arr1, + const Aos_2& arr2, + Aos_2& res) + { + Gps_sym_diff_functor func; + overlay(arr1, arr2, res, func); + _remove_redundant_edges(&res); + _fix_curves_direction(res); + } + + template + void _symmetric_difference(const Polygon_& pgn) + { + if (_is_empty(pgn)) return; + + if (_is_plane(pgn)) + { + this->complement(); + return; + } + if (this->is_empty()) + { + Aos_2* arr = new Aos_2(m_traits); + _insert(pgn, *arr); + delete (this->m_arr); + this->m_arr = arr; + return; + } + + if (this->is_plane()) + { + Aos_2* arr = new Aos_2(m_traits); + _insert(pgn, *arr); + delete (this->m_arr); + this->m_arr = arr; + this->complement(); + return; + } + + Aos_2 second_arr; + _insert(pgn, second_arr); + _symmetric_difference(second_arr); + } + + + void _symmetric_difference(const Self& other) + { + if (other.is_empty()) return; + + if (other.is_plane()) + { + this->complement(); + return; + } + if (this->is_empty()) + { + *(this->m_arr) = *(other.m_arr); + return; + } + + if (this->is_plane()) + { + *(this->m_arr) = *(other.m_arr); + this->complement(); + return; + } + + _symmetric_difference(*(other.m_arr)); + } + +}; + +#include + +CGAL_END_NAMESPACE + +#endif // CGAL_GENERAL_POLYGON_SET_ON_SURFACE_2_H diff --git a/Boolean_set_operations_2/include/CGAL/Polygon_set_2.h b/Boolean_set_operations_2/include/CGAL/Polygon_set_2.h index 847da727fdc..96029be1b02 100644 --- a/Boolean_set_operations_2/include/CGAL/Polygon_set_2.h +++ b/Boolean_set_operations_2/include/CGAL/Polygon_set_2.h @@ -40,6 +40,7 @@ class Polygon_set_2 : private: typedef General_polygon_set_2, Dcel_> Base; + typedef typename Base::Base Base_of_base; typedef Polygon_set_2 Self; public: @@ -237,9 +238,9 @@ public: private: - inline const Base& base(const Self& other) const + inline const Base_of_base& base(const Self& other) const { - return (static_cast(other)); + return (static_cast(other)); } }; diff --git a/Boolean_set_operations_2/test/Boolean_set_operations_2/test_polygon_validation.cpp b/Boolean_set_operations_2/test/Boolean_set_operations_2/test_polygon_validation.cpp index 45143ede658..ed8181c7d10 100644 --- a/Boolean_set_operations_2/test/Boolean_set_operations_2/test_polygon_validation.cpp +++ b/Boolean_set_operations_2/test/Boolean_set_operations_2/test_polygon_validation.cpp @@ -106,9 +106,9 @@ int main (int argc, char **argv) { int result = 0; for (int i=1;i<10;i++) { - std::stringstream strs; - std::string si; - strs << i; + std::stringstream strs; + std::string si; + strs << i; strs >> si; std::string filename = testfilePrefix + si + testfileSuffix; const char *cfilename = filename.c_str(); @@ -126,8 +126,11 @@ int main (int argc, char **argv) { } if (result == 0) std::cout <<"ALL TESTS SUCCEEDED!" << std::endl; - else + else + { std::cout <<"SOME TESTS FAILED" << std::endl; + return 1; + } return (0); }