cgma
|
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 }