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

Go to the documentation of this file.
00001 // $Id: boundingbox.cpp,v 1.9 2006/05/24 16:52:40 sean Exp $
00002 // $Copyright: (c)2001 National Biocomputation Center, Stanford University $
00003 
00004 #include <list.h>
00005 #include <GLUT/glut.h>
00006 
00007 #include "boundingbox.h"
00008 #include "facearray.h"
00009 #include "object.h"
00010 
00011 
00012 //*** BoundingBox ***
00013 
00014 // constructor for BoundingBox superclass
00015 BoundingBox::BoundingBox(BoundingBox *parent_)
00016 {
00017     parent = parent_;
00018 }
00019 
00020 // destructor for BoundingBox superclass
00021 BoundingBox::~BoundingBox()
00022 {
00023     parent = NULL;
00024         object = NULL;
00025     min = Point3D(0, 0, 0);
00026     max = Point3D(-1, -1, -1);
00027 }
00028 
00029 // Creates a tree from a given object
00030 BoundingBox* BoundingBox::createTree(Object* object) {
00031         int i;
00032 
00033         // Build list of faces
00034         List<BoundingBoxLeaf*> bbList;
00035         if (object->getCollisionFaces().NumElements() > 0) {
00036                 // build tree with only collision faces
00037                 for (i = 0; i < object->getCollisionFaces().NumElements(); i++) {
00038                         bbList.Append(new BoundingBoxLeaf(object->getCollisionFaces()[i]));
00039                 }
00040         }
00041         else {
00042                 // take all faces
00043                 FaceArray* faceArray = object->getFaceArray();
00044                 int numFaces = faceArray->getNumFaces();
00045                 for (i = 0; i < numFaces; i++) {
00046                         bbList.Append(new BoundingBoxLeaf(faceArray->getFace(i)));
00047                 }
00048         }
00049 
00050         // Return the tree
00051         return createTree(bbList);
00052 }
00053 
00054 // Creates a tree from a list of bounding box leafes
00055 BoundingBox* BoundingBox::createTree(List<BoundingBoxLeaf*> &bbList) {
00056         int i;
00057 
00058         if (bbList.NumElements() == 0) {
00059                 // no elements, return null!
00060                 return NULL;
00061         }
00062         else if (bbList.NumElements() == 1) {
00063                 // one element, return the single leaf itself!
00064                 return bbList[0];
00065         }
00066         else {
00067                 // Find min and max
00068                 const double LARGE = 1e10;
00069                 double min[3] = { LARGE, LARGE, LARGE };
00070                 double max[3] = { -LARGE, -LARGE, -LARGE };
00071 
00072                 for (i = 0; i < bbList.NumElements(); i++) {
00073                         BoundingBoxLeaf* leaf = bbList[i];
00074                         if (min[0] > leaf->min.x) {
00075                                 min[0] = leaf->min.x;
00076                         }
00077                         if (max[0] < leaf->max.x) {
00078                                 max[0] = leaf->max.x;
00079                         }
00080                         if (min[1] > leaf->min.y) {
00081                                 min[1] = leaf->min.y;
00082                         }
00083                         if (max[1] < leaf->max.y) {
00084                                 max[1] = leaf->max.y;
00085                         }
00086                         if (min[2] > leaf->min.z) {
00087                                 min[2] = leaf->min.z;
00088                         }
00089                         if (max[2] < leaf->max.z) {
00090                                 max[2] = leaf->max.z;
00091                         }
00092                 }
00093 
00094                 // Find axis (x, y -OR- z) where to split & middle
00095                 int splitAxis = 0;
00096                 if ((max[1] - min[1]) > (max[splitAxis] - min[splitAxis])) {
00097                         splitAxis = 1;
00098                 }
00099                 if ((max[2] - min[2]) > (max[splitAxis] - min[splitAxis])) {
00100                         splitAxis = 2;
00101                 }
00102                 double middle = (min[splitAxis] + max[splitAxis]) / 2;
00103 
00104                 // split into two lists
00105                 List<BoundingBoxLeaf*> bbListLeft;
00106                 List<BoundingBoxLeaf*> bbListRight;
00107                 for (i = 0; i < bbList.NumElements(); i++) {
00108                         BoundingBoxLeaf* leaf = bbList[i];
00109                         switch (splitAxis) {
00110                                 case 0:
00111                                         if (leaf->getFace()->getCenter().x < middle) {
00112                                                 bbListLeft.Append(leaf);
00113                                         }
00114                                         else {
00115                                                 bbListRight.Append(leaf);
00116                                         }
00117                                         break;
00118                                 case 1:
00119                                         if (leaf->getFace()->getCenter().y < middle) {
00120                                                 bbListLeft.Append(leaf);
00121                                         }
00122                                         else {
00123                                                 bbListRight.Append(leaf);
00124                                         }
00125                                         break;
00126                                 case 2:
00127                                         if (leaf->getFace()->getCenter().z < middle) {
00128                                                 bbListLeft.Append(leaf);
00129                                         }
00130                                         else {
00131                                                 bbListRight.Append(leaf);
00132                                         }
00133                                         break;
00134                         }
00135                 }
00136 
00137                 // if one list empty, move one element
00138                 if (bbListLeft.NumElements() == 0) {
00139                         bbListLeft.Append(bbListRight[0]);
00140                         bbListRight.DeleteElement(bbListRight[0]);
00141                 }
00142                 else if (bbListRight.NumElements() == 0) {
00143                         bbListRight.Append(bbListLeft[0]);
00144                         bbListLeft.DeleteElement(bbListLeft[0]);
00145                 }
00146 
00147                 // build tree
00148                 BoundingBox* bbTreeLeft = createTree(bbListLeft);
00149                 BoundingBox* bbTreeRight = createTree(bbListRight);
00150 
00151                 // return tree
00152                 BoundingBoxNode* bbTree = new BoundingBoxNode(bbTreeLeft, bbTreeRight);
00153                 return bbTree;
00154         }
00155 }
00156 
00157 // draw bounding box for min and max
00158 void BoundingBox::draw()
00159 {
00160     // and draw myself (2x glVertext3f = One Line)
00161         if (hasMarker()) {
00162                 // draw marker in purpule
00163                 glColor3f(1.0, 0.0, 1.0);
00164         }
00165         else {
00166                 // no marker -> gray translucent color
00167                 glColor4f(0.8f, 0.8f, 0.8f, 0.6f);
00168         }
00169 
00170         // draw lines
00171         glBegin(GL_LINES);
00172                  glVertex3f(min.x, min.y, min.z);   
00173                  glVertex3f(max.x, min.y, min.z);   
00174                  glVertex3f(min.x, min.y, min.z);   
00175                  glVertex3f(min.x, max.y, min.z);   
00176                  glVertex3f(min.x, min.y, min.z);   
00177                  glVertex3f(min.x, min.y, max.z);   
00178                  
00179                  glVertex3f(min.x, max.y, max.z);
00180                  glVertex3f(max.x, max.y, max.z);
00181                  glVertex3f(min.x, max.y, max.z);
00182                  glVertex3f(min.x, min.y, max.z);
00183                  glVertex3f(min.x, max.y, max.z);
00184                  glVertex3f(min.x, max.y, min.z);
00185 
00186                  glVertex3f(max.x, min.y, max.z);
00187                  glVertex3f(max.x, max.y, max.z);
00188                  glVertex3f(max.x, min.y, max.z);
00189                  glVertex3f(min.x, min.y, max.z);
00190                  glVertex3f(max.x, min.y, max.z);
00191                  glVertex3f(max.x, min.y, min.z);
00192 
00193                  glVertex3f(max.x, max.y, min.z);
00194                  glVertex3f(max.x, max.y, max.z);
00195                  glVertex3f(max.x, max.y, min.z);
00196                  glVertex3f(min.x, max.y, min.z);
00197                  glVertex3f(max.x, max.y, min.z);
00198                  glVertex3f(max.x, min.y, min.z);
00199         glEnd();
00200 }
00201 
00202 // Returns true if boxes overlap, false otherwise
00203 bool BoundingBox::overlap(BoundingBox* boundingBox) {
00204         Point3D otherMin = boundingBox->getMin();
00205         Point3D otherMax = boundingBox->getMax();
00206 
00207         if ((otherMin.x < max.x) && (otherMax.x > min.x) &&
00208                 (otherMin.y < max.y) && (otherMax.y > min.y) &&
00209                 (otherMin.z < max.z) && (otherMax.z > min.z)) {
00210                 // yipee! there's an overlap
00211                 return true;
00212         }
00213         else {
00214                 // nope, no overlap
00215                 return false;
00216         }
00217 }
00218 
00219 // Returns the center of the bounding box
00220 Point3D BoundingBox::center() {
00221         Point3D center;
00222         center.x = (min.x + max.x) / 2;
00223         center.y = (min.y + max.y) / 2;
00224         center.z = (min.z + max.z) / 2;
00225         return center;
00226 }
00227 
00228 //*** BoundingBoxNode ***
00229 
00230 // Constructor for node
00231 BoundingBoxNode::BoundingBoxNode(BoundingBox *left_, 
00232                                  BoundingBox *right_, 
00233                                                                  BoundingBox *parent_) : BoundingBox(parent_)
00234 {
00235     left = left_;
00236     right = right_;
00237         marker = false;
00238 
00239     if (left) {
00240         left->parent = this;
00241                 object = left->getObject();
00242     }
00243     if (right) {
00244         right->parent = this;
00245                 object = right->getObject();
00246     }
00247 
00248         // non-recursive update 
00249         internalUpdate();
00250 }
00251 
00252 // node destructor, recursively deletes its subtree
00253 BoundingBoxNode::~BoundingBoxNode()
00254 {
00255     if (left) {
00256                 delete left;
00257         }
00258         if (right) {
00259                 delete right;
00260         }
00261 
00262     left = NULL;
00263     right = NULL;
00264 }
00265 
00266 // draw all the boxes
00267 void BoundingBoxNode::draw()
00268 {
00269     // recurse
00270     if (left) {
00271         left->draw();
00272         }
00273     if (right) {
00274         right->draw();
00275         }
00276 
00277         // draw myself
00278         BoundingBox::draw();
00279 }
00280 
00281 // update bounding box positions
00282 void BoundingBoxNode::update() 
00283 {
00284         // update left and right min maxes first (recursive)
00285         left->update();
00286         right->update();
00287 
00288         // non-recursive self-update
00289         internalUpdate();
00290 }
00291 
00292 // internal update without recursion
00293 void BoundingBoxNode::internalUpdate() {
00294         // based on new left and right bounding box, calculate new
00295         Point3D minLeft = left->getMin();
00296         Point3D maxLeft = left->getMax();
00297         Point3D minRight = right->getMin();
00298         Point3D maxRight = right->getMax();
00299 
00300         min.x = (minLeft.x < minRight.x) ? minLeft.x : minRight.x;
00301         min.y = (minLeft.y < minRight.y) ? minLeft.y : minRight.y;
00302         min.z = (minLeft.z < minRight.z) ? minLeft.z : minRight.z;
00303         max.x = (maxLeft.x > maxRight.x) ? maxLeft.x : maxRight.x;
00304         max.y = (maxLeft.y > maxRight.y) ? maxLeft.y : maxRight.y;
00305         max.z = (maxLeft.z > maxRight.z) ? maxLeft.z : maxRight.z;
00306 
00307         // adjust normal vector
00308         normal = left->getNormal() + right->getNormal();
00309         normal.Normalize();
00310 }
00311 
00312 // detect collisions
00313 void BoundingBoxNode::detectCollisions(BoundingBox* boundingBox, int myLevel, int otherLevel,
00314                                                                            ReallocableArray<CollisionBoxPair>* collisionPairs)
00315 {
00316         if (overlap(boundingBox)) {
00317                 if (boundingBox->isLeaf()) {
00318                         if (myLevel > 0) {
00319                                 // recursively detect collisions
00320                                 myLevel--;
00321                                 left->detectCollisions(boundingBox, myLevel, otherLevel, collisionPairs);
00322                                 right->detectCollisions(boundingBox, myLevel, otherLevel, collisionPairs);
00323                         }
00324                         else {
00325                                 // just add current solution as collision pair (approximation)
00326                                 Face* otherFace = ((BoundingBoxLeaf*)boundingBox)->getFace();
00327                                 if (otherFace->intersectsBox(&min, &max)) {
00328                                         CollisionBoxPair collisionPair;
00329                                         collisionPair.myCollisionBox = this;
00330                                         collisionPair.otherCollisionBox = boundingBox;
00331                                         collisionPairs->Append(collisionPair);
00332                                 }
00333                         }
00334                 }
00335                 else {
00336                         if ((myLevel > 0) && (otherLevel > 0)) {
00337                                 if (getVolume() > boundingBox->getVolume()) {
00338                                         // recursively detect collisions
00339                                         otherLevel--;
00340                                         detectCollisions(((BoundingBoxNode*)boundingBox)->getLeft(), 
00341                                                              myLevel, otherLevel, collisionPairs);
00342                                         detectCollisions(((BoundingBoxNode*)boundingBox)->getRight(), 
00343                                                              myLevel, otherLevel, collisionPairs);
00344                                 }
00345                                 else {
00346                                         // recursively detect collisions
00347                                         myLevel--;
00348                                         left->detectCollisions(boundingBox, myLevel, otherLevel, collisionPairs);
00349                                         right->detectCollisions(boundingBox, myLevel, otherLevel, collisionPairs);
00350                                 }
00351                         }
00352                         else if ((myLevel <= 0) && (otherLevel <= 0)) {
00353                                 // just add current solution as collision pair (approximation)
00354                                 CollisionBoxPair collisionPair;
00355                                 collisionPair.myCollisionBox = this;
00356                                 collisionPair.otherCollisionBox = boundingBox;
00357                                 collisionPairs->Append(collisionPair);
00358                         }
00359                         else if (myLevel > 0) {
00360                                 // recursively detect collisions
00361                                 myLevel--;
00362                                 left->detectCollisions(boundingBox, myLevel, otherLevel, collisionPairs);
00363                                 right->detectCollisions(boundingBox, myLevel, otherLevel, collisionPairs);
00364                         }
00365                         else {
00366                                 // recursively detect collisions
00367                                 otherLevel--;
00368                                 detectCollisions(((BoundingBoxNode*)boundingBox)->getLeft(), 
00369                                                          myLevel, otherLevel, collisionPairs);
00370                                 detectCollisions(((BoundingBoxNode*)boundingBox)->getRight(), 
00371                                                          myLevel, otherLevel, collisionPairs);
00372                         }
00373                 }
00374         }
00375 }
00376 
00377 // Returns the depth of the collision
00378 double BoundingBoxNode::collisionDepth(BoundingBox* boundingBox) {
00379         if (boundingBox->isLeaf()) {
00380                 // 1. we calculate the distance from triangle to center of bounding box
00381                 Face* otherFace = ((BoundingBoxLeaf*)boundingBox)->getFace();
00382                 Point3D bbCenter = center();
00383                 double distance = otherFace->PlaneDistanceToPoint(bbCenter);
00384 
00385                 // 2. we subtract the length of bounding box center to one of its nodes
00386                 Point3D bbVector = bbCenter - min;
00387                 double length = bbVector.Length();
00388 
00389                 return distance - length;
00390         }
00391         else {
00392                 // compare depth of two bounding boxes
00393                 Point3D otherMin = boundingBox->getMin();
00394                 Point3D otherMax = boundingBox->getMax();
00395 
00396                 double xDepth = min.x - otherMin.x;
00397                 if (xDepth < 0) {
00398                         xDepth = -xDepth;
00399                 }
00400                 xDepth = xDepth - (getWidth() / 2) - (boundingBox->getWidth() / 2);
00401                 if (xDepth > 0) {
00402                         xDepth = 0;
00403                 }
00404 
00405                 double yDepth = min.y - otherMin.y;
00406                 if (yDepth < 0) {
00407                         yDepth = -yDepth;
00408                 }
00409                 yDepth = yDepth - (getHeight() / 2) - (boundingBox->getHeight() / 2);
00410                 if (yDepth > 0) {
00411                         yDepth = 0;
00412                 }
00413 
00414                 double zDepth = min.z - otherMin.z;
00415                 if (zDepth < 0) {
00416                         zDepth = -zDepth;
00417                 }
00418                 zDepth = zDepth - (getDepth() / 2) - (boundingBox->getDepth() / 2);
00419                 if (zDepth > 0) {
00420                         zDepth = 0;
00421                 }
00422 
00423                 return xDepth + yDepth + zDepth;
00424         }
00425 }
00426 
00427 
00428 
00429 //*** BoundingBoxLeaf ***
00430 
00431 // Constructor for leaf
00432 BoundingBoxLeaf::BoundingBoxLeaf(Face *face_, BoundingBox *parent_) : BoundingBox(parent_)
00433 {
00434     face = face_;
00435         object = face->getFaceArray()->getObject();
00436 
00437         // update min max
00438         update();
00439 }
00440 
00441 // leaf destructor
00442 BoundingBoxLeaf::~BoundingBoxLeaf()
00443 {
00444     face = NULL;
00445 }
00446 
00447 // update bounding box positions
00448 void BoundingBoxLeaf::update() 
00449 {
00450         // get min and max
00451         const double LARGE = 1e10;
00452         min = Point3D(LARGE, LARGE, LARGE);
00453         max = Point3D(-LARGE, -LARGE, -LARGE);
00454         for (int i = 0; i < 3; i++) {
00455                 Node* node = face->getNodeLink(i);
00456                 if (node->p.x < min.x) {
00457                         min.x = node->p.x;
00458                 }
00459                 if (node->p.x > max.x) {
00460                         max.x = node->p.x;
00461                 }
00462                 if (node->p.y < min.y) {
00463                         min.y = node->p.y;
00464                 }
00465                 if (node->p.y > max.y) {
00466                         max.y = node->p.y;
00467                 }
00468                 if (node->p.z < min.z) {
00469                         min.z = node->p.z;
00470                 }
00471                 if (node->p.z > max.z) {
00472                         max.z = node->p.z;
00473                 }
00474         }
00475 
00476         // adjust normal
00477         normal = face->getNormal();
00478 }
00479 
00480 // detect collisions
00481 void BoundingBoxLeaf::detectCollisions(BoundingBox* boundingBox, int myLevel, int otherLevel,
00482                                                                            ReallocableArray<CollisionBoxPair>* collisionPairs)
00483 {
00484         if (overlap(boundingBox)) {
00485                 if (boundingBox->isLeaf()) {
00486                         // check if faces intersect
00487                         Face* otherFace = ((BoundingBoxLeaf*)boundingBox)->getFace();
00488                         if (face->intersectsFace(otherFace)) {
00489                                 // if overlap, add as collision pair
00490                                 CollisionBoxPair collisionPair;
00491                                 collisionPair.myCollisionBox = this;
00492                                 collisionPair.otherCollisionBox = boundingBox;
00493                                 collisionPairs->Append(collisionPair);
00494                         }
00495                 }
00496                 else {
00497                         // recursively detect collisions
00498                         if (otherLevel > 0) {
00499                                 // need to go further down
00500                                 otherLevel--;
00501                                 detectCollisions(((BoundingBoxNode*)boundingBox)->getLeft(), 
00502                                                      myLevel, otherLevel, collisionPairs);
00503                                 detectCollisions(((BoundingBoxNode*)boundingBox)->getRight(), 
00504                                                      myLevel, otherLevel, collisionPairs);
00505                         }
00506                         else {
00507                                 // just add current solution as collision pair (approximation)
00508                                 if (face->intersectsBox(&boundingBox->getMin(), &boundingBox->getMax())) {
00509                                         CollisionBoxPair collisionPair;
00510                                         collisionPair.myCollisionBox = this;
00511                                         collisionPair.otherCollisionBox = boundingBox;
00512                                         collisionPairs->Append(collisionPair);
00513                                 }
00514                         }
00515                 }
00516         }
00517 }
00518 
00519 // Returns the depth of the collision (=0 is no collision / <0 is collision depth)
00520 double BoundingBoxLeaf::collisionDepth(BoundingBox* boundingBox) {
00521         if (boundingBox->isLeaf()) {
00522                 // find deepest node in other triangle
00523                 Face* otherFace = ((BoundingBoxLeaf*)boundingBox)->getFace();
00524                 double minDistance = 0;
00525                 for (int i = 0; i < 3; i++) {
00526                         Node* node = face->getNodeLink(i);
00527                         double currentDistance = otherFace->PlaneDistanceToPoint(node->p);
00528                         if (currentDistance < minDistance) { 
00529                                 minDistance = currentDistance; 
00530                         }
00531                 }
00532                 return minDistance;
00533         }
00534         else {
00535                 // 1. we calculate the distance from triangle to center of bounding box 
00536                 Point3D bbCenter = boundingBox->center();
00537                 double distance = face->PlaneDistanceToPoint(bbCenter);
00538 
00539                 // 2. we subtract the length of bounding box center to one of its nodes
00540                 Point3D bbVector = bbCenter - boundingBox->getMin();
00541                 double length = bbVector.Length();
00542 
00543                 return distance - length;
00544         }
00545 }

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