Blender V2.61 - r43446

btBox2dBox2dCollisionAlgorithm.cpp

Go to the documentation of this file.
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 }