cgma
RTree.cpp
Go to the documentation of this file.
00001 //---------------------------------------------------------------------------
00002 // Class Name:  RTree
00003 // Description: Rectangle tree.  Multidimensional access method (efficient
00004 //              method to find ranges of boxes.
00005 // The algorithm was taken from the following paper:
00006 //        Guttman, A., "R-Trees: A Dynamic Index Structure for
00007 //              Spatial Searching", Proceedings of the SIGMOD
00008 //              Conference, Boston, June 1984, p. 47-57.
00009 // Creation Date: 3/29/02
00010 // Owner:  David R. White
00011 //---------------------------------------------------------------------------
00012 
00013 //---------------------------------
00014 //Include Files
00015 //---------------------------------
00016 #include "RTree.hpp"
00017 #include "RTreeNode.hpp"
00018 #include "CubitBox.hpp"
00019 #include "CubitVector.hpp"
00020 #include "DLIList.hpp"
00021 #include "PriorityQueue.hpp"
00022 //---------------------------
00023 //Initialize Static Members
00024 //---------------------------
00025 
00026 #ifdef INLINE_TEMPLATES
00027 #define MY_INLINE inline
00028 #else
00029 #define MY_INLINE
00030 #endif
00031 template <class Z> MY_INLINE RTree<Z>::RTree (double tol)
00032 {
00033   myRoot = NULL;
00034   myTolerance = tol;
00035   maxChildren = 8;
00036   minChildren = 2;
00037 }
00038 template <class Z> MY_INLINE RTree<Z>::RTree (double tol, int max_c, int min_c)
00039 {
00040   myRoot = NULL;
00041   myTolerance = tol;
00042   maxChildren = max_c;
00043   minChildren = min_c;
00044 }
00045 template <class Z> MY_INLINE RTree<Z>::~RTree()
00046 {
00047   if ( myRoot != NULL )
00048   {
00049       //Go through and get all the children in a list.
00050     DLIList <RTreeNode<Z>*> to_delete;
00051     to_list(to_delete, myRoot);
00052     int ii;
00053     for(ii = to_delete.size(); ii > 0; ii-- )
00054       delete to_delete.pop();
00055     delete myRoot;
00056   }
00057 }
00058 template <class Z> MY_INLINE void RTree<Z>::to_list(DLIList <RTreeNode<Z>*> &member_list,
00059                                           RTreeNode<Z> *top)
00060 {
00061     //Get the children of the top into the list.
00062   int ii;
00063   RTreeNode <Z> *curr_node;
00064   for ( ii = 0; ii < top->num_children(); ii++ )
00065   {
00066     curr_node = top->get_child(ii);
00067     member_list.append(curr_node);
00068       //don't go below the bottom level...
00069     if ( curr_node->get_leaf_level() == 0 )
00070       continue;
00071     to_list(member_list, curr_node);
00072   }
00073   return;
00074 }
00075 
00076 template <class Z> MY_INLINE CubitStatus RTree<Z>::add(Z data)
00077 {
00078   CubitStatus stat;
00079   RTreeNode<Z> *new_root;
00080   RTreeNode<Z> *new_node = new RTreeNode<Z> (data, myTolerance, maxChildren,
00081                                              minChildren);
00082   if ( myRoot == NULL )
00083   {
00084     CubitBox b_box = data->bounding_box();
00085     myRoot = new RTreeNode <Z> (b_box, maxChildren, minChildren);
00086     myRoot->set_leaf_level(LEAF_RNODE);
00087     stat = myRoot->insert(new_node, new_root);
00088       //this shouldn't change the root, or fail!
00089     if ( stat != CUBIT_SUCCESS || new_root != NULL )
00090     {
00091       PRINT_ERROR("Insertion into RTree failed.\n");
00092       return CUBIT_FAILURE;
00093     }
00094     return CUBIT_SUCCESS;
00095   }
00096   
00097   stat = myRoot->insert(new_node, new_root);
00098   if ( stat != CUBIT_SUCCESS )
00099   {
00100     PRINT_ERROR("Insertion into RTree failed.\n");
00101     return CUBIT_FAILURE;
00102   }
00103   if ( new_root != NULL )
00104   {
00105       //this is fine, it just means we are adding more
00106       //so the root had to be split...
00107     myRoot = new_root;
00108   }
00109   return CUBIT_SUCCESS;
00110 }
00111 template <class Z> MY_INLINE CubitStatus RTree<Z>::find(const CubitBox &range_box,
00112                                               DLIList <Z> &range_members )
00113 {
00114     //Find all of the members of the RTree that intersect this range_box.
00115   if ( myRoot == NULL )
00116   {
00117       // Nothing has been added to this Tree yet, so we are not going to find this
00118       // object in it.
00119       return CUBIT_SUCCESS;
00120   }
00121   CubitStatus stat = recursive_find(myRoot, range_box, range_members);
00122   if ( stat != CUBIT_SUCCESS )
00123     return CUBIT_FAILURE;
00124   else
00125     return CUBIT_SUCCESS;
00126 }
00127 template <class Z> MY_INLINE CubitStatus RTree<Z>::recursive_find(RTreeNode<Z> *rect_tree,
00128                                                         const CubitBox &range_box,
00129                                                         DLIList <Z> &range_members )
00130 {
00131   CubitBox rect_box = rect_tree->bounding_box();
00132   if ( !range_box.overlap(myTolerance, rect_box ) )
00133     return CUBIT_SUCCESS;
00134 
00135     //Now see if this is a data member.  If it is, append the data to the
00136     //list.
00137   if (rect_tree->is_data() )
00138   {
00139     range_members.append(rect_tree->get_data());
00140     return CUBIT_SUCCESS;
00141   }
00142     //Now if this is anything else we need to keep iterating...
00143   int loop_size = rect_tree->num_children();
00144     //We are doing a depth-first search of the tree.  Not
00145     //all branches will need to be followed since they won't
00146     //all overlap...
00147   int ii;
00148   RTreeNode<Z> *curr_node;
00149   CubitStatus stat;
00150   for ( ii = 0; ii < loop_size; ii++ )
00151   {
00152     curr_node = rect_tree->get_child(ii);
00153     if ( curr_node == NULL )
00154     {
00155       PRINT_ERROR("Problems finding boxes in range.\n");
00156       assert(curr_node != NULL);
00157       return CUBIT_FAILURE;
00158     }
00159     stat = recursive_find(curr_node, range_box, range_members);
00160     if ( stat != CUBIT_SUCCESS )
00161       return stat;
00162   }
00163   
00164   return CUBIT_SUCCESS;
00165 }
00166 template <class Z> MY_INLINE CubitBoolean RTree<Z>::remove( Z data )
00167 {
00168   RTreeNode<Z> *new_root = NULL;
00169   CubitBoolean delete_root = CUBIT_FALSE;
00170   CubitBoolean return_val = myRoot->remove( data, new_root, delete_root );
00171   if ( new_root != NULL )
00172   {
00173       //Only if we are condensing the tree do we want to delete the root node.
00174       //There are other reasons the root has changed (rebalance...), in which
00175       //cases the root is now a child of the new root...
00176     if ( delete_root )
00177       delete myRoot;
00178     myRoot = new_root;
00179   }
00180   return return_val;
00181 }
00182 //--------------------------------------------------------------------------
00183 //Algorithm: min_dist_sq
00184 //Description:  Finds the minimum distance squared between the given
00185 //              point and the box. If the point is on or in the box, the
00186 //              min distance is zero.
00187 //--------------------------------------------------------------------------
00188 template <class Z> MY_INLINE
00189 double RTree<Z>::min_dist_sq(CubitVector &q,
00190                              CubitBox &b_box)
00191 {
00192   CubitVector b_min, b_max;
00193   b_min = b_box.minimum();
00194   b_max = b_box.maximum();
00195   double dist;
00196   CubitVector r;
00197 
00198   if ( q.x() < b_min.x() )
00199     r.x(b_min.x());
00200   else if ( q.x() > b_max.x() )
00201     r.x(b_max.x());
00202   else
00203     r.x(q.x());
00204   
00205   if ( q.y() < b_min.y() )
00206     r.y(b_min.y());
00207   else if ( q.y() > b_max.y() )
00208     r.y(b_max.y());
00209   else
00210     r.y(q.y());
00211   
00212   if ( q.z() < b_min.z() )
00213     r.z(b_min.z());
00214   else if ( q.z() > b_max.z() )
00215     r.z(b_max.z());
00216   else
00217     r.z(q.z());
00218   
00219   dist = (q-r).length_squared();
00220 
00221   return dist;
00222 }
00223 template <class Z> MY_INLINE
00224 bool RTree<Z>::less_than_func(RTreeNode<Z> *&node_a,
00225                               RTreeNode<Z> *&node_b)
00226 {
00227   if ( node_a->get_dist() < node_b->get_dist() )
00228     return true;
00229   else
00230     return false;
00231 }
00232 
00233 template <class Z> MY_INLINE
00234 CubitStatus RTree<Z>::k_nearest_neighbor(CubitVector &q,
00235                                          int k,
00236                                          double &closest_dist,
00237                                          DLIList<Z> &nearest_neighbors,
00238                                          typename RTree<Z>::DistSqFunc dist_sq_point_data)
00239 {
00240     //first create the priority queue.
00241   PriorityQueue< RTreeNode<Z>*> near_queue(RTree<Z>::less_than_func);
00242   
00243   myRoot->set_dist(0.0);
00244   near_queue.push(myRoot);
00245   RTreeNode<Z> *element, *child_element;
00246   int num_found = 0;
00247   int ii;
00248   double data_dist, box_dist;
00249   Z data;
00250   
00251   while( !near_queue.empty() )
00252   {
00253     element = near_queue.top();
00254     near_queue.pop();
00255     if ( element->is_data() )
00256     {
00257       data = element->get_data();
00258         //calculate the exact distance.
00259       data_dist = dist_sq_point_data(q, data);
00260         //compare this distance with the next item's distance.
00261       if ( element->dist_is_box() && !near_queue.empty() &&
00262            data_dist > near_queue.top()->get_dist())
00263       {
00264           //If its bigger, add it back into the list
00265           //with the updated distance.
00266         element->set_dist(data_dist);
00267         near_queue.push(element);
00268         element->set_dist_is_box(0);
00269       }
00270       else
00271       {
00272         nearest_neighbors.append(element->get_data());
00273         if ( num_found == 0 )
00274           closest_dist = element->get_dist();
00275         num_found++;
00276         if ( num_found == k )
00277           return CUBIT_SUCCESS;
00278       }
00279     }
00280     else 
00281     {
00282       for ( ii = 0; ii < element->num_children(); ii++ )
00283       {
00284         child_element = element->get_child(ii);
00285         CubitBox bounding_box = child_element->bounding_box();
00286         box_dist = min_dist_sq(q, bounding_box);
00287         child_element->set_dist(box_dist);
00288         near_queue.push(child_element);
00289       }
00290     }
00291   }
00292   return CUBIT_FAILURE;
00293 }
00294 
00295 template <class Z> MY_INLINE
00296 CubitStatus RTree<Z>::find( const CubitVector &ray_origin, const CubitVector &ray_direction,
00297       DLIList <Z> &range_members)
00298 {
00299     //Find all of the members of the RTree that intersect this ray.
00300   if ( myRoot == NULL )
00301   {
00302       // Nothing has been added to this Tree yet, so we are not going to find this
00303       // object in it.
00304       return CUBIT_SUCCESS;
00305   }
00306   CubitStatus stat = recursive_find(myRoot, ray_origin, ray_direction, range_members);
00307   if ( stat != CUBIT_SUCCESS )
00308     return CUBIT_FAILURE;
00309   else
00310     return CUBIT_SUCCESS;
00311 }
00312 
00313 template <class Z> MY_INLINE
00314 CubitStatus RTree<Z>::recursive_find(RTreeNode<Z> *rect_tree,
00315                              const CubitVector &ray_origin,
00316                              const CubitVector &ray_direction,
00317                              DLIList <Z> &range_members)
00318 {
00319   CubitBox rect_box = rect_tree->bounding_box();
00320   //if ( !range_box.overlap(myTolerance, rect_box ) )
00321   if ( !rect_box.intersect(ray_origin, ray_direction) )
00322     return CUBIT_SUCCESS;
00323 
00324     //Now see if this is a data member.  If it is, append the data to the
00325     //list.
00326   if (rect_tree->is_data() )
00327   {
00328     range_members.append(rect_tree->get_data());
00329     return CUBIT_SUCCESS;
00330   }
00331     //Now if this is anything else we need to keep iterating...
00332   int loop_size = rect_tree->num_children();
00333     //We are doing a depth-first search of the tree.  Not
00334     //all branches will need to be followed since they won't
00335     //all overlap...
00336   int ii;
00337   RTreeNode<Z> *curr_node;
00338   CubitStatus stat;
00339   for ( ii = 0; ii < loop_size; ii++ )
00340   {
00341     curr_node = rect_tree->get_child(ii);
00342     if ( curr_node == NULL )
00343     {
00344       PRINT_ERROR("Problems finding boxes in range.\n");
00345       assert(curr_node != NULL);
00346       return CUBIT_FAILURE;
00347     }
00348     stat = recursive_find(curr_node, ray_origin, ray_direction, range_members);
00349     if ( stat != CUBIT_SUCCESS )
00350       return stat;
00351   }
00352   
00353   return CUBIT_SUCCESS;
00354 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines