FarseerPhysics.Dynamics.Contacts.ContactSolver.solveVelocityConstraints C# (CSharp) Method

solveVelocityConstraints() public method

public solveVelocityConstraints ( ) : void
return void
		public void solveVelocityConstraints()
		{
			for( int i = 0; i < _count; ++i )
			{
				ContactVelocityConstraint vc = _velocityConstraints[i];

				int indexA = vc.indexA;
				int indexB = vc.indexB;
				float mA = vc.invMassA;
				float iA = vc.invIA;
				float mB = vc.invMassB;
				float iB = vc.invIB;
				int pointCount = vc.pointCount;

				Vector2 vA = _velocities[indexA].v;
				float wA = _velocities[indexA].w;
				Vector2 vB = _velocities[indexB].v;
				float wB = _velocities[indexB].w;

				Vector2 normal = vc.normal;
				Vector2 tangent = MathUtils.cross( normal, 1.0f );
				float friction = vc.friction;

				Debug.Assert( pointCount == 1 || pointCount == 2 );

				// Solve tangent constraints first because non-penetration is more important
				// than friction.
				for( int j = 0; j < pointCount; ++j )
				{
					VelocityConstraintPoint vcp = vc.points[j];

					// Relative velocity at contact
					Vector2 dv = vB + MathUtils.cross( wB, vcp.rB ) - vA - MathUtils.cross( wA, vcp.rA );

					// Compute tangent force
					float vt = Vector2.Dot( dv, tangent ) - vc.tangentSpeed;
					float lambda = vcp.tangentMass * ( -vt );

					// b2Clamp the accumulated force
					float maxFriction = friction * vcp.normalImpulse;
					float newImpulse = MathUtils.clamp( vcp.tangentImpulse + lambda, -maxFriction, maxFriction );
					lambda = newImpulse - vcp.tangentImpulse;
					vcp.tangentImpulse = newImpulse;

					// Apply contact impulse
					Vector2 P = lambda * tangent;

					vA -= mA * P;
					wA -= iA * MathUtils.cross( vcp.rA, P );

					vB += mB * P;
					wB += iB * MathUtils.cross( vcp.rB, P );
				}

				// Solve normal constraints
				if( vc.pointCount == 1 )
				{
					VelocityConstraintPoint vcp = vc.points[0];

					// Relative velocity at contact
					Vector2 dv = vB + MathUtils.cross( wB, vcp.rB ) - vA - MathUtils.cross( wA, vcp.rA );

					// Compute normal impulse
					float vn = Vector2.Dot( dv, normal );
					float lambda = -vcp.normalMass * ( vn - vcp.velocityBias );

					// b2Clamp the accumulated impulse
					float newImpulse = Math.Max( vcp.normalImpulse + lambda, 0.0f );
					lambda = newImpulse - vcp.normalImpulse;
					vcp.normalImpulse = newImpulse;

					// Apply contact impulse
					Vector2 P = lambda * normal;
					vA -= mA * P;
					wA -= iA * MathUtils.cross( vcp.rA, P );

					vB += mB * P;
					wB += iB * MathUtils.cross( vcp.rB, P );
				}
				else
				{
					// Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite).
					// Build the mini LCP for this contact patch
					//
					// vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2
					//
					// A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n )
					// b = vn0 - velocityBias
					//
					// The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i
					// implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases
					// 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
					// solution that satisfies the problem is chosen.
					// 
					// In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires
					// that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i).
					//
					// Substitute:
					// 
					// x = a + d
					// 
					// a := old total impulse
					// x := new total impulse
					// d := incremental impulse 
					//
					// For the current iteration we extend the formula for the incremental impulse
					// to compute the new total impulse:
					//
					// vn = A * d + b
					//    = A * (x - a) + b
					//    = A * x + b - A * a
					//    = A * x + b'
					// b' = b - A * a;

					VelocityConstraintPoint cp1 = vc.points[0];
					VelocityConstraintPoint cp2 = vc.points[1];

					Vector2 a = new Vector2( cp1.normalImpulse, cp2.normalImpulse );
					Debug.Assert( a.X >= 0.0f && a.Y >= 0.0f );

					// Relative velocity at contact
					Vector2 dv1 = vB + MathUtils.cross( wB, cp1.rB ) - vA - MathUtils.cross( wA, cp1.rA );
					Vector2 dv2 = vB + MathUtils.cross( wB, cp2.rB ) - vA - MathUtils.cross( wA, cp2.rA );

					// Compute normal velocity
					float vn1 = Vector2.Dot( dv1, normal );
					float vn2 = Vector2.Dot( dv2, normal );

					Vector2 b = new Vector2();
					b.X = vn1 - cp1.velocityBias;
					b.Y = vn2 - cp2.velocityBias;

					// Compute b'
					b -= MathUtils.mul( ref vc.K, a );

					const float k_errorTol = 1e-3f;
					//B2_NOT_USED(k_errorTol);

					for( ;;)
					{
						//
						// Case 1: vn = 0
						//
						// 0 = A * x + b'
						//
						// Solve for x:
						//
						// x = - inv(A) * b'
						//
						Vector2 x = -MathUtils.mul( ref vc.normalMass, b );

						if( x.X >= 0.0f && x.Y >= 0.0f )
						{
							// Get the incremental impulse
							Vector2 d = x - a;

							// Apply incremental impulse
							Vector2 P1 = d.X * normal;
							Vector2 P2 = d.Y * normal;
							vA -= mA * ( P1 + P2 );
							wA -= iA * ( MathUtils.cross( cp1.rA, P1 ) + MathUtils.cross( cp2.rA, P2 ) );

							vB += mB * ( P1 + P2 );
							wB += iB * ( MathUtils.cross( cp1.rB, P1 ) + MathUtils.cross( cp2.rB, P2 ) );

							// Accumulate
							cp1.normalImpulse = x.X;
							cp2.normalImpulse = x.Y;

#if B2_DEBUG_SOLVER
					// Postconditions
					dv1 = vB + MathUtils.Cross(wB, cp1.rB) - vA - MathUtils.Cross(wA, cp1.rA);
					dv2 = vB + MathUtils.Cross(wB, cp2.rB) - vA - MathUtils.Cross(wA, cp2.rA);

					// Compute normal velocity
					vn1 = Vector2.Dot(dv1, normal);
					vn2 = Vector2.Dot(dv2, normal);

					b2Assert(b2Abs(vn1 - cp1.velocityBias) < k_errorTol);
					b2Assert(b2Abs(vn2 - cp2.velocityBias) < k_errorTol);
#endif
							break;
						}

						//
						// Case 2: vn1 = 0 and x2 = 0
						//
						//   0 = a11 * x1 + a12 * 0 + b1' 
						// vn2 = a21 * x1 + a22 * 0 + b2'
						//
						x.X = -cp1.normalMass * b.X;
						x.Y = 0.0f;
						vn1 = 0.0f;
						vn2 = vc.K.ex.Y * x.X + b.Y;

						if( x.X >= 0.0f && vn2 >= 0.0f )
						{
							// Get the incremental impulse
							Vector2 d = x - a;

							// Apply incremental impulse
							Vector2 P1 = d.X * normal;
							Vector2 P2 = d.Y * normal;
							vA -= mA * ( P1 + P2 );
							wA -= iA * ( MathUtils.cross( cp1.rA, P1 ) + MathUtils.cross( cp2.rA, P2 ) );

							vB += mB * ( P1 + P2 );
							wB += iB * ( MathUtils.cross( cp1.rB, P1 ) + MathUtils.cross( cp2.rB, P2 ) );

							// Accumulate
							cp1.normalImpulse = x.X;
							cp2.normalImpulse = x.Y;

#if B2_DEBUG_SOLVER
					// Postconditions
					dv1 = vB + MathUtils.Cross(wB, cp1.rB) - vA - MathUtils.Cross(wA, cp1.rA);

					// Compute normal velocity
					vn1 = Vector2.Dot(dv1, normal);

					b2Assert(b2Abs(vn1 - cp1.velocityBias) < k_errorTol);
#endif
							break;
						}


						//
						// Case 3: vn2 = 0 and x1 = 0
						//
						// vn1 = a11 * 0 + a12 * x2 + b1' 
						//   0 = a21 * 0 + a22 * x2 + b2'
						//
						x.X = 0.0f;
						x.Y = -cp2.normalMass * b.Y;
						vn1 = vc.K.ey.X * x.Y + b.X;
						vn2 = 0.0f;

						if( x.Y >= 0.0f && vn1 >= 0.0f )
						{
							// Resubstitute for the incremental impulse
							Vector2 d = x - a;

							// Apply incremental impulse
							Vector2 P1 = d.X * normal;
							Vector2 P2 = d.Y * normal;
							vA -= mA * ( P1 + P2 );
							wA -= iA * ( MathUtils.cross( cp1.rA, P1 ) + MathUtils.cross( cp2.rA, P2 ) );

							vB += mB * ( P1 + P2 );
							wB += iB * ( MathUtils.cross( cp1.rB, P1 ) + MathUtils.cross( cp2.rB, P2 ) );

							// Accumulate
							cp1.normalImpulse = x.X;
							cp2.normalImpulse = x.Y;

#if B2_DEBUG_SOLVER
					// Postconditions
					dv2 = vB + MathUtils.Cross(wB, cp2.rB) - vA - MathUtils.Cross(wA, cp2.rA);

					// Compute normal velocity
					vn2 = Vector2.Dot(dv2, normal);

					b2Assert(b2Abs(vn2 - cp2.velocityBias) < k_errorTol);
#endif
							break;
						}

						//
						// Case 4: x1 = 0 and x2 = 0
						// 
						// vn1 = b1
						// vn2 = b2;
						x.X = 0.0f;
						x.Y = 0.0f;
						vn1 = b.X;
						vn2 = b.Y;

						if( vn1 >= 0.0f && vn2 >= 0.0f )
						{
							// Resubstitute for the incremental impulse
							Vector2 d = x - a;

							// Apply incremental impulse
							Vector2 P1 = d.X * normal;
							Vector2 P2 = d.Y * normal;
							vA -= mA * ( P1 + P2 );
							wA -= iA * ( MathUtils.cross( cp1.rA, P1 ) + MathUtils.cross( cp2.rA, P2 ) );

							vB += mB * ( P1 + P2 );
							wB += iB * ( MathUtils.cross( cp1.rB, P1 ) + MathUtils.cross( cp2.rB, P2 ) );

							// Accumulate
							cp1.normalImpulse = x.X;
							cp2.normalImpulse = x.Y;

							break;
						}

						// No solution, give up. This is hit sometimes, but it doesn't seem to matter.
						break;
					}
				}

				_velocities[indexA].v = vA;
				_velocities[indexA].w = wA;
				_velocities[indexB].v = vB;
				_velocities[indexB].w = wB;
			}
		}