From de47ee0a277bd20a200ed26c25da2ec43b2be0bf Mon Sep 17 00:00:00 2001 From: Pierre Alliez Date: Wed, 8 Jul 2009 12:02:28 +0000 Subject: [PATCH] AABB tree: do_intersect now calls the First_primitive traversal traits (much faster) performance section updated --- AABB_tree/demo/AABB_tree/types.h | 5 - AABB_tree/doc_tex/AABB_tree/performances.tex | 10 +- AABB_tree/include/CGAL/AABB_tree.h | 1147 +++++++++--------- 3 files changed, 576 insertions(+), 586 deletions(-) diff --git a/AABB_tree/demo/AABB_tree/types.h b/AABB_tree/demo/AABB_tree/types.h index 2d8ac118615..3a8e779a339 100644 --- a/AABB_tree/demo/AABB_tree/types.h +++ b/AABB_tree/demo/AABB_tree/types.h @@ -1,14 +1,9 @@ #ifndef AABB_DEMO_TYPES_H #define AABB_DEMO_TYPES_H -#include -//#include -//#include #include typedef CGAL::Simple_cartesian Kernel; // fastest in experiments -//typedef CGAL::Cartesian Kernel; -//typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::FT FT; typedef Kernel::Ray_3 Ray; diff --git a/AABB_tree/doc_tex/AABB_tree/performances.tex b/AABB_tree/doc_tex/AABB_tree/performances.tex index 60fb93ae0b4..9e6f62a85df 100644 --- a/AABB_tree/doc_tex/AABB_tree/performances.tex +++ b/AABB_tree/doc_tex/AABB_tree/performances.tex @@ -49,7 +49,7 @@ The following table measures the number of intersection queries per second on th \hline Function & Segment & Ray & Line & Plane \\ \hline - do\_intersect() & 142,806 & 140,309 & 152,327 & 231,066 \\ + do\_intersect() & 187,868 & 185,649 & 206,096 & 377,969 \\ any\_intersection() & 147,468 & 143,230 & 148,235 & 229,336 \\ any\_intersected_primitive() & 190,684 & 190,027 & 208,941 & 360,337 \\ number\_of\_intersected\_primitives() & 144,272 & 141,992 & 153,140 & 230,133 \\ @@ -97,8 +97,6 @@ The following table measures the number of \ccc{all_intersections()} queries per The surface triangle mesh chosen for benchmarking distances is again the knot model in four increasing resolutions obtained through Loop subdivision. In the following table we first measure the tree construction time which includes the construction of the internal KD-tree data structure to accelerate the distance queries (note how the internal KD-tree construction time is negligible compared to the AABB tree construction time, while it brings an acceleration of up to one order of magnitude). We then measure the number of queries per second for the three types distance queries (\ccc{closest_point}, \ccc{squared_distance} and \ccc{closest_point_and_primitive}) from point queries randomly chosen inside the bounding box. -% TODO: check CGAL KD-tree issue - \begin{tabular}{|l|c|c|c|c|} \hline Nb triangles & Construction (in ms) & Closest\_point() & squared\_distance() & closest\_point\_and\_primitive() \\ @@ -111,19 +109,17 @@ The surface triangle mesh chosen for benchmarking distances is again the knot mo \end{tabular} -% TODO: against kernels - \subsection{Summary} The experiments described above are neither exhaustive nor conclusive as we have chosen one specific case where the input primitives are the facets of a triangle surface polyhedron. Nevertheless we provide the reader with some general observations and advices about how to put the AABB tree to use with satisfactory performances. While the tree construction times and memory occupancy do not fluctuate much in our experiments depending on the input surface triangle mesh, the performance expressed in number of queries varies greatly depending on a complex combination of criteria: type of kernel, number of input primitives, distribution of primitives in space, type of function queried, type of query, and location of query in space. -\paragraph{Kernel.} The type of CGAL kernel turns out to dominate the final execution times, the maximum performances being obtained with the simple Cartesian kernel templated with the double precision number type. In applications where the intersection and distance execution times are crucial it is possible to use this kernel for the AABB tree in combination with a more robust kernel for the main data structure. +\paragraph{Kernel.} The type of CGAL kernel turns out to dominate the final execution times, the maximum performances being obtained with the simple Cartesian kernel parameterized with the double precision number type. In applications where the intersection and distance execution times are crucial it is possible to use this kernel for the AABB tree in combination with a more robust kernel for the main data structure. \paragraph{Primitives.} Although the number of input primitives plays an obvious role in the final performance, their distribution in space is at least equally important in order to obtain a well-balanced AABB tree. Ideally the primitives must be evenly distributed in space and the long primitives spanning the bounding box of the tree root node must be avoided as much as possible. It is often beneficial to split these long primitives into smaller ones before constructing the tree, e.g., through recursive longest edge bisection for triangle surface meshes. -\paragraph{Function.} The type of function queried plays another important role. Obviously the ``exhaustive'' functions, which list all intersections, are slower than the ones stopping after the first intersection. Within each of these functions the ones which call only intersection tests (do\_intersect(), number\_of\_intersected\_primitives(), all\_intersected\_primitives()) are faster than the ones which explicitly construct the intersections (any\_intersection() and all\_intersections()). +\paragraph{Function.} The type of function queried plays another important role. Obviously the ``exhaustive'' functions, which list all intersections, are slower than the ones stopping after the first intersection. Within each of these functions the ones which call only intersection tests (do\_intersect(), number\_of\_intersected\_primitives(), any\_intersected\_primitive(), all\_intersected\_primitives()) are faster than the ones which explicitly construct the intersections (any\_intersection() and all\_intersections()). \paragraph{Query.} The type of query (e.g., line, ray, segment or plane used above) plays another role, strongly correlated with the type of function (exhaustive or not, and whether or not it constructs the intersections). When all intersection constructions are needed, the final execution times highly depend on the complexity of the general intersection object. For example a plane query generally intersects a surface triangle mesh into many segments while a segment query generally intersects a surface triangle mesh into few points. Finally, the location of the query in space also plays an obvious role in the performances, especially for the distance queries. Assuming the internal KD-tree constructed through the function \ccc{tree.accelerate_distance_queries()}, it is preferable to specify a query point already close to the surface triangle mesh so that the query traverses only few AABBs of the tree. For a large number of primitive data (greater than 2M faces in our experiments) however we noticed that it is not necessary (and sometimes even slower) to use all reference points when constructing the KD-tree. In these cases we recommend to specify trough the function \ccc{tree.accelerate_distance_queries(begin,end)} fewer reference points (typically not more than 100K) evenly distributed over the input primitives. diff --git a/AABB_tree/include/CGAL/AABB_tree.h b/AABB_tree/include/CGAL/AABB_tree.h index 441f867b38b..f2217941718 100644 --- a/AABB_tree/include/CGAL/AABB_tree.h +++ b/AABB_tree/include/CGAL/AABB_tree.h @@ -28,593 +28,592 @@ namespace CGAL { - /** - * @class AABB_tree - * - * - */ - template - class AABB_tree - { - public: - /// types - typedef typename AABBTraits::FT FT; - typedef typename AABBTraits::Point Point; - typedef typename AABBTraits::size_type size_type; - typedef typename AABBTraits::Primitive Primitive; - typedef typename AABBTraits::Bounding_box Bounding_box; - typedef typename AABBTraits::Primitive::Id Primitive_id; - typedef typename AABBTraits::Point_and_primitive_id Point_and_primitive_id; - typedef typename AABBTraits::Object_and_primitive_id Object_and_primitive_id; + /** + * @class AABB_tree + * + * + */ + template + class AABB_tree + { + public: + /// types + typedef typename AABBTraits::FT FT; + typedef typename AABBTraits::Point Point; + typedef typename AABBTraits::size_type size_type; + typedef typename AABBTraits::Primitive Primitive; + typedef typename AABBTraits::Bounding_box Bounding_box; + typedef typename AABBTraits::Primitive::Id Primitive_id; + typedef typename AABBTraits::Point_and_primitive_id Point_and_primitive_id; + typedef typename AABBTraits::Object_and_primitive_id Object_and_primitive_id; - private: - // internal KD-tree used to accelerate the distance queries - typedef AABB_search_tree Search_tree; + private: + // internal KD-tree used to accelerate the distance queries + typedef AABB_search_tree Search_tree; - public: - /** - * @brief Constructor - * @param first iterator over first primitive to insert - * @param beyond past-the-end iterator - * - * Builds the datastructure. Type ConstPrimitiveIterator can be any const - * iterator on a container of Primitive::id_type such that Primitive has - * a constructor taking a ConstPrimitiveIterator as argument. - */ - template - AABB_tree(ConstPrimitiveIterator first, ConstPrimitiveIterator beyond); + public: + /** + * @brief Constructor + * @param first iterator over first primitive to insert + * @param beyond past-the-end iterator + * + * Builds the datastructure. Type ConstPrimitiveIterator can be any const + * iterator on a container of Primitive::id_type such that Primitive has + * a constructor taking a ConstPrimitiveIterator as argument. + */ + template + AABB_tree(ConstPrimitiveIterator first, ConstPrimitiveIterator beyond); - /// Clears the current tree and rebuilds the datastructure. - /// Type ConstPrimitiveIterator can be any const iterator on - /// a container of Primitive::id_type such that Primitive has - /// a constructor taking a ConstPrimitiveIterator as argument. - /// Returns true if the memory allocation was successful. - template - void rebuild(ConstPrimitiveIterator first, ConstPrimitiveIterator beyond); + /// Clears the current tree and rebuilds the datastructure. + /// Type ConstPrimitiveIterator can be any const iterator on + /// a container of Primitive::id_type such that Primitive has + /// a constructor taking a ConstPrimitiveIterator as argument. + /// Returns true if the memory allocation was successful. + template + void rebuild(ConstPrimitiveIterator first, ConstPrimitiveIterator beyond); - /// Non virtual destructor - ~AABB_tree() - { - clear(); - } + /// Non virtual destructor + ~AABB_tree() + { + clear(); + } - /// Clears the tree - void clear() - { - // clear AABB tree - m_primitives.clear(); - delete [] m_p_root_node; - m_p_root_node = NULL; + /// Clears the tree + void clear() + { + // clear AABB tree + m_primitives.clear(); + delete [] m_p_root_node; + m_p_root_node = NULL; - clear_search_tree(); - } + clear_search_tree(); + } - // bbox and size - Bounding_box bbox() const { return m_p_root_node->bbox(); } - size_type size() const { return m_primitives.size(); } - bool empty() const { return m_primitives.empty(); } + // bbox and size + Bounding_box bbox() const { return m_p_root_node->bbox(); } + size_type size() const { return m_primitives.size(); } + bool empty() const { return m_primitives.empty(); } - /// Construct internal search tree with a given point set - // returns true iff successful memory allocation - template - bool accelerate_distance_queries(ConstPointIterator first, ConstPointIterator beyond); + /// Construct internal search tree with a given point set + // returns true iff successful memory allocation + template + bool accelerate_distance_queries(ConstPointIterator first, ConstPointIterator beyond); - /// Construct internal search tree from - /// a point set taken on the internal primitives - // returns true iff successful memory allocation - bool accelerate_distance_queries(); + /// Construct internal search tree from + /// a point set taken on the internal primitives + // returns true iff successful memory allocation + bool accelerate_distance_queries(); // intersection tests - template - bool do_intersect(const Query& query) const; + template + bool do_intersect(const Query& query) const; // #intersections - template - size_type number_of_intersected_primitives(const Query& query) const; - - // all intersections - template - OutputIterator all_intersected_primitives(const Query& query, OutputIterator out) const; - template - OutputIterator all_intersections(const Query& query, OutputIterator out) const; - - // any intersection - template - boost::optional any_intersected_primitive(const Query& query) const; - template - boost::optional any_intersection(const Query& query) const; - - // distance queries - FT squared_distance(const Point& query) const; - FT squared_distance(const Point& query, const Point& hint) const; - Point closest_point(const Point& query) const; - Point closest_point(const Point& query, const Point& hint) const; - Point_and_primitive_id closest_point_and_primitive(const Point& query) const; - Point_and_primitive_id closest_point_and_primitive(const Point& query, const Point_and_primitive_id& hint) const; - - private: - - // clears internal KD tree - void clear_search_tree() - { - delete m_p_search_tree; - m_p_search_tree = NULL; - m_search_tree_constructed = false; - } - - public: - // made public for advanced use by the polyhedron demo - - /// generic traversal of the tree - template - void traversal(const Query& query, Traversal_traits& traits) const - { - if(!empty()) - m_p_root_node->template traversal(query, traits, m_primitives.size()); - else - std::cerr << "AABB tree traversal with empty tree" << std::endl; - } - - private: - typedef AABB_node Node; - - //------------------------------------------------------- - // Traits classes for traversal computation - //------------------------------------------------------- - /** - * @class First_intersection_traits - */ - template - class First_intersection_traits - { - public: - typedef typename boost::optional Result; - public: - First_intersection_traits() - : m_result() - {} - - bool go_further() const { return !m_result; } - - void intersection(const Query& query, const Primitive& primitive) - { - m_result = AABBTraits().intersection_object()(query, primitive); - } - - bool do_intersect(const Query& query, const Node& node) const - { - return AABBTraits().do_intersect_object()(query, node.bbox()); - } - - Result result() const { return m_result; } - bool is_intersection_found() const { return m_result; } - - private: - Result m_result; - }; - - - /** - * @class Counting_traits - */ - template - class Counting_traits - { - public: - Counting_traits() - : m_nb_intersections(0) - {} - - bool go_further() const { return true; } - - // TOCHECK - void intersection(const Query& query, const Primitive& primitive) - { - if( AABBTraits().do_intersect_object()(query, primitive) ) - { - ++m_nb_intersections; - } - } - - bool do_intersect(const Query& query, const Node& node) const - { - return AABBTraits().do_intersect_object()(query, node.bbox()); - } - - size_type number_of_intersections() const { return m_nb_intersections; } - - private: - size_type m_nb_intersections; - }; - - - /** - * @class Listing_intersection_traits - */ - template - class Listing_intersection_traits - { - public: - Listing_intersection_traits(Output_iterator out_it) - : m_out_it(out_it) {} - - bool go_further() const { return true; } - - void intersection(const Query& query, const Primitive& primitive) - { - boost::optional intersection; - intersection = AABBTraits().intersection_object()(query, primitive); - if(intersection) - { - *m_out_it++ = *intersection; - } - } - - bool do_intersect(const Query& query, const Node& node) const - { - return AABBTraits().do_intersect_object()(query, node.bbox()); - } - - private: - Output_iterator m_out_it; - }; - - - /** - * @class Listing_primitive_traits - */ - template - class Listing_primitive_traits - { - public: - Listing_primitive_traits(Output_iterator out_it) - : m_out_it(out_it) {} - - bool go_further() const { return true; } - - void intersection(const Query& query, const Primitive& primitive) - { - if( AABBTraits().do_intersect_object()(query, primitive) ) - { - *m_out_it++ = primitive.id(); - } - } - - bool do_intersect(const Query& query, const Node& node) const - { - return AABBTraits().do_intersect_object()(query, node.bbox()); - } - - private: - Output_iterator m_out_it; - }; - - - /** - * @class First_primitive_traits - */ - template - class First_primitive_traits - { - public: - First_primitive_traits() - : m_is_found(false) - , m_result() {} - - bool go_further() const { return !m_is_found; } - - void intersection(const Query& query, const Primitive& primitive) - { - if( AABBTraits().do_intersect_object()(query, primitive) ) - { - m_result = boost::optional(primitive.id()); - m_is_found = true; - } - } - - bool do_intersect(const Query& query, const Node& node) const - { - return AABBTraits().do_intersect_object()(query, node.bbox()); - } - - boost::optional result() const { return m_result; } - bool is_intersection_found() const { return m_is_found; } - - private: - bool m_is_found; - boost::optional m_result; - }; - - /** - * @class Distance_traits - */ - class Distance_traits - { - public: - Distance_traits(const Point& hint, - const typename Primitive::Id& hint_primitive) - : m_closest_point(hint), - m_closest_primitive(hint_primitive) - {} - - bool go_further() const { return true; } - - void intersection(const Point& query, const Primitive& primitive) - { - Point new_closest_point = AABBTraits().closest_point_object() - (query, primitive, m_closest_point); - if(new_closest_point != m_closest_point) - { - m_closest_primitive = primitive.id(); - m_closest_point = new_closest_point; // this effectively shrinks the sphere - } - } - - bool do_intersect(const Point& query, const Node& node) const - { - return AABBTraits().compare_distance_object() - (query, node.bbox(), m_closest_point) == CGAL::SMALLER; - } - - Point closest_point() const { return m_closest_point; } - Point_and_primitive_id closest_point_and_primitive() const - { - return Point_and_primitive_id(m_closest_point, m_closest_primitive); - } - - private: - Point m_closest_point; - typename Primitive::Id m_closest_primitive; - }; - - public: - // returns a point which must be on one primitive - Point_and_primitive_id any_reference_point_and_id() const - { - CGAL_assertion(!empty()); - return Point_and_primitive_id(m_primitives[0].reference_point(), m_primitives[0].id()); - } - - public: - Point_and_primitive_id best_hint(const Point& query) const - { - if(m_search_tree_constructed) - return m_p_search_tree->closest_point(query); - else - return this->any_reference_point_and_id(); - } - - private: - // set of input primitives - std::vector m_primitives; - // single root node - Node* m_p_root_node; - // search KD-tree - Search_tree* m_p_search_tree; - bool m_search_tree_constructed; - - private: - // Disabled copy constructor & assignment operator - typedef AABB_tree Self; - AABB_tree(const Self& src); - Self& operator=(const Self& src); - - }; // end class AABB_tree - - template - template - AABB_tree::AABB_tree(ConstPrimitiveIterator first, - ConstPrimitiveIterator beyond) - : m_primitives() - , m_p_root_node(NULL) - , m_p_search_tree(NULL) - , m_search_tree_constructed(false) - { - // Insert each primitive into tree - while ( first != beyond ) - { - m_primitives.push_back(Primitive(first)); - ++first; - } - - CGAL_assertion(m_primitives.size() > 1); - m_p_root_node = new Node[m_primitives.size()-1](); - if(m_p_root_node == NULL) - { - std::cerr << "Unable to allocate memory for AABB tree" << std::endl; - CGAL_assertion(m_p_root_node != NULL); - m_primitives.clear(); - } - else - m_p_root_node->expand(m_primitives.begin(), m_primitives.end(), m_primitives.size()); - } - - // Clears tree and insert a set of primitives - template - template - void AABB_tree::rebuild(ConstPrimitiveIterator first, - ConstPrimitiveIterator beyond) - { - // cleanup current tree and internal KD tree - clear(); - - // inserts primitives - while(first != beyond) - { - m_primitives.push_back(Primitive(first)); - first++; - } - - // allocates tree nodes - m_p_root_node = new Node[m_primitives.size()-1](); - if(m_p_root_node == NULL) - { - std::cerr << "Unable to allocate memory for AABB tree" << std::endl; - m_primitives.clear(); - clear(); - } - - // constructs the tree - m_p_root_node->expand(m_primitives.begin(), m_primitives.end(), m_primitives.size()); - } - - - // constructs the search KD tree from given points - // to accelerate the distance queries - template - template - bool AABB_tree::accelerate_distance_queries(ConstPointIterator first, - ConstPointIterator beyond) - { - // clears current KD tree - clear_search_tree(); - - m_p_search_tree = new Search_tree(first, beyond); - if(m_p_search_tree != NULL) - { - m_search_tree_constructed = true; - return true; - } - else - return false; - } - - // constructs the search KD tree from interal primitives - template - bool AABB_tree::accelerate_distance_queries() - { - CGAL_assertion(!m_primitives.empty()); - - // iterate over primitives to get reference points on them - std::vector points; - typename std::vector::const_iterator it; - for(it = m_primitives.begin(); it != m_primitives.end(); ++it) - points.push_back(Point_and_primitive_id(it->reference_point(), it->id())); - - return accelerate_distance_queries(points.begin(), points.end()); - } - - template - template - bool - AABB_tree::do_intersect(const Query& query) const - { - First_intersection_traits traversal_traits; - this->traversal(query, traversal_traits); - return traversal_traits.is_intersection_found(); - } - - template - template - typename AABB_tree::size_type - AABB_tree::number_of_intersected_primitives(const Query& query) const - { - Counting_traits traversal_traits; - this->traversal(query, traversal_traits); - return traversal_traits.number_of_intersections(); - } - - template - template - OutputIterator - AABB_tree::all_intersected_primitives(const Query& query, - OutputIterator out) const - { - Listing_primitive_traits traversal_traits(out); - this->traversal(query, traversal_traits); - return out; - } - - template - template - OutputIterator - AABB_tree::all_intersections(const Query& query, - OutputIterator out) const - { - Listing_intersection_traits traversal_traits(out); - this->traversal(query, traversal_traits); - return out; - } - - template - template - boost::optional::Object_and_primitive_id> - AABB_tree::any_intersection(const Query& query) const - { - First_intersection_traits traversal_traits; - this->traversal(query, traversal_traits); - return traversal_traits.result(); - } - - template - template - boost::optional::Primitive_id> - AABB_tree::any_intersected_primitive(const Query& query) const - { - First_primitive_traits traversal_traits; - this->traversal(query, traversal_traits); - return traversal_traits.result(); - } - - // closest point with user-specified hint - template - typename AABB_tree::Point - AABB_tree::closest_point(const Point& query, - const Point& hint) const - { - typename Primitive::Id hint_primitive = m_primitives[0].id(); - Distance_traits distance_traits(hint,hint_primitive); - this->traversal(query, distance_traits); - return distance_traits.closest_point(); - } - - // closest point without hint, the search KD-tree is queried for the - // first closest neighbor point to get a hint - template - typename AABB_tree::Point - AABB_tree::closest_point(const Point& query) const - { - const Point_and_primitive_id hint = best_hint(query); - return closest_point(query,hint.first); - } - - // squared distance with user-specified hint - template - typename AABB_tree::FT - AABB_tree::squared_distance(const Point& query, - const Point& hint) const - { - const Point closest = this->closest_point(query, hint); - return typename Tr::Compute_squared_distance_3()(query, closest); - } - - // squared distance without user-specified hint - template - typename AABB_tree::FT - AABB_tree::squared_distance(const Point& query) const - { - const Point closest = this->closest_point(query); - return typename Tr::Compute_squared_distance_3()(query, closest); - } - - // closest point with user-specified hint - template - typename AABB_tree::Point_and_primitive_id - AABB_tree::closest_point_and_primitive(const Point& query) const - { - return closest_point_and_primitive(query,best_hint(query)); - } - - // closest point with user-specified hint - template - typename AABB_tree::Point_and_primitive_id - AABB_tree::closest_point_and_primitive(const Point& query, - const Point_and_primitive_id& hint) const - { - Distance_traits distance_traits(hint.first,hint.second); - this->traversal(query, distance_traits); - return distance_traits.closest_point_and_primitive(); - } + template + size_type number_of_intersected_primitives(const Query& query) const; + + // all intersections + template + OutputIterator all_intersected_primitives(const Query& query, OutputIterator out) const; + template + OutputIterator all_intersections(const Query& query, OutputIterator out) const; + + // any intersection + template + boost::optional any_intersected_primitive(const Query& query) const; + template + boost::optional any_intersection(const Query& query) const; + + // distance queries + FT squared_distance(const Point& query) const; + FT squared_distance(const Point& query, const Point& hint) const; + Point closest_point(const Point& query) const; + Point closest_point(const Point& query, const Point& hint) const; + Point_and_primitive_id closest_point_and_primitive(const Point& query) const; + Point_and_primitive_id closest_point_and_primitive(const Point& query, const Point_and_primitive_id& hint) const; + + private: + + // clears internal KD tree + void clear_search_tree() + { + delete m_p_search_tree; + m_p_search_tree = NULL; + m_search_tree_constructed = false; + } + + public: + // made public for advanced use by the polyhedron demo + + /// generic traversal of the tree + template + void traversal(const Query& query, Traversal_traits& traits) const + { + if(!empty()) + m_p_root_node->template traversal(query, traits, m_primitives.size()); + else + std::cerr << "AABB tree traversal with empty tree" << std::endl; + } + + private: + typedef AABB_node Node; + + //------------------------------------------------------- + // Traits classes for traversal computation + //------------------------------------------------------- + /** + * @class First_intersection_traits + */ + template + class First_intersection_traits + { + public: + typedef typename boost::optional Result; + public: + First_intersection_traits() + : m_result() + {} + + bool go_further() const { return !m_result; } + + void intersection(const Query& query, const Primitive& primitive) + { + m_result = AABBTraits().intersection_object()(query, primitive); + } + + bool do_intersect(const Query& query, const Node& node) const + { + return AABBTraits().do_intersect_object()(query, node.bbox()); + } + + Result result() const { return m_result; } + bool is_intersection_found() const { return m_result; } + + private: + Result m_result; + }; + + + /** + * @class Counting_traits + */ + template + class Counting_traits + { + public: + Counting_traits() + : m_nb_intersections(0) + {} + + bool go_further() const { return true; } + + void intersection(const Query& query, const Primitive& primitive) + { + if( AABBTraits().do_intersect_object()(query, primitive) ) + { + ++m_nb_intersections; + } + } + + bool do_intersect(const Query& query, const Node& node) const + { + return AABBTraits().do_intersect_object()(query, node.bbox()); + } + + size_type number_of_intersections() const { return m_nb_intersections; } + + private: + size_type m_nb_intersections; + }; + + + /** + * @class Listing_intersection_traits + */ + template + class Listing_intersection_traits + { + public: + Listing_intersection_traits(Output_iterator out_it) + : m_out_it(out_it) {} + + bool go_further() const { return true; } + + void intersection(const Query& query, const Primitive& primitive) + { + boost::optional intersection; + intersection = AABBTraits().intersection_object()(query, primitive); + if(intersection) + { + *m_out_it++ = *intersection; + } + } + + bool do_intersect(const Query& query, const Node& node) const + { + return AABBTraits().do_intersect_object()(query, node.bbox()); + } + + private: + Output_iterator m_out_it; + }; + + + /** + * @class Listing_primitive_traits + */ + template + class Listing_primitive_traits + { + public: + Listing_primitive_traits(Output_iterator out_it) + : m_out_it(out_it) {} + + bool go_further() const { return true; } + + void intersection(const Query& query, const Primitive& primitive) + { + if( AABBTraits().do_intersect_object()(query, primitive) ) + { + *m_out_it++ = primitive.id(); + } + } + + bool do_intersect(const Query& query, const Node& node) const + { + return AABBTraits().do_intersect_object()(query, node.bbox()); + } + + private: + Output_iterator m_out_it; + }; + + + /** + * @class First_primitive_traits + */ + template + class First_primitive_traits + { + public: + First_primitive_traits() + : m_is_found(false) + , m_result() {} + + bool go_further() const { return !m_is_found; } + + void intersection(const Query& query, const Primitive& primitive) + { + if( AABBTraits().do_intersect_object()(query, primitive) ) + { + m_result = boost::optional(primitive.id()); + m_is_found = true; + } + } + + bool do_intersect(const Query& query, const Node& node) const + { + return AABBTraits().do_intersect_object()(query, node.bbox()); + } + + boost::optional result() const { return m_result; } + bool is_intersection_found() const { return m_is_found; } + + private: + bool m_is_found; + boost::optional m_result; + }; + + /** + * @class Distance_traits + */ + class Distance_traits + { + public: + Distance_traits(const Point& hint, + const typename Primitive::Id& hint_primitive) + : m_closest_point(hint), + m_closest_primitive(hint_primitive) + {} + + bool go_further() const { return true; } + + void intersection(const Point& query, const Primitive& primitive) + { + Point new_closest_point = AABBTraits().closest_point_object() + (query, primitive, m_closest_point); + if(new_closest_point != m_closest_point) + { + m_closest_primitive = primitive.id(); + m_closest_point = new_closest_point; // this effectively shrinks the sphere + } + } + + bool do_intersect(const Point& query, const Node& node) const + { + return AABBTraits().compare_distance_object() + (query, node.bbox(), m_closest_point) == CGAL::SMALLER; + } + + Point closest_point() const { return m_closest_point; } + Point_and_primitive_id closest_point_and_primitive() const + { + return Point_and_primitive_id(m_closest_point, m_closest_primitive); + } + + private: + Point m_closest_point; + typename Primitive::Id m_closest_primitive; + }; + + public: + // returns a point which must be on one primitive + Point_and_primitive_id any_reference_point_and_id() const + { + CGAL_assertion(!empty()); + return Point_and_primitive_id(m_primitives[0].reference_point(), m_primitives[0].id()); + } + + public: + Point_and_primitive_id best_hint(const Point& query) const + { + if(m_search_tree_constructed) + return m_p_search_tree->closest_point(query); + else + return this->any_reference_point_and_id(); + } + + private: + // set of input primitives + std::vector m_primitives; + // single root node + Node* m_p_root_node; + // search KD-tree + Search_tree* m_p_search_tree; + bool m_search_tree_constructed; + + private: + // Disabled copy constructor & assignment operator + typedef AABB_tree Self; + AABB_tree(const Self& src); + Self& operator=(const Self& src); + + }; // end class AABB_tree + + template + template + AABB_tree::AABB_tree(ConstPrimitiveIterator first, + ConstPrimitiveIterator beyond) + : m_primitives() + , m_p_root_node(NULL) + , m_p_search_tree(NULL) + , m_search_tree_constructed(false) + { + // Insert each primitive into tree + while ( first != beyond ) + { + m_primitives.push_back(Primitive(first)); + ++first; + } + + CGAL_assertion(m_primitives.size() > 1); + m_p_root_node = new Node[m_primitives.size()-1](); + if(m_p_root_node == NULL) + { + std::cerr << "Unable to allocate memory for AABB tree" << std::endl; + CGAL_assertion(m_p_root_node != NULL); + m_primitives.clear(); + } + else + m_p_root_node->expand(m_primitives.begin(), m_primitives.end(), m_primitives.size()); + } + + // Clears tree and insert a set of primitives + template + template + void AABB_tree::rebuild(ConstPrimitiveIterator first, + ConstPrimitiveIterator beyond) + { + // cleanup current tree and internal KD tree + clear(); + + // inserts primitives + while(first != beyond) + { + m_primitives.push_back(Primitive(first)); + first++; + } + + // allocates tree nodes + m_p_root_node = new Node[m_primitives.size()-1](); + if(m_p_root_node == NULL) + { + std::cerr << "Unable to allocate memory for AABB tree" << std::endl; + m_primitives.clear(); + clear(); + } + + // constructs the tree + m_p_root_node->expand(m_primitives.begin(), m_primitives.end(), m_primitives.size()); + } + + + // constructs the search KD tree from given points + // to accelerate the distance queries + template + template + bool AABB_tree::accelerate_distance_queries(ConstPointIterator first, + ConstPointIterator beyond) + { + // clears current KD tree + clear_search_tree(); + + m_p_search_tree = new Search_tree(first, beyond); + if(m_p_search_tree != NULL) + { + m_search_tree_constructed = true; + return true; + } + else + return false; + } + + // constructs the search KD tree from interal primitives + template + bool AABB_tree::accelerate_distance_queries() + { + CGAL_assertion(!m_primitives.empty()); + + // iterate over primitives to get reference points on them + std::vector points; + typename std::vector::const_iterator it; + for(it = m_primitives.begin(); it != m_primitives.end(); ++it) + points.push_back(Point_and_primitive_id(it->reference_point(), it->id())); + + return accelerate_distance_queries(points.begin(), points.end()); + } + + template + template + bool + AABB_tree::do_intersect(const Query& query) const + { + First_primitive_traits traversal_traits; + this->traversal(query, traversal_traits); + return traversal_traits.is_intersection_found(); + } + + template + template + typename AABB_tree::size_type + AABB_tree::number_of_intersected_primitives(const Query& query) const + { + Counting_traits traversal_traits; + this->traversal(query, traversal_traits); + return traversal_traits.number_of_intersections(); + } + + template + template + OutputIterator + AABB_tree::all_intersected_primitives(const Query& query, + OutputIterator out) const + { + Listing_primitive_traits traversal_traits(out); + this->traversal(query, traversal_traits); + return out; + } + + template + template + OutputIterator + AABB_tree::all_intersections(const Query& query, + OutputIterator out) const + { + Listing_intersection_traits traversal_traits(out); + this->traversal(query, traversal_traits); + return out; + } + + template + template + boost::optional::Object_and_primitive_id> + AABB_tree::any_intersection(const Query& query) const + { + First_intersection_traits traversal_traits; + this->traversal(query, traversal_traits); + return traversal_traits.result(); + } + + template + template + boost::optional::Primitive_id> + AABB_tree::any_intersected_primitive(const Query& query) const + { + First_primitive_traits traversal_traits; + this->traversal(query, traversal_traits); + return traversal_traits.result(); + } + + // closest point with user-specified hint + template + typename AABB_tree::Point + AABB_tree::closest_point(const Point& query, + const Point& hint) const + { + typename Primitive::Id hint_primitive = m_primitives[0].id(); + Distance_traits distance_traits(hint,hint_primitive); + this->traversal(query, distance_traits); + return distance_traits.closest_point(); + } + + // closest point without hint, the search KD-tree is queried for the + // first closest neighbor point to get a hint + template + typename AABB_tree::Point + AABB_tree::closest_point(const Point& query) const + { + const Point_and_primitive_id hint = best_hint(query); + return closest_point(query,hint.first); + } + + // squared distance with user-specified hint + template + typename AABB_tree::FT + AABB_tree::squared_distance(const Point& query, + const Point& hint) const + { + const Point closest = this->closest_point(query, hint); + return typename Tr::Compute_squared_distance_3()(query, closest); + } + + // squared distance without user-specified hint + template + typename AABB_tree::FT + AABB_tree::squared_distance(const Point& query) const + { + const Point closest = this->closest_point(query); + return typename Tr::Compute_squared_distance_3()(query, closest); + } + + // closest point with user-specified hint + template + typename AABB_tree::Point_and_primitive_id + AABB_tree::closest_point_and_primitive(const Point& query) const + { + return closest_point_and_primitive(query,best_hint(query)); + } + + // closest point with user-specified hint + template + typename AABB_tree::Point_and_primitive_id + AABB_tree::closest_point_and_primitive(const Point& query, + const Point_and_primitive_id& hint) const + { + Distance_traits distance_traits(hint.first,hint.second); + this->traversal(query, distance_traits); + return distance_traits.closest_point_and_primitive(); + } } // end namespace CGAL