00001
00002
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
00013
00014
00015 BoundingBox::BoundingBox(BoundingBox *parent_)
00016 {
00017 parent = parent_;
00018 }
00019
00020
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
00030 BoundingBox* BoundingBox::createTree(Object* object) {
00031 int i;
00032
00033
00034 List<BoundingBoxLeaf*> bbList;
00035 if (object->getCollisionFaces().NumElements() > 0) {
00036
00037 for (i = 0; i < object->getCollisionFaces().NumElements(); i++) {
00038 bbList.Append(new BoundingBoxLeaf(object->getCollisionFaces()[i]));
00039 }
00040 }
00041 else {
00042
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
00051 return createTree(bbList);
00052 }
00053
00054
00055 BoundingBox* BoundingBox::createTree(List<BoundingBoxLeaf*> &bbList) {
00056 int i;
00057
00058 if (bbList.NumElements() == 0) {
00059
00060 return NULL;
00061 }
00062 else if (bbList.NumElements() == 1) {
00063
00064 return bbList[0];
00065 }
00066 else {
00067
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
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
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
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
00148 BoundingBox* bbTreeLeft = createTree(bbListLeft);
00149 BoundingBox* bbTreeRight = createTree(bbListRight);
00150
00151
00152 BoundingBoxNode* bbTree = new BoundingBoxNode(bbTreeLeft, bbTreeRight);
00153 return bbTree;
00154 }
00155 }
00156
00157
00158 void BoundingBox::draw()
00159 {
00160
00161 if (hasMarker()) {
00162
00163 glColor3f(1.0, 0.0, 1.0);
00164 }
00165 else {
00166
00167 glColor4f(0.8f, 0.8f, 0.8f, 0.6f);
00168 }
00169
00170
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
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
00211 return true;
00212 }
00213 else {
00214
00215 return false;
00216 }
00217 }
00218
00219
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
00229
00230
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
00249 internalUpdate();
00250 }
00251
00252
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
00267 void BoundingBoxNode::draw()
00268 {
00269
00270 if (left) {
00271 left->draw();
00272 }
00273 if (right) {
00274 right->draw();
00275 }
00276
00277
00278 BoundingBox::draw();
00279 }
00280
00281
00282 void BoundingBoxNode::update()
00283 {
00284
00285 left->update();
00286 right->update();
00287
00288
00289 internalUpdate();
00290 }
00291
00292
00293 void BoundingBoxNode::internalUpdate() {
00294
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
00308 normal = left->getNormal() + right->getNormal();
00309 normal.Normalize();
00310 }
00311
00312
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
00320 myLevel--;
00321 left->detectCollisions(boundingBox, myLevel, otherLevel, collisionPairs);
00322 right->detectCollisions(boundingBox, myLevel, otherLevel, collisionPairs);
00323 }
00324 else {
00325
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
00339 otherLevel--;
00340 detectCollisions(((BoundingBoxNode*)boundingBox)->getLeft(),
00341 myLevel, otherLevel, collisionPairs);
00342 detectCollisions(((BoundingBoxNode*)boundingBox)->getRight(),
00343 myLevel, otherLevel, collisionPairs);
00344 }
00345 else {
00346
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
00354 CollisionBoxPair collisionPair;
00355 collisionPair.myCollisionBox = this;
00356 collisionPair.otherCollisionBox = boundingBox;
00357 collisionPairs->Append(collisionPair);
00358 }
00359 else if (myLevel > 0) {
00360
00361 myLevel--;
00362 left->detectCollisions(boundingBox, myLevel, otherLevel, collisionPairs);
00363 right->detectCollisions(boundingBox, myLevel, otherLevel, collisionPairs);
00364 }
00365 else {
00366
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
00378 double BoundingBoxNode::collisionDepth(BoundingBox* boundingBox) {
00379 if (boundingBox->isLeaf()) {
00380
00381 Face* otherFace = ((BoundingBoxLeaf*)boundingBox)->getFace();
00382 Point3D bbCenter = center();
00383 double distance = otherFace->PlaneDistanceToPoint(bbCenter);
00384
00385
00386 Point3D bbVector = bbCenter - min;
00387 double length = bbVector.Length();
00388
00389 return distance - length;
00390 }
00391 else {
00392
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
00430
00431
00432 BoundingBoxLeaf::BoundingBoxLeaf(Face *face_, BoundingBox *parent_) : BoundingBox(parent_)
00433 {
00434 face = face_;
00435 object = face->getFaceArray()->getObject();
00436
00437
00438 update();
00439 }
00440
00441
00442 BoundingBoxLeaf::~BoundingBoxLeaf()
00443 {
00444 face = NULL;
00445 }
00446
00447
00448 void BoundingBoxLeaf::update()
00449 {
00450
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
00477 normal = face->getNormal();
00478 }
00479
00480
00481 void BoundingBoxLeaf::detectCollisions(BoundingBox* boundingBox, int myLevel, int otherLevel,
00482 ReallocableArray<CollisionBoxPair>* collisionPairs)
00483 {
00484 if (overlap(boundingBox)) {
00485 if (boundingBox->isLeaf()) {
00486
00487 Face* otherFace = ((BoundingBoxLeaf*)boundingBox)->getFace();
00488 if (face->intersectsFace(otherFace)) {
00489
00490 CollisionBoxPair collisionPair;
00491 collisionPair.myCollisionBox = this;
00492 collisionPair.otherCollisionBox = boundingBox;
00493 collisionPairs->Append(collisionPair);
00494 }
00495 }
00496 else {
00497
00498 if (otherLevel > 0) {
00499
00500 otherLevel--;
00501 detectCollisions(((BoundingBoxNode*)boundingBox)->getLeft(),
00502 myLevel, otherLevel, collisionPairs);
00503 detectCollisions(((BoundingBoxNode*)boundingBox)->getRight(),
00504 myLevel, otherLevel, collisionPairs);
00505 }
00506 else {
00507
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
00520 double BoundingBoxLeaf::collisionDepth(BoundingBox* boundingBox) {
00521 if (boundingBox->isLeaf()) {
00522
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
00536 Point3D bbCenter = boundingBox->center();
00537 double distance = face->PlaneDistanceToPoint(bbCenter);
00538
00539
00540 Point3D bbVector = bbCenter - boundingBox->getMin();
00541 double length = bbVector.Length();
00542
00543 return distance - length;
00544 }
00545 }