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