1/*
2* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
3*
4* This software is provided 'as-is', without any express or implied
5* warranty. In no event will the authors be held liable for any damages
6* 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
9* freely, subject to the following restrictions:
10* 1. The origin of this software must not be misrepresented; you must not
11* claim that you wrote the original software. If you use this software
12* in a product, an acknowledgment in the product documentation would be
13* appreciated but is not required.
14* 2. Altered source versions must be plainly marked as such, and must not be
15* misrepresented as being the original software.
16* 3. This notice may not be removed or altered from any source distribution.
17*/
18
19#include <Box2D/Dynamics/Contacts/b2ContactSolver.h>
20
21#include <Box2D/Dynamics/Contacts/b2Contact.h>
22#include <Box2D/Dynamics/b2Body.h>
23#include <Box2D/Dynamics/b2Fixture.h>
24#include <Box2D/Dynamics/b2World.h>
25#include <Box2D/Common/b2StackAllocator.h>
26
27#define B2_DEBUG_SOLVER 0
28
29bool g_blockSolve = true;
30
31struct b2ContactPositionConstraint
32{
33 b2Vec2 localPoints[b2_maxManifoldPoints];
34 b2Vec2 localNormal;
35 b2Vec2 localPoint;
36 int32 indexA;
37 int32 indexB;
38 float32 invMassA, invMassB;
39 b2Vec2 localCenterA, localCenterB;
40 float32 invIA, invIB;
41 b2Manifold::Type type;
42 float32 radiusA, radiusB;
43 int32 pointCount;
44};
45
46b2ContactSolver::b2ContactSolver(b2ContactSolverDef* def)
47{
48 m_step = def->step;
49 m_allocator = def->allocator;
50 m_count = def->count;
51 m_positionConstraints = (b2ContactPositionConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactPositionConstraint));
52 m_velocityConstraints = (b2ContactVelocityConstraint*)m_allocator->Allocate(m_count * sizeof(b2ContactVelocityConstraint));
53 m_positions = def->positions;
54 m_velocities = def->velocities;
55 m_contacts = def->contacts;
56
57 // Initialize position independent portions of the constraints.
58 for (int32 i = 0; i < m_count; ++i)
59 {
60 b2Contact* contact = m_contacts[i];
61
62 b2Fixture* fixtureA = contact->m_fixtureA;
63 b2Fixture* fixtureB = contact->m_fixtureB;
64 b2Shape* shapeA = fixtureA->GetShape();
65 b2Shape* shapeB = fixtureB->GetShape();
66 float32 radiusA = shapeA->m_radius;
67 float32 radiusB = shapeB->m_radius;
68 b2Body* bodyA = fixtureA->GetBody();
69 b2Body* bodyB = fixtureB->GetBody();
70 b2Manifold* manifold = contact->GetManifold();
71
72 int32 pointCount = manifold->pointCount;
73 b2Assert(pointCount > 0);
74
75 b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
76 vc->friction = contact->m_friction;
77 vc->restitution = contact->m_restitution;
78 vc->tangentSpeed = contact->m_tangentSpeed;
79 vc->indexA = bodyA->m_islandIndex;
80 vc->indexB = bodyB->m_islandIndex;
81 vc->invMassA = bodyA->m_invMass;
82 vc->invMassB = bodyB->m_invMass;
83 vc->invIA = bodyA->m_invI;
84 vc->invIB = bodyB->m_invI;
85 vc->contactIndex = i;
86 vc->pointCount = pointCount;
87 vc->K.SetZero();
88 vc->normalMass.SetZero();
89
90 b2ContactPositionConstraint* pc = m_positionConstraints + i;
91 pc->indexA = bodyA->m_islandIndex;
92 pc->indexB = bodyB->m_islandIndex;
93 pc->invMassA = bodyA->m_invMass;
94 pc->invMassB = bodyB->m_invMass;
95 pc->localCenterA = bodyA->m_sweep.localCenter;
96 pc->localCenterB = bodyB->m_sweep.localCenter;
97 pc->invIA = bodyA->m_invI;
98 pc->invIB = bodyB->m_invI;
99 pc->localNormal = manifold->localNormal;
100 pc->localPoint = manifold->localPoint;
101 pc->pointCount = pointCount;
102 pc->radiusA = radiusA;
103 pc->radiusB = radiusB;
104 pc->type = manifold->type;
105
106 for (int32 j = 0; j < pointCount; ++j)
107 {
108 b2ManifoldPoint* cp = manifold->points + j;
109 b2VelocityConstraintPoint* vcp = vc->points + j;
110
111 if (m_step.warmStarting)
112 {
113 vcp->normalImpulse = m_step.dtRatio * cp->normalImpulse;
114 vcp->tangentImpulse = m_step.dtRatio * cp->tangentImpulse;
115 }
116 else
117 {
118 vcp->normalImpulse = 0.0f;
119 vcp->tangentImpulse = 0.0f;
120 }
121
122 vcp->rA.SetZero();
123 vcp->rB.SetZero();
124 vcp->normalMass = 0.0f;
125 vcp->tangentMass = 0.0f;
126 vcp->velocityBias = 0.0f;
127
128 pc->localPoints[j] = cp->localPoint;
129 }
130 }
131}
132
133b2ContactSolver::~b2ContactSolver()
134{
135 m_allocator->Free(m_velocityConstraints);
136 m_allocator->Free(m_positionConstraints);
137}
138
139// Initialize position dependent portions of the velocity constraints.
140void b2ContactSolver::InitializeVelocityConstraints()
141{
142 for (int32 i = 0; i < m_count; ++i)
143 {
144 b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
145 b2ContactPositionConstraint* pc = m_positionConstraints + i;
146
147 float32 radiusA = pc->radiusA;
148 float32 radiusB = pc->radiusB;
149 b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold();
150
151 int32 indexA = vc->indexA;
152 int32 indexB = vc->indexB;
153
154 float32 mA = vc->invMassA;
155 float32 mB = vc->invMassB;
156 float32 iA = vc->invIA;
157 float32 iB = vc->invIB;
158 b2Vec2 localCenterA = pc->localCenterA;
159 b2Vec2 localCenterB = pc->localCenterB;
160
161 b2Vec2 cA = m_positions[indexA].c;
162 float32 aA = m_positions[indexA].a;
163 b2Vec2 vA = m_velocities[indexA].v;
164 float32 wA = m_velocities[indexA].w;
165
166 b2Vec2 cB = m_positions[indexB].c;
167 float32 aB = m_positions[indexB].a;
168 b2Vec2 vB = m_velocities[indexB].v;
169 float32 wB = m_velocities[indexB].w;
170
171 b2Assert(manifold->pointCount > 0);
172
173 b2Transform xfA, xfB;
174 xfA.q.Set(aA);
175 xfB.q.Set(aB);
176 xfA.p = cA - b2Mul(xfA.q, localCenterA);
177 xfB.p = cB - b2Mul(xfB.q, localCenterB);
178
179 b2WorldManifold worldManifold;
180 worldManifold.Initialize(manifold, xfA, radiusA, xfB, radiusB);
181
182 vc->normal = worldManifold.normal;
183
184 int32 pointCount = vc->pointCount;
185 for (int32 j = 0; j < pointCount; ++j)
186 {
187 b2VelocityConstraintPoint* vcp = vc->points + j;
188
189 vcp->rA = worldManifold.points[j] - cA;
190 vcp->rB = worldManifold.points[j] - cB;
191
192 float32 rnA = b2Cross(vcp->rA, vc->normal);
193 float32 rnB = b2Cross(vcp->rB, vc->normal);
194
195 float32 kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
196
197 vcp->normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f;
198
199 b2Vec2 tangent = b2Cross(vc->normal, 1.0f);
200
201 float32 rtA = b2Cross(vcp->rA, tangent);
202 float32 rtB = b2Cross(vcp->rB, tangent);
203
204 float32 kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;
205
206 vcp->tangentMass = kTangent > 0.0f ? 1.0f / kTangent : 0.0f;
207
208 // Setup a velocity bias for restitution.
209 vcp->velocityBias = 0.0f;
210 float32 vRel = b2Dot(vc->normal, vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA));
211 if (vRel < -b2_velocityThreshold)
212 {
213 vcp->velocityBias = -vc->restitution * vRel;
214 }
215 }
216
217 // If we have two points, then prepare the block solver.
218 if (vc->pointCount == 2 && g_blockSolve)
219 {
220 b2VelocityConstraintPoint* vcp1 = vc->points + 0;
221 b2VelocityConstraintPoint* vcp2 = vc->points + 1;
222
223 float32 rn1A = b2Cross(vcp1->rA, vc->normal);
224 float32 rn1B = b2Cross(vcp1->rB, vc->normal);
225 float32 rn2A = b2Cross(vcp2->rA, vc->normal);
226 float32 rn2B = b2Cross(vcp2->rB, vc->normal);
227
228 float32 k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B;
229 float32 k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B;
230 float32 k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B;
231
232 // Ensure a reasonable condition number.
233 const float32 k_maxConditionNumber = 1000.0f;
234 if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12))
235 {
236 // K is safe to invert.
237 vc->K.ex.Set(k11, k12);
238 vc->K.ey.Set(k12, k22);
239 vc->normalMass = vc->K.GetInverse();
240 }
241 else
242 {
243 // The constraints are redundant, just use one.
244 // TODO_ERIN use deepest?
245 vc->pointCount = 1;
246 }
247 }
248 }
249}
250
251void b2ContactSolver::WarmStart()
252{
253 // Warm start.
254 for (int32 i = 0; i < m_count; ++i)
255 {
256 b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
257
258 int32 indexA = vc->indexA;
259 int32 indexB = vc->indexB;
260 float32 mA = vc->invMassA;
261 float32 iA = vc->invIA;
262 float32 mB = vc->invMassB;
263 float32 iB = vc->invIB;
264 int32 pointCount = vc->pointCount;
265
266 b2Vec2 vA = m_velocities[indexA].v;
267 float32 wA = m_velocities[indexA].w;
268 b2Vec2 vB = m_velocities[indexB].v;
269 float32 wB = m_velocities[indexB].w;
270
271 b2Vec2 normal = vc->normal;
272 b2Vec2 tangent = b2Cross(normal, 1.0f);
273
274 for (int32 j = 0; j < pointCount; ++j)
275 {
276 b2VelocityConstraintPoint* vcp = vc->points + j;
277 b2Vec2 P = vcp->normalImpulse * normal + vcp->tangentImpulse * tangent;
278 wA -= iA * b2Cross(vcp->rA, P);
279 vA -= mA * P;
280 wB += iB * b2Cross(vcp->rB, P);
281 vB += mB * P;
282 }
283
284 m_velocities[indexA].v = vA;
285 m_velocities[indexA].w = wA;
286 m_velocities[indexB].v = vB;
287 m_velocities[indexB].w = wB;
288 }
289}
290
291void b2ContactSolver::SolveVelocityConstraints()
292{
293 for (int32 i = 0; i < m_count; ++i)
294 {
295 b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
296
297 int32 indexA = vc->indexA;
298 int32 indexB = vc->indexB;
299 float32 mA = vc->invMassA;
300 float32 iA = vc->invIA;
301 float32 mB = vc->invMassB;
302 float32 iB = vc->invIB;
303 int32 pointCount = vc->pointCount;
304
305 b2Vec2 vA = m_velocities[indexA].v;
306 float32 wA = m_velocities[indexA].w;
307 b2Vec2 vB = m_velocities[indexB].v;
308 float32 wB = m_velocities[indexB].w;
309
310 b2Vec2 normal = vc->normal;
311 b2Vec2 tangent = b2Cross(normal, 1.0f);
312 float32 friction = vc->friction;
313
314 b2Assert(pointCount == 1 || pointCount == 2);
315
316 // Solve tangent constraints first because non-penetration is more important
317 // than friction.
318 for (int32 j = 0; j < pointCount; ++j)
319 {
320 b2VelocityConstraintPoint* vcp = vc->points + j;
321
322 // Relative velocity at contact
323 b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA);
324
325 // Compute tangent force
326 float32 vt = b2Dot(dv, tangent) - vc->tangentSpeed;
327 float32 lambda = vcp->tangentMass * (-vt);
328
329 // b2Clamp the accumulated force
330 float32 maxFriction = friction * vcp->normalImpulse;
331 float32 newImpulse = b2Clamp(vcp->tangentImpulse + lambda, -maxFriction, maxFriction);
332 lambda = newImpulse - vcp->tangentImpulse;
333 vcp->tangentImpulse = newImpulse;
334
335 // Apply contact impulse
336 b2Vec2 P = lambda * tangent;
337
338 vA -= mA * P;
339 wA -= iA * b2Cross(vcp->rA, P);
340
341 vB += mB * P;
342 wB += iB * b2Cross(vcp->rB, P);
343 }
344
345 // Solve normal constraints
346 if (pointCount == 1 || g_blockSolve == false)
347 {
348 for (int32 i = 0; i < pointCount; ++i)
349 {
350 b2VelocityConstraintPoint* vcp = vc->points + i;
351
352 // Relative velocity at contact
353 b2Vec2 dv = vB + b2Cross(wB, vcp->rB) - vA - b2Cross(wA, vcp->rA);
354
355 // Compute normal impulse
356 float32 vn = b2Dot(dv, normal);
357 float32 lambda = -vcp->normalMass * (vn - vcp->velocityBias);
358
359 // b2Clamp the accumulated impulse
360 float32 newImpulse = b2Max(vcp->normalImpulse + lambda, 0.0f);
361 lambda = newImpulse - vcp->normalImpulse;
362 vcp->normalImpulse = newImpulse;
363
364 // Apply contact impulse
365 b2Vec2 P = lambda * normal;
366 vA -= mA * P;
367 wA -= iA * b2Cross(vcp->rA, P);
368
369 vB += mB * P;
370 wB += iB * b2Cross(vcp->rB, P);
371 }
372 }
373 else
374 {
375 // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite).
376 // Build the mini LCP for this contact patch
377 //
378 // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2
379 //
380 // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n )
381 // b = vn0 - velocityBias
382 //
383 // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i
384 // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases
385 // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid
386 // solution that satisfies the problem is chosen.
387 //
388 // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires
389 // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i).
390 //
391 // Substitute:
392 //
393 // x = a + d
394 //
395 // a := old total impulse
396 // x := new total impulse
397 // d := incremental impulse
398 //
399 // For the current iteration we extend the formula for the incremental impulse
400 // to compute the new total impulse:
401 //
402 // vn = A * d + b
403 // = A * (x - a) + b
404 // = A * x + b - A * a
405 // = A * x + b'
406 // b' = b - A * a;
407
408 b2VelocityConstraintPoint* cp1 = vc->points + 0;
409 b2VelocityConstraintPoint* cp2 = vc->points + 1;
410
411 b2Vec2 a(cp1->normalImpulse, cp2->normalImpulse);
412 b2Assert(a.x >= 0.0f && a.y >= 0.0f);
413
414 // Relative velocity at contact
415 b2Vec2 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
416 b2Vec2 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
417
418 // Compute normal velocity
419 float32 vn1 = b2Dot(dv1, normal);
420 float32 vn2 = b2Dot(dv2, normal);
421
422 b2Vec2 b;
423 b.x = vn1 - cp1->velocityBias;
424 b.y = vn2 - cp2->velocityBias;
425
426 // Compute b'
427 b -= b2Mul(vc->K, a);
428
429 const float32 k_errorTol = 1e-3f;
430 B2_NOT_USED(k_errorTol);
431
432 for (;;)
433 {
434 //
435 // Case 1: vn = 0
436 //
437 // 0 = A * x + b'
438 //
439 // Solve for x:
440 //
441 // x = - inv(A) * b'
442 //
443 b2Vec2 x = - b2Mul(vc->normalMass, b);
444
445 if (x.x >= 0.0f && x.y >= 0.0f)
446 {
447 // Get the incremental impulse
448 b2Vec2 d = x - a;
449
450 // Apply incremental impulse
451 b2Vec2 P1 = d.x * normal;
452 b2Vec2 P2 = d.y * normal;
453 vA -= mA * (P1 + P2);
454 wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
455
456 vB += mB * (P1 + P2);
457 wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
458
459 // Accumulate
460 cp1->normalImpulse = x.x;
461 cp2->normalImpulse = x.y;
462
463#if B2_DEBUG_SOLVER == 1
464 // Postconditions
465 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
466 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
467
468 // Compute normal velocity
469 vn1 = b2Dot(dv1, normal);
470 vn2 = b2Dot(dv2, normal);
471
472 b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);
473 b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);
474#endif
475 break;
476 }
477
478 //
479 // Case 2: vn1 = 0 and x2 = 0
480 //
481 // 0 = a11 * x1 + a12 * 0 + b1'
482 // vn2 = a21 * x1 + a22 * 0 + b2'
483 //
484 x.x = - cp1->normalMass * b.x;
485 x.y = 0.0f;
486 vn1 = 0.0f;
487 vn2 = vc->K.ex.y * x.x + b.y;
488
489 if (x.x >= 0.0f && vn2 >= 0.0f)
490 {
491 // Get the incremental impulse
492 b2Vec2 d = x - a;
493
494 // Apply incremental impulse
495 b2Vec2 P1 = d.x * normal;
496 b2Vec2 P2 = d.y * normal;
497 vA -= mA * (P1 + P2);
498 wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
499
500 vB += mB * (P1 + P2);
501 wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
502
503 // Accumulate
504 cp1->normalImpulse = x.x;
505 cp2->normalImpulse = x.y;
506
507#if B2_DEBUG_SOLVER == 1
508 // Postconditions
509 dv1 = vB + b2Cross(wB, cp1->rB) - vA - b2Cross(wA, cp1->rA);
510
511 // Compute normal velocity
512 vn1 = b2Dot(dv1, normal);
513
514 b2Assert(b2Abs(vn1 - cp1->velocityBias) < k_errorTol);
515#endif
516 break;
517 }
518
519
520 //
521 // Case 3: vn2 = 0 and x1 = 0
522 //
523 // vn1 = a11 * 0 + a12 * x2 + b1'
524 // 0 = a21 * 0 + a22 * x2 + b2'
525 //
526 x.x = 0.0f;
527 x.y = - cp2->normalMass * b.y;
528 vn1 = vc->K.ey.x * x.y + b.x;
529 vn2 = 0.0f;
530
531 if (x.y >= 0.0f && vn1 >= 0.0f)
532 {
533 // Resubstitute for the incremental impulse
534 b2Vec2 d = x - a;
535
536 // Apply incremental impulse
537 b2Vec2 P1 = d.x * normal;
538 b2Vec2 P2 = d.y * normal;
539 vA -= mA * (P1 + P2);
540 wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
541
542 vB += mB * (P1 + P2);
543 wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
544
545 // Accumulate
546 cp1->normalImpulse = x.x;
547 cp2->normalImpulse = x.y;
548
549#if B2_DEBUG_SOLVER == 1
550 // Postconditions
551 dv2 = vB + b2Cross(wB, cp2->rB) - vA - b2Cross(wA, cp2->rA);
552
553 // Compute normal velocity
554 vn2 = b2Dot(dv2, normal);
555
556 b2Assert(b2Abs(vn2 - cp2->velocityBias) < k_errorTol);
557#endif
558 break;
559 }
560
561 //
562 // Case 4: x1 = 0 and x2 = 0
563 //
564 // vn1 = b1
565 // vn2 = b2;
566 x.x = 0.0f;
567 x.y = 0.0f;
568 vn1 = b.x;
569 vn2 = b.y;
570
571 if (vn1 >= 0.0f && vn2 >= 0.0f )
572 {
573 // Resubstitute for the incremental impulse
574 b2Vec2 d = x - a;
575
576 // Apply incremental impulse
577 b2Vec2 P1 = d.x * normal;
578 b2Vec2 P2 = d.y * normal;
579 vA -= mA * (P1 + P2);
580 wA -= iA * (b2Cross(cp1->rA, P1) + b2Cross(cp2->rA, P2));
581
582 vB += mB * (P1 + P2);
583 wB += iB * (b2Cross(cp1->rB, P1) + b2Cross(cp2->rB, P2));
584
585 // Accumulate
586 cp1->normalImpulse = x.x;
587 cp2->normalImpulse = x.y;
588
589 break;
590 }
591
592 // No solution, give up. This is hit sometimes, but it doesn't seem to matter.
593 break;
594 }
595 }
596
597 m_velocities[indexA].v = vA;
598 m_velocities[indexA].w = wA;
599 m_velocities[indexB].v = vB;
600 m_velocities[indexB].w = wB;
601 }
602}
603
604void b2ContactSolver::StoreImpulses()
605{
606 for (int32 i = 0; i < m_count; ++i)
607 {
608 b2ContactVelocityConstraint* vc = m_velocityConstraints + i;
609 b2Manifold* manifold = m_contacts[vc->contactIndex]->GetManifold();
610
611 for (int32 j = 0; j < vc->pointCount; ++j)
612 {
613 manifold->points[j].normalImpulse = vc->points[j].normalImpulse;
614 manifold->points[j].tangentImpulse = vc->points[j].tangentImpulse;
615 }
616 }
617}
618
619struct b2PositionSolverManifold
620{
621 void Initialize(b2ContactPositionConstraint* pc, const b2Transform& xfA, const b2Transform& xfB, int32 index)
622 {
623 b2Assert(pc->pointCount > 0);
624
625 switch (pc->type)
626 {
627 case b2Manifold::e_circles:
628 {
629 b2Vec2 pointA = b2Mul(xfA, pc->localPoint);
630 b2Vec2 pointB = b2Mul(xfB, pc->localPoints[0]);
631 normal = pointB - pointA;
632 normal.Normalize();
633 point = 0.5f * (pointA + pointB);
634 separation = b2Dot(pointB - pointA, normal) - pc->radiusA - pc->radiusB;
635 }
636 break;
637
638 case b2Manifold::e_faceA:
639 {
640 normal = b2Mul(xfA.q, pc->localNormal);
641 b2Vec2 planePoint = b2Mul(xfA, pc->localPoint);
642
643 b2Vec2 clipPoint = b2Mul(xfB, pc->localPoints[index]);
644 separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB;
645 point = clipPoint;
646 }
647 break;
648
649 case b2Manifold::e_faceB:
650 {
651 normal = b2Mul(xfB.q, pc->localNormal);
652 b2Vec2 planePoint = b2Mul(xfB, pc->localPoint);
653
654 b2Vec2 clipPoint = b2Mul(xfA, pc->localPoints[index]);
655 separation = b2Dot(clipPoint - planePoint, normal) - pc->radiusA - pc->radiusB;
656 point = clipPoint;
657
658 // Ensure normal points from A to B
659 normal = -normal;
660 }
661 break;
662 }
663 }
664
665 b2Vec2 normal;
666 b2Vec2 point;
667 float32 separation;
668};
669
670// Sequential solver.
671bool b2ContactSolver::SolvePositionConstraints()
672{
673 float32 minSeparation = 0.0f;
674
675 for (int32 i = 0; i < m_count; ++i)
676 {
677 b2ContactPositionConstraint* pc = m_positionConstraints + i;
678
679 int32 indexA = pc->indexA;
680 int32 indexB = pc->indexB;
681 b2Vec2 localCenterA = pc->localCenterA;
682 float32 mA = pc->invMassA;
683 float32 iA = pc->invIA;
684 b2Vec2 localCenterB = pc->localCenterB;
685 float32 mB = pc->invMassB;
686 float32 iB = pc->invIB;
687 int32 pointCount = pc->pointCount;
688
689 b2Vec2 cA = m_positions[indexA].c;
690 float32 aA = m_positions[indexA].a;
691
692 b2Vec2 cB = m_positions[indexB].c;
693 float32 aB = m_positions[indexB].a;
694
695 // Solve normal constraints
696 for (int32 j = 0; j < pointCount; ++j)
697 {
698 b2Transform xfA, xfB;
699 xfA.q.Set(aA);
700 xfB.q.Set(aB);
701 xfA.p = cA - b2Mul(xfA.q, localCenterA);
702 xfB.p = cB - b2Mul(xfB.q, localCenterB);
703
704 b2PositionSolverManifold psm;
705 psm.Initialize(pc, xfA, xfB, j);
706 b2Vec2 normal = psm.normal;
707
708 b2Vec2 point = psm.point;
709 float32 separation = psm.separation;
710
711 b2Vec2 rA = point - cA;
712 b2Vec2 rB = point - cB;
713
714 // Track max constraint error.
715 minSeparation = b2Min(minSeparation, separation);
716
717 // Prevent large corrections and allow slop.
718 float32 C = b2Clamp(b2_baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);
719
720 // Compute the effective mass.
721 float32 rnA = b2Cross(rA, normal);
722 float32 rnB = b2Cross(rB, normal);
723 float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
724
725 // Compute normal impulse
726 float32 impulse = K > 0.0f ? - C / K : 0.0f;
727
728 b2Vec2 P = impulse * normal;
729
730 cA -= mA * P;
731 aA -= iA * b2Cross(rA, P);
732
733 cB += mB * P;
734 aB += iB * b2Cross(rB, P);
735 }
736
737 m_positions[indexA].c = cA;
738 m_positions[indexA].a = aA;
739
740 m_positions[indexB].c = cB;
741 m_positions[indexB].a = aB;
742 }
743
744 // We can't expect minSpeparation >= -b2_linearSlop because we don't
745 // push the separation above -b2_linearSlop.
746 return minSeparation >= -3.0f * b2_linearSlop;
747}
748
749// Sequential position solver for position constraints.
750bool b2ContactSolver::SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB)
751{
752 float32 minSeparation = 0.0f;
753
754 for (int32 i = 0; i < m_count; ++i)
755 {
756 b2ContactPositionConstraint* pc = m_positionConstraints + i;
757
758 int32 indexA = pc->indexA;
759 int32 indexB = pc->indexB;
760 b2Vec2 localCenterA = pc->localCenterA;
761 b2Vec2 localCenterB = pc->localCenterB;
762 int32 pointCount = pc->pointCount;
763
764 float32 mA = 0.0f;
765 float32 iA = 0.0f;
766 if (indexA == toiIndexA || indexA == toiIndexB)
767 {
768 mA = pc->invMassA;
769 iA = pc->invIA;
770 }
771
772 float32 mB = 0.0f;
773 float32 iB = 0.;
774 if (indexB == toiIndexA || indexB == toiIndexB)
775 {
776 mB = pc->invMassB;
777 iB = pc->invIB;
778 }
779
780 b2Vec2 cA = m_positions[indexA].c;
781 float32 aA = m_positions[indexA].a;
782
783 b2Vec2 cB = m_positions[indexB].c;
784 float32 aB = m_positions[indexB].a;
785
786 // Solve normal constraints
787 for (int32 j = 0; j < pointCount; ++j)
788 {
789 b2Transform xfA, xfB;
790 xfA.q.Set(aA);
791 xfB.q.Set(aB);
792 xfA.p = cA - b2Mul(xfA.q, localCenterA);
793 xfB.p = cB - b2Mul(xfB.q, localCenterB);
794
795 b2PositionSolverManifold psm;
796 psm.Initialize(pc, xfA, xfB, j);
797 b2Vec2 normal = psm.normal;
798
799 b2Vec2 point = psm.point;
800 float32 separation = psm.separation;
801
802 b2Vec2 rA = point - cA;
803 b2Vec2 rB = point - cB;
804
805 // Track max constraint error.
806 minSeparation = b2Min(minSeparation, separation);
807
808 // Prevent large corrections and allow slop.
809 float32 C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0.0f);
810
811 // Compute the effective mass.
812 float32 rnA = b2Cross(rA, normal);
813 float32 rnB = b2Cross(rB, normal);
814 float32 K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
815
816 // Compute normal impulse
817 float32 impulse = K > 0.0f ? - C / K : 0.0f;
818
819 b2Vec2 P = impulse * normal;
820
821 cA -= mA * P;
822 aA -= iA * b2Cross(rA, P);
823
824 cB += mB * P;
825 aB += iB * b2Cross(rB, P);
826 }
827
828 m_positions[indexA].c = cA;
829 m_positions[indexA].a = aA;
830
831 m_positions[indexB].c = cB;
832 m_positions[indexB].a = aB;
833 }
834
835 // We can't expect minSpeparation >= -b2_linearSlop because we don't
836 // push the separation above -b2_linearSlop.
837 return minSeparation >= -1.5f * b2_linearSlop;
838}
839