diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h b/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h index 16befc318ee..16a15d7ea56 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h @@ -91,6 +91,11 @@ public: /*! Destructor. */ virtual ~Arr_vertex_base() {} + // Access/modification for pointer squatting + void* inc() const { return p_inc; } + void set_inc(void * inc) const + { const_cast(*this).p_inc = inc; } + /*! Check if the point pointer is nullptr. */ bool has_null_point() const { return (p_pt == nullptr); } diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_overlay_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_overlay_2.h index e4c739c8c23..393958f3424 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_overlay_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_overlay_2.h @@ -40,6 +40,89 @@ namespace CGAL { +template +class Indexed_sweep_accessor +{ + const Arr1& arr1; + const Arr2& arr2; + mutable std::vector backup_inc; + +public: + + Indexed_sweep_accessor (const Arr1& arr1, const Arr2& arr2) + : arr1(arr1), arr2(arr2) { } + + std::size_t nb_vertices() const + { + return arr1.number_of_vertices() + arr2.number_of_vertices(); + } + + std::size_t min_end_index (const Curve& c) const + { + if (c.red_halfedge_handle() != typename Curve::HH_red()) + return reinterpret_cast(c.red_halfedge_handle()->target()->inc()); + // else + CGAL_assertion (c.blue_halfedge_handle() != typename Curve::HH_blue()); + return reinterpret_cast(c.blue_halfedge_handle()->target()->inc()); + } + + std::size_t max_end_index (const Curve& c) const + { + if (c.red_halfedge_handle() != typename Curve::HH_red()) + return reinterpret_cast(c.red_halfedge_handle()->source()->inc()); + // else + CGAL_assertion (c.blue_halfedge_handle() != typename Curve::HH_blue()); + return reinterpret_cast(c.blue_halfedge_handle()->source()->inc()); + } + + const Curve& curve (const Curve& c) const + { + return c; + } + + // Initializes indices by squatting Vertex::inc(); + void before_init() const + { + std::size_t idx = 0; + backup_inc.resize (nb_vertices()); + for (typename Arr1::Vertex_const_iterator vit = arr1.vertices_begin(); + vit != arr1.vertices_end(); ++vit, ++idx) + { + CGAL_assertion (idx < backup_inc.size()); + backup_inc[idx] = vit->inc(); + vit->set_inc (reinterpret_cast(idx)); + } + for (typename Arr2::Vertex_const_iterator vit = arr2.vertices_begin(); + vit != arr2.vertices_end(); ++vit, ++idx) + { + CGAL_assertion (idx < backup_inc.size()); + backup_inc[idx] = vit->inc(); + vit->set_inc (reinterpret_cast(idx)); + } + } + + // Restores state of arrangements before index squatting + void after_init() const + { + std::size_t idx = 0; + for (typename Arr1::Vertex_const_iterator vit = arr1.vertices_begin(); + vit != arr1.vertices_end(); ++vit, ++idx) + { + CGAL_assertion (idx < backup_inc.size()); + vit->set_inc (backup_inc[idx]); + } + for (typename Arr2::Vertex_const_iterator vit = arr2.vertices_begin(); + vit != arr2.vertices_end(); ++vit, ++idx) + { + CGAL_assertion (idx < backup_inc.size()); + vit->set_inc (backup_inc[idx]); + } + } + +private: + +}; + /*! Compute the overlay of two input arrangements. * \tparam GeometryTraitsA_2 the geometry traits of the first arrangement. * \tparam GeometryTraitsB_2 the geometry traits of the second arrangement. @@ -183,7 +266,14 @@ overlay(const Arrangement_on_surface_2& arr1 if (total_iso_verts == 0) { // Clear the result arrangement and perform the sweep to construct it. arr.clear(); - surface_sweep.sweep(xcvs_vec.begin(), xcvs_vec.end()); + if (std::is_same::value) + surface_sweep.sweep (xcvs_vec.begin(), xcvs_vec.end()); + else + surface_sweep.indexed_sweep (xcvs_vec, + Indexed_sweep_accessor + + (arr1, arr2)); xcvs_vec.clear(); return; } @@ -215,8 +305,16 @@ overlay(const Arrangement_on_surface_2& arr1 // Clear the result arrangement and perform the sweep to construct it. arr.clear(); - surface_sweep.sweep(xcvs_vec.begin(), xcvs_vec.end(), - pts_vec.begin(), pts_vec.end()); + if (std::is_same::value) + surface_sweep.sweep(xcvs_vec.begin(), xcvs_vec.end(), + pts_vec.begin(), pts_vec.end()); + else + surface_sweep.indexed_sweep (xcvs_vec, + Indexed_sweep_accessor + + (arr1, arr2), + pts_vec.begin(), pts_vec.end()); xcvs_vec.clear(); pts_vec.clear(); } diff --git a/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_traits_2.h index 48815d767f6..3243890c1be 100644 --- a/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_traits_2.h @@ -133,6 +133,8 @@ public: class Ex_x_monotone_curve_2 { public: typedef Base_x_monotone_curve_2 Base; + typedef Halfedge_handle_red HH_red; + typedef Halfedge_handle_blue HH_blue; protected: Base m_base_xcv; // The base curve. diff --git a/Surface_sweep_2/include/CGAL/No_intersection_surface_sweep_2.h b/Surface_sweep_2/include/CGAL/No_intersection_surface_sweep_2.h index 2d504797bed..95d3099e348 100644 --- a/Surface_sweep_2/include/CGAL/No_intersection_surface_sweep_2.h +++ b/Surface_sweep_2/include/CGAL/No_intersection_surface_sweep_2.h @@ -309,6 +309,77 @@ public: m_visitor->after_sweep(); } + /*! + runs the indexed sweep-line algorithm on a given range of + x-monotone curves and accessor. The main difference from the + original `sweep()` function is that the accessor allows to get + indices of end-points and avoid checking several times in the + event queue when the same vertex has several incident edges. + + \param edges A range of edges + \param accessor An object providing, for a value_type `e` of + range `edges`, the following methods: + - size_t min_end_index(e) -> the index of the min end of curve c + - size_t max_end_index(e) -> the index of the max end of curve c + - X_monotone_curve_2 curve(e) -> the x-monotone curve associated to e + - size_t nb_vertices() -> the total number of points/events + - void before_init() -> called before initialization + - void after_init() -> called after initialization + */ + template + void indexed_sweep (const EdgeRange& edges, + const Accessor& accessor) + { + m_visitor->before_sweep(); + accessor.before_init(); + _init_indexed_sweep(edges, accessor); + accessor.after_init(); + _sweep(); + _complete_sweep(); + m_visitor->after_sweep(); + } + + /*! + runs the indexed sweep-line algorithm on a given range of + x-monotone curves and accessor. The main difference from the + original `sweep()` function is that the accessor allows to get + indices of end-points and avoid checking several times in the + event queue when the same vertex has several incident edges. + + Variant with action event points (if a curve passed through an + action point, it will be split). + + \param edges A range of edges + \param accessor An object providing, for a value_type `e` of + range `edges`, the following methods: + - size_t min_end_index(e) -> the index of the min end of curve c + - size_t max_end_index(e) -> the index of the max end of curve c + - X_monotone_curve_2 curve(e) -> the x-monotone curve associated to e + - size_t nb_vertices() -> the total number of points/events + - void before_init() -> called before initialization + - void after_init() -> called after initialization + \param points_begin An iterator for the first point in the range. + \param points_end A past-the-end iterator for this range. + \pre The value-type of PointInputIterator is the + traits-class Point_2. + */ + template + void indexed_sweep (const EdgeRange& edges, + const Accessor& accessor, + PointInputIterator action_points_begin, + PointInputIterator action_points_end) + { + m_visitor->before_sweep(); + accessor.before_init(); + _init_indexed_sweep(edges, accessor); + accessor.after_init(); + _init_points(action_points_begin, action_points_end, Event::ACTION); + _sweep(); + _complete_sweep(); + m_visitor->after_sweep(); + } + /*! Get an iterator for the first subcurve in the status line. */ Status_line_iterator status_line_begin() { return m_statusLine.begin(); } @@ -376,6 +447,32 @@ protected: _init_curve(*cit, index); } + /*! Create a Subcurve object and two Event objects for each curve. */ + template + void _init_indexed_curves(const EdgeRange& edges, + const Accessor& accessor) + { + std::vector events (accessor.nb_vertices()); + + unsigned int index = 0; + for (const auto& e : edges) + { + std::size_t max_end = accessor.max_end_index(e); + std::size_t min_end = accessor.min_end_index(e); + const X_monotone_curve_2& curve = accessor.curve (e); + + // Construct and initialize a subcurve object. + std::allocator_traits::construct(m_subCurveAlloc, m_subCurves + index, m_masterSubcurve ); + (m_subCurves + index)->set_hint(this->m_statusLine.end()); + (m_subCurves + index)->init (curve); + + _init_curve_end(curve, ARR_MAX_END, m_subCurves + index, events, max_end); + _init_curve_end(curve, ARR_MIN_END, m_subCurves + index, events, min_end); + + ++ index; + } + } + /*! Initiliaze the sweep algorithm. */ template void _init_sweep(CurveInputIterator curves_begin, @@ -387,6 +484,17 @@ protected: _init_curves(curves_begin, curves_end); // initialize the curves } + /*! Initiliaze the sweep algorithm. */ + template + void _init_indexed_sweep(const EdgeRange& edges, + const Accessor& accessor) + { + m_num_of_subCurves = + static_cast(std::distance(edges.begin(), edges.end())); + _init_structures(); + _init_indexed_curves(edges, accessor); // initialize the curves + } + /*! Initialize the data structures for the sweep-line algorithm. */ virtual void _init_structures(); @@ -413,6 +521,11 @@ protected: void _init_curve_end(const X_monotone_curve_2& cv, Arr_curve_end ind, Subcurve* sc); + // Variant keeping track of indexed events + void _init_curve_end(const X_monotone_curve_2& cv, Arr_curve_end ind, + Subcurve* sc, + std::vector& events, std::size_t index); + /*! Handle the subcurves that are to the left of the event point (i.e., * subcurves that we are done with). */ @@ -485,6 +598,14 @@ protected: Arr_parameter_space ps_y, Subcurve* sc = nullptr); + // Variant keeping track of indexed events + std::pair _push_event(const Point_2& pt, Attribute type, + Arr_parameter_space ps_x, + Arr_parameter_space ps_y, + Subcurve* sc, + std::vector& events, + std::size_t index); + /*! Push an event point associated with a curve end into the event queue. * \param cv The x-monotone curve. * \param ind The relevant curve end. @@ -503,6 +624,17 @@ protected: Arr_parameter_space ps_y, Subcurve* sc = nullptr); + // Variant keeping track of indexed events + std::pair _push_event(const X_monotone_curve_2& cv, + Arr_curve_end ind, + Attribute type, + Arr_parameter_space ps_x, + Arr_parameter_space ps_y, + Subcurve* sc, + const Point_2& pt, + std::vector& events, + std::size_t index); + void _update_event_at_open_boundary(Event* e, const X_monotone_curve_2& cv, Arr_curve_end ind, diff --git a/Surface_sweep_2/include/CGAL/Surface_sweep_2/No_intersection_surface_sweep_2_impl.h b/Surface_sweep_2/include/CGAL/Surface_sweep_2/No_intersection_surface_sweep_2_impl.h index f08377e5f9b..498984d57b5 100644 --- a/Surface_sweep_2/include/CGAL/Surface_sweep_2/No_intersection_surface_sweep_2_impl.h +++ b/Surface_sweep_2/include/CGAL/Surface_sweep_2/No_intersection_surface_sweep_2_impl.h @@ -301,6 +301,47 @@ _init_curve_end(const X_monotone_curve_2& cv, Arr_curve_end ind, Subcurve* sc) } } +template +void No_intersection_surface_sweep_2:: +_init_curve_end(const X_monotone_curve_2& cv, Arr_curve_end ind, Subcurve* sc, + std::vector& events, std::size_t index) +{ + // Get the boundary conditions of the curve end. + const Attribute end_attr = + (ind == ARR_MIN_END) ? Event::LEFT_END : Event::RIGHT_END; + + Arr_parameter_space ps_x = m_traits->parameter_space_in_x_2_object()(cv, ind); + Arr_parameter_space ps_y = m_traits->parameter_space_in_y_2_object()(cv, ind); + + // Create the corresponding event and push it into the event queue. + std::pair pair_res; + + if (m_traits->is_closed_2_object()(cv, ind)) { + // The curve end is closed and thus associated with a valid endpoint. + const Point_2& pt = (ind == ARR_MIN_END) ? + m_traits->construct_min_vertex_2_object()(cv) : + m_traits->construct_max_vertex_2_object()(cv); + + pair_res = ((ps_x == ARR_INTERIOR) && (ps_y == ARR_INTERIOR)) ? + _push_event(pt, end_attr, ps_x, ps_y, sc, events, index) : + _push_event(cv, ind, end_attr, ps_x, ps_y, sc, pt, events, index); + + // Inform the visitor in case we updated an existing event. + Event* e = pair_res.first; + CGAL_assertion(e->is_closed()); + m_visitor->update_event(e, pt, cv, ind, pair_res.second); + } + else { + // The curve end is open, insert it into the event queue. + pair_res = _push_event(cv, ind, end_attr, ps_x, ps_y, sc); + + // Inform the visitor in case we updated an existing event. + Event* e = pair_res.first; + CGAL_assertion(! e->is_closed()); + _update_event_at_open_boundary(e, cv, ind, pair_res.second); + } +} + //----------------------------------------------------------------------------- // Handle the subcurves to the left of the current event point. // @@ -673,6 +714,72 @@ No_intersection_surface_sweep_2::_push_event(const Point_2& pt, return (std::make_pair(e, !exist)); } +template +std::pair::Event*, bool> +No_intersection_surface_sweep_2::_push_event(const Point_2& pt, + Attribute type, + Arr_parameter_space ps_x, + Arr_parameter_space ps_y, + Subcurve* sc, + std::vector& events, + std::size_t index) +{ + Event* e; + + std::pair + pair_res = std::make_pair (events[index], true); + + // If event does not exist + if (events[index] == Event_queue_iterator()) + { + // Still look for the curve end in the event queue in case two + // point are the the same in the vertex range + m_queueEventLess.set_parameter_space_in_x(ps_x); + m_queueEventLess.set_parameter_space_in_y(ps_y); + pair_res = m_queue->find_lower(pt, m_queueEventLess); + } + + bool exist = pair_res.second; + if (! exist) { + // The point is not found in the event queue - create a new event and + // insert it into the queue. + e = _allocate_event(pt, type, ps_x, ps_y); + } + else { + events[index] = pair_res.first; + // The event associated with the given point already exists in the queue, + // so we just have to update it. + e = *(pair_res.first); + CGAL_assertion(e->is_closed()); + + e->set_attribute(type); + } + + // If we are given a subcurve that the event represents one of its + // endpoints, update the event and the subcurve records accordingly. + // Note that this must be done before we actually insert the new event + // into the event queue. + _add_curve(e, sc, type); + + // Insert the new event into the queue using the hint we got when we + // looked for it. + if (! exist) + events[index] = m_queue->insert_before(pair_res.first, e); + +#ifdef CGAL_SS_VERBOSE + if (! exist) { + CGAL_SS_PRINT_NEW_EVENT(pt, e); + } + else { + CGAL_SS_PRINT_UPDATE_EVENT(pt, e); + } +#endif + + // Return the resulting event and a flag indicating whether we have created + // a new event. + return (std::make_pair(e, !exist)); +} + //----------------------------------------------------------------------------- // Push an event point associated with a curve end into the event queue. // @@ -736,6 +843,72 @@ No_intersection_surface_sweep_2::_push_event(const X_monotone_curve_2& cv, return (std::make_pair(e, !exist)); } +template +std::pair::Event*, bool> +No_intersection_surface_sweep_2::_push_event(const X_monotone_curve_2& cv, + Arr_curve_end ind, + Attribute type, + Arr_parameter_space ps_x, + Arr_parameter_space ps_y, + Subcurve* sc, + const Point_2& pt, + std::vector& events, + std::size_t index) +{ + Event* e; + + std::pair + pair_res = std::make_pair (events[index], true); + + // If event does not exist + if (events[index] == Event_queue_iterator()) + { + // Still look for the curve end in the event queue in case two + // point are the the same in the vertex range + + m_queueEventLess.set_parameter_space_in_x(ps_x); + m_queueEventLess.set_parameter_space_in_y(ps_y); + m_queueEventLess.set_index(ind); + + pair_res = + m_queue->find_lower(cv, m_queueEventLess); + } + + bool exist = pair_res.second; + + if (! exist) { + // The curve end is not found in the event queue - create a new event and + // insert it into the queue. + // The curve end is closed and so it is associated with a valid + // point. + e = _allocate_event(pt, type, ps_x, ps_y); + } + else { + events[index] = pair_res.first; + + // The event associated with the given curve end already exists in the + // queue, so we just have to update it. + e = *(pair_res.first); + CGAL_assertion((e->parameter_space_in_x() == ps_x) && + (e->parameter_space_in_y() == ps_y)); + + e->set_attribute(type); + } + + // If we are given a subcurve that the event represents one of its + // endpoints, update the event and the subcurve records accordingly. + // Note that this must be done before we actually insert the new event + // into the event queue. + _add_curve(e, sc, type); + + // Insert the new event into the queue using the hint we got when we + // looked for it. + if (! exist) + events[index] = m_queue->insert_before(pair_res.first, e); + + return (std::make_pair(e, !exist)); +} + //----------------------------------------------------------------------------- // add a curve as a right curve or left curve when the event is created // or updated.