cgma
|
00001 //--------------------------------------------------------------------------- 00002 // Class Name: RStarTreeNode 00003 // Description: Node of Rectangle tree. Contians many of the 00004 // required functions for building the tree and traversing it. 00005 // The algorithm was taken from the following paper: 00006 // Norbert Beckmann, H. Kriegel, R. Schnieder, and B. Seegar, 00007 // "The R*-tree: An Efficient and Robust Access Method 00008 // for Points and Rectangles", Proceedings of ACM SIGMOD 00009 // Int'l. Conf. on Management of Data, pp. 322-331, 1990. 00010 00011 // Creation Date: 7/21/02 00012 // Owner: David R. White 00013 //--------------------------------------------------------------------------- 00014 00015 //--------------------------------- 00016 //Include Files 00017 //--------------------------------- 00018 #include "RStarTreeNode.hpp" 00019 #include "DLIList.hpp" 00020 #include "CpuTimer.hpp" 00021 //--------------------------- 00022 //Initialize Static Members 00023 //--------------------------- 00024 00025 #ifdef INLINE_TEMPLATES 00026 #define MY_INLINE inline 00027 #else 00028 #define MY_INLINE 00029 #endif 00030 static int id = 0; 00031 00032 template <class Y> MY_INLINE RStarTreeNode<Y>::RStarTreeNode (Y data, double tol, 00033 int max_children, 00034 int min_children) 00035 { 00036 myId = id++; 00037 maxChildren = max_children; 00038 minChildren = min_children; 00039 myChildrenNodes = new RStarTreeNode<Y>* [maxChildren]; 00040 int ii; 00041 for ( ii = 0; ii < maxChildren; ii++ ) 00042 myChildrenNodes[ii] = (RStarTreeNode<Y>*) NULL; 00043 if ( data == NULL ) 00044 { 00045 PRINT_ERROR("Building RTree with null data is not allowed!\n"); 00046 assert(data != NULL); 00047 } 00048 myData = data; 00049 myLevel = DATA_RSTARNODE; 00050 CubitBox temp_box = data->bounding_box(); 00051 //Check to see if any of the min/max pairs are less than the tolerance. 00052 //make them bigger if they are... 00053 CubitVector min = temp_box.minimum(); 00054 CubitVector max = temp_box.maximum(); 00055 if ( max.x() - min.x() < tol ) 00056 { 00057 min.x(min.x()-.6*tol); 00058 max.x(max.x()+.6*tol); 00059 } 00060 if ( max.y() - min.y() < tol ) 00061 { 00062 min.y(min.y()-.6*tol); 00063 max.y(max.y()+.6*tol); 00064 } 00065 if ( max.z() - min.z() < tol ) 00066 { 00067 min.z(min.z()-.6*tol); 00068 max.z(max.z()+.6*tol); 00069 } 00070 myBoundingBox = new CubitBox(min, max); 00071 myParent = NULL; 00072 nextChildIndex = 0; 00073 markedFlag = 0; 00074 distIsBox = 1; 00075 myDist = CUBIT_DBL_MAX; 00076 } 00077 template <class Y> MY_INLINE RStarTreeNode<Y>::RStarTreeNode (CubitBox &bounding_box, 00078 int max_children, 00079 int min_children) 00080 { 00081 myId = id++; 00082 maxChildren = max_children; 00083 minChildren = min_children; 00084 myBoundingBox = new CubitBox(bounding_box); 00085 myChildrenNodes = new RStarTreeNode<Y>* [maxChildren]; 00086 int ii; 00087 for ( ii = 0; ii < maxChildren; ii++ ) 00088 myChildrenNodes[ii] = (RStarTreeNode<Y>*) NULL; 00089 myData = NULL; 00090 myLevel = UNSET_RSTARNODE; 00091 myParent = NULL; 00092 nextChildIndex = 0; 00093 markedFlag = 0; 00094 distIsBox = 1; 00095 myDist = CUBIT_DBL_MAX; 00096 } 00097 //----------------------------------------------------------- 00098 // Destructor 00099 //----------------------------------------------------------- 00100 template <class Y> MY_INLINE RStarTreeNode<Y>::~RStarTreeNode() 00101 { 00102 if ( myChildrenNodes ) 00103 delete [] myChildrenNodes; 00104 if ( myBoundingBox ) 00105 delete myBoundingBox; 00106 } 00107 template <class Y> MY_INLINE void RStarTreeNode<Y>::validate_tree(int print) 00108 { 00109 int ii; 00110 if (print ) 00111 { 00112 PRINT_INFO("Parent %d: Children: ", myId); 00113 for ( ii = 0; ii < num_children(); ii++ ) 00114 { 00115 RStarTreeNode<Y> *curr_node = myChildrenNodes[ii]; 00116 PRINT_INFO("%d ", curr_node->myId); 00117 } 00118 PRINT_INFO("\n"); 00119 } 00120 for ( ii = 0; ii < num_children(); ii++ ) 00121 { 00122 RStarTreeNode<Y> *curr_node = myChildrenNodes[ii]; 00123 assert (curr_node->get_parent() == this ); 00124 curr_node->validate_tree(print); 00125 } 00126 return; 00127 } 00128 //----------------------------------------------------------- 00129 // Algorithm: insert 00130 // Insert a new index entry e into an R-Tree. 00131 // I1. [Find postiion for new record] Invoke choose_sub_tree to select 00132 // a leaf node in l, in which to place e. 00133 // I2. [Add record to leaf node].a) If l has room for 00134 // another entry, install E. b) Otherwise invoke overflow_treatment to 00135 // insert e by reinserting in a different order or spliting l. 00136 // I3. [Propogate changes upward] Invoke adjust_tree on l, also passing ll 00137 // if a split was performed. 00138 // I4. [Grow Tree Taller] If node split propogation caused the root 00139 // to split create a new root whose children are the two resulting 00140 // nodes. 00141 //----------------------------------------------------------- 00142 template <class Y> MY_INLINE CubitStatus RStarTreeNode<Y>::insert(RStarTreeNode<Y> *e, 00143 RStarTreeNode<Y> *&new_root, 00144 int *overflow_flags, 00145 int levels) 00146 { 00147 int print1=0; 00148 if ( print1 ) 00149 this->validate_tree(print1); 00150 CubitStatus stat; 00151 new_root = NULL;//only set this if the root node changes. Assume 00152 //that this RStarTreeNode object is the root... 00153 RStarTreeNode<Y> *root = this; 00154 00155 // I1. Invoke choose_sub_tree to select a leaf node l in which to place 00156 //e 00157 RStarTreeNode<Y> *l = choose_sub_tree(this, e); 00158 assert(l->get_parent() != NULL || l == this ); 00159 00160 //just test. 00161 // make sure l is not null. 00162 // make sure l is one level above e. 00163 if ( l == NULL || l->get_leaf_level() != (e->get_leaf_level() + 1) ) 00164 { 00165 PRINT_ERROR("Choosing leaf for inseartion into rtree failed.\n"); 00166 return CUBIT_FAILURE; 00167 } 00168 RStarTreeNode<Y> *ll = NULL; 00169 //I2 a) If l has room for another entry install e. 00170 if ( l->can_add() ) 00171 { 00172 l->add_child(e, CUBIT_TRUE); 00173 } 00174 else 00175 { 00176 //Call the overflow. 00177 stat = overflow_treatment(l, e, ll, root, new_root, 00178 overflow_flags, levels); 00179 if ( stat != CUBIT_SUCCESS ) 00180 return stat; 00181 } 00182 //adjust the bounding boxes and if needed 00183 //create a new root... 00184 assert(l->get_parent() != NULL || l == root || l == new_root ); 00185 int print = 0; 00186 if ( new_root == NULL && print ) 00187 this->validate_tree(print); 00188 else if ( new_root != NULL && print ) 00189 new_root->validate_tree(print); 00190 00191 stat = adjust_tree(l, ll, root, new_root, 00192 overflow_flags, levels); 00193 if ( stat!= CUBIT_SUCCESS ) 00194 return stat; 00195 return CUBIT_SUCCESS; 00196 } 00197 //-------------------------------------------- 00198 // Algorithm: overflow_treatment 00199 // Decides whether or not to do a reinsert or 00200 // a split. Basically e should go into l, but 00201 // there is no more room for it... 00202 //-------------------------------------------- 00203 template <class Y> MY_INLINE 00204 CubitStatus RStarTreeNode<Y>::overflow_treatment( RStarTreeNode<Y>* l, 00205 RStarTreeNode<Y>* e, 00206 RStarTreeNode<Y> *&ll, 00207 RStarTreeNode<Y> *root, 00208 RStarTreeNode<Y> *&new_root, 00209 int *overflow_flags, int levels) 00210 { 00211 assert(l->get_parent() != NULL || l == root || l == new_root ); 00212 00213 CubitStatus stat; 00214 //Test is this level is not the root level. 00215 if ( l->get_leaf_level() != (levels-1) && overflow_flags[l->get_leaf_level()] == 0) 00216 { 00217 //mark this level as having been reinserted... 00218 overflow_flags[l->get_leaf_level()] = 1; 00219 stat = reinsert(l,e,root,new_root,overflow_flags,levels); 00220 if ( stat != CUBIT_SUCCESS ) 00221 return stat; 00222 } 00223 else 00224 { 00225 stat = split_node(l, e, ll); 00226 if ( stat != CUBIT_SUCCESS ) 00227 return stat; 00228 } 00229 return stat; 00230 } 00231 //-------------------------------------------- 00232 // Private Algorithm: sort_center_distance 00233 // Used for sorting in decreasing order (max first) 00234 // rtree nodes based on their distance value. 00235 //-------------------------------------------- 00236 template <class Y> MY_INLINE 00237 int RStarTreeNode<Y>::sort_center_distance( RStarTreeNode<Y> *&n_1, 00238 RStarTreeNode<Y> *&n_2 ) 00239 { 00240 if ( n_1->get_dist() > n_2->get_dist() ) 00241 return -1; 00242 else if ( n_1->get_dist() < n_2->get_dist() ) 00243 return 1; 00244 else 00245 return 0; 00246 } 00247 //-------------------------------------------- 00248 // Private Algorithm: reinsert 00249 // This algorithm chooses p nodes to remove 00250 // from l and reinsert them into the tree. 00251 //-------------------------------------------- 00252 template <class Y> MY_INLINE 00253 CubitStatus RStarTreeNode<Y>::reinsert(RStarTreeNode<Y>* l, 00254 RStarTreeNode<Y>* e, 00255 RStarTreeNode<Y> *root, 00256 RStarTreeNode<Y> *&new_root, 00257 int *overflow_flags, int levels) 00258 { 00259 DLIList <RStarTreeNode<Y>*> ordered_entries; 00260 RStarTreeNode<Y> *curr_node; 00261 CubitBox big_bound = l->bounding_box(); 00262 big_bound |= e->bounding_box(); 00263 CubitVector center_big = big_bound.center(); 00264 CubitVector center_curr; 00265 double dist_sq; 00266 int ii; 00267 for ( ii = 0; ii < maxChildren; ii++) 00268 { 00269 curr_node = l->myChildrenNodes[ii]; 00270 center_curr = curr_node->bounding_box().center(); 00271 dist_sq = (center_curr-center_big).length_squared(); 00272 curr_node->set_dist(dist_sq); 00273 ordered_entries.append(curr_node); 00274 } 00275 center_curr = e->bounding_box().center(); 00276 dist_sq = (center_curr-center_big).length_squared(); 00277 e->set_dist(dist_sq); 00278 ordered_entries.append(e); 00279 ordered_entries.sort( sort_center_distance ); 00280 //Make sure the sorting worked... 00281 if (ordered_entries.get()->get_dist() < ordered_entries.next()->get_dist()) 00282 { 00283 PRINT_ERROR("Sorting failed in R*Tree.\n"); 00284 assert(0); 00285 return CUBIT_FAILURE; 00286 } 00287 //Calculate P. The rstar tree says to use 30% of M. 00288 //I'll round up... 00289 double P = .3*maxChildren; 00290 int p = (int) (P+0.5); 00291 DLIList <RStarTreeNode<Y>*> reinsert_nodes; 00292 for ( ii = 0; ii < p; ii++ ) 00293 { 00294 reinsert_nodes.append(ordered_entries.get_and_step()); 00295 } 00296 //Now reverse the reinsert nodes, inorder to reinsert 00297 //the minimum distance ones first as the paper says 00298 //this far outperforms the max ones. 00299 reinsert_nodes.reverse(); 00300 00301 //remove these nodes from l. 00302 CubitBoolean e_reinserted = CUBIT_FALSE; 00303 00304 for ( ii = 0; ii < p; ii++ ) 00305 { 00306 curr_node = reinsert_nodes.get_and_step(); 00307 //remember e wasn't part of l anyways... 00308 if ( curr_node == e ) 00309 { 00310 e_reinserted = CUBIT_TRUE; 00311 continue; 00312 } 00313 l->remove_child(curr_node); 00314 curr_node->set_parent(NULL); 00315 } 00316 //ressize the bounding box. 00317 if ( !e_reinserted ) 00318 { 00319 l->add_child(e, CUBIT_FALSE); 00320 } 00321 l->recalc_b_box(); 00322 CubitStatus stat; 00323 RStarTreeNode<Y> *changed_root = NULL; 00324 for ( ii = 0; ii < p; ii++ ) 00325 { 00326 curr_node = reinsert_nodes.get_and_step(); 00327 stat = root->insert(curr_node, new_root, 00328 overflow_flags, levels); 00329 if ( stat != CUBIT_SUCCESS || curr_node->get_parent() == NULL) 00330 { 00331 PRINT_ERROR("RStarTree::reinsert insertion failed.\n"); 00332 return stat; 00333 } 00334 if ( new_root != NULL ) 00335 { 00336 changed_root = new_root; 00337 root = new_root; 00338 } 00339 } 00340 //if the root was split during this, like at one of the middle nodes, 00341 //new root would get reset to null again. Soo, luckily we saved that 00342 //change! Reassign changed_root to new_root. 00343 if ( changed_root != NULL ) 00344 new_root = changed_root; 00345 return CUBIT_SUCCESS; 00346 } 00347 00348 //-------------------------------------------- 00349 // Algorithm: choose_sub_tree: Select a leaf node in which to place 00350 // a new index entry e. Recursive search the subtrees of n 00351 // until n is a leaf node. 00352 //---------------------------------------------- 00353 template <class Y> MY_INLINE 00354 RStarTreeNode<Y>* RStarTreeNode<Y>::choose_sub_tree( RStarTreeNode<Y>* n, 00355 RStarTreeNode<Y>* e ) 00356 { 00357 //If n is a leaf node, or one level greater than e, 00358 //we are done. 00359 if ( n->get_leaf_level() == (e->get_leaf_level() + 1) ) 00360 return n; 00361 //Now choose the entry f in n (children of n that is) 00362 //If the children of n are leaf nodes, then find the entry f in n 00363 // whose rectangle needs least overlap enalargement to include the new data 00364 // rectangle. Resolve ties by choosing the entry whose rectangle needs least 00365 // are enlargement, then the entry with the rectangle of smallest area. 00366 //Else Choose the entry f in n whose rectangle needs least area enlargment to include the new 00367 //data rectangle. Resolve ties by choosing the entry with the rectangle of smallest area. 00368 double min_enlargement = CUBIT_DBL_MAX, curr_enlargement; 00369 double min_overlap = CUBIT_DBL_MAX, curr_overlap; 00370 RStarTreeNode<Y> *curr_node; 00371 int child_index = -1; 00372 int ii; 00373 CubitBox bounding_box; 00374 for(ii = 0; (ii < maxChildren) && (n->myChildrenNodes[ii] != NULL); ii++ ) 00375 { 00376 00377 curr_node = n->myChildrenNodes[ii]; 00378 assert(curr_node->get_parent() != NULL ); 00379 if ( curr_node->get_leaf_level() == (e->get_leaf_level() + 1) ) 00380 { 00381 curr_overlap = calc_overlap(curr_node, e); 00382 if ( curr_overlap <= min_overlap ) 00383 { 00384 if ( curr_overlap == min_overlap && child_index >= 0 ) 00385 { 00386 double curr_enl = calc_enlargement(curr_node, e); 00387 double best_enl = calc_enlargement(n->get_child(ii), e); 00388 if ( curr_enl > best_enl ) 00389 continue; 00390 if ( curr_enl == best_enl ) 00391 { 00392 //only reset if the curr_node has a smaller volume. 00393 double curr_vol = volume(curr_node); 00394 double old_vol = volume(n->myChildrenNodes[child_index]); 00395 if ( old_vol < curr_vol ) 00396 continue; 00397 } 00398 } 00399 child_index = ii; 00400 min_overlap = curr_overlap; 00401 } 00402 } 00403 else 00404 { 00405 curr_enlargement = calc_enlargement(curr_node, e); 00406 if ( curr_enlargement <= min_enlargement ) 00407 { 00408 if ( curr_enlargement == min_enlargement && child_index >= 0 ) 00409 { 00410 //only reset if the curr_node has a smaller volume. 00411 double curr_vol = volume(curr_node); 00412 double old_vol = volume(n->myChildrenNodes[child_index]); 00413 if ( old_vol < curr_vol ) 00414 continue; 00415 } 00416 child_index = ii; 00417 min_enlargement = curr_enlargement; 00418 } 00419 } 00420 } 00421 //do error checking... 00422 if ( child_index == -1 || child_index >= maxChildren ) 00423 return (RStarTreeNode<Y>*)NULL; 00424 RStarTreeNode<Y> *f = n->myChildrenNodes[child_index]; 00425 //Now continue on... 00426 curr_node = choose_sub_tree(f,e); 00427 return curr_node; 00428 } 00429 //---------------------------------------------------------------------- 00430 // calc_overlap: Calculate the total overlap between the add_to and the 00431 // children of current. 00432 //---------------------------------------------------------------------- 00433 template <class Y> MY_INLINE double RStarTreeNode<Y>::calc_overlap(RStarTreeNode<Y> *current, 00434 RStarTreeNode<Y> *add_to) 00435 { 00436 int ii, jj; 00437 CubitBox add_to_box = add_to->bounding_box(); 00438 double total_volume = 0.0; 00439 //calculate the total overlap currently. 00440 CubitBox curr_child_box, other_child_box, temp_box; 00441 for ( ii = 0; ii < current->num_children(); ii++ ) 00442 { 00443 curr_child_box = current->get_child(ii)->bounding_box(); 00444 for ( jj = 0; jj < current->num_children(); jj++ ) 00445 { 00446 if ( ii == jj ) 00447 continue; 00448 temp_box = curr_child_box; 00449 other_child_box.reset(current->get_child(jj)->bounding_box()); 00450 temp_box &= other_child_box; 00451 total_volume += volume(temp_box); 00452 } 00453 } 00454 double prev_total = total_volume; 00455 //add to it the overlap that would occur. 00456 for ( ii = 0; ii < current->num_children(); ii++ ) 00457 { 00458 curr_child_box.reset( current->get_child(ii)->bounding_box()); 00459 curr_child_box &= add_to_box; 00460 total_volume += volume(curr_child_box); 00461 } 00462 //now find the overlap enlargment, total - prev_total... 00463 return (total_volume-prev_total); 00464 } 00465 00466 //---------------------------------------------------------------------- 00467 // calc_enlargement: Calculate the enlargement required for increasing 00468 // the bounding box of current so that it would encapsulate the bounding 00469 // box of add_to. So to do that, create the union of the two bounding 00470 // boxes, then of that supper box subtrace the volume of the current. 00471 // The result should be the volumetric difference between how much 00472 // current has and how much it would need be or the enlargement. 00473 //---------------------------------------------------------------------- 00474 template <class Y> MY_INLINE 00475 double RStarTreeNode<Y>::calc_enlargement(RStarTreeNode<Y> *current, RStarTreeNode<Y> *add_to ) 00476 { 00477 //The enlargement area is the volume of the box that would 00478 //be the union of current and add_to minus the volume of the current. 00479 CubitBox curr_box = current->bounding_box(); 00480 CubitBox add_to_box = add_to->bounding_box(); 00481 CubitBox supper = curr_box; 00482 //Unite add_to_box to the curr_box. 00483 supper|= add_to_box; 00484 double area_big = volume(supper); 00485 return area_big - volume(current); 00486 } 00487 template <class Y> MY_INLINE 00488 double RStarTreeNode<Y>::calc_enlargement(CubitBox ¤t, CubitBox &add_to ) 00489 { 00490 //The enlargement area is the volume of the box that would 00491 //be the union of current and add_to minus the volume of the current. 00492 CubitBox supper = current; 00493 // unite the add_to box. 00494 supper |= add_to; 00495 double area_big = volume(supper); 00496 return area_big - volume(current); 00497 } 00498 //------------------------------------------------------------------ 00499 // Algorithm: adjust_tree 00500 // Description: Ascend from a leaf node L to the root, adjusting covering 00501 // bounding boxes and propagating nodes splits as necesary. 00502 //------------------------------------------------------------------ 00503 template <class Y> MY_INLINE 00504 CubitStatus RStarTreeNode<Y>::adjust_tree(RStarTreeNode<Y> *l, RStarTreeNode<Y> *ll, 00505 RStarTreeNode<Y> *root_node, 00506 RStarTreeNode<Y> *&new_root, 00507 int *overflow_flags, 00508 int levels) 00509 { 00510 CubitStatus stat; 00511 //we need to move up the tree and correct things that have changed. 00512 if ( l == root_node ) 00513 { 00514 if ( ll == NULL ) 00515 return CUBIT_SUCCESS; 00516 else 00517 { 00518 //Create a new root node and store l and ll there 00519 CubitBox root_box = l->bounding_box(); 00520 root_box |= ll->bounding_box(); 00521 new_root = new RStarTreeNode<Y>(root_box, maxChildren, minChildren); 00522 int new_level = l->get_leaf_level() + 1; 00523 new_root->set_leaf_level(new_level); 00524 new_root->add_child(l, CUBIT_TRUE); 00525 new_root->add_child(ll, CUBIT_TRUE); 00526 return CUBIT_SUCCESS; 00527 } 00528 } 00529 else if ( l == new_root && ll == NULL ) 00530 { 00531 return CUBIT_SUCCESS; 00532 } 00533 else if ( l == new_root && ll != NULL ) 00534 { 00535 //Create a new root node and store l and ll there 00536 CubitBox root_box = l->bounding_box(); 00537 root_box |= ll->bounding_box(); 00538 new_root = new RStarTreeNode<Y>(root_box, maxChildren, minChildren); 00539 int new_level = l->get_leaf_level() + 1; 00540 new_root->set_leaf_level(new_level); 00541 new_root->add_child(l, CUBIT_TRUE); 00542 new_root->add_child(ll, CUBIT_TRUE); 00543 return CUBIT_SUCCESS; 00544 } 00545 00546 RStarTreeNode<Y> *parent_node = l->get_parent(); 00547 RStarTreeNode<Y> *new_group = NULL; 00548 if ( ll != NULL ) 00549 { 00550 //We need to add ll to the parent if we can, 00551 //and then we need to update the parent's bounding box... 00552 if ( parent_node->can_add() ) 00553 { 00554 parent_node->add_child(ll, CUBIT_FALSE); 00555 //we need to recalculate the bounding box for the 00556 //entire set since both l and ll were modified... 00557 parent_node->recalc_b_box(); 00558 } 00559 else 00560 { 00561 //Now we must split the children of the parent. l should 00562 //already be in the chilren list of the paretn. So send 00563 //to split node the parent_node and ll. 00564 //parent node during this process will have its b_box recalced. 00565 stat = overflow_treatment(parent_node, ll, new_group, root_node, new_root, 00566 overflow_flags, levels); 00567 if ( stat != CUBIT_SUCCESS ) 00568 { 00569 PRINT_ERROR("Problems splitting node during insertion to RTree.\n"); 00570 return CUBIT_FAILURE; 00571 } 00572 } 00573 } 00574 else 00575 { 00576 //just recalulate the b_box for the parent_node. 00577 parent_node->recalc_b_box(); 00578 } 00579 if ( parent_node->get_parent() == NULL && 00580 parent_node != root_node && 00581 parent_node != new_root ) 00582 { 00583 PRINT_INFO("level = %d\n", parent_node->get_leaf_level()); 00584 PRINT_INFO("levels = %d\n", levels); 00585 PRINT_ERROR("parent_node (%d) == NULL\n", parent_node->myId); 00586 PRINT_ERROR("And l (%d) ", l->myId); 00587 assert(0); 00588 } 00589 stat = adjust_tree(parent_node, new_group, root_node, new_root, 00590 overflow_flags, levels); 00591 if ( stat != CUBIT_SUCCESS ) 00592 return CUBIT_FAILURE; 00593 return CUBIT_SUCCESS; 00594 } 00595 template <class Y> MY_INLINE 00596 int RStarTreeNode<Y>::sort_high_x(RStarTreeNode<Y> *&n_1, 00597 RStarTreeNode<Y> *&n_2 ) 00598 { 00599 CubitVector n_1_high = n_1->bounding_box().maximum(); 00600 CubitVector n_2_high = n_2->bounding_box().maximum(); 00601 00602 if ( n_1_high.x() < n_2_high.x() ) 00603 return -1; 00604 else if ( n_1_high.x() == n_2_high.x() ) 00605 return 0; 00606 else 00607 return 1; 00608 } 00609 template <class Y> MY_INLINE 00610 int RStarTreeNode<Y>::sort_high_y(RStarTreeNode<Y> *&n_1, 00611 RStarTreeNode<Y> *&n_2 ) 00612 { 00613 CubitVector n_1_high = n_1->bounding_box().maximum(); 00614 CubitVector n_2_high = n_2->bounding_box().maximum(); 00615 00616 if ( n_1_high.y() < n_2_high.y() ) 00617 return -1; 00618 else if ( n_1_high.y() == n_2_high.y() ) 00619 return 0; 00620 else 00621 return 1; 00622 } 00623 template <class Y> MY_INLINE 00624 int RStarTreeNode<Y>::sort_high_z(RStarTreeNode<Y> *&n_1, 00625 RStarTreeNode<Y> *&n_2 ) 00626 { 00627 CubitVector n_1_high = n_1->bounding_box().maximum(); 00628 CubitVector n_2_high = n_2->bounding_box().maximum(); 00629 00630 if ( n_1_high.z() < n_2_high.z() ) 00631 return -1; 00632 else if ( n_1_high.z() == n_2_high.z() ) 00633 return 0; 00634 else 00635 return 1; 00636 } 00637 template <class Y> MY_INLINE 00638 int RStarTreeNode<Y>::sort_low_x(RStarTreeNode<Y> *&n_1, 00639 RStarTreeNode<Y> *&n_2 ) 00640 { 00641 CubitVector n_1_low = n_1->bounding_box().minimum(); 00642 CubitVector n_2_low = n_2->bounding_box().minimum(); 00643 00644 if ( n_1_low.x() < n_2_low.x() ) 00645 return -1; 00646 else if ( n_1_low.x() == n_2_low.x() ) 00647 return 0; 00648 else 00649 return 1; 00650 } 00651 template <class Y> MY_INLINE 00652 int RStarTreeNode<Y>::sort_low_y(RStarTreeNode<Y> *&n_1, 00653 RStarTreeNode<Y> *&n_2 ) 00654 { 00655 CubitVector n_1_low = n_1->bounding_box().minimum(); 00656 CubitVector n_2_low = n_2->bounding_box().minimum(); 00657 00658 if ( n_1_low.y() < n_2_low.y() ) 00659 return -1; 00660 else if ( n_1_low.y() == n_2_low.y() ) 00661 return 0; 00662 else 00663 return 1; 00664 } 00665 template <class Y> MY_INLINE 00666 int RStarTreeNode<Y>::sort_low_z(RStarTreeNode<Y> *&n_1, 00667 RStarTreeNode<Y> *&n_2 ) 00668 { 00669 CubitVector n_1_low = n_1->bounding_box().minimum(); 00670 CubitVector n_2_low = n_2->bounding_box().minimum(); 00671 00672 if ( n_1_low.z() < n_2_low.z() ) 00673 return -1; 00674 else if ( n_1_low.z() == n_2_low.z() ) 00675 return 0; 00676 else 00677 return 1; 00678 } 00679 00680 //------------------------------------------------------------------ 00681 // Algorithm: split_node 00682 // This function is rather tricky since it really isn't well 00683 // described Beckmann's paper very well. I looked at other online 00684 // docs and descriptions and came to the current implementation. 00685 // As I understand it the current function does the following: 00686 // First descide which axis the nodes should be split along. 00687 // To accomplish this the nodes that are going to be split (the 00688 // children of l and the node e), are added to two lists. The lists 00689 // are then sorted according to their high and low values along 00690 // the three axis. Then for each each high and low, 00691 // d distributions are created with possible groupings. 00692 // Where d = (maxChildren -2*minChildren +2). These distributions are 00693 // then used to calculate the total margin for each axis. The axis 00694 // with the minimum margin is selected. While calculating the margins 00695 // for each distribution, the best "distribution" for each axis is also 00696 // selected. The best distribution will be the one that has the minimum 00697 // overlap over the entire set of distributions, and high and low sets. 00698 // When the axis is chosen, the correct distribution is then also stored 00699 // or known. The function then splits l into l and ll. 00700 //------------------------------------------------------------------ 00701 template <class Y> MY_INLINE 00702 CubitStatus RStarTreeNode<Y>::split_node( RStarTreeNode<Y> *l, 00703 RStarTreeNode<Y> *e, 00704 RStarTreeNode<Y> *&ll ) 00705 { 00706 int ii; 00707 //create a new list containing all the nodes we want to split. 00708 //create two lists. 00709 DLIList <RStarTreeNode<Y>*> ordered_low, ordered_high; 00710 for ( ii = 0; ii < maxChildren; ii++) 00711 { 00712 ordered_low.append(l->myChildrenNodes[ii]); 00713 ordered_high.append(l->myChildrenNodes[ii]); 00714 } 00715 ordered_low.append(e); 00716 ordered_high.append(e); 00717 //the input list contains all of the nodes. 00718 00719 int d = maxChildren - 2*minChildren + 2; 00720 00721 //Now do the first step, choose the split axis. 00722 //loop over each dimension. 00723 double local_margin, min_margin = CUBIT_DBL_MAX; 00724 DLIList<RStarTreeNode<Y>*> best_group_1, best_group_2; 00725 00726 for ( ii = 0; ii < 3; ii++ ) 00727 { 00728 //Sort the lists according to the high and low dimension. 00729 //Both lists are ordered lowest to highest however. 00730 switch(ii) 00731 { 00732 case(0): 00733 //this is the x dimension. 00734 ordered_low.sort(sort_low_x); 00735 ordered_high.sort(sort_high_x); 00736 break; 00737 case(1): 00738 //this is the y dimension. 00739 ordered_low.sort(sort_low_y); 00740 ordered_high.sort(sort_high_y); 00741 break; 00742 case(2): 00743 //this is the z dimension. 00744 ordered_low.sort(sort_low_z); 00745 ordered_high.sort(sort_high_z); 00746 break; 00747 } 00748 //Now loop over the distributions and sum the margins for the 00749 //different distributions. The axis where the sum of its margins 00750 //is minimal is the correct axis. 00751 int k; 00752 local_margin = 0.0; 00753 double min_overlap = CUBIT_DBL_MAX; 00754 double min_volume = CUBIT_DBL_MAX; 00755 DLIList<RStarTreeNode<Y>*> group_1_low, group_1_high, local_best_1; 00756 DLIList<RStarTreeNode<Y>*> group_2_low, group_2_high, local_best_2; 00757 //just do this so that the code can look familar with the paper. 00758 int m = minChildren; 00759 int M = maxChildren; 00760 //Also determine with distribution is best among these in this axis. 00761 //Store those groups in case this axis is optimum. 00762 for ( k = 0; k < d; k++ ) 00763 { 00764 //build the 4 groups... 00765 int jj; 00766 group_1_low.clean_out(); 00767 group_2_low.clean_out(); 00768 group_1_high.clean_out(); 00769 group_2_high.clean_out(); 00770 for ( jj = 0; jj < (m-1+k); jj++ ) 00771 { 00772 group_1_low.append(ordered_low.next(jj)); 00773 group_1_high.append(ordered_high.next(jj)); 00774 } 00775 for ( jj = (m-1+k); jj < (M+1); jj++ ) 00776 { 00777 group_2_low.append(ordered_low.next(jj)); 00778 group_2_high.append(ordered_high.next(jj)); 00779 } 00780 assert(group_1_low.size() + group_2_low.size() == M+1 ); 00781 //Okay we have the groups. Now calculate the metrics. 00782 //First find the bounding boxes for the groups. 00783 CubitBox group_1_low_box = super_box(group_1_low); 00784 CubitBox group_2_low_box = super_box(group_2_low); 00785 CubitBox group_1_high_box = super_box(group_1_high); 00786 CubitBox group_2_high_box = super_box(group_2_high); 00787 00788 local_margin += margin(group_1_low_box); 00789 local_margin += margin(group_2_low_box); 00790 local_margin += margin(group_1_high_box); 00791 local_margin += margin(group_2_high_box); 00792 //Okay now that we have the margin, that is the portion of the 00793 //code for choosing the correct axis. Now make sure if this axis 00794 //is the right one, we find the right distribution. 00795 00796 double overlap_low, overlap_high; 00797 //remember &= is the overlap or intersection and the volume calculates 00798 //the volume of the overlap or intersection. 00799 overlap_low = volume(group_1_low_box &= group_2_low_box); 00800 overlap_high = volume(group_1_high_box &= group_2_high_box); 00801 CubitBoolean use_low = (overlap_low < overlap_high)? CUBIT_TRUE : CUBIT_FALSE; 00802 double temp_overlap = use_low ? overlap_low : overlap_high; 00803 //Choose the best distribution based on the mininum distribution 00804 if ( temp_overlap < min_overlap ) 00805 { 00806 min_overlap = temp_overlap; 00807 if ( use_low ) 00808 { 00809 local_best_1 = group_1_low; 00810 local_best_2 = group_2_low; 00811 } 00812 else 00813 { 00814 local_best_1 = group_1_high; 00815 local_best_2 = group_2_high; 00816 } 00817 } 00818 //break ties based on the smallest volumes. 00819 else if ( temp_overlap == min_overlap ) 00820 { 00821 //supposed to resolve this by choosing the one with the minimum area. 00822 double tmp_vol; 00823 if ( use_low ){ 00824 tmp_vol = volume(group_1_low_box); 00825 tmp_vol += volume(group_2_low_box); 00826 } 00827 else { 00828 tmp_vol = volume(group_1_high_box); 00829 tmp_vol += volume(group_2_high_box); 00830 } 00831 if ( tmp_vol < min_volume ) 00832 { 00833 min_volume = tmp_vol; 00834 if ( use_low ) 00835 { 00836 local_best_1 = group_1_low; 00837 local_best_2 = group_2_low; 00838 } 00839 else 00840 { 00841 local_best_1 = group_1_high; 00842 local_best_2 = group_2_high; 00843 } 00844 } 00845 } 00846 } 00847 //After the margin has been sumed for the entire distributions, 00848 //choose the axis with the min margin. Note I'm not storing the 00849 //axis because for each distribution I'm also chosing the local 00850 //best based on overlap. Store that local best as the overal all 00851 //best. It only gets stored if the axis is optimum... 00852 if ( local_margin < min_margin ) 00853 { 00854 min_margin = local_margin; 00855 best_group_1 = local_best_1; 00856 best_group_2 = local_best_2; 00857 } 00858 } 00859 //Okay now we have the groups. Clean out l, create ll. 00860 l->flush(best_group_1.get()->bounding_box()); 00861 l->add_child(best_group_1.get_and_step(), CUBIT_FALSE); 00862 l->set_leaf_level(e->get_leaf_level() + 1); 00863 for ( ii = 1; ii < best_group_1.size(); ii++ ) 00864 l->add_child(best_group_1.get_and_step(), CUBIT_TRUE); 00865 ll = new RStarTreeNode<Y>(best_group_2.get()->bounding_box(), 00866 maxChildren, minChildren); 00867 ll->add_child(best_group_2.get_and_step(), CUBIT_FALSE); 00868 ll->set_leaf_level(l->get_leaf_level()); 00869 for ( ii = 1; ii < best_group_2.size(); ii++ ) 00870 ll->add_child(best_group_2.get_and_step(), CUBIT_TRUE); 00871 00872 return CUBIT_SUCCESS; 00873 } 00874 //----------------------------------------------- 00875 //Private Function: Margin 00876 // Calculates the margin of bounding box. 00877 //----------------------------------------------- 00878 template <class Y> MY_INLINE 00879 double RStarTreeNode<Y>::margin(CubitBox &bounding_box) 00880 { 00881 double margin = 4*(bounding_box.x_range() + bounding_box.y_range() 00882 + bounding_box.z_range()); 00883 return margin; 00884 } 00885 //----------------------------------------------- 00886 //Private Function: super_box 00887 // Calculates the overall bounding box of the rtree 00888 // nodes in the list. 00889 //----------------------------------------------- 00890 template <class Y> MY_INLINE 00891 CubitBox RStarTreeNode<Y>::super_box(DLIList<RStarTreeNode<Y>*> &node_list) 00892 { 00893 int ii; 00894 CubitBox bounding_box = node_list.get_and_step()->bounding_box(); 00895 for ( ii = 1; ii < node_list.size(); ii++ ) 00896 { 00897 bounding_box |= node_list.get_and_step()->bounding_box(); 00898 } 00899 return bounding_box; 00900 } 00901 00902 template <class Y> MY_INLINE void RStarTreeNode<Y>::flush( CubitBox &new_box ) 00903 { 00904 int ii; 00905 nextChildIndex = 0; 00906 for ( ii = 0; ii < maxChildren; ii++ ) 00907 myChildrenNodes[ii] = NULL; 00908 delete myBoundingBox; 00909 myBoundingBox = new CubitBox(new_box); 00910 } 00911 template <class Y> MY_INLINE void RStarTreeNode<Y>::add_child(RStarTreeNode<Y> *child_node, 00912 CubitBoolean recalc_b_box) 00913 { 00914 assert(nextChildIndex < maxChildren && child_node != NULL ); 00915 myChildrenNodes[nextChildIndex] = child_node; 00916 //update the bounding box. by uniting with child node... 00917 if ( recalc_b_box ) 00918 { 00919 CubitBox *old_box = myBoundingBox; 00920 myBoundingBox = new CubitBox( *old_box |= child_node->bounding_box()); 00921 delete old_box; 00922 } 00923 nextChildIndex++; 00924 child_node->set_parent(this); 00925 } 00926 template <class Y> MY_INLINE CubitBoolean RStarTreeNode<Y>::can_add() 00927 { 00928 if (nextChildIndex >= maxChildren ) 00929 return CUBIT_FALSE; 00930 else 00931 return CUBIT_TRUE; 00932 } 00933 template <class Y> MY_INLINE int RStarTreeNode<Y>::space_left() 00934 { 00935 return maxChildren - nextChildIndex; 00936 } 00937 template <class Y> MY_INLINE void RStarTreeNode<Y>::recalc_b_box() 00938 { 00939 if(myLevel == DATA_RSTARNODE ) 00940 return; 00941 int ii; 00942 CubitBox temp_box; 00943 CubitBoolean is_first = CUBIT_TRUE; 00944 for ( ii = 0; ii < nextChildIndex; ii++ ) 00945 { 00946 if ( is_first ) 00947 { 00948 is_first = CUBIT_FALSE; 00949 temp_box = myChildrenNodes[ii]->bounding_box(); 00950 } 00951 else 00952 temp_box |= myChildrenNodes[ii]->bounding_box(); 00953 } 00954 delete myBoundingBox; 00955 myBoundingBox = new CubitBox(temp_box); 00956 return; 00957 } 00958 //------------------------------------------------------------- 00959 // Algorithm: remove. Remove index record e from an R-tree. 00960 // D1) [Find node containing record]. Invoke find_leaf to locate 00961 // the leaf node l containing e. Stop if the record was not 00962 // found. 00963 // D2) [Delete record.] Remove e from l. 00964 // D3) [Propagate changes.] Invoke CondenseTree, passing L. 00965 // D4) [Shorten tree.] If the root node has only one child 00966 // after the tree has been adjusted, make the child the new 00967 // root. 00968 //------------------------------------------------------------- 00969 template <class Y> MY_INLINE CubitBoolean RStarTreeNode<Y>::remove( Y e, 00970 RStarTreeNode<Y> *&new_root, 00971 CubitBoolean &delete_root) 00972 { 00973 //D1) Find node containting record. 00974 RStarTreeNode<Y> *l = NULL; 00975 CubitBox my_box = e->bounding_box(); 00976 CubitStatus stat = find_leaf(e, my_box, this, l); 00977 if ( l == NULL || stat != CUBIT_SUCCESS ) 00978 return CUBIT_FALSE; 00979 //Now l is the RStarTreeNode that holds the actual data (a DATA_RSTARNODE) 00980 //not a leaf. This was done for efficiency. 00981 RStarTreeNode<Y> *data_node = l; 00982 l = data_node->get_parent(); 00983 //D2) [Delete record] Remove e from l. 00984 00985 //remove the data node from the children and delete 00986 //the node. 00987 l->remove_child(data_node); 00988 delete data_node; 00989 00990 //D3) [Propogate Changes]. 00991 stat = condense_tree(l, this, new_root); 00992 //D4) [Shorten the tree]. 00993 RStarTreeNode<Y> *root = this; 00994 if ( new_root != NULL ) 00995 root = new_root; 00996 if ( root->num_children() == 1 ) 00997 { 00998 new_root = root->get_child(0); 00999 new_root->set_parent((RStarTreeNode<Y>*)NULL); 01000 delete_root = CUBIT_TRUE; 01001 } 01002 return CUBIT_TRUE; 01003 } 01004 template <class Y> MY_INLINE CubitStatus RStarTreeNode<Y>::find_leaf( Y e, 01005 CubitBox &e_box, 01006 RStarTreeNode<Y> *t, 01007 RStarTreeNode<Y> *&l ) 01008 { 01009 int ii; 01010 CubitStatus stat; 01011 l = NULL; 01012 int loop_size = t->num_children(); 01013 RStarTreeNode<Y> *curr_node; 01014 if ( t->get_leaf_level() > LEAF_RSTARNODE ) 01015 { 01016 for ( ii = 0; ii < loop_size; ii++ ) 01017 { 01018 curr_node = t->get_child(ii); 01019 if ( curr_node == NULL ) 01020 { 01021 PRINT_ERROR("Problems finding boxes in range.\n"); 01022 assert(curr_node != NULL); 01023 return CUBIT_FAILURE; 01024 } 01025 if ( e_box.overlap(GEOMETRY_RESABS, curr_node->bounding_box()) ) 01026 { 01027 //okay now search through this now. 01028 stat = find_leaf(e, e_box,curr_node,l); 01029 if ( l != NULL ) 01030 return CUBIT_SUCCESS; 01031 } 01032 } 01033 } 01034 else if ( t->is_leaf() ) 01035 { 01036 //search through the children for e. 01037 for ( ii = 0; ii < loop_size; ii++ ) 01038 { 01039 curr_node = t->get_child(ii); 01040 if ( curr_node == NULL ) 01041 { 01042 PRINT_ERROR("Problems finding boxes in range.\n"); 01043 assert(curr_node != NULL); 01044 return CUBIT_FAILURE; 01045 } 01046 if ( curr_node->get_data() == e ) 01047 { 01048 l = curr_node; 01049 return CUBIT_SUCCESS; 01050 } 01051 } 01052 } 01053 return CUBIT_SUCCESS; 01054 } 01055 template <class Y> MY_INLINE CubitBoolean RStarTreeNode<Y>::remove_child( RStarTreeNode<Y> *child ) 01056 { 01057 //first find which item this child is at. 01058 int ii; 01059 int index_child = -1; 01060 int loop_size = this->num_children(); 01061 for ( ii = 0; ii < loop_size; ii++ ) 01062 { 01063 if ( myChildrenNodes[ii] == child ) 01064 index_child = ii; 01065 } 01066 if ( index_child == -1 ) 01067 return CUBIT_FALSE; 01068 //Now we need to bubble the array from this point 01069 //upward. 01070 for ( ii = index_child; ii < loop_size-1; ii++ ) 01071 { 01072 myChildrenNodes[ii] = myChildrenNodes[ii+1]; 01073 } 01074 //decrement the position of the next available child. 01075 nextChildIndex--; 01076 //now go from nextChildIndex to the end and make sure it is 01077 //null. 01078 for (ii = nextChildIndex; ii < maxChildren; ii++ ) 01079 myChildrenNodes[ii] = NULL; 01080 01081 return CUBIT_TRUE; 01082 } 01083 //-------------------------------------------------------------------------- 01084 // Algorithm: condense_tree 01085 // Given a leaf node l from which an entry has been deleted, eliminate 01086 // the node if it has too few entries and relocate its entries. Propagate 01087 // node elimination upaward as necessary. Adjust all covering rectangles 01088 // on the path to the root, making them smaller if possible. 01089 // CT1) [Initialize] Set n=l, Set q, the set of eliminated nodes, to be 01090 // empty. 01091 // CT2) [Find parent entry] If n is the root, go to CT6. Otherwise 01092 // let p be the parent of n, and let en be n's entry in p. 01093 // CT3) [Eliminate under-full node.] If n has fewer than minChildren, 01094 // delete en from p and add n to set q. 01095 // CT4) [Adjust covering rectangle] If n has not been eliminated, adjust 01096 // en's bounding box to tightly contain all entries in n. 01097 // CT5) [Move up one level in tree] Set n=p, and repeat from CT2. 01098 // CT6) [Reinsert orphaned entries]. Reinsert all entries of nodes in set q. 01099 // entries from eliminated leaf nodes are re-inserted in tree leaves 01100 // as described in algorithm insert, but entries from higher-level 01101 // nodes must be placed higher in the tree so that leaves of their 01102 // dependent subtrees will be on the same level as leaves of the 01103 // main tree. 01104 //-------------------------------------------------------------------------- 01105 template <class Y> MY_INLINE CubitStatus RStarTreeNode<Y>::condense_tree(RStarTreeNode<Y> *l, 01106 RStarTreeNode<Y> *root, 01107 RStarTreeNode<Y> *&new_root ) 01108 { 01109 int ii; 01110 new_root = NULL; 01111 //CT1) 01112 RStarTreeNode<Y> *n = l, *p; 01113 DLIList <RStarTreeNode<Y>*> set_q; 01114 //CT2) 01115 while ( n != root ) 01116 { 01117 p = n->get_parent(); 01118 if ( n->num_children() < minChildren ) 01119 { 01120 //CT3 01121 //take these children and add them to set_q. 01122 for ( ii = 0;ii < n->num_children(); ii++ ) 01123 set_q.append(n->get_child(ii)); 01124 //remove n from p. 01125 p->remove_child(n); 01126 //delete n. 01127 delete n; 01128 //now continue on. 01129 } 01130 else 01131 { 01132 //CT4 01133 n->recalc_b_box(); 01134 } 01135 //CT5 01136 n = p; 01137 } 01138 //now reinsert all nodes in set_q. 01139 RStarTreeNode<Y> *curr_node, *temp_root; 01140 temp_root = root; 01141 for (ii = set_q.size(); ii > 0; ii-- ) 01142 { 01143 curr_node = set_q.get_and_step(); 01144 temp_root->insert(curr_node, new_root); 01145 if ( new_root != NULL ) 01146 temp_root = new_root; 01147 } 01148 if ( temp_root != root ) 01149 new_root = temp_root; 01150 return CUBIT_SUCCESS; 01151 } 01152 01153 01154 01155