From 5f05c610d1890e00fd868a3f4ff52bd8f2b453a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 22 Apr 2020 14:57:20 +0200 Subject: [PATCH] make the construction of the search tree lazy --- AABB_tree/include/CGAL/AABB_tree.h | 106 ++++++++++++++++------------- 1 file changed, 58 insertions(+), 48 deletions(-) diff --git a/AABB_tree/include/CGAL/AABB_tree.h b/AABB_tree/include/CGAL/AABB_tree.h index 50bc241e85d..30e71319bf1 100644 --- a/AABB_tree/include/CGAL/AABB_tree.h +++ b/AABB_tree/include/CGAL/AABB_tree.h @@ -61,6 +61,8 @@ namespace CGAL { // type of the primitives container typedef std::vector Primitives; + typedef internal::Primitive_helper Helper; + public: typedef AABBTraits AABB_traits; @@ -169,14 +171,15 @@ namespace CGAL { return m_traits; } - /// Clears the tree. + /// Clears the tree and the search tree if it was constructed, + /// and switches on the usage of the search tree to find the hints for the distance queries void clear() { // clear AABB tree clear_nodes(); m_primitives.clear(); clear_search_tree(); - m_use_search_tree = true; + m_use_default_search_tree = true; } /// Returns the axis-aligned bounding box of the whole tree. @@ -441,8 +444,7 @@ public: template bool accelerate_distance_queries(ConstPointIterator first, ConstPointIterator beyond) { - clear_search_tree(); - m_use_search_tree = false; // not a default kd-tree + m_use_default_search_tree = false; return build_kd_tree(first,beyond); } @@ -480,14 +482,22 @@ public: } // clears internal KD tree - void clear_search_tree() const + void clear_search_tree() { +#ifdef CGAL_HAS_THREADS + if ( m_atomic_search_tree_constructed.load() ) +#else if ( m_search_tree_constructed ) +#endif { CGAL_assertion( m_p_search_tree!=nullptr ); delete m_p_search_tree; m_p_search_tree = nullptr; +#ifdef CGAL_HAS_THREADS + m_atomic_search_tree_constructed.store(false); +#else m_search_tree_constructed = false; +#endif } } @@ -519,13 +529,28 @@ public: { CGAL_assertion(!empty()); return Point_and_primitive_id( - internal::Primitive_helper::get_reference_point(m_primitives[0],m_traits), m_primitives[0].id() + Helper::get_reference_point(m_primitives[0],m_traits), m_primitives[0].id() ); } public: Point_and_primitive_id best_hint(const Point& query) const { +#ifdef CGAL_HAS_THREADS + bool m_search_tree_constructed = m_atomic_search_tree_constructed.load(std::memory_order_acquire); +#endif + + // lazily build the search tree in case the default should be used + if (m_use_default_search_tree && !m_search_tree_constructed) + { +#ifdef CGAL_HAS_THREADS + CGAL_SCOPED_LOCK(build_mutex); + m_search_tree_constructed = m_atomic_search_tree_constructed.load(std::memory_order_relaxed); + if (!m_search_tree_constructed) +#endif + m_search_tree_constructed = const_cast(this)->build_kd_tree(); + } + if(m_search_tree_constructed) return m_p_search_tree->closest_point(query); else @@ -534,14 +559,13 @@ public: //! Returns the datum (geometric object) represented `p`. #ifndef DOXYGEN_RUNNING - typename internal::Primitive_helper::Datum_type + typename Helper::Datum_type #else typename AABBTraits::Primitive::Datum_reference #endif datum(Primitive& p)const { - return internal::Primitive_helper:: - get_datum(p, this->traits()); + return Helper::get_datum(p, this->traits()); } private: @@ -579,13 +603,14 @@ public: } // search KD-tree - mutable const Search_tree* m_p_search_tree; - mutable bool m_search_tree_constructed; - bool m_use_search_tree; // indicates whether the internal kd-tree should be built + const Search_tree* m_p_search_tree; + bool m_use_default_search_tree; // indicates whether the internal kd-tree should be built #ifdef CGAL_HAS_THREADS std::atomic m_atomic_need_build; + std::atomic m_atomic_search_tree_constructed; #else bool m_need_build; + bool m_search_tree_constructed; #endif private: @@ -604,12 +629,13 @@ public: , m_primitives() , m_p_root_node(nullptr) , m_p_search_tree(nullptr) - , m_search_tree_constructed(false) - , m_use_search_tree(true) + , m_use_default_search_tree(true) #ifdef CGAL_HAS_THREADS , m_atomic_need_build(false) + , m_atomic_search_tree_constructed(false) #else , m_need_build(false) + , m_search_tree_constructed(false) #endif {} @@ -622,12 +648,13 @@ public: , m_primitives() , m_p_root_node(nullptr) , m_p_search_tree(nullptr) - , m_search_tree_constructed(false) - , m_use_search_tree(true) + , m_use_default_search_tree(true) #ifdef CGAL_HAS_THREADS , m_atomic_need_build(false) + , m_atomic_search_tree_constructed(false) #else , m_need_build(false) + , m_search_tree_constructed(false) #endif { // Insert each primitive into tree @@ -640,6 +667,8 @@ public: ConstPrimitiveIterator beyond, T&& ... t) { + if (m_use_default_search_tree && first!=beyond) + clear_search_tree(); set_shared_data(std::forward(t)...); while(first != beyond) { @@ -680,6 +709,8 @@ public: template void AABB_tree::insert(const Primitive& p) { + if (m_use_default_search_tree) + clear_search_tree(); m_primitives.push_back(p); #ifdef CGAL_HAS_THREADS m_atomic_need_build.store(true); @@ -721,12 +752,6 @@ public: m_need_build = false; #endif } - - // In case the users has switched on the accelerated distance query - // data structure with the default arguments, then it has to be - // /built/rebuilt. - if(!empty() && m_use_search_tree && !m_search_tree_constructed) - build_kd_tree(); } // constructs the search KD tree from given points // to accelerate the distance queries @@ -736,17 +761,11 @@ public: // iterate over primitives to get reference points on them std::vector points; points.reserve(m_primitives.size()); - typename Primitives::const_iterator it; - for(it = m_primitives.begin(); it != m_primitives.end(); ++it) - points.push_back( Point_and_primitive_id( - internal::Primitive_helper::get_reference_point( - *it,m_traits), it->id() ) ); + for(const Primitive& p : m_primitives) + points.push_back( Point_and_primitive_id( Helper::get_reference_point(p, m_traits), p.id() ) ); // clears current KD tree - clear_search_tree(); - bool res = build_kd_tree(points.begin(), points.end()); - m_use_search_tree = true; - return res; + return build_kd_tree(points.begin(), points.end()); } // constructs the search KD tree from given points @@ -756,11 +775,16 @@ public: bool AABB_tree::build_kd_tree(ConstPointIterator first, ConstPointIterator beyond) { + clear_search_tree(); m_p_search_tree = new Search_tree(first, beyond); if(m_p_search_tree != nullptr) { +#ifdef CGAL_HAS_THREADS + m_atomic_search_tree_constructed.store(false, std::memory_order_release); // in case build_kd_tree() is triggered by a call to best_hint() +#else m_search_tree_constructed = true; +#endif return true; } else @@ -774,7 +798,7 @@ public: void AABB_tree::do_not_accelerate_distance_queries() { clear_search_tree(); - m_use_search_tree = false; + m_use_default_search_tree = false; } @@ -782,23 +806,9 @@ public: template bool AABB_tree::accelerate_distance_queries() { + m_use_default_search_tree = true; if(m_primitives.empty()) return true; - -#ifdef CGAL_HAS_THREADS - bool m_need_build = m_atomic_need_build.load();; -#endif - - if (m_use_search_tree) - { - if (!m_need_build) return m_search_tree_constructed; - return true; // default return type, no tree built - } - else - m_use_search_tree = true; - - build_kd_tree(); - - return m_search_tree_constructed; + return build_kd_tree(); } template