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$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
#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 <CGAL/license/Boolean_set_operations_2.h>

View File

@ -9,9 +9,10 @@
//
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Ophir Setter <ophir.setter@cs.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
#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 <CGAL/license/Boolean_set_operations_2.h>
@ -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 <typename Arrangement_, typename BfsVisitor>
template <typename Arrangement_, typename BfsVisitor, template <typename, typename> 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<Mgt2, Event, Allocator>;
using Helper_tmp = typename Tt::template Construction_helper<Event, Subcurve>;
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 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)
public:
/*! Constructor. */
/*! constructs. */
Gps_agg_op(Arr& arr, std::vector<Vertex_handle>& 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_entry>& arr_vec) {
std::list<Meta_X_monotone_curve_2> curves_list;
std::size_t prepare(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) {
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_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;
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_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; }
};

View File

@ -9,9 +9,10 @@
//
// Author(s) : Baruch Zukerman <baruchzu@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
#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 <vector>
@ -70,9 +71,8 @@ public:
Base(traits, visitor)
{}
/*! Perform the sweep. */
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::vector<Arr_entry>& arr_vec) {
CGAL_assertion(this->m_queue->empty() && this->m_statusLine.size() == 0);
@ -80,7 +80,6 @@ public:
using Vertices_map = Unique_hash_map<Vertex_handle, Event*>;
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 <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->_complete_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:
@ -230,7 +245,6 @@ private:
else return (Event::LEFT_END);
}
++circ;
} while (circ != first);
// If we reached here, we should not keep this vertex.

View File

@ -7,12 +7,12 @@
// $Id$
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Baruch Zukerman <baruchzu@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
#define CGAL_BSO_2_GSP_AGG_OP_VISITOR_H
#ifndef CGAL_GSP_AGG_OP_VISITOR_H
#define CGAL_GSP_AGG_OP_VISITOR_H
#include <CGAL/license/Boolean_set_operations_2.h>
@ -43,7 +43,6 @@ public:
private:
using Gt2 = Geometry_traits_2;
using Arr = Arrangement_2;
using Self = Gps_agg_op_base_visitor<Helper, Arr, Visitor_>;
using Visitor = typename Default::Get<Visitor_, Self>::type;
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 :
public Gps_agg_op_base_visitor<
Helper_, Arrangement_,
Gps_agg_op_visitor<Helper_, Arrangement_, Visitor_>> {
typename Default::Get<Visitor_,
Gps_agg_op_visitor<Helper_, Arrangement_, Visitor_>>::type> {
public:
using Helper = Helper_;
using Arrangement_2 = Arrangement_;
@ -145,6 +145,7 @@ private:
using Base = Gps_agg_op_base_visitor<Helper, Arr, 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<Vertex_handle>* vertices_vec) :
Base(arr, hash),
m_event_count(0),

View File

@ -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):

View File

@ -7,10 +7,9 @@
// $Id$
// 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>
// Efi Fogel <efifogel@gmail.com>
#ifndef 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

@ -8,6 +8,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
#ifndef CGAL_GPS_MERGE_H
#define CGAL_GPS_MERGE_H
@ -15,6 +16,8 @@
#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_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_xor_visitor.h>
#include <CGAL/Boolean_set_operations_2/Gps_bfs_intersection_visitor.h>
@ -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<Arrangement_2*, std::vector<Vertex_handle>*>;
public:
void operator()(std::size_t i, std::size_t j, std::size_t jump,
std::vector<Arr_entry>& arr_vec) {
void operator()(std::size_t i, std::size_t j, std::size_t jump, std::vector<Arr_entry>& 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<Vertex_handle>* verts = new std::vector<Vertex_handle>;
Gps_agg_op<Arrangement_2, Visitor>
agg_op(*res, *verts, *(res->traits_adaptor()));
using Agg_op = Gps_agg_op<Arrangement_2, Visitor, Gps_agg_op_visitor>;
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 <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.
*/
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 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 <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
/*! 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 <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.
*/
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

View File

@ -10,7 +10,7 @@
// Author(s) : Baruch Zukerman <baruchzu@post.tau.ac.il>
// Ophir Setter <ophir.setter@cs.tau.ac.il>
// Guy Zucker <guyzucke@post.tau.ac.il>
// Efi Fogel <efifogel@gmail.com>
#ifndef CGAL_GPS_ON_SURFACE_BASE_2_H
#define CGAL_GPS_ON_SURFACE_BASE_2_H
@ -388,7 +388,6 @@ 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.
@ -398,8 +397,10 @@ public:
// 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());
}
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 <typename InputIterator>
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 <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>
@ -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 <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
@ -533,7 +591,6 @@ public:
}
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);
//the result arrangement is at index 0
@ -556,7 +613,6 @@ public:
}
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);
// the result arrangement is at index 0
@ -585,7 +641,6 @@ public:
}
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);
// the result arrangement is at index 0
@ -620,7 +675,6 @@ public:
}
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);
// the result arrangement is at index 0
@ -643,7 +697,6 @@ public:
}
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);
// the result arrangement is at index 0
@ -672,7 +725,6 @@ public:
}
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);
// the result arrangement is at index 0
@ -708,7 +760,6 @@ public:
}
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);
// the result arrangement is at index 0
@ -731,7 +782,6 @@ public:
}
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);
// the result arrangement is at index 0
@ -761,7 +811,6 @@ public:
}
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);
// 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());
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<Vertex_handle>;
@ -1174,11 +1223,16 @@ protected:
}
}
//! Divide & conquer
template <typename Merge>
void _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);
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 <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
void _reset_faces() const { _reset_faces(m_arr); }