00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "collisionModel.h"
00027
00028 #include <algorithm>
00029
00030
00031 #include "debug.h"
00032 #ifdef MKL
00033 #include "mkl_wrappers.h"
00034 #else
00035 #include "lapack_wrappers.h"
00036 #endif
00037
00038 #include "collisionStructures.h"
00039
00040 namespace Collision {
00041
00042 const double Leaf::TOLERANCE = 1.0e-2;
00043 const int Leaf::MAX_LEAF_TRIANGLES = 1;
00044
00045 void Jacobi(double a[3][3], double v[3][3]);
00046 void print(const double a[3][3]);
00047
00048 position Leaf::getMeanVertex()
00049 {
00050 position mean(0,0,0);
00051 if (mTriangles.empty()) return mean;
00052
00053 std::list<Triangle>::iterator it;
00054 for (it=mTriangles.begin(); it!=mTriangles.end(); it++) {
00055 mean = mean + (*it).v1;
00056 mean = mean + (*it).v2;
00057 mean = mean + (*it).v3;
00058 }
00059 mean = ( 1.0 / ( 3.0 * (int)mTriangles.size() ) ) * mean;
00060 return mean;
00061 }
00062
00063 double Leaf::getMedianProjection(const vec3 &axis)
00064 {
00065 if (mTriangles.empty()) return 0.0;
00066 std::vector<double> projections;
00067 std::list<Triangle>::iterator it;
00068 for (it=mTriangles.begin(); it!=mTriangles.end(); it++) {
00069 position mean = (*it).v1 + (*it).v2 + (*it).v3;
00070 mean = (1.0 / 3.0) * mean;
00071 double projection = (mean - position::ORIGIN) % axis;
00072 projections.push_back(projection);
00073 }
00074 if (projections.size() == 1) {
00075 return projections.front();
00076 }
00077 std::nth_element(projections.begin(), projections.begin() + projections.size()/2, projections.end());
00078 return *(projections.begin() + projections.size()/2);
00079 }
00080
00081 void boxSize(const position &p, vec3 &min, vec3 &max,
00082 const vec3 &x, const vec3 &y, const vec3 &z, double tolerance)
00083 {
00084 vec3 d = p - position::ORIGIN;
00085 double dx = d % x;
00086 double dy = d % y;
00087 double dz = d % z;
00088 if ( dx + tolerance > max.x() ) max.x() = dx + tolerance;
00089 if ( dy + tolerance > max.y() ) max.y() = dy + tolerance;
00090 if ( dz + tolerance > max.z() ) max.z() = dz + tolerance;
00091 if ( dx - tolerance < min.x() ) min.x() = dx - tolerance;
00092 if ( dy - tolerance < min.y() ) min.y() = dy - tolerance;
00093 if ( dz - tolerance < min.z() ) min.z() = dz - tolerance;
00094 }
00095
00096 void Leaf::fitBox(const mat3 &R, vec3 ¢er, vec3 &halfSize)
00097 {
00098 vec3 x = R.row(0);
00099 vec3 y = R.row(1);
00100 vec3 z = R.row(2);
00101 vec3 max(-1.0e10, -1.0e10, -1.0e10);
00102 vec3 min( 1.0e10, 1.0e10, 1.0e10);
00103 std::list<Triangle>::iterator it;
00104 for (it=mTriangles.begin(); it!=mTriangles.end(); it++) {
00105 boxSize( (*it).v1, min, max, x, y, z, TOLERANCE);
00106 boxSize( (*it).v2, min, max, x, y, z, TOLERANCE);
00107 boxSize( (*it).v3, min, max, x, y, z, TOLERANCE);
00108 }
00109 DBGP("Max: " << max);
00110 DBGP("Min: " << min);
00111 for (int i=0; i<3; i++) {
00112 halfSize[i] = 0.5 * (max[i] - min[i]);
00113 }
00114 DBGP("computed halfsize: " << halfSize);
00115
00116 center = min + halfSize;
00117 center = R.inverse() * center;
00118
00119 for (int i=0; i<3; i++) {
00120 if (halfSize[i] < TOLERANCE) {
00121 if (halfSize[i] < 0.5 * TOLERANCE) {
00122 DBGA("Warning: degenerate box computed");
00123 }
00124 halfSize[i] = TOLERANCE;
00125 }
00126 }
00127 DBGP("returned halfsize: " << halfSize);
00128 }
00129
00131 void Leaf::areaWeightedCovarianceMatrix(double covMat[3][3])
00132 {
00133 for (int i=0; i<3; i++) {
00134 for (int j=0; j<3; j++) {
00135 covMat[i][j] = 0.0;
00136 }
00137 }
00138 double totalArea = 0;
00139 position areaWeightedMedian(0.0, 0.0, 0.0);
00140 std::list<Triangle>::iterator it;
00141 for (it=mTriangles.begin(); it!=mTriangles.end(); it++) {
00142 position m = it->centroid();
00143 double area = it->area();
00144 totalArea += area;
00145 areaWeightedMedian = areaWeightedMedian + area * m;
00146 for (int i=0; i<3; i++) {
00147 for (int j=0; j<3; j++) {
00148
00149 covMat[i][j] += (area / 12.0) * (9*m[i]*m[j] +
00150 it->v1[i]*it->v1[j] +
00151 it->v2[i]*it->v2[j] +
00152 it->v3[i]*it->v3[j] );
00153 }
00154 }
00155 }
00156 areaWeightedMedian = (1.0 / totalArea) * areaWeightedMedian;
00157 for (int i=0; i<3; i++) {
00158 for (int j=0; j<3; j++) {
00159 covMat[i][j] = (1.0 / totalArea) * covMat[i][j] -
00160 areaWeightedMedian[i]*areaWeightedMedian[j];
00161 }
00162 }
00163 }
00164
00165 void Leaf::computeBboxOO()
00166 {
00167
00168 double covMat[3][3], v[3][3];
00169 areaWeightedCovarianceMatrix(covMat);
00170 DBGP("Cov mat:"); DBGST(print(covMat));
00171
00172
00173 Jacobi(covMat, v);
00174 DBGP("eigenvalues:"); DBGST(print(covMat));
00175 DBGP("eigenVectors:"); DBGST(print(v));
00176 int first = 0, second = 1, third = 2;
00177 if (covMat[1][1] > covMat[0][0]) {
00178 std::swap(first, second);
00179 }
00180 if (covMat[2][2] > covMat[first][first]) {
00181 std::swap(first, third);
00182 }
00183 if (covMat[third][third] > covMat[second][second]) {
00184 std::swap(second, third);
00185 }
00186 DBGP("Eigenvalues: " << covMat[first][first] << " " << covMat[second][second]
00187 << " " << covMat[third][third]);
00188
00189
00190 vec3 xAxis(v[0][first], v[1][first], v[2][first]);
00191 vec3 yAxis(v[0][second], v[1][second], v[2][second]);
00192 vec3 zAxis = normalise(xAxis) * normalise(yAxis);
00193 yAxis = zAxis * normalise(xAxis);
00194 xAxis = yAxis * zAxis;
00195 mat3 R(xAxis, yAxis, zAxis);
00196
00197 DBGP("Matrix: " << R);
00198
00199
00200 vec3 halfSize, center;
00201 fitBox(R, center, halfSize);
00202
00203
00204 first = 0;
00205 if (halfSize.y() > halfSize.x()) first = 1;
00206 if (halfSize.z() > halfSize[first]) first = 2;
00207 transf rotate = transf::IDENTITY;
00208 if (first == 1) {
00209
00210 rotate = rotate_transf(M_PI/2.0, vec3(0,0,1));
00211 } else if (first == 2) {
00212
00213 rotate = rotate_transf(M_PI/2.0, vec3(0,1,0));
00214 }
00215 halfSize = halfSize * rotate;
00216 for (int i=0; i<3; i++) {
00217 if (halfSize[i] < 0) halfSize[i] = -halfSize[i];
00218 }
00219 mat3 RR;
00220 rotate.rotation().ToRotationMatrix(RR);
00221 R = RR * R;
00222
00223 mBbox.halfSize = halfSize;
00224 mBbox.setTran( transf(R, center ) );
00225 }
00226
00227 void Leaf::computeBboxAA()
00228 {
00229 mat3 R( vec3::X, vec3::Y, vec3::Z);
00230 vec3 halfSize, center;
00231 fitBox(R, center, halfSize);
00232 mBbox.halfSize = halfSize;
00233 mBbox.setTran( transf(R, center ) );
00234 }
00235
00246 Branch* Leaf::split()
00247 {
00248
00249 if ( (int)mTriangles.size() <= MAX_LEAF_TRIANGLES ) return NULL;
00250
00251
00252
00253
00254 vec3 xAxis = vec3(1,0,0) * mBbox.getTran();
00255 vec3 yAxis = vec3(0,1,0) * mBbox.getTran();
00256 vec3 zAxis = vec3(0,0,1) * mBbox.getTran();
00257 if (mBbox.halfSize.y() > mBbox.halfSize.x()) {
00258 DBGA("Unexpected bounding box dominant axis. Extents: ");
00259 DBGA(mBbox.halfSize.x() << " " << mBbox.halfSize.y() << " " << mBbox.halfSize.z());
00260
00261 std::swap(xAxis, yAxis);
00262 yAxis = - yAxis;
00263 }
00264 if (mBbox.halfSize.z() > mBbox.halfSize.y() &&
00265 mBbox.halfSize.z() > mBbox.halfSize.x() ) {
00266 DBGA("Unexpected bounding box dominant axis. Extents: ");
00267 DBGA(mBbox.halfSize.x() << " " << mBbox.halfSize.y() << " " << mBbox.halfSize.z());
00268
00269 std::swap(xAxis, zAxis);
00270 zAxis = - zAxis;
00271 }
00272
00273
00274
00275 double sepPoint = (getMeanVertex() - position::ORIGIN) % xAxis;
00276
00277
00278
00279
00280
00281 Leaf *child1 = new Leaf();
00282 Leaf *child2 = new Leaf();
00283
00284
00285
00286 balancedSplit(xAxis, sepPoint, child1, child2);
00287
00288
00289 if (!child1->getNumTriangles() || !child2->getNumTriangles()) {
00290 child1->clearTriangles();
00291 child2->clearTriangles();
00292 sepPoint = getMedianProjection(xAxis);
00293 balancedSplit(xAxis, sepPoint, child1, child2);
00294 }
00295
00296
00297
00298
00299
00300
00301
00302 if (!child1->getNumTriangles() || !child2->getNumTriangles()) {
00303 child1->clearTriangles();
00304 child2->clearTriangles();
00305 randomSplit(child1, child2);
00306 }
00307
00308
00309 child1->computeBbox();
00310 child2->computeBbox();
00311
00312
00313 Branch* b = new Branch(child1, child2, mBbox);
00314 return b;
00315 }
00316
00318 void Leaf::balancedSplit(vec3 axis, double sepPoint, Leaf *child1, Leaf *child2)
00319 {
00320 std::list<Triangle>::iterator it;
00321 for (it=mTriangles.begin(); it!=mTriangles.end(); it++) {
00322 position median(0,0,0);
00323 median = median + (*it).v1;
00324 median = median + (*it).v2;
00325 median = median + (*it).v3;
00326 median = ( 1.0 / 3.0 ) * median;
00327 vec3 m = median - position::ORIGIN;
00328 double d = m % axis;
00329 if ( d < sepPoint ) {
00330 child1->addTriangle(*it);
00331 } else {
00332 child2->addTriangle(*it);
00333 }
00334 }
00335 }
00336
00338 void Leaf::randomSplit(Leaf *child1, Leaf *child2)
00339 {
00340 std::list<Triangle>::iterator it;
00341 bool one = true;
00342 for (it=mTriangles.begin(); it!=mTriangles.end(); it++) {
00343 if (one) {
00344 child1->addTriangle(*it);
00345 } else {
00346 child2->addTriangle(*it);
00347 }
00348 one = !one;
00349 }
00350 }
00351
00352 bool
00353 compareProjections(const std::pair<Triangle, double> &p1,
00354 const std::pair<Triangle, double> &p2) {
00355 return p1.second < p2.second;
00356 }
00357
00364 void
00365 Leaf::optimalSplit(const vec3 &x, const vec3 &y, const vec3 &z, Leaf *child1, Leaf *child2)
00366 {
00367
00368 std::vector< std::pair<Triangle,double> > sortedTriangles;
00369 std::list<Triangle>::iterator it;
00370 for (it=mTriangles.begin(); it!=mTriangles.end(); it++) {
00371 position median = (*it).v1 + (*it).v2 + (*it).v3;
00372 median = ( 1.0 / 3.0 ) * median;
00373 double projection = (median - position::ORIGIN) % x;
00374 sortedTriangles.push_back( std::pair<Triangle,double>(*it,projection) );
00375 }
00376 std::sort(sortedTriangles.begin(), sortedTriangles.end(), compareProjections);
00377
00378
00379 std::vector<double> volumesUp;
00380 vec3 max(-1.0e10, -1.0e10, -1.0e10);
00381 vec3 min( 1.0e10, 1.0e10, 1.0e10);
00382 std::vector< std::pair<Triangle,double> >::iterator it2;
00383 for (it2 = sortedTriangles.begin(); it2!=sortedTriangles.end(); it2++) {
00384 boxSize((*it2).first.v1, min, max, x, y, z, Leaf::TOLERANCE);
00385 boxSize((*it2).first.v2, min, max, x, y, z, Leaf::TOLERANCE);
00386 boxSize((*it2).first.v3, min, max, x, y, z, Leaf::TOLERANCE);
00387 double volumeSq = (max[0] - min[0]) * (max[1] - min[1]) * (max[2] - min[2]);
00388 volumesUp.push_back(volumeSq);
00389 }
00390
00391 std::vector<double> volumesDown;
00392 max.set(-1.0e10, -1.0e10, -1.0e10);
00393 min.set( 1.0e10, 1.0e10, 1.0e10);
00394 std::vector< std::pair<Triangle,double> >::reverse_iterator it3;
00395 for (it3 = sortedTriangles.rbegin(); it3!=sortedTriangles.rend(); it3++) {
00396 boxSize((*it3).first.v1, min, max, x, y, z, Leaf::TOLERANCE);
00397 boxSize((*it3).first.v2, min, max, x, y, z, Leaf::TOLERANCE);
00398 boxSize((*it3).first.v3, min, max, x, y, z, Leaf::TOLERANCE);
00399 double volumeSq = (max[0] - min[0]) * (max[1] - min[1]) * (max[2] - min[2]);
00400 volumesDown.push_back(volumeSq);
00401 }
00402 assert( volumesUp.size() == volumesDown.size() );
00403
00404
00405 for (int i=0; i<(int)volumesUp.size(); i++) {
00406 volumesUp[i] += volumesDown[ volumesDown.size()-i-1 ];
00407 }
00408 std::vector<double>::iterator minVolIt = std::min_element(volumesUp.begin(), volumesUp.end());
00409
00410
00411 std::vector<double>::iterator it4;
00412 int index=0;
00413 for (it4 = volumesUp.begin(); it4 != minVolIt; it4++) {
00414 child1->addTriangle(sortedTriangles[index].first);
00415 index++;
00416 }
00417 for (it4 = minVolIt; it4 != volumesUp.end(); it4++) {
00418 child2->addTriangle(sortedTriangles[index].first);
00419 index++;
00420 }
00421 }
00422
00423
00424 void Node::getBVRecurse(int currentDepth, int desiredDepth, std::vector<BoundingBox> *bvs)
00425 {
00426 if (currentDepth == desiredDepth || isLeaf() ) {
00427 bvs->push_back( BoundingBox(mBbox) );
00428 DBGP("BBox tran: " << mBbox.getTran());
00429 DBGP("BBox size: " << mBbox.halfSize);
00430 return;
00431 }
00432 }
00433
00434 void Branch::getBVRecurse(int currentDepth, int desiredDepth, std::vector<BoundingBox> *bvs)
00435 {
00436 Node::getBVRecurse(currentDepth, desiredDepth, bvs);
00437 if (currentDepth < desiredDepth) {
00438 mChild1->getBVRecurse(currentDepth+1, desiredDepth, bvs);
00439 mChild2->getBVRecurse(currentDepth+1, desiredDepth, bvs);
00440 }
00441 }
00442
00451 void CollisionModel::cloneModel(CollisionModel *original)
00452 {
00453 if (mClone || original->mClone) {
00454 DBGA("WARNING: cloning of clones! Not well tested!");
00455 }
00456 delete mRoot;
00457 mRoot = original->mRoot;
00458 mClone = true;
00459 }
00460
00461 void CollisionModel::getBoundingVolumes(int depth, std::vector<BoundingBox> *bvs)
00462 {
00463 mRoot->getBVRecurse(0, depth, bvs);
00464 }
00465
00470 void
00471 CollisionModel::addTriangle(Triangle t)
00472 {
00473 if (mClone) {
00474 DBGA("Cannot add triangles to clones!");
00475 assert(0);
00476 return;
00477 }
00478 if (!mRoot->isLeaf()) {
00479 DBGA("Reset model before adding triangles");
00480 return;
00481 }
00482 static_cast<Leaf*>(mRoot)->addTriangle(t);
00483 }
00484
00489 void
00490 CollisionModel::reset()
00491 {
00492 if (mClone) {
00493 DBGA("Cannot reset a clone!");
00494 assert(0);
00495 return;
00496 }
00497 delete mRoot;
00498 mRoot = new Leaf();
00499 }
00500
00501
00502 void
00503 CollisionModel::build()
00504 {
00505 if (mClone) {
00506 DBGA("Cannot build a cloned model!");
00507 assert(0);
00508 return;
00509 }
00510 if (!mRoot->isLeaf()) {
00511 DBGA("Model already built. Reset first.");
00512 return;
00513 }
00514 DBGP("Buid bboxes from triangles: " << static_cast<Leaf*>(mRoot)->getNumTriangles());
00515 static_cast<Leaf*>(mRoot)->computeBbox();
00516
00517 Branch *tmp = mRoot->split();
00518 if (tmp) {
00519 delete mRoot;
00520 mRoot = tmp;
00521 tmp->splitRecurse(0,-1);
00522 }
00523 DBGP("Split finished, hierarchy size: " << mRoot->countRecurse());
00524 }
00525
00526
00527
00528
00529
00530
00531 inline void multiply(double r[3][3], const double a[3][3], const double b[3][3]) {
00532 for (int i=0; i<3; i++) {
00533 for (int j=0; j<3; j++) {
00534 r[i][j] = 0.0;
00535 for (int k=0; k<3; k++) {
00536 r[i][j] += a[i][k] * b[k][j];
00537 }
00538 }
00539 }
00540 }
00541
00542 inline void copy(double r[3][3], const double o[3][3]) {
00543 for (int i=0; i<3; i++) {
00544 for (int j=0; j<3; j++) {
00545 r[i][j] = o[i][j];
00546 }
00547 }
00548 }
00549
00550 inline void transpose(double r[3][3], const double o[3][3]) {
00551 for (int i=0; i<3; i++) {
00552 for (int j=0; j<3; j++) {
00553 r[i][j] = o[j][i];
00554 }
00555 }
00556 }
00557
00558 void print(const double a[3][3])
00559 {
00560 DBGA(a[0][0] << " " << a[0][1] << " " << a[0][2]);
00561 DBGA(a[1][0] << " " << a[1][1] << " " << a[1][2]);
00562 DBGA(a[2][0] << " " << a[2][1] << " " << a[2][2]);
00563 }
00564
00565
00566
00567
00568
00569
00570 void SymSchur2(double a[3][3], int p, int q, double &c, double &s)
00571 {
00572 if (fabs(a[p][q]) > 0.0001f) {
00573 double r = (a[q][q] - a[p][p]) / (2.0f * a[p][q]);
00574 double t;
00575 if (r >= 0.0f)
00576 t = 1.0f / (r + sqrt(1.0f + r*r));
00577 else
00578 t = -1.0f / (-r + sqrt(1.0f + r*r));
00579 c = 1.0f / sqrt(1.0f + t*t);
00580 s = t * c;
00581 } else {
00582 c = 1.0f;
00583 s = 0.0f;
00584 }
00585 }
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595 void Jacobi(double a[3][3], double v[3][3])
00596 {
00597 int i, j, n, p, q;
00598 double prevoff, c, s;
00599 double J[3][3], tmp1[3][3], tmp2[3][3];
00600
00601
00602 for (i = 0; i < 3; i++) {
00603 v[i][0] = v[i][1] = v[i][2] = 0.0f;
00604 v[i][i] = 1.0f;
00605 }
00606
00607
00608 const int MAX_ITERATIONS = 50;
00609 for (n = 0; n < MAX_ITERATIONS; n++) {
00610
00611 p = 0; q = 1;
00612 for (i = 0; i < 3; i++) {
00613 for (j = 0; j < 3; j++) {
00614 if (i == j) continue;
00615 if (fabs(a[i][j]) > fabs(a[p][q])) {
00616 p = i;
00617 q = j;
00618 }
00619 }
00620 }
00621
00622
00623
00624 SymSchur2(a, p, q, c, s);
00625 for (i = 0; i < 3; i++) {
00626 J[i][0] = J[i][1] = J[i][2] = 0.0f;
00627 J[i][i] = 1.0f;
00628 }
00629 J[p][p] = c; J[p][q] = s;
00630 J[q][p] = -s; J[q][q] = c;
00631
00632
00633
00634 multiply(tmp1, v, J);
00635 copy(v, tmp1);
00636
00637
00638
00639 transpose(tmp1, J);
00640 multiply(tmp2, tmp1, a);
00641 multiply(tmp1, tmp2, J);
00642 copy(a, tmp1);
00643
00644
00645 double off = 0.0f;
00646 for (i = 0; i < 3; i++) {
00647 for (j = 0; j < 3; j++) {
00648 if (i == j) continue;
00649 off += a[i][j] * a[i][j];
00650 }
00651 }
00652
00653
00654
00655 if (n > 2 && off >= prevoff)
00656 return;
00657
00658 prevoff = off;
00659 }
00660 }
00661
00662
00663 }