/Users/craigcornelius/Projects/SPRING Mac Release 0.2/boundingsphere.cpp

Go to the documentation of this file.
00001 // $Id: boundingsphere.cpp,v 1.30 2006/05/24 16:52:40 sean Exp $
00002 #include "boundingsphere.h"
00003 #include "object.h"
00004 
00005 #ifdef _WIN32
00006 #include <glut.h>
00007 #else
00008 #include <GLUT/glut.h>
00009 #include <OpenGL/gl.h>
00010 #endif
00011 
00012 //#include <queue.h>
00013 
00014 const char* BoundingSphere::rcsid = "@(#) $Id: boundingsphere.cpp,v 1.30 2006/05/24 16:52:40 sean Exp $ $Copyright: (c)2001 National Biocomputation Center, Stanford University $";
00015 
00016 // OLDUPDATE uses a leaf set instead of a priority queue (PQ is 10-20% faster)
00017 #define OLDUPDATE 
00018 #ifdef OLDUPDATE
00019 BSLset BoundingSphereLeaf::sphereLeafSet;
00020 #else
00021 BSqueue BoundingSphere::spherePQ;
00022 #endif
00023 int bncount = 0;
00024 
00025 int BoundingSphere::debug = 0;
00026 int BoundingSphere::return_first_collision_only = 0;
00027 
00029 // Helper functions
00031 
00032 bool scompare::operator() (const BoundingSphere* s1, 
00033                            const BoundingSphere* s2) const
00034 { return (s1->level < s2->level); }
00035 
00036 void swapptr(void **a, void **b)
00037 {
00038     void* temp = *a;
00039     *a = *b;
00040     *b = temp;
00041 }
00042 
00043 
00045 //  BoundingSphere functions
00047 
00048 // constructor for BoundingSphere superclass
00049 BoundingSphere::BoundingSphere(BoundingSphere *parent_)
00050 {
00051     parent = parent_;
00052     
00053     if (parent) level = parent->level + 1;
00054     else level = 0;     // root
00055     
00056     // center and radius set in subclasses
00057     
00058     inQueue = false;
00059     enabled = 1;
00060 }
00061 
00062 // destructor for BoundingSphere superclass
00063 BoundingSphere::~BoundingSphere()
00064 {
00065 
00066     parent = NULL;
00067     center = Point3D(-1, -1, -1);
00068     radius = -1;
00069     level = -1;
00070     inQueue = false;
00071 }
00072 
00073 // threshold prevents the old sphere from being excessively big
00074 // radius must be bigger than newRadius for threshold to matter
00075 // threshold should be >= 1.
00076 bool BoundingSphere::remainsValid(Point3D newCenter, double newRadius, 
00077                                   double threshold)
00078 {
00079     if ((center.Dist(newCenter) + newRadius) > radius)
00080         return false;
00081     
00082     double ratio = radius/newRadius;
00083     
00084     if (ratio > threshold)
00085         return false;
00086     
00087     return true;
00088 }
00089 
00090 // this returns the Node* covered by given bounding sphere tree which is
00091 // closest to pt (and not more than thresh away from pt)
00092 Node* BoundingSphere::findClosestNode(BoundingSphere *s, Point3D pt, 
00093                                       double *thresh)
00094 {
00095     if (!s->isLeaf())
00096         return(((BoundingSphereNode *)s)->findClosestNode(pt, thresh));
00097     else
00098         return(((BoundingSphereLeaf *)s)->findClosestNode(pt, thresh));
00099 }
00100 
00101 Node* BoundingSphereNode::findClosestNode(Point3D pt, double *thresh)
00102 {
00103     // is pt close enough to this sphere
00104     double squaredSep = center.SquaredDist(pt);
00105     if (squaredSep >= (radius + *thresh)*(radius + *thresh))
00106         return(NULL);
00107     
00108     // call for left child
00109     Node *nl = BoundingSphere::findClosestNode(left, pt, thresh);
00110     
00111     // call for right child if it exists
00112     if (right) {
00113         Node *nr = BoundingSphere::findClosestNode(right, pt, thresh);
00114         if (nr)
00115             return(nr);
00116     }
00117     return(nl);
00118 }
00119 
00120 Node* BoundingSphereLeaf::findClosestNode(Point3D pt, double *thresh)
00121 {
00122     Node *ret_node = NULL;
00123     
00124     // is pt close enough to this sphere
00125     double squaredSep = center.SquaredDist(pt);
00126     if (squaredSep >= (radius + *thresh)*(radius + *thresh))
00127         return(ret_node);
00128     
00129     // are any of the Nodes associated with the primitive close enough to pt?
00130     // if so, modify the return node and the current threshold
00131     double squaredThresh = (*thresh)*(*thresh);
00132     switch (feature_type) {
00133         case tetra_ptr:
00134         squaredSep = pt.SquaredDist(getTetra()->getNodeLink(0)->p);
00135         if (squaredSep < squaredThresh) {
00136             ret_node = getTetra()->getNodeLink(0);
00137             *thresh = sqrt(squaredSep);
00138             squaredThresh = squaredSep;
00139         }
00140         squaredSep = pt.SquaredDist(getTetra()->getNodeLink(1)->p);
00141         if (squaredSep < squaredThresh) {
00142             ret_node = getTetra()->getNodeLink(1);
00143             *thresh = sqrt(squaredSep);
00144             squaredThresh = squaredSep;
00145         }
00146         squaredSep = pt.SquaredDist(getTetra()->getNodeLink(2)->p);
00147         if (squaredSep < squaredThresh) {
00148             ret_node = getTetra()->getNodeLink(2);
00149             *thresh = sqrt(squaredSep);
00150             squaredThresh = squaredSep;
00151         }
00152         squaredSep = pt.SquaredDist(getTetra()->getNodeLink(3)->p);
00153         if (squaredSep < squaredThresh) {
00154             ret_node = getTetra()->getNodeLink(2);
00155             *thresh = sqrt(squaredSep);
00156             squaredThresh = squaredSep;
00157         }
00158         break;
00159         
00160         case face_ptr:
00161         squaredSep = pt.SquaredDist(getFace()->getNodeLink(0)->p);
00162         if (squaredSep < squaredThresh) {
00163             ret_node = getFace()->getNodeLink(0);
00164             *thresh = sqrt(squaredSep);
00165             squaredThresh = squaredSep;
00166         }
00167         squaredSep = pt.SquaredDist(getFace()->getNodeLink(1)->p);
00168         if (squaredSep < squaredThresh) {
00169             ret_node = getFace()->getNodeLink(1);
00170             *thresh = sqrt(squaredSep);
00171             squaredThresh = squaredSep;
00172         }
00173         squaredSep = pt.SquaredDist(getFace()->getNodeLink(2)->p);
00174         if (squaredSep < squaredThresh) {
00175             ret_node = getFace()->getNodeLink(2);
00176             *thresh = sqrt(squaredSep);
00177             squaredThresh = squaredSep;
00178         }
00179         break;
00180     case edge_ptr:
00181         squaredSep = pt.SquaredDist(getEdge()->getNodeLink(0)->p);
00182         if (squaredSep < squaredThresh) {
00183             ret_node = getEdge()->getNodeLink(0);
00184             *thresh = sqrt(squaredSep);
00185             squaredThresh = squaredSep;
00186         }
00187         squaredSep = pt.SquaredDist(getEdge()->getNodeLink(1)->p);
00188         if (squaredSep < squaredThresh) {
00189             ret_node = getEdge()->getNodeLink(1);
00190             *thresh = sqrt(squaredSep);
00191             squaredThresh = squaredSep;
00192         }
00193         break;
00194     case node_ptr:
00195         squaredSep = pt.SquaredDist(getNode()->p);
00196         if (squaredSep < squaredThresh) {
00197             ret_node = getNode();
00198             *thresh = sqrt(squaredSep);
00199             squaredThresh = squaredSep;
00200         }
00201         break;
00202     }
00203     
00204     // now return the closest node (if any are closer than current thresh)
00205     //  pertaining to this feature
00206     return(ret_node);
00207 }
00208 
00209 int BoundingSphere::hasAncestor(BoundingSphere* b)
00210 {
00211     BoundingSphere* ptr = this;
00212     
00213     while (ptr != NULL) {
00214         if (ptr == b) return(1);        // found it!
00215         ptr = ptr->getParent();
00216     }
00217     
00218     // didn't find it
00219     return(0);
00220 }
00221 
00222 int BoundingSphere::getDepth()
00223 {
00224     BoundingSphere* parent = getParent();
00225     
00226     if (parent == NULL) return(1);
00227     else return ( 1+ parent->getDepth() );
00228 }
00229 
00230 BoundingSphereNode* BoundingSphere::findCommonAncestor(BoundingSphere* b[], 
00231                                                        int num)
00232 {
00233     if (num <= 0) return(NULL);
00234     
00235     // start off with the 0th guy's parent
00236     BoundingSphere* cur = b[0]->getParent();
00237     
00238     // loop over all the other ones
00239     for (int i=0; i<num; i++) {
00240         // if b[i] doesn't have cur as an ancestor, move cur up until it is
00241         while (!b[i]->hasAncestor(cur) && (cur != NULL)) {
00242             cur = cur->getParent();
00243         }
00244     }
00245     
00246     return((BoundingSphereNode*)cur);
00247 }
00248 
00249 // sets value of enabled variable for subtree under us
00250 void BoundingSphere::markTreeEnabled(int enabled_)
00251 {
00252     // set ours
00253     enabled = enabled_;
00254     
00255     // and recurse with children if we have any
00256     if (!isLeaf()) {
00257         BoundingSphereNode* me = (BoundingSphereNode*)this;
00258         BoundingSphere* my_left = me->getLeft();
00259         BoundingSphere* my_right = me->getRight();
00260         if (my_left) my_left->markTreeEnabled(enabled_);
00261         if (my_right) my_right->markTreeEnabled(enabled_);
00262     }
00263 }
00264 
00265 // propagates enabled value up tree from here to root
00266 void BoundingSphere::propEnabled(int enabled_)
00267 {
00268     // set ours
00269     enabled = enabled_;
00270     
00271     // and propagate up tree
00272     BoundingSphere* ptr = getParent();
00273     while (ptr) {
00274         ptr->enabled = enabled_;
00275         ptr = ptr->getParent();
00276     }
00277 }
00278 
00279 int BoundingSphere::numLeafs()
00280 {
00281     // trivial case
00282     if (isLeaf()) 
00283         return(1);
00284     
00285     // otherwise, I'm a BSN
00286     BoundingSphereNode* me = (BoundingSphereNode*)this;
00287     
00288     // get my left and right children
00289     BoundingSphere* left = me->getLeft();
00290     BoundingSphere* right = me->getRight();
00291     
00292     // recurse 
00293     int num = 0;
00294     if (left) num += left->numLeafs();
00295     if (right) num += right->numLeafs();
00296     
00297     // and return
00298     return(num);
00299 }
00300 
00301 int BoundingSphere::numEnabledLeafs()
00302 {
00303     // trivial case
00304     if (isLeaf()) 
00305         return( enabled );
00306     
00307     // otherwise, I'm a BSN
00308     BoundingSphereNode* me = (BoundingSphereNode*)this;
00309     
00310     // get my left and right children
00311     BoundingSphere* left = me->getLeft();
00312     BoundingSphere* right = me->getRight();
00313     
00314     // recurse 
00315     int num = 0;
00316     if (left) num += left->numEnabledLeafs();
00317     if (right) num += right->numEnabledLeafs();
00318     
00319     // and return
00320     return(num);
00321 }
00322 
00323 int BoundingSphere::dist(BoundingSphere *sa, BoundingSphere *sb, double error, 
00324                          double init)
00325 {
00326     if (debug==2) 
00327         cerr << " BoundingSphere::dist(" << sa << ", " << sb
00328         << ", " << error << ", " << init << ")\n";
00329     
00330     // sanity check
00331     if (!sa || !sb) return(0);
00332     
00333     // performance optimization
00334     if (!sa->enabled) return(0);
00335     if (!sb->enabled) return(0);
00336     
00337     if (!sa->isLeaf()) {
00338         if (debug==3) cerr << "sa is not a leaf" << endl;
00339         return (BoundingSphereNode::dist((BoundingSphereNode *)sa, sb, error, 
00340             init));
00341     }
00342     if (debug==3) cerr << "sa is a leaf" << endl;
00343     
00344     if (!sb->isLeaf()) {
00345         if (debug==3) cerr << "sb is not a leaf" << endl;
00346         return (BoundingSphereNode::dist((BoundingSphereNode *)sb, sa, error, 
00347             init));
00348     }
00349     if (debug==3) cerr << "sb is a leaf" << endl;
00350     
00351     return (BoundingSphereLeaf::dist((BoundingSphereLeaf *)sa, 
00352         (BoundingSphereLeaf *)sb, error, init));
00353 }
00354 
00355 // will I need a couple of these with different arguments depending 
00356 // on the node type being traversed??
00357 int BoundingSphere::addLeaf(BoundingSphereLeaf *sa, BoundingSphere *sb)
00358 {
00359     if (debug==2) cerr << "BoundingSphere::addLeaf " << endl;
00360     
00361     if (!sa->isLeaf()) {
00362         if (debug==3) cerr << "sa is not a leaf" << endl;
00363         return (0);
00364     }
00365     
00366     if (!sb->isLeaf()) {
00367         
00368         int split = 0;
00369         
00370         const Point3D &acenter = sa->getCenter();
00371         
00372         double sacenter[3];
00373         sacenter[0] = acenter.x;
00374         sacenter[1] = acenter.y;
00375         sacenter[2] = acenter.z;
00376         
00377         const Point3D &bcenter = ((BoundingSphereNode*)sb)->getCenter();
00378         
00379         double sbcenter[3];
00380         sbcenter[0] = bcenter.x;
00381         sbcenter[1] = bcenter.y;
00382         sbcenter[2] = bcenter.z;
00383         
00384         if ((sbcenter[1] - sacenter[1]) > (sbcenter[split] - sacenter[split]))
00385             split = 1;
00386         if ((sbcenter[2] - sacenter[2]) > (sbcenter[split] - sacenter[split]))
00387             split = 2;
00388         
00389         if (sacenter[split] < sbcenter[split]) {
00390             return(BoundingSphere::addLeaf(sa, ((BoundingSphereNode*)sb)->getLeft() ));
00391         } 
00392         else {
00393             return(BoundingSphere::addLeaf(sa, ((BoundingSphereNode*)sb)->getRight() ));
00394         }
00395     }   
00396     
00397     
00398     // if you get here then that means sb is a leaf
00399     // the node above the leaf may have 1 or 2 children
00400     BoundingSphereNode* sc = ((BoundingSphereNode*)sb->parent); 
00401     
00402     // can sa and sb also be split on some axis to know
00403     // which side to add it to??
00404     
00405     if ( sc->getLeft() == sb ) { 
00406         BoundingSphereNode* mid = new BoundingSphereNode(sb,sa,sc);
00407         sc->setLeft(mid);
00408                 mid->setParent(sc);
00409     }
00410     else {
00411         BoundingSphereNode* mid = new BoundingSphereNode(sa,sb,sc);
00412         sc->setRight(mid);
00413                 mid->setParent(sc);
00414     }
00415     
00416     return (1);
00417 }
00418 
00419 
00420 int BoundingSphere::removeLeaf(BoundingSphereLeaf *sa)
00421 {
00422     if (debug==1) cerr << "BoundingSphere::removeLeaf " << endl;
00423     
00424     if (!sa->isLeaf()) {
00425         if (debug==1) cerr << "sa is not a leaf" << endl;
00426         return (0);
00427     }
00428     
00429     BoundingSphereLeaf *buddy = NULL; 
00430     BoundingSphereNode *oneUp = NULL;
00431         oneUp = (BoundingSphereNode*)sa->parent;
00432     
00433     if (oneUp) {
00434                 if (sa == oneUp->getLeft()){
00435                         buddy = (BoundingSphereLeaf*)((BoundingSphereNode*)oneUp)->getRight();
00436                         oneUp->setRight(NULL); // this is so at the sa destructor, we dont remove buddy
00437                 }
00438                 else {
00439                         buddy = (BoundingSphereLeaf*)((BoundingSphereNode*)oneUp)->getLeft();
00440                         oneUp->setLeft(NULL); 
00441                 }
00442     
00443     
00444                 BoundingSphereNode *twoUp = NULL;
00445                 twoUp = (BoundingSphereNode*)oneUp->parent;
00446     
00447                 if (twoUp) {
00448                         if (oneUp == twoUp->getLeft()){
00449                                 twoUp->setLeft(buddy);
00450                                 buddy->setParent(twoUp);
00451                         }
00452                         else{
00453                                 twoUp->setRight(buddy);
00454                                 buddy->setParent(twoUp);
00455                         }                       
00456                         delete ((BoundingSphereNode *)oneUp); // atthis destructor, buddy remains intact, but sa is deleted
00457                 }
00458                 else {
00459                         if(buddy == NULL){
00460                                 delete ((BoundingSphereNode *)oneUp);           
00461                                 return (1);
00462                         } else {
00463                                 sa->getFeatureObject()->setBoundingSphereRoot((BoundingSphereNode *)buddy); // make buddy the root of the tree
00464                                 buddy->setParent(NULL);
00465                                 delete ((BoundingSphereNode *)oneUp);
00466                                 return (1);
00467                         }
00468                 }
00469 
00470     }
00471         else {
00472                 // this leaf is the root, just remove the whole tree
00473                 sa->getFeatureObject()->setBoundingSphereRoot(NULL);
00474                 delete ((BoundingSphereLeaf *)sa);
00475         }
00476     
00477     return (1);
00478     
00479 }
00480 
00481 
00483 //  BoundingSphereNode functions
00485 
00486 
00487 void BoundingSphereNode::drawSubtree()
00488 {
00489     // recurse
00490     if (left)
00491         if (left->isLeaf())
00492             ((BoundingSphereLeaf *)left)->draw();
00493         else
00494             ((BoundingSphereNode *)left)->drawSubtree();
00495         if (right)
00496             if (right->isLeaf())
00497                 ((BoundingSphereLeaf *)right)->draw();
00498             else
00499                 ((BoundingSphereNode *)right)->drawSubtree();
00500             
00501             // and draw myself
00502             glColor4f((level+1)%2, ((level+1)%3)/2.0, ((level+1)%5)/4.0, 0.2);
00503             glTranslated(center.x, center.y, center.z);
00504             glutSolidSphere(radius, 8, 8);
00505             glTranslated(-center.x, -center.y, -center.z);
00506 }
00507 
00508 // no recursion
00509 BoundingSphereNode::BoundingSphereNode(BoundingSphere *left_, 
00510                                        BoundingSphere *right_, BoundingSphere *parent_)
00511                                        : BoundingSphere(parent_)
00512 {
00513     // BoundingSphere superclass sets its own values
00514     
00515     left = left_;
00516     right = right_;
00517     
00518     if (left) {
00519         left->parent = this;
00520         left->level = level + 1;
00521     }
00522     if (right) {
00523         right->parent = this;
00524         right->level = level + 1;
00525     }
00526     
00527     bncount++;
00528     if (debug==3) 
00529         cerr << "making node " << this << " with " << left << " and " 
00530         << right << endl;
00531     
00532     procChange();
00533 }
00534 
00535 // creates root node and recurses on sphereList to build tree
00536 BoundingSphereNode::BoundingSphereNode(BSlist &sphereList, 
00537                                        BoundingSphere *parent_)
00538                                        : BoundingSphere(parent_)
00539 {
00540     bncount++;
00541     if (debug==3) {
00542         cerr << "making node " << this << " with " << sphereList.NumElements() 
00543             << " children to be sorted" << endl;
00544     }
00545     
00546     // find max/min etc. 
00547     BSlist leftList, rightList;    
00548     
00549     double min[3] = { LARGE,  LARGE,  LARGE};
00550     double max[3] = {-LARGE, -LARGE, -LARGE};
00551     
00552     double mid;
00553     
00554     int split = 0;
00555     
00556     {   // compute center and min/max values for the spheres
00557         for (int sphereIter=0; sphereIter<sphereList.NumElements(); sphereIter++) {
00558             
00559             BoundingSphere *cur = sphereList[sphereIter];    
00560             const Point3D &center = cur->getCenter();
00561             
00562             double ncenter[3];
00563             ncenter[0] = center.x;
00564             ncenter[1] = center.y;
00565             ncenter[2] = center.z;
00566             
00567             for (int i = 0; i < 3; i++) {
00568                 if (ncenter[i] < min[i])
00569                     min[i] = ncenter[i];
00570                 if (ncenter[i] > max[i])
00571                     max[i] = ncenter[i];
00572             }
00573         }
00574     }
00575     
00576     if ((max[1] - min[1]) > (max[split] - min[split]))
00577         split = 1;    
00578     if ((max[2] - min[2]) > (max[split] - min[split]))
00579         split = 2;
00580     
00581     mid = (min[split] + max[split]) / 2;
00582     
00583     
00584     // use this info to split the data 
00585     for (int sphereIter=0; sphereIter < sphereList.NumElements(); sphereIter++) {
00586         BoundingSphere *cur = sphereList[sphereIter];
00587         const Point3D &center = cur->getCenter();
00588         
00589         double ncenter[3];
00590         ncenter[0] = center.x;
00591         ncenter[1] = center.y;
00592         ncenter[2] = center.z;
00593         
00594         if (ncenter[split] < mid) {
00595             leftList.Append(cur);
00596         } else {
00597             rightList.Append(cur);
00598         }
00599     }
00600     
00601     // if left list ended up empty, copy at least one element over (first one)
00602     if ( leftList.NumElements() == 0 && rightList.NumElements() ) {
00603         // copy over 1 item from leftlist to rightlist
00604         leftList.Append(rightList[0]);
00605         rightList.DeleteElement(rightList[0]);
00606     }
00607     
00608     // now, if leftlist only has 1 element, take it out and we're done
00609     if (leftList.NumElements() == 1) {
00610         left = leftList[0];
00611         // sets the leaf node's parent
00612         left->parent = this;
00613         left->level = level + 1;
00614         if (debug==2) cerr << "left: " << left << " parent: " << this << endl;
00615     } 
00616     else        // more than 1 element, recurse
00617         left = new BoundingSphereNode(leftList, this);
00618     
00619     // now, if rightlist only has 1 element, take it out and we're done
00620     if (rightList.NumElements() == 1) {
00621         right = rightList[0];
00622         // sets the leaf node's parent
00623         right->parent = this;
00624         right->level = level + 1;
00625         if (debug==2) cerr << "right: " << right << " parent: " << this << endl;
00626     } 
00627     else        // more than 1 element, recurse
00628         if (rightList.NumElements()) right = new BoundingSphereNode(rightList, this);
00629         
00630         procChange();
00631 }
00632 
00633 // node destructor, recursively deletes its subtree
00634 BoundingSphereNode::~BoundingSphereNode()
00635 {
00636     if (left) {
00637         if (left->isLeaf())
00638             delete ((BoundingSphereLeaf *)left);
00639         else
00640             delete ((BoundingSphereNode *)left);
00641         }
00642         if (right) {
00643             if (right->isLeaf())
00644                 delete ((BoundingSphereLeaf *)right);
00645             else
00646                 delete ((BoundingSphereNode *)right);
00647         }
00648             
00649     if (debug && !parent)
00650        cout << "deleting sphere tree\n";
00651 
00652     left = NULL;
00653     right = NULL;
00654 }
00655 
00656 int BoundingSphereNode::dist(BoundingSphereNode *sa, BoundingSphere *sb, 
00657                              double error, double init)
00658 {
00659     if (debug==2) 
00660         cerr << " BoundingSphereNode::dist(" << sa << ", " << sb
00661         << ", " << error << ", " << init << ")\n";
00662     
00663     // sb is also not a leaf, and sa is smaller, swap so sa is bigger
00664     if (!sb->isLeaf() && (sa->getRadius() < sb->getRadius())) {
00665         swapptr((void **)&sa, (void **)&sb);
00666     }
00667     
00668     // get locals
00669     Point3D sa_center = sa->getCenter(); Point3D sb_center = sb->getCenter();
00670     double sa_radius = sa->getRadius(); double sb_radius = sb->getRadius();
00671     double squaredSep = sa_center.SquaredDist(sb_center);
00672     
00673     if (debug==3) {
00674         cerr << "tester " << sa << " center " << sa_center << endl;
00675         cerr << "tester " << sa << " radius " << sa_radius << endl;
00676         cerr << "testee " << sb << " center " << sb_center << endl;
00677         cerr << "testee " << sb << " radius " << sb_radius << endl;
00678         cerr << "squaredSep " << squaredSep << endl;
00679         cerr << "test " << (squaredSep - (sa_radius + sb_radius)) << endl;
00680     }
00681     
00682     double radius_sum = sa_radius + sb_radius;
00683     if (squaredSep > (radius_sum * radius_sum)) {
00684         if (debug==3) cerr << "earliest cut out " << endl;
00685         return 0; // they do not overlap
00686     }
00687     
00688     // do left child
00689     int ldist = BoundingSphere::dist(sa->left, sb, error, init);
00690     
00691     // if our option says to only return the first collision, 
00692     // and if we have one, return
00693     if (return_first_collision_only && ldist)
00694         return ldist;
00695     
00696     if (debug==3) cerr << "returning control to dist2 testing right" << endl;
00697     
00698     // do right child
00699     int rdist = 0;
00700     if (sa->right) {
00701         rdist = BoundingSphere::dist(sa->right, sb, error, init);
00702         
00703         // if our option says to only return the first collision, 
00704         // and if we have one now, return
00705         if (return_first_collision_only && rdist)
00706             return rdist;
00707     }
00708     
00709     // return values
00710     if (ldist || rdist) return 1;
00711     return 0;
00712 }
00713 
00714 bool BoundingSphereNode::procChange()
00715 {
00716     if (debug)
00717         cerr << level << " BSN::procChange " << this << endl;
00718     
00719     // get current info for left side
00720     Point3D lc = left->getCenter();
00721     double lr = left->getRadius();
00722     
00723     if (debug==3) {
00724         cerr << left << " left center " << lc << " radius " << lr << endl;
00725         if (left->isLeaf()) cerr << "leaf index " << 
00726             ((BoundingSphereLeaf *)left)->getFeatureIndex() 
00727             << endl;
00728     }
00729     
00730     // our new info
00731     double newRadius;
00732     Point3D newCenter;
00733     
00734     if (right) {
00735         Point3D rc = right->getCenter();
00736         double rr = right->getRadius();
00737         
00738         if (debug==3) {
00739             cerr << right << " right center " << rc << " radius " << rr << endl;
00740             if (right->isLeaf()) cerr << "leaf index " << 
00741                 ((BoundingSphereLeaf *)right)->getFeatureIndex()
00742                 << endl;
00743         }
00744         
00745         // get distance between lc and rc
00746         double dist = lc.Dist(rc);
00747         
00748         if (debug==3) {
00749             cerr << " dist " << dist << endl;
00750             cerr << " dist plus left " << dist + lr << endl;
00751             cerr << " dist plus right " << dist + rr << endl;
00752         }
00753         
00754         
00755         if ( rr > (dist + lr) ) {
00756             if (debug==1) cerr << " left inside right sphere" << endl;
00757             newRadius = rr;
00758             newCenter = rc;
00759         }
00760         else if ( lr > (dist + rr) ) {
00761             if (debug==1) cerr << " right inside left sphere" << endl;
00762             newRadius = lr;
00763             newCenter = lc;
00764         }
00765         else {
00766             if (debug==3) 
00767                 cerr << " i'm not in either, just going to add them " << endl;
00768             newRadius = (dist + lr + rr) / 2.0;
00769             
00770             if (dist != 0)
00771                 newCenter.interp(lc, rc, (newRadius - lr) / dist); 
00772             else { // they are circumspheres
00773                 if (lr > rr) { // take the larger one
00774                     newCenter = lc; 
00775                     // before steve just took the left, how did he 
00776                     //    know it was truly larger?
00777                     newRadius = lr;
00778                 }
00779                 else {
00780                     newCenter = rc;
00781                     newRadius = rr;
00782                 }
00783             }
00784         }
00785     }    // right
00786     else {
00787         if (debug==3) cerr << "no right " << endl;
00788         newCenter = lc;
00789         newRadius = lr;
00790     }
00791     
00792     // set our new values
00793     this->center = newCenter;
00794     this->radius = newRadius;
00795     if (debug==3) 
00796         cerr << this << " my center " << center << " radius " << radius << endl;
00797     
00798     // and get outta here
00799     return true;
00800 }
00801 
00802 
00804 //  BoundingSphereLeaf functions
00806 BoundingSphereLeaf::BoundingSphereLeaf(Tetra *tetra_, BoundingSphere *parent_)
00807 : BoundingSphere(parent_)
00808 {
00809   if (debug == 2) {
00810                 cout << "BoundingSphereLeaf" << endl;
00811                 cout << "parent: " << parent << endl;
00812         }
00813         
00814   feature_ptr.tetra = tetra_;
00815   feature_type = tetra_ptr;     
00816         if (debug==2) cout << "tetra: " << feature_ptr.tetra << endl;
00817 
00818   feature_ptr.tetra->setBoundingSphere(this);
00819 
00820   setRadiusAndCenterFromFeature();
00821 
00822   if (debug==3) {
00823     cout << "making leaf: " << this << endl;    
00824     cout << "tetra: " << getFeatureIndex() << endl;
00825     cout << "radius: " << radius << endl;
00826     cout << "center: " << center << endl;
00827   }
00828 
00829   inQueue = false;
00830 }
00831 
00832 BoundingSphereLeaf::BoundingSphereLeaf(Face *face_, BoundingSphere *parent_)
00833 : BoundingSphere(parent_)
00834 {
00835     if (debug==2) cerr << "BoundingSphereLeaf" << endl;
00836     
00837     feature_ptr.face = face_;
00838     feature_type = face_ptr;
00839     if (debug==2) cerr << "face: " << feature_ptr.face << endl;
00840     
00841     feature_ptr.face->setBoundingSphere(this);
00842     
00843     setRadiusAndCenterFromFeature();
00844     
00845     if (debug==3) {
00846         cerr << "making leaf: " << this << endl;    
00847         cerr << "face: " << getFeatureIndex() << endl;
00848         cerr << "radius: " << radius << endl;
00849         cerr << "center: " << center << endl;
00850             cerr << "feature:" << feature_ptr.face->getIndex() << endl;
00851     }
00852 }
00853 
00854 BoundingSphereLeaf::BoundingSphereLeaf(Edge *edge_, BoundingSphere *parent_)
00855 : BoundingSphere(parent_)
00856 {
00857     if (debug==2) cerr << "BoundingSphereLeaf" << endl;
00858     
00859     feature_ptr.edge = edge_;
00860     feature_type = edge_ptr;
00861     if (debug==2) cerr << "edge: " << feature_ptr.edge << endl;
00862     
00863     feature_ptr.edge->setBoundingSphere(this);
00864     
00865     setRadiusAndCenterFromFeature();
00866     
00867     if (debug==3) {
00868         cerr << "making leaf: " << this << endl;    
00869         cerr << "edge: " << getFeatureIndex() << endl;
00870         cerr << "radius: " << radius << endl;
00871         cerr << "center: " << center << endl;
00872     }
00873 }
00874 
00875 BoundingSphereLeaf::BoundingSphereLeaf(Node *node_, BoundingSphere *parent_)
00876 : BoundingSphere(parent_)
00877 {
00878     if (debug==2) cerr << "BoundingSphereLeaf" << endl;
00879     
00880     feature_ptr.node = node_;
00881     feature_type = node_ptr;
00882     if (debug==2) cerr << "node: " << feature_ptr.node << endl;
00883     
00884     feature_ptr.node->setBoundingSphere(this);
00885     
00886     setRadiusAndCenterFromFeature();
00887     
00888     if (debug==3) {
00889         cerr << "making leaf: " << this << endl;    
00890         cerr << "node: " << getFeatureIndex() << endl;
00891         cerr << "radius: " << radius << endl;
00892         cerr << "center: " << center << endl;
00893     }
00894 }
00895 
00896 // leaf destructor
00897 BoundingSphereLeaf::~BoundingSphereLeaf()
00898 {
00899     feature_type = face_ptr;
00900     feature_ptr.face = NULL;
00901         sphereLeafSet.DeleteAll();
00902 }
00903 
00904 void BoundingSphereLeaf::draw()
00905 {
00906     // draw a sphere around myself
00907     glColor4f(1.0, 1.0, 1.0, 0.2);
00908     glTranslated(center.x, center.y, center.z);
00909     glutSolidSphere(radius, 8, 8);
00910     glTranslated(-center.x, -center.y, -center.z);
00911 }
00912 
00913 int BoundingSphereLeaf::dist(BoundingSphereLeaf *sa, BoundingSphereLeaf *sb, 
00914                              double error, double init)
00915 {
00916     if (debug==2) 
00917         cerr << " BoundingSphereLeaf::dist(" << sa << ", " << sb
00918         << ", " << error << ", " << init << ")\n";
00919     
00920     // first check if these 2 leaf spheres have any overlap
00921     Point3D sbcent = sb->getCenter();
00922     double squared = sa->getCenter().SquaredDist(sbcent);
00923     double sarad = sa->getRadius(); double sbrad = sb->getRadius();
00924     if (squared > (sarad+sbrad)*(sarad+sbrad))
00925         return 0;
00926     
00927     // now see if the underlying features are colliding
00928     Point3D int_p;
00929     int ret_val = 1;  // assume there is a collision, if not make it 0
00930     double dist = 0.0;
00931     double param1 = 0.0, param2 = 0.0;
00932     Point3D nearpt;
00933     
00934     //
00935     // face-face potential collision
00936     //
00937     if (sa->feature_type == face_ptr && sb->feature_type == face_ptr) {
00938         
00939         // same object, and same spheres (ie same face) or adjacent faces
00940         if (sa->getFeatureObject() == sb->getFeatureObject() &&
00941             (sa == sb || sa->getFace()->isAdjacent(sb->getFace())))
00942             return(0);
00943         
00944         // if error value is >0, then assume we're trying to do fast but
00945         // less accurate tests, so just assume we have a collision if the
00946         // leaf-node bounding spheres (bsphere of faces) are intersecting
00947         if (error > 0.0)
00948             ret_val = 1;
00949         else  // do the test
00950             ret_val = sa->feature_ptr.face->intersectsFace(sb->feature_ptr.face, 
00951             &int_p);
00952         // if we failed, cut out early
00953         if (!ret_val) return(0);
00954     }  // end face-face
00955     
00956     //
00957     // edge-edge potential collision
00958     //
00959     else if (sa->feature_type == edge_ptr && sb->feature_type == edge_ptr) {
00960       int i1 = sa->getEdge()->getIndex();
00961       int i2 = sb->getEdge()->getIndex();
00962 #define SEPARATION 3  // don't want edges closer than this to cause collisions
00963       // same object, and nearly adjacent edges
00964       if (sa->getFeatureObject() == sb->getFeatureObject() &&
00965           i1 < i2+SEPARATION && i1 > i2-SEPARATION)
00966         return(0);
00967         
00968       // otherwise, do the test
00969       dist = sa->feature_ptr.edge->EdgeDistanceToEdge(sb->feature_ptr.edge,
00970                                                       &param1, &param2);
00971         
00972       // too far- cut out early (should use error value here someday)
00973       if (dist > 0.5*(sa->getFeatureObject()->getEdgeThresh() + 
00974                       sb->getFeatureObject()->getEdgeThresh()))
00975         return(0);//must return here!, not set ret_val
00976     }  // end edge-edge
00977     
00978     //
00979     // face-edge or edge-face potential collision
00980     //
00981     else if ((sa->feature_type == face_ptr && sb->feature_type == edge_ptr) ||
00982              (sa->feature_type == edge_ptr && sb->feature_type == face_ptr)) {
00983 
00984       // swap the (local) sa and sb pointers so that sa is edge, sb is face
00985       // ok b/c sa is local ptr, and &sa is its address, so contents of the
00986       //   spheres don't change, just their local names.
00987       if (sa->feature_type == face_ptr)
00988         swapptr((void **)&sa, (void **)&sb);
00989 
00990       dist = sa->feature_ptr.edge->EdgeDistanceToFaceNoIntersect
00991         (sb->feature_ptr.face, &param1, &nearpt);
00992 
00993       // too far -- cut out early
00994       if (dist > 0.5*(sa->getFeatureObject()->getEdgeThresh()))
00995         return(0);
00996 
00997       //testing:
00998       //cout << "Edge: " << sa->feature_ptr.edge->getIndex() << "  Face: " <<
00999       //sb->feature_ptr.face->getIndex() << "  Dist: " << dist << "  pt: " <<
01000       //nearpt << endl;
01001       // old way: finding edge/face intersection
01002       //ret_val = sa->feature_ptr.face->intersectsEdge(sb->feature_ptr.edge, 
01003       //                                               &int_p);
01004       //if (!ret_val) return(0);
01005     }  // end face-edge and edge-face
01006     
01007     // some other feature pair that's not handled yet, assume no collision
01008     else { 
01009         return(0);
01010     }
01011     
01012     // now we add the collisions to the appropriate objects
01013     Collision_pair pair;
01014     Object *myObj = sa->getFeatureObject();
01015     Object *otherObj = sb->getFeatureObject();
01016 
01017     // for collisions of edge objects
01018     if (sa->feature_type == edge_ptr && sb->feature_type == edge_ptr) {
01019       int append_flag = 1;
01020       if (myObj == otherObj) { // self-collision
01021         // here's some code to avoid adding the same collision twice, which
01022         //     is a problem for self-collisions
01023         // NB: i1 and i2 are already guaranteed to be non-= and non-adjacent
01024         //     based on SEPARATION above
01025         int i1 = sa->getEdge()->getIndex();
01026         int i2 = sb->getEdge()->getIndex();
01027         for (int k = 0; k < myObj->CollisionPairGetNumElements(); k++) {
01028           int j1 =
01029             myObj->CollisionPairGet(k).mySphere->getEdge()->getIndex();
01030           int j2 =
01031             myObj->CollisionPairGet(k).otherSphere->getEdge()->getIndex();
01032           if ((i1 == j1 && i2 == j2) || (i1 == j2 && i2 == j1))
01033             append_flag = 0;
01034         } // for each collision
01035       } // self-collision
01036       if (append_flag) {
01037         pair.mySphere = sa;
01038         pair.otherSphere = sb;
01039         pair.near1 = param1;
01040         pair.near2 = param2;
01041         pair.dist = dist;
01042         myObj->CollisionPairAdd(pair);
01043       }
01044       if (myObj != otherObj) { // add collisions for other edge object
01045         // switch spheres, switch params
01046         pair.mySphere = sb;
01047         pair.otherSphere = sa;
01048         pair.near1 = param2;
01049         pair.near2 = param1;
01050         pair.dist = dist;
01051         otherObj->CollisionPairAdd(pair);
01052       }
01053     }
01054     // for edge-face collisions
01055     else if (sa->feature_type == edge_ptr && sb->feature_type == face_ptr) {
01056       pair.mySphere = sa;
01057       pair.otherSphere = sb;
01058       pair.near1 = param1;
01059       pair.int_pt = nearpt;
01060       pair.dist = dist;
01061       myObj->CollisionPairAdd(pair);
01062       // switch spheres, add to other object
01063       pair.mySphere = sb;
01064       pair.otherSphere = sa;
01065       pair.near1 = param1;
01066       pair.int_pt = nearpt;
01067       pair.dist = dist;
01068       otherObj->CollisionPairAdd(pair);
01069     }
01070     // don't have face-edge collisions: pointers swapped to make edge-face
01071 
01072     // for other collisions (e.g. face-face)
01073     else {
01074       // save this collision_pair structure and add to this object
01075       pair.mySphere = sa;
01076       pair.otherSphere = sb;
01077       pair.int_pt = int_p;
01078       myObj->CollisionPairAdd(pair);
01079 
01080       // now swich MY and OTHER, and add it to other object
01081       pair.mySphere = sb;
01082       pair.otherSphere = sa;
01083       otherObj->CollisionPairAdd(pair);
01084     }
01085 
01086 
01087     // debugging
01088     if (debug == 2) {
01089         cout << "2:I'm colliding over here: [" 
01090             << myObj->getName() << "]-" << sa->getFeatureIndex() << " - [" 
01091             << otherObj->getName() << "]-" << sb->getFeatureIndex() << endl;
01092     }
01093     
01094     // return value indicating there was a collision
01095     return ret_val;
01096 }
01097 
01098 bool BoundingSphereLeaf::procChange()
01099 {
01100     if (debug)
01101         cerr << getFeatureObject()->getName() << " index:" << getFeatureIndex()
01102         << " level:" << level << " BSL::procChange" << endl;
01103     
01104     // got rid of processed variable, if we call this on a leaf, it's because 
01105     // the leaf is in the update list, so we always update and return true
01106     // the return value is only used in the old 'propChange' method
01107     setRadiusAndCenterFromFeature();
01108     
01109     if (debug==3) {
01110         cerr << "updating leaf: " << this << endl;    
01111         switch (feature_type) {
01112         case tetra_ptr:
01113             cerr << "tetra: " << getFeatureIndex() << endl;
01114             break;
01115         case face_ptr:
01116             cerr << "face: " << getFeatureIndex() << endl;
01117             break;
01118         case edge_ptr:
01119             cerr << "edge: " << getFeatureIndex() << endl;
01120             break;
01121         case node_ptr:
01122             cerr << "node: " << getFeatureIndex() << endl;
01123             break;
01124         }
01125         cerr << "radius: " << radius << endl;
01126         cerr << "center: " << center << endl;
01127     }
01128     return true;
01129 }
01130 
01131 void BoundingSphereLeaf::insertInUpdateList()
01132 {
01133     // performance optmization
01134     if (!enabled) return;
01135     
01136     // note the sphereLeafSet or spherePQ is static, just one exists, so we
01137     // do all our sphere updates for all objects at once
01138 #ifdef OLDUPDATE
01139     sphereLeafSet.AddElement(this);
01140 #else
01141     if (inQueue == false) {
01142         // avoid pushing a leaf sphere into the priority queue more than once
01143         spherePQ.push(this);
01144         inQueue = true;
01145     }
01146 #endif
01147 }
01148 
01149 void BoundingSphereLeaf::processUpdate()
01150 {
01151     if (debug==2) cerr << "BoundingSphereLeaf::processUpdate()" << endl;
01152     
01153 #ifdef OLDUPDATE    
01154     // old method: go through the leaf set, propagate each change upwards
01155     if (debug==3) cerr << " set size: " << sphereLeafSet.NumElements() << endl;
01156     
01157     for (int slsIter=0; slsIter<sphereLeafSet.NumElements(); slsIter++)
01158         (sphereLeafSet[slsIter])->propChange();
01159     
01160     sphereLeafSet.DeleteAll();
01161 #else
01162     // new method: go through the priority queue, starts out with just leaves,
01163     // then each adds its parent if the parent is not already in the queue
01164     while (!spherePQ.empty()) {
01165         // get and pop the highest priority sphere (eg closest to leaf)
01166         BoundingSphere *top = spherePQ.top();
01167         spherePQ.pop();
01168         // process it and mark it as no longer in batch
01169         top->procChange();
01170         top->inQueue = false;
01171         // and stick its parent in queue if not there already
01172         if (top->parent && !top->parent->inQueue) {
01173             spherePQ.push(top->parent);
01174             top->parent->inQueue = true;
01175             assert(top->parent->level < top->level);
01176         }
01177     }
01178 #endif
01179 }
01180 
01181 void BoundingSphereLeaf::setRadiusAndCenterFromFeature()
01182 {
01183     switch (feature_type) {
01184     case tetra_ptr:
01185         this->radius = feature_ptr.tetra->getRadius(); 
01186         this->center = feature_ptr.tetra->getCenter(); 
01187         break;
01188     case face_ptr:
01189         this->radius = feature_ptr.face->getRadius(); 
01190         this->center = feature_ptr.face->getCenter(); 
01191         break;
01192     case edge_ptr:
01193       // use MAX so that we find collisions as soon as inside threshold
01194         this->radius = MAX(getFeatureObject()->getEdgeThresh(),
01195                            feature_ptr.edge->getRadius()); 
01196         this->center = feature_ptr.edge->getCenter(); 
01197         break;
01198     case node_ptr:
01199         this->radius = feature_ptr.node->getRadius(); 
01200         this->center = feature_ptr.node->getCenter(); 
01201         break;
01202     }
01203 }
01204 
01205 Object* BoundingSphereLeaf::getFeatureObject()
01206 {
01207     Object *obj = NULL;
01208     switch (feature_type) {
01209      case tetra_ptr:
01210         obj = feature_ptr.tetra->getTetraArray()->getObject();
01211         break;
01212     case face_ptr:
01213         obj = feature_ptr.face->getFaceArray()->getObject();
01214         break;
01215     case edge_ptr:
01216         obj = feature_ptr.edge->getEdgeArray()->getObject();
01217         break;
01218     case node_ptr:
01219         obj = feature_ptr.node->getNodeArray()->getObject();
01220         break;
01221     }
01222     return (obj);
01223 }
01224 
01225 int BoundingSphereLeaf::getFeatureIndex()
01226 {
01227     int index = 0;
01228     switch (feature_type) {
01229      case tetra_ptr:
01230         index = feature_ptr.tetra->getIndex();
01231         break;
01232     case face_ptr:
01233         index = feature_ptr.face->getIndex();
01234         break;
01235     case edge_ptr:
01236         index = feature_ptr.edge->getIndex();
01237         break;
01238     case node_ptr:
01239         index = feature_ptr.node->getIndex();
01240         break;
01241     }
01242     return(index);
01243 }

Generated on Thu Aug 30 11:03:13 2007 for SPRING Mac by  doxygen 1.5.3