contrib/brl/bbas/imesh/algo/imesh_kd_tree.txx
Go to the documentation of this file.
00001 // This is brl/bbas/imesh/algo/imesh_kd_tree.txx
00002 #ifndef imesh_kd_tree_txx_
00003 #define imesh_kd_tree_txx_
00004 //:
00005 // \file
00006 // \brief A KD-Tree template code
00007 // \author Matt Leotta (mleotta@lems.brown.edu)
00008 // \date June 3, 2008
00009 //
00010 // \verbatim
00011 //  Modifications
00012 //   <none yet>
00013 // \endverbatim
00014 
00015 #include "imesh_kd_tree.h"
00016 
00017 #include <vcl_algorithm.h>
00018 #include <vcl_limits.h>
00019 #include <vcl_cassert.h>
00020 
00021 
00022 //: returns the index of the closest leaf node
00023 // The functor \a dist computes the distance between a point and leaf index
00024 // \param dists (if specified) returns a vector of all explored nodes
00025 //        and the closest square distance found so far
00026 template <class F>
00027 unsigned int
00028 imesh_closest_index(const vgl_point_3d<double>& query,
00029                     const vcl_auto_ptr<imesh_kd_tree_node>& kd_root,
00030                     F dist,
00031                     vcl_vector<imesh_kd_tree_queue_entry>* dists = 0)
00032 {
00033   // find the root leaves containing the query point
00034   vcl_vector<imesh_kd_tree_queue_entry> leaf_queue, internal_queue;
00035   imesh_kd_tree_traverse(query,kd_root,leaf_queue,internal_queue);
00036   assert(!leaf_queue.empty());
00037   vcl_make_heap( leaf_queue.begin(), leaf_queue.end() );
00038   vcl_make_heap( internal_queue.begin(), internal_queue.end() );
00039 
00040   double closest_dist2 = vcl_numeric_limits<double>::infinity();
00041   unsigned int closest_ind = 0;
00042 
00043   if (dists)
00044     dists->clear();
00045 
00046 
00047   // find the closest of the contained leaves
00048   vcl_pop_heap( leaf_queue.begin(), leaf_queue.end() );
00049   vcl_vector<imesh_kd_tree_queue_entry>::iterator back = leaf_queue.end();
00050   --back;
00051   bool break_early = true;
00052   while (back->val_ < closest_dist2)
00053   {
00054     double new_dist2 = dist(query,back->node_->index_);
00055     new_dist2 *= new_dist2;
00056     if (dists)
00057       dists->push_back(imesh_kd_tree_queue_entry(new_dist2,back->node_));
00058     if (new_dist2 < closest_dist2) {
00059       closest_dist2 = new_dist2;
00060       closest_ind = back->node_->index_;
00061     }
00062     if (leaf_queue.begin() == back) {
00063       break_early = false;
00064       break;
00065     }
00066     vcl_pop_heap( leaf_queue.begin(), back );
00067     --back;
00068   }
00069   // add the unexplored leaves
00070   if (dists && break_early) {
00071     ++back;
00072     vcl_vector<imesh_kd_tree_queue_entry>::iterator itr = leaf_queue.begin();
00073     for (; itr != back; ++itr)
00074       dists->push_back(*itr);
00075   }
00076   assert(!dists || dists->size() == leaf_queue.size());
00077 
00078 
00079   // check for other closer internal nodes
00080   vcl_pop_heap( internal_queue.begin(), internal_queue.end() );
00081   while (!internal_queue.empty() && internal_queue.back().val_ < closest_dist2)
00082   {
00083     imesh_kd_tree_node* current = internal_queue.back().node_;
00084     internal_queue.pop_back();
00085 
00086     if (current->is_leaf())
00087     {
00088       double new_dist2 = dist(query,current->index_);
00089       new_dist2 *= new_dist2;
00090       if (dists)
00091         dists->push_back(imesh_kd_tree_queue_entry(new_dist2,current));
00092       if (new_dist2 < closest_dist2) {
00093         closest_dist2 = new_dist2;
00094         closest_ind = current->index_;
00095       }
00096     }
00097     else
00098     {
00099       double left_dist2 = imesh_min_sq_dist(query,current->left_->inner_box_);
00100       if (left_dist2 < closest_dist2) {
00101         internal_queue.push_back(imesh_kd_tree_queue_entry(left_dist2,
00102                                                            current->left_.get()));
00103         vcl_push_heap(internal_queue.begin(), internal_queue.end());
00104       }
00105       else if (dists)
00106         dists->push_back(imesh_kd_tree_queue_entry(left_dist2,current->left_.get()));
00107 
00108       double right_dist2 = imesh_min_sq_dist(query,current->right_->inner_box_);
00109       if (right_dist2 < closest_dist2) {
00110         internal_queue.push_back(imesh_kd_tree_queue_entry(right_dist2,
00111                                                            current->right_.get()));
00112         vcl_push_heap(internal_queue.begin(), internal_queue.end());
00113       }
00114       else if (dists)
00115         dists->push_back(imesh_kd_tree_queue_entry(right_dist2,current->right_.get()));
00116     }
00117 
00118     if (!internal_queue.empty())
00119       vcl_pop_heap( internal_queue.begin(), internal_queue.end() );
00120   }
00121   if (dists) {
00122     vcl_vector<imesh_kd_tree_queue_entry>::iterator itr = internal_queue.begin();
00123     for (; itr != internal_queue.end(); ++itr)
00124       dists->push_back(*itr);
00125   }
00126 
00127   return closest_ind;
00128 }
00129 
00130 
00131 #endif // imesh_kd_tree_txx_