cgma
RStarTreeNode.cpp
Go to the documentation of this file.
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 &current, 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   
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines