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 16a15d7ea56..790600b274e 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h @@ -479,7 +479,18 @@ public: const Inner_ccb* inner_ccb() const { CGAL_precondition(is_on_inner_ccb()); - return (reinterpret_cast(_clean_pointer(this->p_comp))); + + const Inner_ccb* out = reinterpret_cast(_clean_pointer(this->p_comp)); + if (out->is_valid()) + return out; + + // else reduce path and get valid iccb + const Inner_ccb* valid = out->next(); + while (!valid->is_valid()) + valid = valid->next(); + const_cast(out)->set_next(const_cast(valid)); + const_cast(this)->set_inner_ccb(valid); + return valid; } /*! Get an incident inner CCB (non-const version). @@ -488,11 +499,28 @@ public: Inner_ccb* inner_ccb() { CGAL_precondition(is_on_inner_ccb()); - return (reinterpret_cast(_clean_pointer(this->p_comp))); + + Inner_ccb* out = reinterpret_cast(_clean_pointer(this->p_comp)); + if (out->is_valid()) + return out; + + // else reduce path and get valid iccb + Inner_ccb* valid = out->next(); + while (!valid->is_valid()) + valid = valid->next(); + out->set_next(valid); + set_inner_ccb(valid); + return valid; + } + + Inner_ccb* inner_ccb_no_redirect() + { + CGAL_precondition(is_on_inner_ccb()); + return reinterpret_cast(_clean_pointer(this->p_comp)); } /*! Set the incident inner CCB. */ - void set_inner_ccb(Inner_ccb *ic) + void set_inner_ccb(const Inner_ccb *ic) { // Set the component pointer and set its LSB. this->p_comp = _set_lsb(ic); @@ -769,57 +797,111 @@ public: typedef typename Face::Inner_ccb_iterator Inner_ccb_iterator; private: - Face* p_f; // The face the contains the CCB in its interior. + union + { + Face* f; // The face the contains the CCB in its interior. + Arr_inner_ccb* icc; // next inner CCB in chain to valid icc + } f_or_icc; Inner_ccb_iterator iter; // The inner CCB identifier. - bool iter_is_not_singular; + enum + { + ITER_IS_SINGULAR, // singular = default iterator, not initialized + ITER_IS_NOT_SINGULAR, // not singular = iterator was assigned and is valid + INVALID // invalid = the inner CCB is invalid and + // only links to another inner CCB + // in chain to valid CCB + } status; public: /*! Default constructor. */ - Arr_inner_ccb() : p_f(nullptr), iter_is_not_singular(false) {} + Arr_inner_ccb() : status(ITER_IS_SINGULAR) { f_or_icc.f = nullptr; } /*! Copy constructor. */ Arr_inner_ccb(const Arr_inner_ccb& other) : - p_f(other.p_f), iter_is_not_singular(other.iter_is_not_singular) - { if (other.iter_is_not_singular) iter = other.iter; } + f_or_icc(other.f_or_icc), status(other.status) + { if (other.status == ITER_IS_NOT_SINGULAR) iter = other.iter; } /*! Get a halfedge along the component (const version). */ - const Halfedge* halfedge() const { return (*iter); } + const Halfedge* halfedge() const + { + CGAL_assertion (is_valid()); + return (*iter); + } /*! Get a halfedge along the component (non-const version). */ - Halfedge* halfedge() { return (*iter); } + Halfedge* halfedge() + { + CGAL_assertion (is_valid()); + return (*iter); + } /*! Set a representative halfedge for the component. */ - void set_halfedge(Halfedge *he) { *iter = he; } + void set_halfedge(Halfedge *he) + { + CGAL_assertion (is_valid()); + *iter = he; + } /*! Get the incident face (const version). */ - const Face* face() const { return (p_f); } + const Face* face() const + { + CGAL_assertion (status != INVALID); + return f_or_icc.f; + } /*! Get the incident face (non-const version). */ - Face* face() { return (p_f); } + Face* face() + { + CGAL_assertion (status != INVALID); + return f_or_icc.f; + } /*! Set the incident face. */ - void set_face(Face* f) { p_f = f; } + void set_face(Face* f) + { + CGAL_assertion (status != INVALID); + f_or_icc.f = f; + } /*! Get the iterator (const version). */ Inner_ccb_iterator iterator() const { - CGAL_assertion(iter_is_not_singular); + CGAL_assertion(status == ITER_IS_NOT_SINGULAR); return (iter); } /*! Get the iterator (non-const version). */ Inner_ccb_iterator iterator() { - CGAL_assertion(iter_is_not_singular); + CGAL_assertion(status == ITER_IS_NOT_SINGULAR); return (iter); } /*! Set the inner CCB iterator. */ void set_iterator(Inner_ccb_iterator it) { + CGAL_assertion (is_valid()); iter = it; - iter_is_not_singular = true; + status = ITER_IS_NOT_SINGULAR; } + + /*! Check validity */ + bool is_valid() const { return (status != INVALID); } + + /*! Get the next CCB to primary chain. */ + Arr_inner_ccb* next() const + { + CGAL_assertion (status == INVALID); + return f_or_icc.icc; + } + + /*! Set the next CCB to primary chain. */ + void set_next(Arr_inner_ccb* next) + { + status = INVALID; + f_or_icc.icc = next; + } + }; /*! \class @@ -943,6 +1025,7 @@ public: typedef typename Face_list::iterator Face_iterator; typedef CGAL::N_step_adaptor_derived Edge_iterator; + typedef typename Inner_ccb_list::iterator Inner_ccb_iterator; // Definitions of const iterators. typedef typename Vertex_list::const_iterator Vertex_const_iterator; @@ -1019,6 +1102,9 @@ public: { return make_prevent_deref_range(edges_begin(), edges_end()); } + + Inner_ccb_iterator inner_ccbs_begin() { return in_ccbs.begin(); } + Inner_ccb_iterator inner_ccbs_end() { return in_ccbs.end(); } //@} /// \name Obtaining constant iterators. diff --git a/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_on_surface_2_impl.h b/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_on_surface_2_impl.h index 7b714c12412..42f3cc048a9 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_on_surface_2_impl.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_on_surface_2_impl.h @@ -2741,14 +2741,24 @@ _insert_at_vertices(DHalfedge* he_to, he1->set_inner_ccb(ic1); he2->set_inner_ccb(ic1); - // Make all halfedges along ic2 to point to ic1. - DHalfedge* curr; + if (m_sweep_mode) + { + // Inner CCB are obtained using Halfedge::inner_ccb() which + // performs path reduction and always return valid iCCB + CGAL_assertion(ic1->is_valid()); + CGAL_assertion(ic2->is_valid()); + ic2->set_next(ic1); + } + else + { + // Make all halfedges along ic2 to point to ic1. + DHalfedge* curr; + for (curr = he2->next(); curr != he1; curr = curr->next()) + curr->set_inner_ccb(ic1); - for (curr = he2->next(); curr != he1; curr = curr->next()) - curr->set_inner_ccb(ic1); - - // Delete the redundant inner CCB. - _dcel().delete_inner_ccb(ic2); + // Delete the redundant inner CCB. + _dcel().delete_inner_ccb(ic2); + } // Notify the observers that we have merged the two inner CCBs. _notify_after_merge_inner_ccb(fh, (Halfedge_handle(he1))->ccb()); diff --git a/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h b/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h index dacb1ed50a1..23423db1a7e 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h @@ -911,6 +911,14 @@ protected: bool m_own_traits; // inidicates whether the geometry // traits should be freed up. + bool m_sweep_mode = false; + // sweep mode efficiently + // merges inner CCB but + // keeps invalid inner CCB + // and memory overhead that + // should be cleaned + // afterwards + public: /// \name Constructors. //@{ @@ -941,6 +949,9 @@ public: /*! Destructor. */ virtual ~Arrangement_on_surface_2(); + /*! Change mode. */ + void set_sweep_mode (bool mode) { m_sweep_mode = mode; } + /*! Clear the arrangement. */ virtual void clear(); //@} @@ -1518,6 +1529,39 @@ public: //@} + /*! + * Cleans the inner CCB if sweep mode was used, by removing all + * non-valid inner CCBs + */ + void clean_inner_ccbs_after_sweep() + { + for (DHalfedge_iter he = _dcel().halfedges_begin(); + he != _dcel().halfedges_end(); ++ he) + { + if (!he->is_on_inner_ccb()) + continue; + + DInner_ccb* ic1 = he->inner_ccb_no_redirect(); + if (ic1->is_valid()) + continue; + + // Calling Halfedge::inner_ccb() reduces the path and makes the + // halfedge point to a correct CCB + DInner_ccb* ic2 = he->inner_ccb(); + CGAL_USE(ic2); + CGAL_assertion (ic2->halfedge()->is_on_inner_ccb() + && ic2->halfedge()->inner_ccb_no_redirect() == ic2); + } + + typename Dcel::Inner_ccb_iterator it = _dcel().inner_ccbs_begin(); + while (it != _dcel().inner_ccbs_end()) + { + typename Dcel::Inner_ccb_iterator current = it ++; + if (!current->is_valid()) + _dcel().delete_inner_ccb(&*current); + } + } + protected: /// \name Determining the boundary-side conditions. //@{ diff --git a/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_construction_ss_visitor.h b/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_construction_ss_visitor.h index c8c9b9b57f0..1e3544ec566 100644 --- a/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_construction_ss_visitor.h +++ b/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_construction_ss_visitor.h @@ -142,6 +142,9 @@ public: /* A notification issued before the sweep process starts. */ inline void before_sweep(); + /* A notification issued after the sweep process stops. */ + inline void after_sweep(); + /*! * A notification invoked before the sweep-line starts handling the given * event. @@ -267,7 +270,21 @@ private: // Notifies the helper that the sweep process now starts. template void Arr_construction_ss_visitor::before_sweep() -{ m_helper.before_sweep(); } +{ + m_helper.before_sweep(); + m_arr->set_sweep_mode(true); +} + + +//----------------------------------------------------------------------------- +// A notification issued after the sweep process stops. +template +void Arr_construction_ss_visitor::after_sweep() +{ + m_arr->clean_inner_ccbs_after_sweep(); + m_arr->set_sweep_mode(false); +} + //----------------------------------------------------------------------------- // A notification invoked before the sweep-line starts handling the given diff --git a/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_ss_visitor.h b/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_ss_visitor.h index f9f697a3b40..8fbcc861d5f 100644 --- a/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_ss_visitor.h +++ b/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_ss_visitor.h @@ -552,6 +552,8 @@ Arr_overlay_ss_visitor::update_event(Event* e, template void Arr_overlay_ss_visitor::after_sweep() { + Base::after_sweep(); + // Notify boundary vertices: typename Vertex_map::iterator it; for (it = m_vertices_map.begin(); it != m_vertices_map.end(); ++it) {