Blender V2.61 - r43446
|
00001 /* 00002 Bullet Continuous Collision Detection and Physics Library 00003 * The b2CollidePolygons routines are Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 00004 00005 This software is provided 'as-is', without any express or implied warranty. 00006 In no event will the authors be held liable for any damages arising from the use of this software. 00007 Permission is granted to anyone to use this software for any purpose, 00008 including commercial applications, and to alter it and redistribute it freely, 00009 subject to the following restrictions: 00010 00011 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. 00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 00013 3. This notice may not be removed or altered from any source distribution. 00014 */ 00015 00018 00019 #include "btBox2dBox2dCollisionAlgorithm.h" 00020 #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" 00021 #include "BulletCollision/CollisionShapes/btBoxShape.h" 00022 #include "BulletCollision/CollisionDispatch/btCollisionObject.h" 00023 #include "BulletCollision/CollisionDispatch/btBoxBoxDetector.h" 00024 #include "BulletCollision/CollisionShapes/btBox2dShape.h" 00025 00026 #define USE_PERSISTENT_CONTACTS 1 00027 00028 btBox2dBox2dCollisionAlgorithm::btBox2dBox2dCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* obj0,btCollisionObject* obj1) 00029 : btActivatingCollisionAlgorithm(ci,obj0,obj1), 00030 m_ownManifold(false), 00031 m_manifoldPtr(mf) 00032 { 00033 if (!m_manifoldPtr && m_dispatcher->needsCollision(obj0,obj1)) 00034 { 00035 m_manifoldPtr = m_dispatcher->getNewManifold(obj0,obj1); 00036 m_ownManifold = true; 00037 } 00038 } 00039 00040 btBox2dBox2dCollisionAlgorithm::~btBox2dBox2dCollisionAlgorithm() 00041 { 00042 00043 if (m_ownManifold) 00044 { 00045 if (m_manifoldPtr) 00046 m_dispatcher->releaseManifold(m_manifoldPtr); 00047 } 00048 00049 } 00050 00051 00052 void b2CollidePolygons(btManifoldResult* manifold, const btBox2dShape* polyA, const btTransform& xfA, const btBox2dShape* polyB, const btTransform& xfB); 00053 00054 //#include <stdio.h> 00055 void btBox2dBox2dCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) 00056 { 00057 if (!m_manifoldPtr) 00058 return; 00059 00060 btCollisionObject* col0 = body0; 00061 btCollisionObject* col1 = body1; 00062 btBox2dShape* box0 = (btBox2dShape*)col0->getCollisionShape(); 00063 btBox2dShape* box1 = (btBox2dShape*)col1->getCollisionShape(); 00064 00065 resultOut->setPersistentManifold(m_manifoldPtr); 00066 00067 b2CollidePolygons(resultOut,box0,col0->getWorldTransform(),box1,col1->getWorldTransform()); 00068 00069 // refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added 00070 if (m_ownManifold) 00071 { 00072 resultOut->refreshContactPoints(); 00073 } 00074 00075 } 00076 00077 btScalar btBox2dBox2dCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/,btCollisionObject* /*body1*/,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/) 00078 { 00079 //not yet 00080 return 1.f; 00081 } 00082 00083 00084 struct ClipVertex 00085 { 00086 btVector3 v; 00087 int id; 00088 //b2ContactID id; 00089 //b2ContactID id; 00090 }; 00091 00092 #define b2Dot(a,b) (a).dot(b) 00093 #define b2Mul(a,b) (a)*(b) 00094 #define b2MulT(a,b) (a).transpose()*(b) 00095 #define b2Cross(a,b) (a).cross(b) 00096 #define btCrossS(a,s) btVector3(s * a.getY(), -s * a.getX(),0.f) 00097 00098 int b2_maxManifoldPoints =2; 00099 00100 static int ClipSegmentToLine(ClipVertex vOut[2], ClipVertex vIn[2], 00101 const btVector3& normal, btScalar offset) 00102 { 00103 // Start with no output points 00104 int numOut = 0; 00105 00106 // Calculate the distance of end points to the line 00107 btScalar distance0 = b2Dot(normal, vIn[0].v) - offset; 00108 btScalar distance1 = b2Dot(normal, vIn[1].v) - offset; 00109 00110 // If the points are behind the plane 00111 if (distance0 <= 0.0f) vOut[numOut++] = vIn[0]; 00112 if (distance1 <= 0.0f) vOut[numOut++] = vIn[1]; 00113 00114 // If the points are on different sides of the plane 00115 if (distance0 * distance1 < 0.0f) 00116 { 00117 // Find intersection point of edge and plane 00118 btScalar interp = distance0 / (distance0 - distance1); 00119 vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v); 00120 if (distance0 > 0.0f) 00121 { 00122 vOut[numOut].id = vIn[0].id; 00123 } 00124 else 00125 { 00126 vOut[numOut].id = vIn[1].id; 00127 } 00128 ++numOut; 00129 } 00130 00131 return numOut; 00132 } 00133 00134 // Find the separation between poly1 and poly2 for a give edge normal on poly1. 00135 static btScalar EdgeSeparation(const btBox2dShape* poly1, const btTransform& xf1, int edge1, 00136 const btBox2dShape* poly2, const btTransform& xf2) 00137 { 00138 const btVector3* vertices1 = poly1->getVertices(); 00139 const btVector3* normals1 = poly1->getNormals(); 00140 00141 int count2 = poly2->getVertexCount(); 00142 const btVector3* vertices2 = poly2->getVertices(); 00143 00144 btAssert(0 <= edge1 && edge1 < poly1->getVertexCount()); 00145 00146 // Convert normal from poly1's frame into poly2's frame. 00147 btVector3 normal1World = b2Mul(xf1.getBasis(), normals1[edge1]); 00148 btVector3 normal1 = b2MulT(xf2.getBasis(), normal1World); 00149 00150 // Find support vertex on poly2 for -normal. 00151 int index = 0; 00152 btScalar minDot = BT_LARGE_FLOAT; 00153 00154 for (int i = 0; i < count2; ++i) 00155 { 00156 btScalar dot = b2Dot(vertices2[i], normal1); 00157 if (dot < minDot) 00158 { 00159 minDot = dot; 00160 index = i; 00161 } 00162 } 00163 00164 btVector3 v1 = b2Mul(xf1, vertices1[edge1]); 00165 btVector3 v2 = b2Mul(xf2, vertices2[index]); 00166 btScalar separation = b2Dot(v2 - v1, normal1World); 00167 return separation; 00168 } 00169 00170 // Find the max separation between poly1 and poly2 using edge normals from poly1. 00171 static btScalar FindMaxSeparation(int* edgeIndex, 00172 const btBox2dShape* poly1, const btTransform& xf1, 00173 const btBox2dShape* poly2, const btTransform& xf2) 00174 { 00175 int count1 = poly1->getVertexCount(); 00176 const btVector3* normals1 = poly1->getNormals(); 00177 00178 // Vector pointing from the centroid of poly1 to the centroid of poly2. 00179 btVector3 d = b2Mul(xf2, poly2->getCentroid()) - b2Mul(xf1, poly1->getCentroid()); 00180 btVector3 dLocal1 = b2MulT(xf1.getBasis(), d); 00181 00182 // Find edge normal on poly1 that has the largest projection onto d. 00183 int edge = 0; 00184 btScalar maxDot = -BT_LARGE_FLOAT; 00185 for (int i = 0; i < count1; ++i) 00186 { 00187 btScalar dot = b2Dot(normals1[i], dLocal1); 00188 if (dot > maxDot) 00189 { 00190 maxDot = dot; 00191 edge = i; 00192 } 00193 } 00194 00195 // Get the separation for the edge normal. 00196 btScalar s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); 00197 if (s > 0.0f) 00198 { 00199 return s; 00200 } 00201 00202 // Check the separation for the previous edge normal. 00203 int prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; 00204 btScalar sPrev = EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); 00205 if (sPrev > 0.0f) 00206 { 00207 return sPrev; 00208 } 00209 00210 // Check the separation for the next edge normal. 00211 int nextEdge = edge + 1 < count1 ? edge + 1 : 0; 00212 btScalar sNext = EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); 00213 if (sNext > 0.0f) 00214 { 00215 return sNext; 00216 } 00217 00218 // Find the best edge and the search direction. 00219 int bestEdge; 00220 btScalar bestSeparation; 00221 int increment; 00222 if (sPrev > s && sPrev > sNext) 00223 { 00224 increment = -1; 00225 bestEdge = prevEdge; 00226 bestSeparation = sPrev; 00227 } 00228 else if (sNext > s) 00229 { 00230 increment = 1; 00231 bestEdge = nextEdge; 00232 bestSeparation = sNext; 00233 } 00234 else 00235 { 00236 *edgeIndex = edge; 00237 return s; 00238 } 00239 00240 // Perform a local search for the best edge normal. 00241 for ( ; ; ) 00242 { 00243 if (increment == -1) 00244 edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; 00245 else 00246 edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; 00247 00248 s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); 00249 if (s > 0.0f) 00250 { 00251 return s; 00252 } 00253 00254 if (s > bestSeparation) 00255 { 00256 bestEdge = edge; 00257 bestSeparation = s; 00258 } 00259 else 00260 { 00261 break; 00262 } 00263 } 00264 00265 *edgeIndex = bestEdge; 00266 return bestSeparation; 00267 } 00268 00269 static void FindIncidentEdge(ClipVertex c[2], 00270 const btBox2dShape* poly1, const btTransform& xf1, int edge1, 00271 const btBox2dShape* poly2, const btTransform& xf2) 00272 { 00273 const btVector3* normals1 = poly1->getNormals(); 00274 00275 int count2 = poly2->getVertexCount(); 00276 const btVector3* vertices2 = poly2->getVertices(); 00277 const btVector3* normals2 = poly2->getNormals(); 00278 00279 btAssert(0 <= edge1 && edge1 < poly1->getVertexCount()); 00280 00281 // Get the normal of the reference edge in poly2's frame. 00282 btVector3 normal1 = b2MulT(xf2.getBasis(), b2Mul(xf1.getBasis(), normals1[edge1])); 00283 00284 // Find the incident edge on poly2. 00285 int index = 0; 00286 btScalar minDot = BT_LARGE_FLOAT; 00287 for (int i = 0; i < count2; ++i) 00288 { 00289 btScalar dot = b2Dot(normal1, normals2[i]); 00290 if (dot < minDot) 00291 { 00292 minDot = dot; 00293 index = i; 00294 } 00295 } 00296 00297 // Build the clip vertices for the incident edge. 00298 int i1 = index; 00299 int i2 = i1 + 1 < count2 ? i1 + 1 : 0; 00300 00301 c[0].v = b2Mul(xf2, vertices2[i1]); 00302 // c[0].id.features.referenceEdge = (unsigned char)edge1; 00303 // c[0].id.features.incidentEdge = (unsigned char)i1; 00304 // c[0].id.features.incidentVertex = 0; 00305 00306 c[1].v = b2Mul(xf2, vertices2[i2]); 00307 // c[1].id.features.referenceEdge = (unsigned char)edge1; 00308 // c[1].id.features.incidentEdge = (unsigned char)i2; 00309 // c[1].id.features.incidentVertex = 1; 00310 } 00311 00312 // Find edge normal of max separation on A - return if separating axis is found 00313 // Find edge normal of max separation on B - return if separation axis is found 00314 // Choose reference edge as min(minA, minB) 00315 // Find incident edge 00316 // Clip 00317 00318 // The normal points from 1 to 2 00319 void b2CollidePolygons(btManifoldResult* manifold, 00320 const btBox2dShape* polyA, const btTransform& xfA, 00321 const btBox2dShape* polyB, const btTransform& xfB) 00322 { 00323 00324 int edgeA = 0; 00325 btScalar separationA = FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); 00326 if (separationA > 0.0f) 00327 return; 00328 00329 int edgeB = 0; 00330 btScalar separationB = FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); 00331 if (separationB > 0.0f) 00332 return; 00333 00334 const btBox2dShape* poly1; // reference poly 00335 const btBox2dShape* poly2; // incident poly 00336 btTransform xf1, xf2; 00337 int edge1; // reference edge 00338 unsigned char flip; 00339 const btScalar k_relativeTol = 0.98f; 00340 const btScalar k_absoluteTol = 0.001f; 00341 00342 // TODO_ERIN use "radius" of poly for absolute tolerance. 00343 if (separationB > k_relativeTol * separationA + k_absoluteTol) 00344 { 00345 poly1 = polyB; 00346 poly2 = polyA; 00347 xf1 = xfB; 00348 xf2 = xfA; 00349 edge1 = edgeB; 00350 flip = 1; 00351 } 00352 else 00353 { 00354 poly1 = polyA; 00355 poly2 = polyB; 00356 xf1 = xfA; 00357 xf2 = xfB; 00358 edge1 = edgeA; 00359 flip = 0; 00360 } 00361 00362 ClipVertex incidentEdge[2]; 00363 FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); 00364 00365 int count1 = poly1->getVertexCount(); 00366 const btVector3* vertices1 = poly1->getVertices(); 00367 00368 btVector3 v11 = vertices1[edge1]; 00369 btVector3 v12 = edge1 + 1 < count1 ? vertices1[edge1+1] : vertices1[0]; 00370 00371 btVector3 dv = v12 - v11; 00372 btVector3 sideNormal = b2Mul(xf1.getBasis(), v12 - v11); 00373 sideNormal.normalize(); 00374 btVector3 frontNormal = btCrossS(sideNormal, 1.0f); 00375 00376 00377 v11 = b2Mul(xf1, v11); 00378 v12 = b2Mul(xf1, v12); 00379 00380 btScalar frontOffset = b2Dot(frontNormal, v11); 00381 btScalar sideOffset1 = -b2Dot(sideNormal, v11); 00382 btScalar sideOffset2 = b2Dot(sideNormal, v12); 00383 00384 // Clip incident edge against extruded edge1 side edges. 00385 ClipVertex clipPoints1[2]; 00386 clipPoints1[0].v.setValue(0,0,0); 00387 clipPoints1[1].v.setValue(0,0,0); 00388 00389 ClipVertex clipPoints2[2]; 00390 clipPoints2[0].v.setValue(0,0,0); 00391 clipPoints2[1].v.setValue(0,0,0); 00392 00393 00394 int np; 00395 00396 // Clip to box side 1 00397 np = ClipSegmentToLine(clipPoints1, incidentEdge, -sideNormal, sideOffset1); 00398 00399 if (np < 2) 00400 return; 00401 00402 // Clip to negative box side 1 00403 np = ClipSegmentToLine(clipPoints2, clipPoints1, sideNormal, sideOffset2); 00404 00405 if (np < 2) 00406 { 00407 return; 00408 } 00409 00410 // Now clipPoints2 contains the clipped points. 00411 btVector3 manifoldNormal = flip ? -frontNormal : frontNormal; 00412 00413 int pointCount = 0; 00414 for (int i = 0; i < b2_maxManifoldPoints; ++i) 00415 { 00416 btScalar separation = b2Dot(frontNormal, clipPoints2[i].v) - frontOffset; 00417 00418 if (separation <= 0.0f) 00419 { 00420 00421 //b2ManifoldPoint* cp = manifold->points + pointCount; 00422 //btScalar separation = separation; 00423 //cp->localPoint1 = b2MulT(xfA, clipPoints2[i].v); 00424 //cp->localPoint2 = b2MulT(xfB, clipPoints2[i].v); 00425 00426 manifold->addContactPoint(-manifoldNormal,clipPoints2[i].v,separation); 00427 00428 // cp->id = clipPoints2[i].id; 00429 // cp->id.features.flip = flip; 00430 ++pointCount; 00431 } 00432 } 00433 00434 // manifold->pointCount = pointCount;} 00435 }