Interception sweep for do_intersect()

This commit is contained in:
Efi Fogel 2025-08-28 12:11:48 +03:00
parent a366725c85
commit f69ad03ef8
9 changed files with 391 additions and 117 deletions

View File

@ -7,12 +7,11 @@
// $Id$ // $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
// //
//
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il> // Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Efi Fogel <efifogel@gmail.com> // Efi Fogel <efifogel@gmail.com>
#ifndef CGAL_BSO_2_GPS_AGG_META_TRAITS_H #ifndef CGAL_GPS_AGG_META_TRAITS_H
#define CGAL_BSO_2_GPS_AGG_META_TRAITS_H #define CGAL_GPS_AGG_META_TRAITS_H
#include <CGAL/license/Boolean_set_operations_2.h> #include <CGAL/license/Boolean_set_operations_2.h>

View File

@ -7,11 +7,12 @@
// $Id$ // $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
// //
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il> // Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Ophir Setter <ophir.setter@cs.tau.ac.il> // Ophir Setter <ophir.setter@cs.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
#ifndef CGAL_BSO_2_GPS_AGG_OP_H #ifndef CGAL_GPS_AGG_OP_H
#define CGAL_BSO_2_GPS_AGG_OP_H #define CGAL_GPS_AGG_OP_H
#include <CGAL/license/Boolean_set_operations_2.h> #include <CGAL/license/Boolean_set_operations_2.h>
@ -19,8 +20,8 @@
* *
* The class Gps_agg_op is responsible for aggregated Boolean set operations * The class Gps_agg_op is responsible for aggregated Boolean set operations
* depending on a visitor template parameter. It uses the surface-sweep * depending on a visitor template parameter. It uses the surface-sweep
* algorithm from the arrangement packages to overlay all the polygon sets, and * algorithm from the surface-sweep package to overlay all the polygon sets, and
* then it uses a BFS that determines which of the faces is contained in the * then it uses a BFS that determines which of the faces are contained in the
* result using the visitor. * result using the visitor.
*/ */
@ -37,7 +38,7 @@
namespace CGAL { namespace CGAL {
template <typename Arrangement_, typename BfsVisitor> template <typename Arrangement_, typename BfsVisitor, template <typename, typename> class SweepVisitor>
class Gps_agg_op { class Gps_agg_op {
using Arrangement_2 = Arrangement_; using Arrangement_2 = Arrangement_;
using Bfs_visitor = BfsVisitor; using Bfs_visitor = BfsVisitor;
@ -74,7 +75,7 @@ class Gps_agg_op {
using Subcurve = Arr_construction_subcurve<Mgt2, Event, Allocator>; using Subcurve = Arr_construction_subcurve<Mgt2, Event, Allocator>;
using Helper_tmp = typename Tt::template Construction_helper<Event, Subcurve>; using Helper_tmp = typename Tt::template Construction_helper<Event, Subcurve>;
using Helper = typename Helper_tmp::template rebind<Mgt2, Arr, Event, Subcurve>::other; using Helper = typename Helper_tmp::template rebind<Mgt2, Arr, Event, Subcurve>::other;
using Visitor = Gps_agg_op_visitor<Helper, Arr>; using Visitor = SweepVisitor<Helper, Arr>;
using Surface_sweep_2 = Gps_agg_op_surface_sweep_2<Arr, Visitor>; using Surface_sweep_2 = Gps_agg_op_surface_sweep_2<Arr, Visitor>;
using Edges_hash = Unique_hash_map<Halfedge_handle, std::size_t>; using Edges_hash = Unique_hash_map<Halfedge_handle, std::size_t>;
@ -90,7 +91,7 @@ protected:
Faces_hash m_faces_hash; // maps face to its IC (inside count) Faces_hash m_faces_hash; // maps face to its IC (inside count)
public: public:
/*! Constructor. */ /*! constructs. */
Gps_agg_op(Arr& arr, std::vector<Vertex_handle>& vert_vec, const Gt2& tr) : Gps_agg_op(Arr& arr, std::vector<Vertex_handle>& vert_vec, const Gt2& tr) :
m_arr(&arr), m_arr(&arr),
m_traits(new Mgt2(tr)), m_traits(new Mgt2(tr)),
@ -98,38 +99,38 @@ public:
m_surface_sweep(m_traits, &m_visitor) m_surface_sweep(m_traits, &m_visitor)
{} {}
void sweep_arrangements(std::size_t lower, std::size_t upper, std::size_t prepare(std::size_t lower, std::size_t upper, std::size_t jump,
std::size_t jump, std::vector<Arr_entry>& arr_vec) { std::vector<Arr_entry>& arr_vec, std::list<Meta_X_monotone_curve_2>& curves_list) {
std::list<Meta_X_monotone_curve_2> curves_list;
std::size_t n_inf_pgn = 0; // number of infinite polygons (arrangement std::size_t n_inf_pgn = 0; // number of infinite polygons (arrangement
// with a contained unbounded face // with a contained unbounded face
std::size_t n_pgn = 0; // number of polygons (arrangements) for (auto i = lower; i <= upper; i += jump) {
for (std::size_t i = lower; i <= upper; i += jump, ++n_pgn) {
// The BFS scan (after the loop) starts in the reference face, // The BFS scan (after the loop) starts in the reference face,
// so we count the number of polygons that contain the reference face. // so we count the number of polygons that contain the reference face.
Arr* arr = (arr_vec[i]).first; Arr* arr = (arr_vec[i]).first;
if (arr->reference_face()->contained()) ++n_inf_pgn; if (arr->reference_face()->contained()) ++n_inf_pgn;
Edge_iterator itr = arr->edges_begin(); for (auto itr = arr->edges_begin(); itr != arr->edges_end(); ++itr) {
for(; itr != arr->edges_end(); ++itr) {
// take only relevant edges (which separate between contained and // take only relevant edges (which separate between contained and
// non-contained faces. // non-contained faces.
Halfedge_iterator he = itr; Halfedge_handle he = itr;
if (he->face()->contained() == he->twin()->face()->contained()) if (he->face()->contained() == he->twin()->face()->contained()) continue;
continue; if ((Arr_halfedge_direction)he->direction() == ARR_RIGHT_TO_LEFT) he = he->twin();
if ((Arr_halfedge_direction)he->direction() == ARR_RIGHT_TO_LEFT)
he = he->twin();
Curve_data cv_data(arr, he, 1, 0); Curve_data cv_data(arr, he, 1, 0);
curves_list.push_back(Meta_X_monotone_curve_2(he->curve(), cv_data)); 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(), /*! sweeps the plane without interceptions.
lower, upper, jump, arr_vec); */
void sweep_arrangements(std::size_t lower, std::size_t upper, std::size_t jump,
std::vector<Arr_entry>& arr_vec) {
std::size_t n_pgn = upper - lower + 1; // number of polygons (arrangements)
std::list<Meta_X_monotone_curve_2> 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; m_faces_hash[m_arr->reference_face()] = n_inf_pgn;
Bfs_visitor visitor(&m_edges_hash, &m_faces_hash, n_pgn); Bfs_visitor visitor(&m_edges_hash, &m_faces_hash, n_pgn);
visitor.visit_ubf(m_arr->faces_begin(), n_inf_pgn); visitor.visit_ubf(m_arr->faces_begin(), n_inf_pgn);
@ -138,7 +139,26 @@ public:
visitor.after_scan(*m_arr); 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_entry>& arr_vec) {
std::list<Meta_X_monotone_curve_2> 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; } ~Gps_agg_op() { delete m_traits; }
}; };

View File

@ -7,11 +7,12 @@
// $Id$ // $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
// //
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il> // Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Ron Wein <wein@post.tau.ac.il> // Ron Wein <wein@post.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
#ifndef CGAL_BSO_2_GSP_AGG_OP_SURFACE_SWEEP_2_H #ifndef CGAL_GSP_AGG_OP_SURFACE_SWEEP_2_H
#define CGAL_BSO_2_GSP_AGG_OP_SURFACE_SWEEP_2_H #define CGAL_GSP_AGG_OP_SURFACE_SWEEP_2_H
#include <vector> #include <vector>
@ -70,17 +71,15 @@ public:
Base(traits, visitor) Base(traits, visitor)
{} {}
/*! Perform the sweep. */
template <typename CurveInputIterator> template <typename CurveInputIterator>
void sweep(CurveInputIterator curves_begin, CurveInputIterator curves_end, void pre_process(CurveInputIterator curves_begin, CurveInputIterator curves_end,
std::size_t lower, std::size_t upper, std::size_t jump, std::size_t lower, std::size_t upper, std::size_t jump,
std::vector<Arr_entry>& arr_vec) { std::vector<Arr_entry>& arr_vec) {
CGAL_assertion(this->m_queue->empty() && this->m_statusLine.size() == 0); CGAL_assertion(this->m_queue->empty() && this->m_statusLine.size() == 0);
using Vertices_map = Unique_hash_map<Vertex_handle, Event*>; using Vertices_map = Unique_hash_map<Vertex_handle, Event*>;
using Compare_xy_2 = typename Gt2::Compare_xy_2; using Compare_xy_2 = typename Gt2::Compare_xy_2;
this->m_visitor->before_sweep();
// Allocate all of the Subcurve objects as one block. // Allocate all of the Subcurve objects as one block.
this->m_num_of_subCurves = std::distance(curves_begin, curves_end); this->m_num_of_subCurves = std::distance(curves_begin, curves_end);
if (this->m_num_of_subCurves > 0) if (this->m_num_of_subCurves > 0)
@ -203,13 +202,29 @@ public:
e_right->add_curve_to_left(this->m_subCurves + index); e_right->add_curve_to_left(this->m_subCurves + index);
this->_add_curve_to_right(e_left, this->m_subCurves + index); this->_add_curve_to_right(e_left, this->m_subCurves + index);
} }
}
// Perform the sweep: /*! Perform the sweep. */
template <typename CurveInputIterator>
void sweep(CurveInputIterator curves_begin, CurveInputIterator curves_end,
std::size_t lower, std::size_t upper, std::size_t jump, std::vector<Arr_entry>& arr_vec) {
this->m_visitor->before_sweep();
pre_process(curves_begin, curves_end,lower, upper, jump, arr_vec);
this->_sweep(); this->_sweep();
this->_complete_sweep(); this->_complete_sweep();
this->m_visitor->after_sweep(); this->m_visitor->after_sweep();
}
return; /*! Perform the sweep. */
template <typename CurveInputIterator>
bool sweep_intercept(CurveInputIterator curves_begin, CurveInputIterator curves_end,
std::size_t lower, std::size_t upper, std::size_t jump, std::vector<Arr_entry>& 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: private:
@ -230,7 +245,6 @@ private:
else return (Event::LEFT_END); else return (Event::LEFT_END);
} }
++circ; ++circ;
} while (circ != first); } while (circ != first);
// If we reached here, we should not keep this vertex. // If we reached here, we should not keep this vertex.

View File

@ -7,12 +7,12 @@
// $Id$ // $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
// //
//
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il> // Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Ron Wein <wein@post.tau.ac.il> // Ron Wein <wein@post.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
#ifndef CGAL_BSO_2_GSP_AGG_OP_VISITOR_H #ifndef CGAL_GSP_AGG_OP_VISITOR_H
#define CGAL_BSO_2_GSP_AGG_OP_VISITOR_H #define CGAL_GSP_AGG_OP_VISITOR_H
#include <CGAL/license/Boolean_set_operations_2.h> #include <CGAL/license/Boolean_set_operations_2.h>
@ -31,7 +31,7 @@ class Gps_agg_op_base_visitor :
Helper_, Helper_,
typename Default::Get<Visitor_, Gps_agg_op_base_visitor<Helper_, typename Default::Get<Visitor_, Gps_agg_op_base_visitor<Helper_,
Arrangement_, Arrangement_,
Visitor_> >::type> { Visitor_>>::type> {
public: public:
using Helper = Helper_; using Helper = Helper_;
using Arrangement_2 = Arrangement_; using Arrangement_2 = Arrangement_;
@ -43,7 +43,6 @@ public:
private: private:
using Gt2 = Geometry_traits_2; using Gt2 = Geometry_traits_2;
using Arr = Arrangement_2; using Arr = Arrangement_2;
using Self = Gps_agg_op_base_visitor<Helper, Arr, Visitor_>; using Self = Gps_agg_op_base_visitor<Helper, Arr, Visitor_>;
using Visitor = typename Default::Get<Visitor_, Self>::type; using Visitor = typename Default::Get<Visitor_, Self>::type;
using Base = Arr_construction_ss_visitor<Helper, Visitor>; using Base = Arr_construction_ss_visitor<Helper, Visitor>;
@ -127,7 +126,8 @@ template <typename Helper_, typename Arrangement_, typename Visitor_ = Default>
class Gps_agg_op_visitor : class Gps_agg_op_visitor :
public Gps_agg_op_base_visitor< public Gps_agg_op_base_visitor<
Helper_, Arrangement_, Helper_, Arrangement_,
Gps_agg_op_visitor<Helper_, Arrangement_, Visitor_>> { typename Default::Get<Visitor_,
Gps_agg_op_visitor<Helper_, Arrangement_, Visitor_>>::type> {
public: public:
using Helper = Helper_; using Helper = Helper_;
using Arrangement_2 = Arrangement_; using Arrangement_2 = Arrangement_;
@ -145,6 +145,7 @@ private:
using Base = Gps_agg_op_base_visitor<Helper, Arr, Visitor>; using Base = Gps_agg_op_base_visitor<Helper, Arr, Visitor>;
public: public:
using Edges_hash = typename Base::Edges_hash;
using Halfedge_handle = typename Base::Halfedge_handle; using Halfedge_handle = typename Base::Halfedge_handle;
using Vertex_handle = typename Base::Vertex_handle; using Vertex_handle = typename Base::Vertex_handle;
using X_monotone_curve_2 = typename Gt2::X_monotone_curve_2; using X_monotone_curve_2 = typename Gt2::X_monotone_curve_2;
@ -156,7 +157,7 @@ protected:
// ascending order. // ascending order.
public: public:
Gps_agg_op_visitor(Arr* arr, typename Base::Edges_hash* hash, Gps_agg_op_visitor(Arr* arr, Edges_hash* hash,
std::vector<Vertex_handle>* vertices_vec) : std::vector<Vertex_handle>* vertices_vec) :
Base(arr, hash), Base(arr, hash),
m_event_count(0), m_event_count(0),
@ -210,7 +211,7 @@ public:
CGAL_assertion((Arr_halfedge_direction)res_he->direction() == CGAL_assertion((Arr_halfedge_direction)res_he->direction() ==
ARR_LEFT_TO_RIGHT); ARR_LEFT_TO_RIGHT);
_insert_vertex (curr_event, res_he->target()); _insert_vertex(curr_event, res_he->target());
return res_he; return res_he;
} }

View File

@ -43,7 +43,6 @@ protected:
std::size_t m_num_of_polygons; // number of polygons std::size_t m_num_of_polygons; // number of polygons
public: public:
Gps_bfs_base_visitor(Edges_hash* edges_hash, Gps_bfs_base_visitor(Edges_hash* edges_hash,
Faces_hash* faces_hash, Faces_hash* faces_hash,
std::size_t n_pgn): std::size_t n_pgn):
@ -79,12 +78,12 @@ public:
protected: protected:
// compute the inside count of a face // compute the inside count of a face
std::size_t compute_ic(Face_iterator f1, std::size_t compute_ic(Face_iterator f1,
Face_iterator f2, Face_iterator f2,
Halfedge_iterator he) { Halfedge_iterator he) {
CGAL_assertion(m_edges_hash->is_defined(he) && CGAL_assertion(m_edges_hash->is_defined(he) &&
m_edges_hash->is_defined(he->twin()) && m_edges_hash->is_defined(he->twin()) &&
m_faces_hash->is_defined(f1) && m_faces_hash->is_defined(f1) &&
!m_faces_hash->is_defined(f2)); ! m_faces_hash->is_defined(f2));
std::size_t ic_f2 = std::size_t ic_f2 =
(*m_faces_hash)[f1] - (*m_edges_hash)[he] + (*m_edges_hash)[he->twin()]; (*m_faces_hash)[f1] - (*m_edges_hash)[he] + (*m_edges_hash)[he->twin()];
(*m_faces_hash)[f2] = ic_f2; (*m_faces_hash)[f2] = ic_f2;

View File

@ -7,10 +7,9 @@
// $Id$ // $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
// //
// // Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Ophir Setter <ophir.setter@cs.tau.ac.il>
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il> // Efi Fogel <efifogel@gmail.com>
// Ophir Setter <ophir.setter@cs.tau.ac.il>
#ifndef CGAL_GPS_BFS_INTERSECTION_VISITOR_H #ifndef CGAL_GPS_BFS_INTERSECTION_VISITOR_H
#define CGAL_GPS_BFS_INTERSECTION_VISITOR_H #define CGAL_GPS_BFS_INTERSECTION_VISITOR_H

View File

@ -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 <efifogel@gmail.com>
#ifndef CGAL_GSP_DO_INTERSECT_AGG_OP_VISITOR_H
#define CGAL_GSP_DO_INTERSECT_AGG_OP_VISITOR_H
#include <vector>
#include <CGAL/license/Boolean_set_operations_2.h>
#include <CGAL/Boolean_set_operations_2/Gps_agg_op_visitor.h>
#include <CGAL/Default.h>
namespace CGAL {
template <typename Helper_, typename Arrangement_, typename Visitor_ = Default>
class Gps_do_intersect_agg_op_visitor :
public Gps_agg_op_visitor<
Helper_, Arrangement_,
typename Default::Get<Visitor_, Gps_do_intersect_agg_op_visitor<Helper_, Arrangement_, Visitor_>>::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<Helper, Arr, Visitor_>;
using Visitor = typename Default::Get<Visitor_, Self>::type;
using Base = Gps_agg_op_visitor<Helper, Arr, 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<Vertex_handle>* 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

View File

@ -7,7 +7,8 @@
// $Id$ // $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
// //
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il> // Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
#ifndef CGAL_GPS_MERGE_H #ifndef CGAL_GPS_MERGE_H
#define CGAL_GPS_MERGE_H #define CGAL_GPS_MERGE_H
@ -15,6 +16,8 @@
#include <CGAL/license/Boolean_set_operations_2.h> #include <CGAL/license/Boolean_set_operations_2.h>
#include <CGAL/Boolean_set_operations_2/Gps_agg_op.h> #include <CGAL/Boolean_set_operations_2/Gps_agg_op.h>
#include <CGAL/Boolean_set_operations_2/Gps_agg_op_visitor.h>
#include <CGAL/Boolean_set_operations_2/Gps_do_intersect_agg_op_visitor.h>
#include <CGAL/Boolean_set_operations_2/Gps_bfs_join_visitor.h> #include <CGAL/Boolean_set_operations_2/Gps_bfs_join_visitor.h>
#include <CGAL/Boolean_set_operations_2/Gps_bfs_xor_visitor.h> #include <CGAL/Boolean_set_operations_2/Gps_bfs_xor_visitor.h>
#include <CGAL/Boolean_set_operations_2/Gps_bfs_intersection_visitor.h> #include <CGAL/Boolean_set_operations_2/Gps_bfs_intersection_visitor.h>
@ -23,16 +26,16 @@
namespace CGAL { namespace CGAL {
/*! \file Gps_merge.h /*! \file Gps_merge.h
* \brief This file contains classes that are responsible for merging *
* two sets of polygons in the divide-and-conquer algorithm. * This file contains classes that are responsible for merging two sets of
* The file contains 3 mergers: Join_merge, Intersection_merge and * polygons in the divide-and-conquer algorithm. The file contains 3 mergers:
* Xor_merge. Join_merge is used when we want to merge the two sets, * Join_merge, Intersection_merge and Xor_merge. Join_merge is used when we want
* Intersection_merge is used for intersection, and Xor_merge is used * to merge the two sets, Intersection_merge is used for intersection, and
* for symmetric difference. * Xor_merge is used for symmetric difference.
*/ */
//! Base_merge /*! Base_merge
/*! Base_merge is the base class for all merger classes. * Base_merge is the base class for all merger classes.
* All merges used BFS algorithm with a different visitor when discovering * All merges used BFS algorithm with a different visitor when discovering
* a new face. * a new face.
*/ */
@ -44,17 +47,15 @@ class Base_merge {
using Arr_entry = std::pair<Arrangement_2*, std::vector<Vertex_handle>*>; using Arr_entry = std::pair<Arrangement_2*, std::vector<Vertex_handle>*>;
public: public:
void operator()(std::size_t i, std::size_t j, std::size_t jump, void operator()(std::size_t i, std::size_t j, std::size_t jump, std::vector<Arr_entry>& arr_vec) {
std::vector<Arr_entry>& arr_vec) {
if (i == j) return; if (i == j) return;
const typename Arrangement_2::Geometry_traits_2* tr = const auto* tr = arr_vec[i].first->geometry_traits();
arr_vec[i].first->geometry_traits();
Arrangement_2* res = new Arrangement_2(tr); Arrangement_2* res = new Arrangement_2(tr);
std::vector<Vertex_handle>* verts = new std::vector<Vertex_handle>; std::vector<Vertex_handle>* verts = new std::vector<Vertex_handle>;
Gps_agg_op<Arrangement_2, Visitor> using Agg_op = Gps_agg_op<Arrangement_2, Visitor, Gps_agg_op_visitor>;
agg_op(*res, *verts, *(res->traits_adaptor())); Agg_op agg_op(*res, *verts, *(res->traits_adaptor()));
agg_op.sweep_arrangements(i, j, jump, arr_vec); agg_op.sweep_arrangements(i, j, jump, arr_vec);
for (std::size_t count = i; count <= j; count += jump) { for (std::size_t count = i; count <= j; count += jump) {
@ -67,29 +68,69 @@ public:
} }
}; };
//! Join_merge /*! Base_intercepted_merge
/*! Join_merge is used to join two sets of polygons together in the D&C * 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 <typename Arrangement_, typename Visitor_>
class Base_intercepted_merge {
using Arrangement_2 = Arrangement_;
using Visitor = Visitor_;
using Vertex_handle = typename Arrangement_2::Vertex_handle;
using Arr_entry = std::pair<Arrangement_2*, std::vector<Vertex_handle>*>;
public:
bool operator()(std::size_t i, std::size_t j, std::size_t jump, std::vector<Arr_entry>& 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<Vertex_handle>* verts = new std::vector<Vertex_handle>;
using Agg_op = Gps_agg_op<Arrangement_2, Visitor, Gps_do_intersect_agg_op_visitor>;
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. * algorithm. It is a base merge with a visitor that joins faces.
*/ */
template <typename Arrangement_> template <typename Arrangement_>
class Join_merge : public Base_merge<Arrangement_, Gps_bfs_join_visitor<Arrangement_>> class Join_merge : public Base_merge<Arrangement_, Gps_bfs_join_visitor<Arrangement_>>{};
{};
//! Intersection_merge /*! Intersection_merge
/*! Intersection_merge is used to merge two sets of polygons creating their * Intersection_merge is used to merge two sets of polygons creating their
* intersection. * intersection.
*/ */
template <typename Arrangement_> template <typename Arrangement_>
class Intersection_merge : public Base_merge<Arrangement_, Gps_bfs_intersection_visitor<Arrangement_>> class Intersection_merge : public Base_merge<Arrangement_, Gps_bfs_intersection_visitor<Arrangement_>>{};
{};
//! Xor_merge /*! Do_intersect_merge
/*! Xor_merge is used to merge two sets of polygons creating their * 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 <typename Arrangement_>
class Do_intersect_merge : public Base_intercepted_merge<Arrangement_, Gps_bfs_intersection_visitor<Arrangement_>>{};
/*! Xor_merge
* Xor_merge is used to merge two sets of polygons creating their
* symmetric difference. * symmetric difference.
*/ */
template <typename Arrangement_> template <typename Arrangement_>
class Xor_merge : public Base_merge<Arrangement_, Gps_bfs_xor_visitor<Arrangement_>> class Xor_merge : public Base_merge<Arrangement_, Gps_bfs_xor_visitor<Arrangement_>>{};
{};
} //namespace CGAL } //namespace CGAL

View File

@ -10,7 +10,7 @@
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il> // Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Ophir Setter <ophir.setter@cs.tau.ac.il> // Ophir Setter <ophir.setter@cs.tau.ac.il>
// Guy Zucker <guyzucke@post.tau.ac.il> // Guy Zucker <guyzucke@post.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
#ifndef CGAL_GPS_ON_SURFACE_BASE_2_H #ifndef CGAL_GPS_ON_SURFACE_BASE_2_H
#define 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; } 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
// 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
// contained in the polygon set (there can be several faces in an empty // arrangement, dependent on the topology traits.
// arrangement, dependent on the topology traits. // The point is that if the arrangement is "empty" (meaning that no curve
// 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
// 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
// all the faces (created by the topology traits) should have the same // result for contained() --- from Boolean operations point of view there
// result for contained() --- from Boolean operations point of view there // can not be an empty arrangement which has several faces with different
// can not be an empty arrangement which has several faces with different // attributes.
// attributes. bool is_empty() const { this->_is_empty(m_arr); }
return (m_arr->is_empty() && !m_arr->faces_begin()->contained());
} bool _is_empty(Aos_2* arr) const
{ return (arr->is_empty() && ! arr->faces_begin()->contained()); }
bool is_plane() const { bool is_plane() const {
// Same comment as in "is_empty" above, just with adjustments. // Same comment as in "is_empty" above, just with adjustments.
@ -493,8 +494,33 @@ public:
template <typename InputIterator> template <typename InputIterator>
bool do_intersect(InputIterator begin, InputIterator end, std::size_t k = 5) { bool do_intersect(InputIterator begin, InputIterator end, std::size_t k = 5) {
Self other(*this); Self other(*this);
other.intersection(begin, end, k); return other._do_intersect(begin, end, k);
return (other.is_empty()); }
// intersects a range of polygons
template <typename InputIterator>
inline bool _do_intersect(InputIterator begin, InputIterator end, std::size_t k) {
std::vector<Arr_entry> 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<Aos_2> 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 <typename InputIterator1, typename InputIterator2> template <typename InputIterator1, typename InputIterator2>
@ -502,8 +528,40 @@ public:
InputIterator2 begin2, InputIterator2 end2, InputIterator2 begin2, InputIterator2 end2,
std::size_t k = 5) { std::size_t k = 5) {
Self other(*this); Self other(*this);
other.intersection(begin1, end1, begin2, end2, k); return other._do_intersect(begin1, end1, begin2, end2, k);
return (other.is_empty()); }
template <typename InputIterator1, typename InputIterator2>
bool _do_intersect(InputIterator1 begin1, InputIterator1 end1,
InputIterator2 begin2, InputIterator2 end2,
std::size_t k = 5) {
std::vector<Arr_entry> 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<Aos_2> 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 // joins a range of polygons
@ -533,7 +591,6 @@ public:
} }
Join_merge<Aos_2> join_merge; Join_merge<Aos_2> join_merge;
_build_sorted_vertices_vectors(arr_vec);
_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, join_merge); _divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, join_merge);
//the result arrangement is at index 0 //the result arrangement is at index 0
@ -556,7 +613,6 @@ public:
} }
Join_merge<Aos_2> join_merge; Join_merge<Aos_2> join_merge;
_build_sorted_vertices_vectors(arr_vec);
_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, join_merge); _divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, join_merge);
// the result arrangement is at index 0 // the result arrangement is at index 0
@ -585,7 +641,6 @@ public:
} }
Join_merge<Aos_2> join_merge; Join_merge<Aos_2> join_merge;
_build_sorted_vertices_vectors(arr_vec);
_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, join_merge); _divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, join_merge);
// the result arrangement is at index 0 // the result arrangement is at index 0
@ -620,7 +675,6 @@ public:
} }
Intersection_merge<Aos_2> intersection_merge; Intersection_merge<Aos_2> intersection_merge;
_build_sorted_vertices_vectors(arr_vec);
_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, intersection_merge); _divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, intersection_merge);
// the result arrangement is at index 0 // the result arrangement is at index 0
@ -636,14 +690,13 @@ public:
arr_vec[0].first = this->m_arr; arr_vec[0].first = this->m_arr;
std::size_t i = 1; 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); ValidationPolicy::is_valid((*itr), *m_traits);
arr_vec[i].first = new Aos_2(m_traits); arr_vec[i].first = new Aos_2(m_traits);
_insert(*itr, *(arr_vec[i].first)); _insert(*itr, *(arr_vec[i].first));
} }
Intersection_merge<Aos_2> intersection_merge; Intersection_merge<Aos_2> intersection_merge;
_build_sorted_vertices_vectors(arr_vec);
_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, intersection_merge); _divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, intersection_merge);
// the result arrangement is at index 0 // the result arrangement is at index 0
@ -659,20 +712,19 @@ public:
arr_vec[0].first = this->m_arr; arr_vec[0].first = this->m_arr;
std::size_t i = 1; 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); ValidationPolicy::is_valid(*itr1, *m_traits);
arr_vec[i].first = new Aos_2(m_traits); arr_vec[i].first = new Aos_2(m_traits);
_insert(*itr1, *(arr_vec[i].first)); _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); ValidationPolicy::is_valid(*itr2,*m_traits);
arr_vec[i].first = new Aos_2(m_traits); arr_vec[i].first = new Aos_2(m_traits);
_insert(*itr2, *(arr_vec[i].first)); _insert(*itr2, *(arr_vec[i].first));
} }
Intersection_merge<Aos_2> intersection_merge; Intersection_merge<Aos_2> intersection_merge;
_build_sorted_vertices_vectors(arr_vec);
_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, intersection_merge); _divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, intersection_merge);
// the result arrangement is at index 0 // the result arrangement is at index 0
@ -708,7 +760,6 @@ public:
} }
Xor_merge<Aos_2> xor_merge; Xor_merge<Aos_2> xor_merge;
_build_sorted_vertices_vectors(arr_vec);
_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, xor_merge); _divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, xor_merge);
// the result arrangement is at index 0 // the result arrangement is at index 0
@ -731,7 +782,6 @@ public:
} }
Xor_merge<Aos_2> xor_merge; Xor_merge<Aos_2> xor_merge;
_build_sorted_vertices_vectors(arr_vec);
_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, xor_merge); _divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, xor_merge);
// the result arrangement is at index 0 // the result arrangement is at index 0
@ -761,7 +811,6 @@ public:
} }
Xor_merge<Aos_2> xor_merge; Xor_merge<Aos_2> xor_merge;
_build_sorted_vertices_vectors(arr_vec);
_divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, xor_merge); _divide_and_conquer(0, arr_vec.size() - 1, arr_vec, k, xor_merge);
// the result arrangement is at index 0 // the result arrangement is at index 0
@ -1155,10 +1204,10 @@ protected:
} }
} }
void _build_sorted_vertices_vectors(std::vector<Arr_entry>& 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_entry>& arr_vec) {
Less_vertex_handle comp(m_traits->compare_xy_2_object()); Less_vertex_handle comp(m_traits->compare_xy_2_object());
const std::size_t n = arr_vec.size(); for (std::size_t i = lower; i < upper + 1; i++) {
for (std::size_t i = 0; i < n; i++) {
// Allocate a vector of handles to all vertices in the current arrangement. // Allocate a vector of handles to all vertices in the current arrangement.
Aos_2* p_arr = arr_vec[i].first; Aos_2* p_arr = arr_vec[i].first;
arr_vec[i].second = new std::vector<Vertex_handle>; arr_vec[i].second = new std::vector<Vertex_handle>;
@ -1174,11 +1223,16 @@ protected:
} }
} }
//! Divide & conquer
template <typename Merge> template <typename Merge>
void _divide_and_conquer(std::size_t lower, std::size_t upper, void _divide_and_conquer(std::size_t lower, std::size_t upper,
std::vector<Arr_entry>& arr_vec, std::vector<Arr_entry>& arr_vec,
std::size_t k, Merge merge_func) { 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) { 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); merge_func(lower, upper, 1, arr_vec);
return; return;
} }
@ -1187,12 +1241,71 @@ protected:
auto curr_lower = lower; auto curr_lower = lower;
for (std::size_t i = 0; i < k - 1; ++i, curr_lower += sub_size) { 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); _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); _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); 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 <typename Merge>
bool do_intersect_divide_and_conquer(std::size_t lower, std::size_t upper,
std::vector<Arr_entry>& 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 // marks all faces as non-visited
void _reset_faces() const { _reset_faces(m_arr); } void _reset_faces() const { _reset_faces(m_arr); }