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 }

Generated on Mon Feb 15 22:17:02 2010 for Bullet Collision Detection & Physics Library by  doxygen 1.6.1