2 Bullet Continuous Collision Detection and Physics Library
3 * The b2CollidePolygons routines are Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
11 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
16 ///btBox2dBox2dCollisionAlgorithm, with modified b2CollidePolygons routines from the Box2D library.
17 ///The modifications include: switching from b2Vec to btVector3, redefinition of b2Dot, b2Cross
19 #include "btBox2dBox2dCollisionAlgorithm.h"
20 #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
21 #include "BulletCollision/CollisionShapes/btBoxShape.h"
22 #include "BulletCollision/CollisionDispatch/btCollisionObject.h"
23 #include "BulletCollision/CollisionDispatch/btBoxBoxDetector.h"
24 #include "BulletCollision/CollisionShapes/btBox2dShape.h"
25 #include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
27 #define USE_PERSISTENT_CONTACTS 1
29 btBox2dBox2dCollisionAlgorithm::btBox2dBox2dCollisionAlgorithm(btPersistentManifold* mf, const btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* obj0Wrap, const btCollisionObjectWrapper* obj1Wrap)
30 : btActivatingCollisionAlgorithm(ci, obj0Wrap, obj1Wrap),
34 if (!m_manifoldPtr && m_dispatcher->needsCollision(obj0Wrap->getCollisionObject(), obj1Wrap->getCollisionObject()))
36 m_manifoldPtr = m_dispatcher->getNewManifold(obj0Wrap->getCollisionObject(), obj1Wrap->getCollisionObject());
41 btBox2dBox2dCollisionAlgorithm::~btBox2dBox2dCollisionAlgorithm()
46 m_dispatcher->releaseManifold(m_manifoldPtr);
50 void b2CollidePolygons(btManifoldResult* manifold, const btBox2dShape* polyA, const btTransform& xfA, const btBox2dShape* polyB, const btTransform& xfB);
53 void btBox2dBox2dCollisionAlgorithm::processCollision(const btCollisionObjectWrapper* body0Wrap, const btCollisionObjectWrapper* body1Wrap, const btDispatcherInfo& dispatchInfo, btManifoldResult* resultOut)
58 const btBox2dShape* box0 = (const btBox2dShape*)body0Wrap->getCollisionShape();
59 const btBox2dShape* box1 = (const btBox2dShape*)body1Wrap->getCollisionShape();
61 resultOut->setPersistentManifold(m_manifoldPtr);
63 b2CollidePolygons(resultOut, box0, body0Wrap->getWorldTransform(), box1, body1Wrap->getWorldTransform());
65 // refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added
68 resultOut->refreshContactPoints();
72 btScalar btBox2dBox2dCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/, btCollisionObject* /*body1*/, const btDispatcherInfo& /*dispatchInfo*/, btManifoldResult* /*resultOut*/)
86 #define b2Dot(a, b) (a).dot(b)
87 #define b2Mul(a, b) (a) * (b)
88 #define b2MulT(a, b) (a).transpose() * (b)
89 #define b2Cross(a, b) (a).cross(b)
90 #define btCrossS(a, s) btVector3(s* a.getY(), -s* a.getX(), 0.f)
92 int b2_maxManifoldPoints = 2;
94 static int ClipSegmentToLine(ClipVertex vOut[2], ClipVertex vIn[2],
95 const btVector3& normal, btScalar offset)
97 // Start with no output points
100 // Calculate the distance of end points to the line
101 btScalar distance0 = b2Dot(normal, vIn[0].v) - offset;
102 btScalar distance1 = b2Dot(normal, vIn[1].v) - offset;
104 // If the points are behind the plane
105 if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
106 if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
108 // If the points are on different sides of the plane
109 if (distance0 * distance1 < 0.0f)
111 // Find intersection point of edge and plane
112 btScalar interp = distance0 / (distance0 - distance1);
113 vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
114 if (distance0 > 0.0f)
116 vOut[numOut].id = vIn[0].id;
120 vOut[numOut].id = vIn[1].id;
128 // Find the separation between poly1 and poly2 for a give edge normal on poly1.
129 static btScalar EdgeSeparation(const btBox2dShape* poly1, const btTransform& xf1, int edge1,
130 const btBox2dShape* poly2, const btTransform& xf2)
132 const btVector3* vertices1 = poly1->getVertices();
133 const btVector3* normals1 = poly1->getNormals();
135 int count2 = poly2->getVertexCount();
136 const btVector3* vertices2 = poly2->getVertices();
138 btAssert(0 <= edge1 && edge1 < poly1->getVertexCount());
140 // Convert normal from poly1's frame into poly2's frame.
141 btVector3 normal1World = b2Mul(xf1.getBasis(), normals1[edge1]);
142 btVector3 normal1 = b2MulT(xf2.getBasis(), normal1World);
144 // Find support vertex on poly2 for -normal.
146 btScalar minDot = BT_LARGE_FLOAT;
149 index = (int)normal1.minDot(vertices2, count2, minDot);
151 btVector3 v1 = b2Mul(xf1, vertices1[edge1]);
152 btVector3 v2 = b2Mul(xf2, vertices2[index]);
153 btScalar separation = b2Dot(v2 - v1, normal1World);
157 // Find the max separation between poly1 and poly2 using edge normals from poly1.
158 static btScalar FindMaxSeparation(int* edgeIndex,
159 const btBox2dShape* poly1, const btTransform& xf1,
160 const btBox2dShape* poly2, const btTransform& xf2)
162 int count1 = poly1->getVertexCount();
163 const btVector3* normals1 = poly1->getNormals();
165 // Vector pointing from the centroid of poly1 to the centroid of poly2.
166 btVector3 d = b2Mul(xf2, poly2->getCentroid()) - b2Mul(xf1, poly1->getCentroid());
167 btVector3 dLocal1 = b2MulT(xf1.getBasis(), d);
169 // Find edge normal on poly1 that has the largest projection onto d.
173 edge = (int)dLocal1.maxDot(normals1, count1, maxDot);
175 // Get the separation for the edge normal.
176 btScalar s = EdgeSeparation(poly1, xf1, edge, poly2, xf2);
182 // Check the separation for the previous edge normal.
183 int prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
184 btScalar sPrev = EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2);
190 // Check the separation for the next edge normal.
191 int nextEdge = edge + 1 < count1 ? edge + 1 : 0;
192 btScalar sNext = EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2);
198 // Find the best edge and the search direction.
200 btScalar bestSeparation;
202 if (sPrev > s && sPrev > sNext)
206 bestSeparation = sPrev;
212 bestSeparation = sNext;
220 // Perform a local search for the best edge normal.
224 edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
226 edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
228 s = EdgeSeparation(poly1, xf1, edge, poly2, xf2);
234 if (s > bestSeparation)
245 *edgeIndex = bestEdge;
246 return bestSeparation;
249 static void FindIncidentEdge(ClipVertex c[2],
250 const btBox2dShape* poly1, const btTransform& xf1, int edge1,
251 const btBox2dShape* poly2, const btTransform& xf2)
253 const btVector3* normals1 = poly1->getNormals();
255 int count2 = poly2->getVertexCount();
256 const btVector3* vertices2 = poly2->getVertices();
257 const btVector3* normals2 = poly2->getNormals();
259 btAssert(0 <= edge1 && edge1 < poly1->getVertexCount());
261 // Get the normal of the reference edge in poly2's frame.
262 btVector3 normal1 = b2MulT(xf2.getBasis(), b2Mul(xf1.getBasis(), normals1[edge1]));
264 // Find the incident edge on poly2.
266 btScalar minDot = BT_LARGE_FLOAT;
267 for (int i = 0; i < count2; ++i)
269 btScalar dot = b2Dot(normal1, normals2[i]);
277 // Build the clip vertices for the incident edge.
279 int i2 = i1 + 1 < count2 ? i1 + 1 : 0;
281 c[0].v = b2Mul(xf2, vertices2[i1]);
282 // c[0].id.features.referenceEdge = (unsigned char)edge1;
283 // c[0].id.features.incidentEdge = (unsigned char)i1;
284 // c[0].id.features.incidentVertex = 0;
286 c[1].v = b2Mul(xf2, vertices2[i2]);
287 // c[1].id.features.referenceEdge = (unsigned char)edge1;
288 // c[1].id.features.incidentEdge = (unsigned char)i2;
289 // c[1].id.features.incidentVertex = 1;
292 // Find edge normal of max separation on A - return if separating axis is found
293 // Find edge normal of max separation on B - return if separation axis is found
294 // Choose reference edge as min(minA, minB)
295 // Find incident edge
298 // The normal points from 1 to 2
299 void b2CollidePolygons(btManifoldResult* manifold,
300 const btBox2dShape* polyA, const btTransform& xfA,
301 const btBox2dShape* polyB, const btTransform& xfB)
304 btScalar separationA = FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);
305 if (separationA > 0.0f)
309 btScalar separationB = FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);
310 if (separationB > 0.0f)
313 const btBox2dShape* poly1; // reference poly
314 const btBox2dShape* poly2; // incident poly
315 btTransform xf1, xf2;
316 int edge1; // reference edge
318 const btScalar k_relativeTol = 0.98f;
319 const btScalar k_absoluteTol = 0.001f;
321 // TODO_ERIN use "radius" of poly for absolute tolerance.
322 if (separationB > k_relativeTol * separationA + k_absoluteTol)
341 ClipVertex incidentEdge[2];
342 FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);
344 int count1 = poly1->getVertexCount();
345 const btVector3* vertices1 = poly1->getVertices();
347 btVector3 v11 = vertices1[edge1];
348 btVector3 v12 = edge1 + 1 < count1 ? vertices1[edge1 + 1] : vertices1[0];
350 //btVector3 dv = v12 - v11;
351 btVector3 sideNormal = b2Mul(xf1.getBasis(), v12 - v11);
352 sideNormal.normalize();
353 btVector3 frontNormal = btCrossS(sideNormal, 1.0f);
355 v11 = b2Mul(xf1, v11);
356 v12 = b2Mul(xf1, v12);
358 btScalar frontOffset = b2Dot(frontNormal, v11);
359 btScalar sideOffset1 = -b2Dot(sideNormal, v11);
360 btScalar sideOffset2 = b2Dot(sideNormal, v12);
362 // Clip incident edge against extruded edge1 side edges.
363 ClipVertex clipPoints1[2];
364 clipPoints1[0].v.setValue(0, 0, 0);
365 clipPoints1[1].v.setValue(0, 0, 0);
367 ClipVertex clipPoints2[2];
368 clipPoints2[0].v.setValue(0, 0, 0);
369 clipPoints2[1].v.setValue(0, 0, 0);
373 // Clip to box side 1
374 np = ClipSegmentToLine(clipPoints1, incidentEdge, -sideNormal, sideOffset1);
379 // Clip to negative box side 1
380 np = ClipSegmentToLine(clipPoints2, clipPoints1, sideNormal, sideOffset2);
387 // Now clipPoints2 contains the clipped points.
388 btVector3 manifoldNormal = flip ? -frontNormal : frontNormal;
391 for (int i = 0; i < b2_maxManifoldPoints; ++i)
393 btScalar separation = b2Dot(frontNormal, clipPoints2[i].v) - frontOffset;
395 if (separation <= 0.0f)
397 //b2ManifoldPoint* cp = manifold->points + pointCount;
398 //btScalar separation = separation;
399 //cp->localPoint1 = b2MulT(xfA, clipPoints2[i].v);
400 //cp->localPoint2 = b2MulT(xfB, clipPoints2[i].v);
402 manifold->addContactPoint(-manifoldNormal, clipPoints2[i].v, separation);
404 // cp->id = clipPoints2[i].id;
405 // cp->id.features.flip = flip;
410 // manifold->pointCount = pointCount;}