Added an alternative divide & conquer for running do_intersect.

This commit is contained in:
Efi Fogel 2025-08-30 20:47:31 +03:00
parent f4a02aeaef
commit 29715e44a4
4 changed files with 312 additions and 47 deletions

View File

@ -99,11 +99,13 @@ public:
m_surface_sweep(m_traits, &m_visitor)
{}
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::pair<std::size_t, 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
for (auto i = lower; i <= upper; i += jump) {
std::size_t n_pgn = 0; // number of polygons (arrangements)
for (auto i = lower; i <= upper; i += jump, ++n_pgn) {
// The BFS scan (after the loop) starts in the reference face,
// so we count the number of polygons that contain the reference face.
Arr* arr = (arr_vec[i]).first;
@ -120,16 +122,16 @@ public:
curves_list.push_back(Meta_X_monotone_curve_2(he->curve(), cv_data));
}
}
return n_inf_pgn;
return std::make_pair(n_inf_pgn, n_pgn);
}
/*! 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::size_t n_inf_pgn, n_pgn;
std::list<Meta_X_monotone_curve_2> curves_list;
auto n_inf_pgn = prepare(lower, upper, jump, arr_vec, curves_list);
std::tie(n_inf_pgn, n_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);
@ -143,13 +145,56 @@ public:
*/
bool sweep_intercept_arrangements(std::size_t lower, std::size_t upper, std::size_t jump,
std::vector<Arr_entry>& arr_vec) {
std::size_t n_inf_pgn, n_pgn;
std::list<Meta_X_monotone_curve_2> curves_list;
auto n_inf_pgn = prepare(lower, upper, jump, arr_vec, curves_list);
std::tie(n_inf_pgn, n_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;
}
template <typename InputIterator>
std::size_t prepare2(InputIterator begin, InputIterator end, 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
for (auto it = begin; it != end; ++it) {
// 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 = it->first;
if (arr->reference_face()->contained()) ++n_inf_pgn;
for (auto ite = arr->edges_begin(); ite != arr->edges_end(); ++ite) {
// take only relevant edges (which separate between contained and
// non-contained faces.
Halfedge_handle he = ite;
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;
}
/*! sweeps the plane without interceptions, but stop when an intersection occurs.
*/
template <typename InputIterator>
bool sweep_intercept_arrangements2(InputIterator begin, InputIterator end) {
std::list<Meta_X_monotone_curve_2> curves_list;
auto n_inf_pgn = prepare2(begin, end, curves_list);
auto res = m_surface_sweep.sweep_intercept2(curves_list.begin(), curves_list.end(), begin, end);
if (res) return true;
m_faces_hash[m_arr->reference_face()] = n_inf_pgn;
std::size_t n_pgn = std::distance(begin, end); // 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);

View File

@ -204,6 +204,139 @@ public:
}
}
template <typename CurveInputIterator, typename InputIterator>
void pre_process2(CurveInputIterator curves_begin, CurveInputIterator curves_end,
InputIterator begin, InputIterator end) {
CGAL_assertion(this->m_queue->empty() && this->m_statusLine.size() == 0);
using Vertices_map = Unique_hash_map<Vertex_handle, Event*>;
using Compare_xy_2 = typename Gt2::Compare_xy_2;
// 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)
this->m_subCurves =
this->m_subCurveAlloc.allocate(this->m_num_of_subCurves);
// Initialize the event queue using the vertices vectors. Note that these
// vertices are already sorted, we simply have to merge them
Vertices_map vert_map;
Vertex_handle vh;
Vertex_handle invalid_v;
// std::size_t i = lower;
auto it = begin;
auto n = it->second->size();
std::size_t j;
EventQueueIter q_iter;
bool first = true;
Attribute event_type;
Event* event;
for (j = 0; j < n && (vh = (*(it->second))[j]) != invalid_v; j++) {
// Insert the vertices of the first vector one after the other.
event_type = _type_of_vertex(vh);
if (event_type == Event::DEFAULT) continue;
event = this->_allocate_event(vh->point(), event_type,
ARR_INTERIOR, ARR_INTERIOR);
// \todo When the boolean set operations are extended to support
// unbounded curves, we will need here a special treatment.
#ifndef CGAL_ARRANGEMENT_ON_SURFACE_2_H
event->set_finite();
#endif
if (! first) {
q_iter = this->m_queue->insert_after(q_iter, event);
}
else {
q_iter = this->m_queue->insert(event);
first = false;
}
vert_map[vh] = event;
}
Comparison_result res = LARGER;
Compare_xy_2 comp_xy = this->m_traits->compare_xy_2_object();
EventQueueIter q_end = this->m_queue->end();
for (++it; it != end; ++it) {
// Merge the vertices of the other vectors into the existing queue.
q_iter = this->m_queue->begin();
n = it->second->size();
for (j = 0; j < n && (vh = (*(it->second))[j]) != invalid_v; j++) {
event_type = _type_of_vertex(vh);
if (event_type == Event::DEFAULT) continue;
while ((q_iter != q_end) &&
(res = comp_xy(vh->point(), (*q_iter)->point())) == LARGER)
{
++q_iter;
}
if (res == SMALLER || q_iter == q_end) {
event = this->_allocate_event(vh->point(), event_type,
ARR_INTERIOR, ARR_INTERIOR);
// \todo When the boolean set operations are extended to support
// unbounded curves, we will need here a special treatment.
#ifndef CGAL_ARRANGEMENT_ON_SURFACE_2_H
event->set_finite();
#endif
this->m_queue->insert_before(q_iter, event);
vert_map[vh] = event;
}
else if (res == EQUAL) {
// In this case q_iter points to an event already associated with
// the vertex, so we just update the map:
vert_map[vh] = *q_iter;
}
}
}
// Go over all curves (which are associated with halfedges) and associate
// them with the events we have just created.
std::size_t index = 0;
CurveInputIterator iter;
Halfedge_handle he;
Event* e_left;
Event* e_right;
for (iter = curves_begin; iter != curves_end; ++iter, index++) {
// Get the events associated with the end-vertices of the current
// halfedge.
he = iter->data().halfedge();
CGAL_assertion(vert_map.is_defined(he->source()));
CGAL_assertion(vert_map.is_defined(he->target()));
if ((Arr_halfedge_direction)he->direction() == ARR_LEFT_TO_RIGHT) {
e_left = vert_map[he->source()];
e_right = vert_map[he->target()];
}
else {
e_left = vert_map[he->target()];
e_right = vert_map[he->source()];
}
// Create the subcurve object.
using Subcurve_alloc = decltype(this->m_subCurveAlloc);
std::allocator_traits<Subcurve_alloc>::construct(this->m_subCurveAlloc,
this->m_subCurves + index,
this->m_masterSubcurve);
(this->m_subCurves + index)->init(*iter);
(this->m_subCurves + index)->set_left_event(e_left);
(this->m_subCurves + index)->set_right_event(e_right);
e_right->add_curve_to_left(this->m_subCurves + index);
this->_add_curve_to_right(e_left, this->m_subCurves + index);
}
}
/*! Perform the sweep. */
template <typename CurveInputIterator>
void sweep(CurveInputIterator curves_begin, CurveInputIterator curves_end,
@ -227,6 +360,18 @@ public:
return this->m_visitor->found_intersection();
}
/*! Perform the sweep. */
template <typename CurveInputIterator, typename InputIterator>
bool sweep_intercept2(CurveInputIterator curves_begin, CurveInputIterator curves_end,
InputIterator begin, InputIterator end) {
this->m_visitor->before_sweep();
pre_process2(curves_begin, curves_end, begin, end);
this->_sweep();
this->_complete_sweep();
this->m_visitor->after_sweep();
return this->m_visitor->found_intersection();
}
private:
/*!
* Check if the given vertex is an endpoint of an edge we are going

View File

@ -81,6 +81,24 @@ class Base_intercepted_merge {
using Arr_entry = std::pair<Arrangement_2*, std::vector<Vertex_handle>*>;
public:
template <typename InputIterator>
bool operator()(InputIterator begin, InputIterator end) {
CGAL_assertion(begin != end);
const auto* tr = begin->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_arrangements2(begin, end);
begin->first = arr;
begin->second = verts;
return res;
}
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;
@ -94,7 +112,9 @@ public:
for (auto count = i; count <= j; count += jump) {
delete (arr_vec[count].first);
arr_vec[count].first = nullptr;
delete (arr_vec[count].second);
arr_vec[count].second = nullptr;
}
arr_vec[i].first = arr;

View File

@ -7,14 +7,16 @@
// $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>
// Guy Zucker <guyzucke@post.tau.ac.il>
// 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
#include <algorithm>
#include <CGAL/license/Boolean_set_operations_2.h>
#include <CGAL/disable_warnings.h>
@ -114,8 +116,8 @@ private:
using Vertex_const_handle = typename Aos_2::Vertex_const_handle;
using Halfedge_around_vertex_const_circulator = typename Aos_2::Halfedge_around_vertex_const_circulator;
using Arr_entry = std::pair<Aos_2 *, std::vector<Vertex_handle> *>;
using Vertices = std::vector<Vertex_handle>;
using Arr_entry = std::pair<Aos_2*, Vertices*>;
using Point_location = typename Arrangement_on_surface_2::Topology_traits::Default_point_location_strategy;
@ -127,8 +129,9 @@ protected:
CGAL::Arr_traits_adaptor_2<Traits_2> m_traits_adaptor;
bool m_traits_owner;
// the underlying arrangement
Aos_2* m_arr;
Aos_2* m_arr; // the underlying arrangement
Vertices* m_vertices; // sorted vertices
public:
// constructs default
@ -500,6 +503,16 @@ public:
// intersects a range of polygons
template <typename InputIterator>
inline bool _do_intersect(InputIterator begin, InputIterator end, std::size_t k) {
// m_vertices = new Vertices;
// sort_vertices(*m_arr, *m_vertices);
// Do_intersect_merge<Aos_2> do_intersect_merge;
// auto res = do_intersect_divide_and_conquer2(begin, end, k, do_intersect_merge);
// delete m_vertices;
// if (res) return res;
// remove_redundant_edges();
// _reset_faces();
// return is_empty();
std::vector<Arr_entry> arr_vec(std::distance(begin, end) + 1);
arr_vec[0].first = this->m_arr;
std::size_t i = 1;
@ -516,7 +529,13 @@ public:
// The resulting arrangement is at index 0
this->m_arr = arr_vec[0].first;
delete arr_vec[0].second;
if (res) return res;
if (res) {
for (auto i = 1; i < arr_vec.size(); ++i) {
if (arr_vec[i].first) delete arr_vec[i].first;
if (arr_vec[i].second) delete arr_vec[i].second;
}
return res;
}
_remove_redundant_edges(arr_vec[0].first);
_reset_faces(arr_vec[0].first);
@ -557,7 +576,13 @@ public:
// The resulting arrangement is at index 0
this->m_arr = arr_vec[0].first;
delete arr_vec[0].second;
if (res) return res;
if (res) {
for (auto i = 1; i < arr_vec.size(); ++i) {
if (arr_vec[i].first) delete arr_vec[i].first;
if (arr_vec[i].second) delete arr_vec[i].second;
}
return res;
}
_remove_redundant_edges(arr_vec[0].first);
_reset_faces(arr_vec[0].first);
@ -680,6 +705,7 @@ public:
// the result arrangement is at index 0
this->m_arr = arr_vec[0].first;
delete arr_vec[0].second;
std::cout << "XXXX 1 no. faces: " << m_arr->number_of_faces() << "\n";
}
// intersects a range of polygons with holes
@ -702,6 +728,7 @@ public:
// the result arrangement is at index 0
this->m_arr = arr_vec[0].first;
delete arr_vec[0].second;
std::cout << "XXXX 2 no. edges: " << m_arr->number_of_edges() << "\n";
}
template <typename InputIterator1, typename InputIterator2>
@ -1223,6 +1250,17 @@ protected:
}
}
//! extracts and sorts the vertices
void sort_vertices(Aos_2& arr, Vertices& vertices) {
std::size_t j = 0;
vertices.resize(arr.number_of_vertices());
for (auto vit = arr.vertices_begin(); vit != arr.vertices_end(); ++vit) vertices[j++] = vit;
// Sort the vector.
Less_vertex_handle comp(m_traits->compare_xy_2_object());
std::sort(vertices.begin(), vertices.end(), comp);
}
//! Divide & conquer
template <typename Merge>
void _divide_and_conquer(std::size_t lower, std::size_t upper,
@ -1261,10 +1299,10 @@ protected:
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";
// 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";
// 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);
}
@ -1272,40 +1310,57 @@ protected:
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;
auto res = do_intersect_divide_and_conquer(curr_lower, curr_lower + sub_size-1, arr_vec, k, merge_func);
// indent -= 2;
if (res) return res;
}
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;
}
// indent += 2;
auto res = do_intersect_divide_and_conquer(curr_lower, upper, arr_vec, k, merge_func);
// indent -= 2;
if (res) return res;
std::cout << std::setw(indent) << "" << "Merging [" << lower << "," << curr_lower << "," << sub_size << "]\n";
// std::cout << std::setw(indent) << "" << "Merging [" << lower << "," << curr_lower << "," << sub_size << "]\n";
return merge_func(lower, curr_lower, sub_size, arr_vec);
}
template <typename InputIterator, typename Merge>
bool do_intersect_divide_and_conquer2(InputIterator begin, InputIterator end, std::size_t k, Merge merge) {
std::vector<Arr_entry> arr_entries;
arr_entries.reserve(k);
arr_entries.resize(1);
arr_entries[0].first = m_arr;
arr_entries[0].second = m_vertices;
std::size_t size = std::distance(begin, end);
auto it = begin;
while (it != end) {
std::size_t num = std::min(size+1, k);
arr_entries.resize(num);
for (std::size_t i = 1; i < num; ++i) {
// process pgn
auto* p_arr = new Aos_2(m_traits);
auto* p_vertices = new Vertices;
ValidationPolicy::is_valid(*it, *m_traits);
arr_entries[i].first = p_arr;
arr_entries[i].second = p_vertices;
_insert(*it++, *p_arr);
sort_vertices(*p_arr, *p_vertices);
}
auto res = merge(arr_entries.begin(), arr_entries.end());
for (std::size_t i = 1; i < num; ++i) {
delete arr_entries[i].first;
delete arr_entries[i].second;
}
arr_entries.resize(1);
size -= (num-1);
}
m_arr = arr_entries[0].first;
m_vertices = arr_entries[0].second;
arr_entries.clear();
}
// marks all faces as non-visited
void _reset_faces() const { _reset_faces(m_arr); }