Blender V2.61 - r43446
|
00001 00002 /* 00003 Bullet Continuous Collision Detection and Physics Library 00004 Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 00005 00006 This software is provided 'as-is', without any express or implied warranty. 00007 In no event will the authors be held liable for any damages arising from the use of this software. 00008 Permission is granted to anyone to use this software for any purpose, 00009 including commercial applications, and to alter it and redistribute it freely, 00010 subject to the following restrictions: 00011 00012 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 00013 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 00014 3. This notice may not be removed or altered from any source distribution. 00015 00016 Elsevier CDROM license agreements grants nonexclusive license to use the software 00017 for any purpose, commercial or non-commercial as long as the following credit is included 00018 identifying the original source of the software: 00019 00020 Parts of the source are "from the book Real-Time Collision Detection by 00021 Christer Ericson, published by Morgan Kaufmann Publishers, 00022 (c) 2005 Elsevier Inc." 00023 00024 */ 00025 00026 00027 #include "btVoronoiSimplexSolver.h" 00028 00029 #define VERTA 0 00030 #define VERTB 1 00031 #define VERTC 2 00032 #define VERTD 3 00033 00034 #define CATCH_DEGENERATE_TETRAHEDRON 1 00035 void btVoronoiSimplexSolver::removeVertex(int index) 00036 { 00037 00038 btAssert(m_numVertices>0); 00039 m_numVertices--; 00040 m_simplexVectorW[index] = m_simplexVectorW[m_numVertices]; 00041 m_simplexPointsP[index] = m_simplexPointsP[m_numVertices]; 00042 m_simplexPointsQ[index] = m_simplexPointsQ[m_numVertices]; 00043 } 00044 00045 void btVoronoiSimplexSolver::reduceVertices (const btUsageBitfield& usedVerts) 00046 { 00047 if ((numVertices() >= 4) && (!usedVerts.usedVertexD)) 00048 removeVertex(3); 00049 00050 if ((numVertices() >= 3) && (!usedVerts.usedVertexC)) 00051 removeVertex(2); 00052 00053 if ((numVertices() >= 2) && (!usedVerts.usedVertexB)) 00054 removeVertex(1); 00055 00056 if ((numVertices() >= 1) && (!usedVerts.usedVertexA)) 00057 removeVertex(0); 00058 00059 } 00060 00061 00062 00063 00064 00065 //clear the simplex, remove all the vertices 00066 void btVoronoiSimplexSolver::reset() 00067 { 00068 m_cachedValidClosest = false; 00069 m_numVertices = 0; 00070 m_needsUpdate = true; 00071 m_lastW = btVector3(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); 00072 m_cachedBC.reset(); 00073 } 00074 00075 00076 00077 //add a vertex 00078 void btVoronoiSimplexSolver::addVertex(const btVector3& w, const btVector3& p, const btVector3& q) 00079 { 00080 m_lastW = w; 00081 m_needsUpdate = true; 00082 00083 m_simplexVectorW[m_numVertices] = w; 00084 m_simplexPointsP[m_numVertices] = p; 00085 m_simplexPointsQ[m_numVertices] = q; 00086 00087 m_numVertices++; 00088 } 00089 00090 bool btVoronoiSimplexSolver::updateClosestVectorAndPoints() 00091 { 00092 00093 if (m_needsUpdate) 00094 { 00095 m_cachedBC.reset(); 00096 00097 m_needsUpdate = false; 00098 00099 switch (numVertices()) 00100 { 00101 case 0: 00102 m_cachedValidClosest = false; 00103 break; 00104 case 1: 00105 { 00106 m_cachedP1 = m_simplexPointsP[0]; 00107 m_cachedP2 = m_simplexPointsQ[0]; 00108 m_cachedV = m_cachedP1-m_cachedP2; //== m_simplexVectorW[0] 00109 m_cachedBC.reset(); 00110 m_cachedBC.setBarycentricCoordinates(btScalar(1.),btScalar(0.),btScalar(0.),btScalar(0.)); 00111 m_cachedValidClosest = m_cachedBC.isValid(); 00112 break; 00113 }; 00114 case 2: 00115 { 00116 //closest point origin from line segment 00117 const btVector3& from = m_simplexVectorW[0]; 00118 const btVector3& to = m_simplexVectorW[1]; 00119 btVector3 nearest; 00120 00121 btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); 00122 btVector3 diff = p - from; 00123 btVector3 v = to - from; 00124 btScalar t = v.dot(diff); 00125 00126 if (t > 0) { 00127 btScalar dotVV = v.dot(v); 00128 if (t < dotVV) { 00129 t /= dotVV; 00130 diff -= t*v; 00131 m_cachedBC.m_usedVertices.usedVertexA = true; 00132 m_cachedBC.m_usedVertices.usedVertexB = true; 00133 } else { 00134 t = 1; 00135 diff -= v; 00136 //reduce to 1 point 00137 m_cachedBC.m_usedVertices.usedVertexB = true; 00138 } 00139 } else 00140 { 00141 t = 0; 00142 //reduce to 1 point 00143 m_cachedBC.m_usedVertices.usedVertexA = true; 00144 } 00145 m_cachedBC.setBarycentricCoordinates(1-t,t); 00146 nearest = from + t*v; 00147 00148 m_cachedP1 = m_simplexPointsP[0] + t * (m_simplexPointsP[1] - m_simplexPointsP[0]); 00149 m_cachedP2 = m_simplexPointsQ[0] + t * (m_simplexPointsQ[1] - m_simplexPointsQ[0]); 00150 m_cachedV = m_cachedP1 - m_cachedP2; 00151 00152 reduceVertices(m_cachedBC.m_usedVertices); 00153 00154 m_cachedValidClosest = m_cachedBC.isValid(); 00155 break; 00156 } 00157 case 3: 00158 { 00159 //closest point origin from triangle 00160 btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); 00161 00162 const btVector3& a = m_simplexVectorW[0]; 00163 const btVector3& b = m_simplexVectorW[1]; 00164 const btVector3& c = m_simplexVectorW[2]; 00165 00166 closestPtPointTriangle(p,a,b,c,m_cachedBC); 00167 m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] + 00168 m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] + 00169 m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2]; 00170 00171 m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] + 00172 m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] + 00173 m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2]; 00174 00175 m_cachedV = m_cachedP1-m_cachedP2; 00176 00177 reduceVertices (m_cachedBC.m_usedVertices); 00178 m_cachedValidClosest = m_cachedBC.isValid(); 00179 00180 break; 00181 } 00182 case 4: 00183 { 00184 00185 00186 btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); 00187 00188 const btVector3& a = m_simplexVectorW[0]; 00189 const btVector3& b = m_simplexVectorW[1]; 00190 const btVector3& c = m_simplexVectorW[2]; 00191 const btVector3& d = m_simplexVectorW[3]; 00192 00193 bool hasSeperation = closestPtPointTetrahedron(p,a,b,c,d,m_cachedBC); 00194 00195 if (hasSeperation) 00196 { 00197 00198 m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] + 00199 m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] + 00200 m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2] + 00201 m_simplexPointsP[3] * m_cachedBC.m_barycentricCoords[3]; 00202 00203 m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] + 00204 m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] + 00205 m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2] + 00206 m_simplexPointsQ[3] * m_cachedBC.m_barycentricCoords[3]; 00207 00208 m_cachedV = m_cachedP1-m_cachedP2; 00209 reduceVertices (m_cachedBC.m_usedVertices); 00210 } else 00211 { 00212 // printf("sub distance got penetration\n"); 00213 00214 if (m_cachedBC.m_degenerate) 00215 { 00216 m_cachedValidClosest = false; 00217 } else 00218 { 00219 m_cachedValidClosest = true; 00220 //degenerate case == false, penetration = true + zero 00221 m_cachedV.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); 00222 } 00223 break; 00224 } 00225 00226 m_cachedValidClosest = m_cachedBC.isValid(); 00227 00228 //closest point origin from tetrahedron 00229 break; 00230 } 00231 default: 00232 { 00233 m_cachedValidClosest = false; 00234 } 00235 }; 00236 } 00237 00238 return m_cachedValidClosest; 00239 00240 } 00241 00242 //return/calculate the closest vertex 00243 bool btVoronoiSimplexSolver::closest(btVector3& v) 00244 { 00245 bool succes = updateClosestVectorAndPoints(); 00246 v = m_cachedV; 00247 return succes; 00248 } 00249 00250 00251 00252 btScalar btVoronoiSimplexSolver::maxVertex() 00253 { 00254 int i, numverts = numVertices(); 00255 btScalar maxV = btScalar(0.); 00256 for (i=0;i<numverts;i++) 00257 { 00258 btScalar curLen2 = m_simplexVectorW[i].length2(); 00259 if (maxV < curLen2) 00260 maxV = curLen2; 00261 } 00262 return maxV; 00263 } 00264 00265 00266 00267 //return the current simplex 00268 int btVoronoiSimplexSolver::getSimplex(btVector3 *pBuf, btVector3 *qBuf, btVector3 *yBuf) const 00269 { 00270 int i; 00271 for (i=0;i<numVertices();i++) 00272 { 00273 yBuf[i] = m_simplexVectorW[i]; 00274 pBuf[i] = m_simplexPointsP[i]; 00275 qBuf[i] = m_simplexPointsQ[i]; 00276 } 00277 return numVertices(); 00278 } 00279 00280 00281 00282 00283 bool btVoronoiSimplexSolver::inSimplex(const btVector3& w) 00284 { 00285 bool found = false; 00286 int i, numverts = numVertices(); 00287 //btScalar maxV = btScalar(0.); 00288 00289 //w is in the current (reduced) simplex 00290 for (i=0;i<numverts;i++) 00291 { 00292 #ifdef BT_USE_EQUAL_VERTEX_THRESHOLD 00293 if ( m_simplexVectorW[i].distance2(w) <= m_equalVertexThreshold) 00294 #else 00295 if (m_simplexVectorW[i] == w) 00296 #endif 00297 found = true; 00298 } 00299 00300 //check in case lastW is already removed 00301 if (w == m_lastW) 00302 return true; 00303 00304 return found; 00305 } 00306 00307 void btVoronoiSimplexSolver::backup_closest(btVector3& v) 00308 { 00309 v = m_cachedV; 00310 } 00311 00312 00313 bool btVoronoiSimplexSolver::emptySimplex() const 00314 { 00315 return (numVertices() == 0); 00316 00317 } 00318 00319 void btVoronoiSimplexSolver::compute_points(btVector3& p1, btVector3& p2) 00320 { 00321 updateClosestVectorAndPoints(); 00322 p1 = m_cachedP1; 00323 p2 = m_cachedP2; 00324 00325 } 00326 00327 00328 00329 00330 bool btVoronoiSimplexSolver::closestPtPointTriangle(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c,btSubSimplexClosestResult& result) 00331 { 00332 result.m_usedVertices.reset(); 00333 00334 // Check if P in vertex region outside A 00335 btVector3 ab = b - a; 00336 btVector3 ac = c - a; 00337 btVector3 ap = p - a; 00338 btScalar d1 = ab.dot(ap); 00339 btScalar d2 = ac.dot(ap); 00340 if (d1 <= btScalar(0.0) && d2 <= btScalar(0.0)) 00341 { 00342 result.m_closestPointOnSimplex = a; 00343 result.m_usedVertices.usedVertexA = true; 00344 result.setBarycentricCoordinates(1,0,0); 00345 return true;// a; // barycentric coordinates (1,0,0) 00346 } 00347 00348 // Check if P in vertex region outside B 00349 btVector3 bp = p - b; 00350 btScalar d3 = ab.dot(bp); 00351 btScalar d4 = ac.dot(bp); 00352 if (d3 >= btScalar(0.0) && d4 <= d3) 00353 { 00354 result.m_closestPointOnSimplex = b; 00355 result.m_usedVertices.usedVertexB = true; 00356 result.setBarycentricCoordinates(0,1,0); 00357 00358 return true; // b; // barycentric coordinates (0,1,0) 00359 } 00360 // Check if P in edge region of AB, if so return projection of P onto AB 00361 btScalar vc = d1*d4 - d3*d2; 00362 if (vc <= btScalar(0.0) && d1 >= btScalar(0.0) && d3 <= btScalar(0.0)) { 00363 btScalar v = d1 / (d1 - d3); 00364 result.m_closestPointOnSimplex = a + v * ab; 00365 result.m_usedVertices.usedVertexA = true; 00366 result.m_usedVertices.usedVertexB = true; 00367 result.setBarycentricCoordinates(1-v,v,0); 00368 return true; 00369 //return a + v * ab; // barycentric coordinates (1-v,v,0) 00370 } 00371 00372 // Check if P in vertex region outside C 00373 btVector3 cp = p - c; 00374 btScalar d5 = ab.dot(cp); 00375 btScalar d6 = ac.dot(cp); 00376 if (d6 >= btScalar(0.0) && d5 <= d6) 00377 { 00378 result.m_closestPointOnSimplex = c; 00379 result.m_usedVertices.usedVertexC = true; 00380 result.setBarycentricCoordinates(0,0,1); 00381 return true;//c; // barycentric coordinates (0,0,1) 00382 } 00383 00384 // Check if P in edge region of AC, if so return projection of P onto AC 00385 btScalar vb = d5*d2 - d1*d6; 00386 if (vb <= btScalar(0.0) && d2 >= btScalar(0.0) && d6 <= btScalar(0.0)) { 00387 btScalar w = d2 / (d2 - d6); 00388 result.m_closestPointOnSimplex = a + w * ac; 00389 result.m_usedVertices.usedVertexA = true; 00390 result.m_usedVertices.usedVertexC = true; 00391 result.setBarycentricCoordinates(1-w,0,w); 00392 return true; 00393 //return a + w * ac; // barycentric coordinates (1-w,0,w) 00394 } 00395 00396 // Check if P in edge region of BC, if so return projection of P onto BC 00397 btScalar va = d3*d6 - d5*d4; 00398 if (va <= btScalar(0.0) && (d4 - d3) >= btScalar(0.0) && (d5 - d6) >= btScalar(0.0)) { 00399 btScalar w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); 00400 00401 result.m_closestPointOnSimplex = b + w * (c - b); 00402 result.m_usedVertices.usedVertexB = true; 00403 result.m_usedVertices.usedVertexC = true; 00404 result.setBarycentricCoordinates(0,1-w,w); 00405 return true; 00406 // return b + w * (c - b); // barycentric coordinates (0,1-w,w) 00407 } 00408 00409 // P inside face region. Compute Q through its barycentric coordinates (u,v,w) 00410 btScalar denom = btScalar(1.0) / (va + vb + vc); 00411 btScalar v = vb * denom; 00412 btScalar w = vc * denom; 00413 00414 result.m_closestPointOnSimplex = a + ab * v + ac * w; 00415 result.m_usedVertices.usedVertexA = true; 00416 result.m_usedVertices.usedVertexB = true; 00417 result.m_usedVertices.usedVertexC = true; 00418 result.setBarycentricCoordinates(1-v-w,v,w); 00419 00420 return true; 00421 // return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = btScalar(1.0) - v - w 00422 00423 } 00424 00425 00426 00427 00428 00430 int btVoronoiSimplexSolver::pointOutsideOfPlane(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d) 00431 { 00432 btVector3 normal = (b-a).cross(c-a); 00433 00434 btScalar signp = (p - a).dot(normal); // [AP AB AC] 00435 btScalar signd = (d - a).dot( normal); // [AD AB AC] 00436 00437 #ifdef CATCH_DEGENERATE_TETRAHEDRON 00438 #ifdef BT_USE_DOUBLE_PRECISION 00439 if (signd * signd < (btScalar(1e-8) * btScalar(1e-8))) 00440 { 00441 return -1; 00442 } 00443 #else 00444 if (signd * signd < (btScalar(1e-4) * btScalar(1e-4))) 00445 { 00446 // printf("affine dependent/degenerate\n");// 00447 return -1; 00448 } 00449 #endif 00450 00451 #endif 00452 // Points on opposite sides if expression signs are opposite 00453 return signp * signd < btScalar(0.); 00454 } 00455 00456 00457 bool btVoronoiSimplexSolver::closestPtPointTetrahedron(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, btSubSimplexClosestResult& finalResult) 00458 { 00459 btSubSimplexClosestResult tempResult; 00460 00461 // Start out assuming point inside all halfspaces, so closest to itself 00462 finalResult.m_closestPointOnSimplex = p; 00463 finalResult.m_usedVertices.reset(); 00464 finalResult.m_usedVertices.usedVertexA = true; 00465 finalResult.m_usedVertices.usedVertexB = true; 00466 finalResult.m_usedVertices.usedVertexC = true; 00467 finalResult.m_usedVertices.usedVertexD = true; 00468 00469 int pointOutsideABC = pointOutsideOfPlane(p, a, b, c, d); 00470 int pointOutsideACD = pointOutsideOfPlane(p, a, c, d, b); 00471 int pointOutsideADB = pointOutsideOfPlane(p, a, d, b, c); 00472 int pointOutsideBDC = pointOutsideOfPlane(p, b, d, c, a); 00473 00474 if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0) 00475 { 00476 finalResult.m_degenerate = true; 00477 return false; 00478 } 00479 00480 if (!pointOutsideABC && !pointOutsideACD && !pointOutsideADB && !pointOutsideBDC) 00481 { 00482 return false; 00483 } 00484 00485 00486 btScalar bestSqDist = FLT_MAX; 00487 // If point outside face abc then compute closest point on abc 00488 if (pointOutsideABC) 00489 { 00490 closestPtPointTriangle(p, a, b, c,tempResult); 00491 btVector3 q = tempResult.m_closestPointOnSimplex; 00492 00493 btScalar sqDist = (q - p).dot( q - p); 00494 // Update best closest point if (squared) distance is less than current best 00495 if (sqDist < bestSqDist) { 00496 bestSqDist = sqDist; 00497 finalResult.m_closestPointOnSimplex = q; 00498 //convert result bitmask! 00499 finalResult.m_usedVertices.reset(); 00500 finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; 00501 finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexB; 00502 finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC; 00503 finalResult.setBarycentricCoordinates( 00504 tempResult.m_barycentricCoords[VERTA], 00505 tempResult.m_barycentricCoords[VERTB], 00506 tempResult.m_barycentricCoords[VERTC], 00507 0 00508 ); 00509 00510 } 00511 } 00512 00513 00514 // Repeat test for face acd 00515 if (pointOutsideACD) 00516 { 00517 closestPtPointTriangle(p, a, c, d,tempResult); 00518 btVector3 q = tempResult.m_closestPointOnSimplex; 00519 //convert result bitmask! 00520 00521 btScalar sqDist = (q - p).dot( q - p); 00522 if (sqDist < bestSqDist) 00523 { 00524 bestSqDist = sqDist; 00525 finalResult.m_closestPointOnSimplex = q; 00526 finalResult.m_usedVertices.reset(); 00527 finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; 00528 00529 finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexB; 00530 finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexC; 00531 finalResult.setBarycentricCoordinates( 00532 tempResult.m_barycentricCoords[VERTA], 00533 0, 00534 tempResult.m_barycentricCoords[VERTB], 00535 tempResult.m_barycentricCoords[VERTC] 00536 ); 00537 00538 } 00539 } 00540 // Repeat test for face adb 00541 00542 00543 if (pointOutsideADB) 00544 { 00545 closestPtPointTriangle(p, a, d, b,tempResult); 00546 btVector3 q = tempResult.m_closestPointOnSimplex; 00547 //convert result bitmask! 00548 00549 btScalar sqDist = (q - p).dot( q - p); 00550 if (sqDist < bestSqDist) 00551 { 00552 bestSqDist = sqDist; 00553 finalResult.m_closestPointOnSimplex = q; 00554 finalResult.m_usedVertices.reset(); 00555 finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; 00556 finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexC; 00557 00558 finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB; 00559 finalResult.setBarycentricCoordinates( 00560 tempResult.m_barycentricCoords[VERTA], 00561 tempResult.m_barycentricCoords[VERTC], 00562 0, 00563 tempResult.m_barycentricCoords[VERTB] 00564 ); 00565 00566 } 00567 } 00568 // Repeat test for face bdc 00569 00570 00571 if (pointOutsideBDC) 00572 { 00573 closestPtPointTriangle(p, b, d, c,tempResult); 00574 btVector3 q = tempResult.m_closestPointOnSimplex; 00575 //convert result bitmask! 00576 btScalar sqDist = (q - p).dot( q - p); 00577 if (sqDist < bestSqDist) 00578 { 00579 bestSqDist = sqDist; 00580 finalResult.m_closestPointOnSimplex = q; 00581 finalResult.m_usedVertices.reset(); 00582 // 00583 finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexA; 00584 finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC; 00585 finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB; 00586 00587 finalResult.setBarycentricCoordinates( 00588 0, 00589 tempResult.m_barycentricCoords[VERTA], 00590 tempResult.m_barycentricCoords[VERTC], 00591 tempResult.m_barycentricCoords[VERTB] 00592 ); 00593 00594 } 00595 } 00596 00597 //help! we ended up full ! 00598 00599 if (finalResult.m_usedVertices.usedVertexA && 00600 finalResult.m_usedVertices.usedVertexB && 00601 finalResult.m_usedVertices.usedVertexC && 00602 finalResult.m_usedVertices.usedVertexD) 00603 { 00604 return true; 00605 } 00606 00607 return true; 00608 } 00609