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 ec25b70e006..54e19d69c21 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 @@ -7,12 +7,11 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// // Author(s) : Baruch Zukerman // Efi Fogel -#ifndef CGAL_BSO_2_GPS_AGG_META_TRAITS_H -#define CGAL_BSO_2_GPS_AGG_META_TRAITS_H +#ifndef CGAL_GPS_AGG_META_TRAITS_H +#define CGAL_GPS_AGG_META_TRAITS_H #include 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 6cf7deb8cdc..b74d8c69889 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 @@ -7,11 +7,12 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Baruch Zukerman -// Ophir Setter +// Author(s) : Baruch Zukerman +// Ophir Setter +// Efi Fogel -#ifndef CGAL_BSO_2_GPS_AGG_OP_H -#define CGAL_BSO_2_GPS_AGG_OP_H +#ifndef CGAL_GPS_AGG_OP_H +#define CGAL_GPS_AGG_OP_H #include @@ -19,8 +20,8 @@ * * The class Gps_agg_op is responsible for aggregated Boolean set operations * depending on a visitor template parameter. It uses the surface-sweep - * 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 + * algorithm from the surface-sweep package to overlay all the polygon sets, and + * then it uses a BFS that determines which of the faces are contained in the * result using the visitor. */ @@ -37,7 +38,7 @@ namespace CGAL { -template +template class SweepVisitor> class Gps_agg_op { using Arrangement_2 = Arrangement_; using Bfs_visitor = BfsVisitor; @@ -74,7 +75,7 @@ class Gps_agg_op { using Subcurve = Arr_construction_subcurve; using Helper_tmp = typename Tt::template Construction_helper; using Helper = typename Helper_tmp::template rebind::other; - using Visitor = Gps_agg_op_visitor; + using Visitor = SweepVisitor; using Surface_sweep_2 = Gps_agg_op_surface_sweep_2; using Edges_hash = Unique_hash_map; @@ -90,7 +91,7 @@ protected: Faces_hash m_faces_hash; // maps face to its IC (inside count) public: - /*! Constructor. */ + /*! constructs. */ Gps_agg_op(Arr& arr, std::vector& vert_vec, const Gt2& tr) : m_arr(&arr), m_traits(new Mgt2(tr)), @@ -98,38 +99,38 @@ public: m_surface_sweep(m_traits, &m_visitor) {} - void sweep_arrangements(std::size_t lower, std::size_t upper, - std::size_t jump, std::vector& arr_vec) { - std::list curves_list; - + std::size_t prepare(std::size_t lower, std::size_t upper, std::size_t jump, + std::vector& arr_vec, std::list& curves_list) { std::size_t n_inf_pgn = 0; // number of infinite polygons (arrangement // with a contained unbounded face - std::size_t n_pgn = 0; // number of polygons (arrangements) - - for (std::size_t i = lower; i <= upper; i += jump, ++n_pgn) { + for (auto i = lower; i <= upper; i += jump) { // The BFS scan (after the loop) starts in the reference face, // so we count the number of polygons that contain the reference face. Arr* arr = (arr_vec[i]).first; if (arr->reference_face()->contained()) ++n_inf_pgn; - Edge_iterator itr = arr->edges_begin(); - for(; itr != arr->edges_end(); ++itr) { + for (auto itr = arr->edges_begin(); itr != arr->edges_end(); ++itr) { // take only relevant edges (which separate between contained and // non-contained faces. - Halfedge_iterator he = itr; - if (he->face()->contained() == he->twin()->face()->contained()) - continue; - if ((Arr_halfedge_direction)he->direction() == ARR_RIGHT_TO_LEFT) - he = he->twin(); + Halfedge_handle he = itr; + if (he->face()->contained() == he->twin()->face()->contained()) continue; + if ((Arr_halfedge_direction)he->direction() == ARR_RIGHT_TO_LEFT) he = he->twin(); Curve_data cv_data(arr, he, 1, 0); curves_list.push_back(Meta_X_monotone_curve_2(he->curve(), cv_data)); } } + return n_inf_pgn; + } - m_surface_sweep.sweep(curves_list.begin(), curves_list.end(), - lower, upper, jump, arr_vec); - + /*! sweeps the plane without interceptions. + */ + void sweep_arrangements(std::size_t lower, std::size_t upper, std::size_t jump, + std::vector& arr_vec) { + std::size_t n_pgn = upper - lower + 1; // number of polygons (arrangements) + std::list curves_list; + auto n_inf_pgn = prepare(lower, upper, jump, arr_vec, curves_list); + m_surface_sweep.sweep(curves_list.begin(), curves_list.end(), lower, upper, jump, arr_vec); 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->faces_begin(), n_inf_pgn); @@ -138,7 +139,26 @@ public: visitor.after_scan(*m_arr); } - /*! Destruct. + /*! sweeps the plane without interceptions, but stop when an intersection occurs. + */ + bool sweep_intercept_arrangements(std::size_t lower, std::size_t upper, std::size_t jump, + std::vector& arr_vec) { + std::list curves_list; + auto n_inf_pgn = prepare(lower, upper, jump, arr_vec, curves_list); + auto res = m_surface_sweep.sweep_intercept(curves_list.begin(), curves_list.end(), lower, upper, jump, arr_vec); + if (res) return true; + + m_faces_hash[m_arr->reference_face()] = n_inf_pgn; + std::size_t n_pgn = upper - lower + 1; // number of polygons (arrangements) + Bfs_visitor visitor(&m_edges_hash, &m_faces_hash, n_pgn); + visitor.visit_ubf(m_arr->faces_begin(), n_inf_pgn); + Bfs_scanner scanner(visitor); + scanner.scan(*m_arr); + visitor.after_scan(*m_arr); + return false; + } + + /*! destructs. */ ~Gps_agg_op() { delete m_traits; } }; diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op_surface_sweep_2.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op_surface_sweep_2.h index 33254fee5a0..ae6cb35b55c 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op_surface_sweep_2.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_agg_op_surface_sweep_2.h @@ -7,11 +7,12 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Baruch Zukerman -// Ron Wein +// Author(s) : Baruch Zukerman +// Ron Wein +// Efi Fogel -#ifndef CGAL_BSO_2_GSP_AGG_OP_SURFACE_SWEEP_2_H -#define CGAL_BSO_2_GSP_AGG_OP_SURFACE_SWEEP_2_H +#ifndef CGAL_GSP_AGG_OP_SURFACE_SWEEP_2_H +#define CGAL_GSP_AGG_OP_SURFACE_SWEEP_2_H #include @@ -70,17 +71,15 @@ public: Base(traits, visitor) {} - /*! Perform the sweep. */ template - void sweep(CurveInputIterator curves_begin, CurveInputIterator curves_end, - std::size_t lower, std::size_t upper, std::size_t jump, - std::vector& arr_vec) { + void pre_process(CurveInputIterator curves_begin, CurveInputIterator curves_end, + std::size_t lower, std::size_t upper, std::size_t jump, + std::vector& arr_vec) { CGAL_assertion(this->m_queue->empty() && this->m_statusLine.size() == 0); using Vertices_map = Unique_hash_map; using Compare_xy_2 = typename Gt2::Compare_xy_2; - this->m_visitor->before_sweep(); // Allocate all of the Subcurve objects as one block. this->m_num_of_subCurves = std::distance(curves_begin, curves_end); if (this->m_num_of_subCurves > 0) @@ -203,13 +202,29 @@ public: e_right->add_curve_to_left(this->m_subCurves + index); this->_add_curve_to_right(e_left, this->m_subCurves + index); } + } - // Perform the sweep: + /*! Perform the sweep. */ + template + void sweep(CurveInputIterator curves_begin, CurveInputIterator curves_end, + std::size_t lower, std::size_t upper, std::size_t jump, std::vector& arr_vec) { + this->m_visitor->before_sweep(); + pre_process(curves_begin, curves_end,lower, upper, jump, arr_vec); this->_sweep(); this->_complete_sweep(); this->m_visitor->after_sweep(); + } - return; + /*! Perform the sweep. */ + template + bool sweep_intercept(CurveInputIterator curves_begin, CurveInputIterator curves_end, + std::size_t lower, std::size_t upper, std::size_t jump, std::vector& arr_vec) { + this->m_visitor->before_sweep(); + pre_process(curves_begin, curves_end,lower, upper, jump, arr_vec); + this->_sweep(); + this->_complete_sweep(); + this->m_visitor->after_sweep(); + return this->m_visitor->found_intersection(); } private: @@ -230,7 +245,6 @@ private: else return (Event::LEFT_END); } ++circ; - } while (circ != first); // If we reached here, we should not keep this vertex. 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 b18a3ad2b0e..71ab8e64521 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 @@ -7,12 +7,12 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// // Author(s) : Baruch Zukerman // Ron Wein +// Efi Fogel -#ifndef CGAL_BSO_2_GSP_AGG_OP_VISITOR_H -#define CGAL_BSO_2_GSP_AGG_OP_VISITOR_H +#ifndef CGAL_GSP_AGG_OP_VISITOR_H +#define CGAL_GSP_AGG_OP_VISITOR_H #include @@ -31,7 +31,7 @@ class Gps_agg_op_base_visitor : Helper_, typename Default::Get >::type> { + Visitor_>>::type> { public: using Helper = Helper_; using Arrangement_2 = Arrangement_; @@ -43,7 +43,6 @@ public: private: using Gt2 = Geometry_traits_2; using Arr = Arrangement_2; - using Self = Gps_agg_op_base_visitor; using Visitor = typename Default::Get::type; using Base = Arr_construction_ss_visitor; @@ -127,7 +126,8 @@ template class Gps_agg_op_visitor : public Gps_agg_op_base_visitor< Helper_, Arrangement_, - Gps_agg_op_visitor> { + typename Default::Get>::type> { public: using Helper = Helper_; using Arrangement_2 = Arrangement_; @@ -145,6 +145,7 @@ private: using Base = Gps_agg_op_base_visitor; public: + using Edges_hash = typename Base::Edges_hash; using Halfedge_handle = typename Base::Halfedge_handle; using Vertex_handle = typename Base::Vertex_handle; using X_monotone_curve_2 = typename Gt2::X_monotone_curve_2; @@ -156,7 +157,7 @@ protected: // ascending order. public: - Gps_agg_op_visitor(Arr* arr, typename Base::Edges_hash* hash, + Gps_agg_op_visitor(Arr* arr, Edges_hash* hash, std::vector* vertices_vec) : Base(arr, hash), m_event_count(0), @@ -210,7 +211,7 @@ public: CGAL_assertion((Arr_halfedge_direction)res_he->direction() == ARR_LEFT_TO_RIGHT); - _insert_vertex (curr_event, res_he->target()); + _insert_vertex(curr_event, res_he->target()); return res_he; } 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 1dca9c8c9f1..b269c73623b 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 @@ -43,7 +43,6 @@ protected: std::size_t m_num_of_polygons; // number of polygons public: - Gps_bfs_base_visitor(Edges_hash* edges_hash, Faces_hash* faces_hash, std::size_t n_pgn): @@ -79,12 +78,12 @@ public: protected: // compute the inside count of a face std::size_t compute_ic(Face_iterator f1, - Face_iterator f2, - Halfedge_iterator he) { + Face_iterator f2, + 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)); + ! m_faces_hash->is_defined(f2)); std::size_t ic_f2 = (*m_faces_hash)[f1] - (*m_edges_hash)[he] + (*m_edges_hash)[he->twin()]; (*m_faces_hash)[f2] = 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 b562c8ca52c..d3b4ec19be4 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 @@ -7,10 +7,9 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// - -// Author(s) : Baruch Zukerman -// Ophir Setter +// Author(s) : Baruch Zukerman +// Ophir Setter +// Efi Fogel #ifndef CGAL_GPS_BFS_INTERSECTION_VISITOR_H #define CGAL_GPS_BFS_INTERSECTION_VISITOR_H diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_do_intersect_agg_op_visitor.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_do_intersect_agg_op_visitor.h new file mode 100644 index 00000000000..0e11afafa7e --- /dev/null +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_do_intersect_agg_op_visitor.h @@ -0,0 +1,88 @@ +// Copyright (c) 2005 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Efi Fogel + +#ifndef CGAL_GSP_DO_INTERSECT_AGG_OP_VISITOR_H +#define CGAL_GSP_DO_INTERSECT_AGG_OP_VISITOR_H + +#include + +#include +#include +#include + +namespace CGAL { + +template +class Gps_do_intersect_agg_op_visitor : + public Gps_agg_op_visitor< + Helper_, Arrangement_, + typename Default::Get>::type> { +public: + using Helper = Helper_; + using Arrangement_2 = Arrangement_; + using Geometry_traits_2 = typename Helper::Geometry_traits_2; + using Event = typename Helper::Event; + using Subcurve = typename Helper::Subcurve; + +private: + using Gt2 = Geometry_traits_2; + using Arr = Arrangement_2; + using Self = Gps_do_intersect_agg_op_visitor; + using Visitor = typename Default::Get::type; + using Base = Gps_agg_op_visitor; + +protected: + bool m_found_x; + +public: + using Edges_hash = typename Base::Edges_hash; + using Vertex_handle = typename Base::Vertex_handle; + using Status_line_iterator = typename Base::Status_line_iterator; + using X_monotone_curve_2 = typename Base::X_monotone_curve_2; + using Point_2 = typename Base::Point_2; + + Gps_do_intersect_agg_op_visitor(Arr* arr, Edges_hash* hash, + std::vector* vertices_vec) : + Base(arr, hash, vertices_vec), + m_found_x(false) + {} + + /*! Update an event that corresponds to a curve endpoint. */ + void update_event(Event* e, const Point_2& end_point, const X_monotone_curve_2& cv, Arr_curve_end cv_end, bool is_new) + { return Base::update_event(e, end_point, cv, cv_end, is_new); } + + /*! Update an event that corresponds to a curve endpoint */ + void update_event(Event* e, const X_monotone_curve_2& cv, Arr_curve_end cv_end, bool is_new ) + { return Base::update_event(e, cv, cv_end, is_new); } + + /*! Update an event that corresponds to a curve endpoint */ + void update_event(Event* e, const Point_2& p, bool is_new) + { return Base::update_event(e, p, is_new); } + + /*! Update an event that corresponds to an intersection */ + void update_event(Event* e, Subcurve* sc) { return Base::update_event(e, sc); } + + /*! Update an event that corresponds to an intersection between curves */ + void update_event(Event*, Subcurve*, Subcurve*, bool is_new) { m_found_x = true; } + + bool after_handle_event(Event* e, Status_line_iterator iter, bool flag) { + auto res = Base::after_handle_event(e, iter, flag); + if (m_found_x) this->surface_sweep()->stop_sweep(); + return res; + } + + /*! Getter */ + bool found_intersection() { return m_found_x; } +}; + +} // namespace CGAL + +#endif 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 85ddf2a9492..382afd5ba5f 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 @@ -7,7 +7,8 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Baruch Zukerman +// Author(s) : Baruch Zukerman +// Efi Fogel #ifndef CGAL_GPS_MERGE_H #define CGAL_GPS_MERGE_H @@ -15,6 +16,8 @@ #include #include +#include +#include #include #include #include @@ -23,16 +26,16 @@ namespace CGAL { /*! \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. + * + * 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. +/*! 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. */ @@ -44,17 +47,15 @@ class Base_merge { using Arr_entry = std::pair*>; public: - void operator()(std::size_t i, std::size_t j, std::size_t jump, - std::vector& arr_vec) { + void operator()(std::size_t i, std::size_t j, std::size_t jump, std::vector& arr_vec) { if (i == j) return; - const typename Arrangement_2::Geometry_traits_2* tr = - arr_vec[i].first->geometry_traits(); + const auto* 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, *(res->traits_adaptor())); + using Agg_op = Gps_agg_op; + Agg_op agg_op(*res, *verts, *(res->traits_adaptor())); agg_op.sweep_arrangements(i, j, jump, arr_vec); for (std::size_t count = i; count <= j; count += jump) { @@ -67,29 +68,69 @@ public: } }; -//! Join_merge -/*! Join_merge is used to join two sets of polygons together in the D&C +/*! Base_intercepted_merge + * Base_intercepted_merge is the base class for all merger classes that can be + * interceted (e.g., when an intersection is detected). All merges used BFS + * algorithm with a different visitor when discovering a new face. + */ +template +class Base_intercepted_merge { + using Arrangement_2 = Arrangement_; + using Visitor = Visitor_; + using Vertex_handle = typename Arrangement_2::Vertex_handle; + using Arr_entry = std::pair*>; + +public: + bool operator()(std::size_t i, std::size_t j, std::size_t jump, std::vector& arr_vec) { + if (i == j) return false; + + const auto* tr = arr_vec[i].first->geometry_traits(); + Arrangement_2* arr = new Arrangement_2(tr); + std::vector* verts = new std::vector; + + using Agg_op = Gps_agg_op; + Agg_op agg_op(*arr, *verts, *(arr->traits_adaptor())); + auto res = agg_op.sweep_intercept_arrangements(i, j, jump, arr_vec); + + for (auto count = i; count <= j; count += jump) { + delete (arr_vec[count].first); + delete (arr_vec[count].second); + } + + arr_vec[i].first = arr; + arr_vec[i].second = verts; + return res; + } +}; + +/*! 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 Join_merge : public Base_merge> -{}; +class Join_merge : public Base_merge>{}; -//! Intersection_merge -/*! Intersection_merge is used to merge two sets of polygons creating their +/*! Intersection_merge + * Intersection_merge is used to merge two sets of polygons creating their * intersection. */ template -class Intersection_merge : public Base_merge> -{}; +class Intersection_merge : public Base_merge>{}; -//! Xor_merge -/*! Xor_merge is used to merge two sets of polygons creating their +/*! Do_intersect_merge + * Do_intersect_merge is used to merge two sets of polygons creating their + * intersection. When an intersection in the interior of the boundary curves + * is detected, the sweep is intercepted. + */ +template +class Do_intersect_merge : public Base_intercepted_merge>{}; + +/*! Xor_merge + * Xor_merge is used to merge two sets of polygons creating their * symmetric difference. */ template -class Xor_merge : public Base_merge> -{}; +class Xor_merge : public Base_merge>{}; } //namespace CGAL diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_on_surface_base_2.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_on_surface_base_2.h index d7d3b9f911c..60530dfd831 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_on_surface_base_2.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Gps_on_surface_base_2.h @@ -10,7 +10,7 @@ // Author(s) : Baruch Zukerman // Ophir Setter // Guy Zucker - +// Efi Fogel #ifndef CGAL_GPS_ON_SURFACE_BASE_2_H #define CGAL_GPS_ON_SURFACE_BASE_2_H @@ -388,18 +388,19 @@ public: 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 - // contained in the polygon set (there can be several faces in an empty - // arrangement, dependent 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 several faces with different - // attributes. - return (m_arr->is_empty() && !m_arr->faces_begin()->contained()); - } + // We have to check that all the faces of an empty arrangement are not + // contained in the polygon set (there can be several faces in an empty + // arrangement, dependent 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 several faces with different + // attributes. + bool is_empty() const { this->_is_empty(m_arr); } + + bool _is_empty(Aos_2* arr) const + { return (arr->is_empty() && ! arr->faces_begin()->contained()); } bool is_plane() const { // Same comment as in "is_empty" above, just with adjustments. @@ -493,8 +494,33 @@ public: template bool do_intersect(InputIterator begin, InputIterator end, std::size_t k = 5) { Self other(*this); - other.intersection(begin, end, k); - return (other.is_empty()); + return other._do_intersect(begin, end, k); + } + + // intersects a range of polygons + template + inline bool _do_intersect(InputIterator begin, InputIterator end, std::size_t k) { + std::vector arr_vec(std::distance(begin, end) + 1); + arr_vec[0].first = this->m_arr; + std::size_t i = 1; + + for (auto it = begin; it != end; ++it, ++i) { + ValidationPolicy::is_valid((*it), *m_traits); + arr_vec[i].first = new Aos_2(m_traits); + _insert(*it, *(arr_vec[i].first)); + } + + Do_intersect_merge do_intersect_merge; + auto res = do_intersect_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, do_intersect_merge); + + // The resulting arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + if (res) return res; + + _remove_redundant_edges(arr_vec[0].first); + _reset_faces(arr_vec[0].first); + return (_is_empty(arr_vec[0].first)); } template @@ -502,8 +528,40 @@ public: InputIterator2 begin2, InputIterator2 end2, std::size_t k = 5) { Self other(*this); - other.intersection(begin1, end1, begin2, end2, k); - return (other.is_empty()); + return other._do_intersect(begin1, end1, begin2, end2, k); + } + + template + bool _do_intersect(InputIterator1 begin1, InputIterator1 end1, + InputIterator2 begin2, InputIterator2 end2, + std::size_t k = 5) { + std::vector arr_vec(std::distance(begin1, end1) + std::distance(begin2, end2) + 1); + arr_vec[0].first = this->m_arr; + std::size_t i = 1; + + for (InputIterator1 itr1 = begin1; itr1 != end1; ++itr1, ++i) { + ValidationPolicy::is_valid(*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) { + ValidationPolicy::is_valid(*itr2,*m_traits); + arr_vec[i].first = new Aos_2(m_traits); + _insert(*itr2, *(arr_vec[i].first)); + } + + Do_intersect_merge do_intersect_merge; + auto res = do_intersect_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, do_intersect_merge); + + // The resulting arrangement is at index 0 + this->m_arr = arr_vec[0].first; + delete arr_vec[0].second; + if (res) return res; + + _remove_redundant_edges(arr_vec[0].first); + _reset_faces(arr_vec[0].first); + return (_is_empty(arr_vec[0].first)); } // joins a range of polygons @@ -533,7 +591,6 @@ public: } 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 @@ -556,7 +613,6 @@ public: } 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 @@ -585,7 +641,6 @@ public: } 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 @@ -620,7 +675,6 @@ public: } 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 @@ -636,14 +690,13 @@ public: arr_vec[0].first = this->m_arr; std::size_t i = 1; - for (InputIterator itr = begin; itr!=end; ++itr, ++i) { + for (InputIterator itr = begin; itr != end; ++itr, ++i) { ValidationPolicy::is_valid((*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 @@ -659,20 +712,19 @@ public: arr_vec[0].first = this->m_arr; std::size_t i = 1; - for (InputIterator1 itr1 = begin1; itr1!=end1; ++itr1, ++i) { + for (InputIterator1 itr1 = begin1; itr1 != end1; ++itr1, ++i) { ValidationPolicy::is_valid(*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) { + for (InputIterator2 itr2 = begin2; itr2 != end2; ++itr2, ++i) { ValidationPolicy::is_valid(*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 @@ -708,7 +760,6 @@ public: } 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 @@ -731,7 +782,6 @@ public: } 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 @@ -761,7 +811,6 @@ public: } 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 @@ -1155,10 +1204,10 @@ protected: } } - void _build_sorted_vertices_vectors(std::vector& arr_vec) { + //! Allocate, collect , and sort the vertex handles of the arrangements in the given interval + void _build_sorted_vertices_vectors(std::size_t lower, std::size_t upper, std::vector& arr_vec) { Less_vertex_handle comp(m_traits->compare_xy_2_object()); - const std::size_t n = arr_vec.size(); - for (std::size_t i = 0; i < n; i++) { + for (std::size_t i = lower; i < upper + 1; i++) { // Allocate a vector of handles to all vertices in the current arrangement. Aos_2* p_arr = arr_vec[i].first; arr_vec[i].second = new std::vector; @@ -1174,11 +1223,16 @@ protected: } } + //! Divide & conquer template void _divide_and_conquer(std::size_t lower, std::size_t upper, std::vector& arr_vec, std::size_t k, Merge merge_func) { + static int indent = 0; + std::cout << std::setw(indent) << "" << "D&C [" << lower << "," << upper << "," << k << "]\n"; if ((upper - lower) < k) { + std::cout << std::setw(indent) << "" << "Merging [" << lower << "," << upper << "," << 1 << "]\n"; + _build_sorted_vertices_vectors(lower, upper, arr_vec); merge_func(lower, upper, 1, arr_vec); return; } @@ -1187,12 +1241,71 @@ protected: auto curr_lower = lower; for (std::size_t i = 0; i < k - 1; ++i, curr_lower += sub_size) { + indent += 2; _divide_and_conquer(curr_lower, curr_lower + sub_size-1, arr_vec, k, merge_func); + indent -= 2; } + indent += 2; _divide_and_conquer(curr_lower, upper, arr_vec, k, merge_func); + indent -= 2; + std::cout << std::setw(indent) << "" << "Merging [" << lower << "," << curr_lower << "," << sub_size << "]\n"; merge_func(lower, curr_lower, sub_size, arr_vec); } + /*! Divide & conquer tailored for the do_intersect() function. + * It returns a Boolean value indicating whether an intersection in the + * interiors of the curves have been detected. Also, it terminates + * as a sson as such an intersection has been detected. + */ + template + bool do_intersect_divide_and_conquer(std::size_t lower, std::size_t upper, + std::vector& arr_vec, + std::size_t k, Merge merge_func) { + static int indent = 0; + std::cout << std::setw(indent) << "" << "D&C [" << lower << "," << upper << "," << k << "]\n"; + if ((upper - lower) < k) { + std::cout << std::setw(indent) << "" << "Merging [" << lower << "," << upper << "," << 1 << "]\n"; + _build_sorted_vertices_vectors(lower, upper, arr_vec); + return merge_func(lower, upper, 1, arr_vec); + } + + auto sub_size = ((upper - lower + 1) / k); + auto curr_lower = lower; + + bool res = false; + for (std::size_t i = 0; i < k - 1; ++i, curr_lower += sub_size) { + indent += 2; + res = do_intersect_divide_and_conquer(curr_lower, curr_lower + sub_size-1, arr_vec, k, merge_func); + indent -= 2; + if (res) break; + } + if (res) { + // Clean up the entries that have been created + std::cout << std::setw(indent) << "" << "Cleaning [" << lower + sub_size << "," << curr_lower << "," << sub_size << "]\n"; + for (auto count = lower + sub_size; count <= curr_lower; count += sub_size) { + delete (arr_vec[count].first); + delete (arr_vec[count].second); + } + return true; + } + + indent += 2; + res = do_intersect_divide_and_conquer(curr_lower, upper, arr_vec, k, merge_func); + indent -= 2; + if (res) { + // Clean up the entries that have been created + std::cout << std::setw(indent) << "" << "Cleaning [" << lower + sub_size << "," << curr_lower << "," << sub_size << "]\n"; + for (std::size_t count = lower + sub_size; count <= curr_lower; count += sub_size) { + delete (arr_vec[count].first); + delete (arr_vec[count].second); + } + return true; + } + + std::cout << std::setw(indent) << "" << "Merging [" << lower << "," << curr_lower << "," << sub_size << "]\n"; + return merge_func(lower, curr_lower, sub_size, arr_vec); + } + // marks all faces as non-visited void _reset_faces() const { _reset_faces(m_arr); }