private void MoveAABB(ref AABB aabb) { Vec2 d = new Vec2(); d.X = Box2DXMath.Random(-0.5f, 0.5f); d.Y = Box2DXMath.Random(-0.5f, 0.5f); //d.x = 2.0f; //d.y = 0.0f; aabb.LowerBound += d; aabb.UpperBound += d; Vec2 c0 = 0.5f * (aabb.LowerBound + aabb.UpperBound); Vec2 min = new Vec2(); min.Set(-_extent, 0.0f); Vec2 max = new Vec2(); max.Set(_extent, 2.0f * _extent); Vec2 c = Box2DXMath.Clamp(c0, min, max); aabb.LowerBound += c - c0; aabb.UpperBound += c - c0; }
internal override bool SolvePositionConstraints() { Body b1 = _body1; Body b2 = _body2; float invMass1 = b1._invMass, invMass2 = b2._invMass; float invI1 = b1._invI, invI2 = b2._invI; Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter()); Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter()); Vec2 p1 = b1._sweep.C + r1; Vec2 p2 = b2._sweep.C + r2; Vec2 d = p2 - p1; Vec2 ay1 = Box2DXMath.Mul(b1.GetXForm().R, _localYAxis1); // Solve linear (point-to-line) constraint. float linearC = Vec2.Dot(ay1, d); // Prevent overly large corrections. linearC = Box2DXMath.Clamp(linearC, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection); float linearImpulse = -_linearMass * linearC; b1._sweep.C += (invMass1 * linearImpulse) * _linearJacobian.Linear1; b1._sweep.A += invI1 * linearImpulse * _linearJacobian.Angular1; //b1->SynchronizeTransform(); // updated by angular constraint b2._sweep.C += (invMass2 * linearImpulse) * _linearJacobian.Linear2; b2._sweep.A += invI2 * linearImpulse * _linearJacobian.Angular2; //b2->SynchronizeTransform(); // updated by angular constraint float positionError = Box2DXMath.Abs(linearC); // Solve angular constraint. float angularC = b2._sweep.A - b1._sweep.A - _refAngle; // Prevent overly large corrections. angularC = Box2DXMath.Clamp(angularC, -Settings.MaxAngularCorrection, Settings.MaxAngularCorrection); float angularImpulse = -_angularMass * angularC; b1._sweep.A -= b1._invI * angularImpulse; b2._sweep.A += b2._invI * angularImpulse; b1.SynchronizeTransform(); b2.SynchronizeTransform(); float angularError = Box2DXMath.Abs(angularC); // Solve linear limit constraint. if (_enableLimit && _limitState != LimitState.InactiveLimit) { Vec2 r1_ = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter()); Vec2 r2_ = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter()); Vec2 p1_ = b1._sweep.C + r1_; Vec2 p2_ = b2._sweep.C + r2_; Vec2 d_ = p2_ - p1_; Vec2 ax1 = Box2DXMath.Mul(b1.GetXForm().R, _localXAxis1); float translation = Vec2.Dot(ax1, d_); float limitImpulse = 0.0f; if (_limitState == LimitState.EqualLimits) { // Prevent large angular corrections float limitC = Box2DXMath.Clamp(translation, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection); limitImpulse = -_motorMass * limitC; positionError = Box2DXMath.Max(positionError, Box2DXMath.Abs(angularC)); } else if (_limitState == LimitState.AtLowerLimit) { float limitC = translation - _lowerTranslation; positionError = Box2DXMath.Max(positionError, -limitC); // Prevent large linear corrections and allow some slop. limitC = Box2DXMath.Clamp(limitC + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f); limitImpulse = -_motorMass * limitC; float oldLimitImpulse = _limitPositionImpulse; _limitPositionImpulse = Box2DXMath.Max(_limitPositionImpulse + limitImpulse, 0.0f); limitImpulse = _limitPositionImpulse - oldLimitImpulse; } else if (_limitState == LimitState.AtUpperLimit) { float limitC = translation - _upperTranslation; positionError = Box2DXMath.Max(positionError, limitC); // Prevent large linear corrections and allow some slop. limitC = Box2DXMath.Clamp(limitC - Settings.LinearSlop, 0.0f, Settings.MaxLinearCorrection); limitImpulse = -_motorMass * limitC; float oldLimitImpulse = _limitPositionImpulse; _limitPositionImpulse = Box2DXMath.Min(_limitPositionImpulse + limitImpulse, 0.0f); limitImpulse = _limitPositionImpulse - oldLimitImpulse; } b1._sweep.C += (invMass1 * limitImpulse) * _motorJacobian.Linear1; b1._sweep.A += invI1 * limitImpulse * _motorJacobian.Angular1; b2._sweep.C += (invMass2 * limitImpulse) * _motorJacobian.Linear2; b2._sweep.A += invI2 * limitImpulse * _motorJacobian.Angular2; b1.SynchronizeTransform(); b2.SynchronizeTransform(); } return(positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop); }
internal override bool SolvePositionConstraints(float baumgarte) { Body b1 = _body1; Body b2 = _body2; Vec2 s1 = _ground.GetXForm().Position + _groundAnchor1; Vec2 s2 = _ground.GetXForm().Position + _groundAnchor2; float linearError = 0.0f; if (_state == LimitState.AtUpperLimit) { Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter()); Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter()); Vec2 p1 = b1._sweep.C + r1; Vec2 p2 = b2._sweep.C + r2; // Get the pulley axes. _u1 = p1 - s1; _u2 = p2 - s2; float length1 = _u1.Length(); float length2 = _u2.Length(); if (length1 > Settings.LinearSlop) { _u1 *= 1.0f / length1; } else { _u1.SetZero(); } if (length2 > Settings.LinearSlop) { _u2 *= 1.0f / length2; } else { _u2.SetZero(); } float C = _constant - length1 - _ratio * length2; linearError = Box2DXMath.Max(linearError, -C); C = Box2DXMath.Clamp(C + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f); float impulse = -_pulleyMass * C; Vec2 P1 = -impulse * _u1; Vec2 P2 = -_ratio * impulse * _u2; b1._sweep.C += b1._invMass * P1; b1._sweep.A += b1._invI * Vec2.Cross(r1, P1); b2._sweep.C += b2._invMass * P2; b2._sweep.A += b2._invI * Vec2.Cross(r2, P2); b1.SynchronizeTransform(); b2.SynchronizeTransform(); } if (_limitState1 == LimitState.AtUpperLimit) { Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter()); Vec2 p1 = b1._sweep.C + r1; _u1 = p1 - s1; float length1 = _u1.Length(); if (length1 > Settings.LinearSlop) { _u1 *= 1.0f / length1; } else { _u1.SetZero(); } float C = _maxLength1 - length1; linearError = Box2DXMath.Max(linearError, -C); C = Box2DXMath.Clamp(C + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f); float impulse = -_limitMass1 * C; Vec2 P1 = -impulse * _u1; b1._sweep.C += b1._invMass * P1; b1._sweep.A += b1._invI * Vec2.Cross(r1, P1); b1.SynchronizeTransform(); } if (_limitState2 == LimitState.AtUpperLimit) { Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter()); Vec2 p2 = b2._sweep.C + r2; _u2 = p2 - s2; float length2 = _u2.Length(); if (length2 > Settings.LinearSlop) { _u2 *= 1.0f / length2; } else { _u2.SetZero(); } float C = _maxLength2 - length2; linearError = Box2DXMath.Max(linearError, -C); C = Box2DXMath.Clamp(C + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f); float impulse = -_limitMass2 * C; Vec2 P2 = -impulse * _u2; b2._sweep.C += b2._invMass * P2; b2._sweep.A += b2._invI * Vec2.Cross(r2, P2); b2.SynchronizeTransform(); } return(linearError < Settings.LinearSlop); }
internal override void SolveVelocityConstraints(TimeStep step) { Body b1 = _body1; Body b2 = _body2; float invMass1 = b1._invMass, invMass2 = b2._invMass; float invI1 = b1._invI, invI2 = b2._invI; // Solve linear constraint. float linearCdot = _linearJacobian.Compute(b1._linearVelocity, b1._angularVelocity, b2._linearVelocity, b2._angularVelocity); float force = -Settings.FORCE_INV_SCALE(step.Inv_Dt) * _linearMass * linearCdot; _force += force; float P = Settings.FORCE_SCALE(step.Dt) * force; b1._linearVelocity += (invMass1 * P) * _linearJacobian.Linear1; b1._angularVelocity += invI1 * P * _linearJacobian.Angular1; b2._linearVelocity += (invMass2 * P) * _linearJacobian.Linear2; b2._angularVelocity += invI2 * P * _linearJacobian.Angular2; // Solve angular constraint. float angularCdot = b2._angularVelocity - b1._angularVelocity; float torque = -Settings.FORCE_INV_SCALE(step.Inv_Dt) * _angularMass * angularCdot; _torque += torque; float L = Settings.FORCE_SCALE(step.Dt) * torque; b1._angularVelocity -= invI1 * L; b2._angularVelocity += invI2 * L; // Solve linear motor constraint. if (_enableMotor && _limitState != LimitState.EqualLimits) { float motorCdot = _motorJacobian.Compute(b1._linearVelocity, b1._angularVelocity, b2._linearVelocity, b2._angularVelocity) - _motorSpeed; float motorForce = -Settings.FORCE_INV_SCALE(step.Inv_Dt) * _motorMass * motorCdot; float oldMotorForce = _motorForce; _motorForce = Box2DXMath.Clamp(_motorForce + motorForce, -_maxMotorForce, _maxMotorForce); motorForce = _motorForce - oldMotorForce; float P_ = Settings.FORCE_SCALE(step.Dt) * motorForce; b1._linearVelocity += (invMass1 * P_) * _motorJacobian.Linear1; b1._angularVelocity += invI1 * P_ * _motorJacobian.Angular1; b2._linearVelocity += (invMass2 * P_) * _motorJacobian.Linear2; b2._angularVelocity += invI2 * P_ * _motorJacobian.Angular2; } // Solve linear limit constraint. if (_enableLimit && _limitState != LimitState.InactiveLimit) { float limitCdot = _motorJacobian.Compute(b1._linearVelocity, b1._angularVelocity, b2._linearVelocity, b2._angularVelocity); float limitForce = -Settings.FORCE_INV_SCALE(step.Inv_Dt) * _motorMass * limitCdot; if (_limitState == LimitState.EqualLimits) { _limitForce += limitForce; } else if (_limitState == LimitState.AtLowerLimit) { float oldLimitForce = _limitForce; _limitForce = Box2DXMath.Max(_limitForce + limitForce, 0.0f); limitForce = _limitForce - oldLimitForce; } else if (_limitState == LimitState.AtUpperLimit) { float oldLimitForce = _limitForce; _limitForce = Box2DXMath.Min(_limitForce + limitForce, 0.0f); limitForce = _limitForce - oldLimitForce; } float P_ = Settings.FORCE_SCALE(step.Dt) * limitForce; b1._linearVelocity += (invMass1 * P_) * _motorJacobian.Linear1; b1._angularVelocity += invI1 * P_ * _motorJacobian.Angular1; b2._linearVelocity += (invMass2 * P_) * _motorJacobian.Linear2; b2._angularVelocity += invI2 * P_ * _motorJacobian.Angular2; } }
internal override bool SolvePositionConstraints() { Body b1 = _body1; Body b2 = _body2; float positionError = 0.0f; // Solve point-to-point position error. Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter()); Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter()); Vec2 p1 = b1._sweep.C + r1; Vec2 p2 = b2._sweep.C + r2; Vec2 ptpC = p2 - p1; positionError = ptpC.Length(); // Prevent overly large corrections. //b2Vec2 dpMax(b2_maxLinearCorrection, b2_maxLinearCorrection); //ptpC = b2Clamp(ptpC, -dpMax, dpMax); float invMass1 = b1._invMass, invMass2 = b2._invMass; float invI1 = b1._invI, invI2 = b2._invI; Mat22 K1 = new Mat22(); K1.Col1.X = invMass1 + invMass2; K1.Col2.X = 0.0f; K1.Col1.Y = 0.0f; K1.Col2.Y = invMass1 + invMass2; Mat22 K2 = new Mat22(); K2.Col1.X = invI1 * r1.Y * r1.Y; K2.Col2.X = -invI1 * r1.X * r1.Y; K2.Col1.Y = -invI1 * r1.X * r1.Y; K2.Col2.Y = invI1 * r1.X * r1.X; Mat22 K3 = new Mat22(); K3.Col1.X = invI2 * r2.Y * r2.Y; K3.Col2.X = -invI2 * r2.X * r2.Y; K3.Col1.Y = -invI2 * r2.X * r2.Y; K3.Col2.Y = invI2 * r2.X * r2.X; Mat22 K = K1 + K2 + K3; Vec2 impulse = K.Solve(-ptpC); b1._sweep.C -= b1._invMass * impulse; b1._sweep.A -= b1._invI * Vec2.Cross(r1, impulse); b2._sweep.C += b2._invMass * impulse; b2._sweep.A += b2._invI * Vec2.Cross(r2, impulse); b1.SynchronizeTransform(); b2.SynchronizeTransform(); // Handle limits. float angularError = 0.0f; if (_enableLimit && _limitState != LimitState.InactiveLimit) { float angle = b2._sweep.A - b1._sweep.A - _referenceAngle; float limitImpulse = 0.0f; if (_limitState == LimitState.EqualLimits) { // Prevent large angular corrections float limitC = Box2DXMath.Clamp(angle, -Settings.MaxAngularCorrection, Settings.MaxAngularCorrection); limitImpulse = -_motorMass * limitC; angularError = Box2DXMath.Abs(limitC); } else if (_limitState == LimitState.AtLowerLimit) { float limitC = angle - _lowerAngle; angularError = Box2DXMath.Max(0.0f, -limitC); // Prevent large angular corrections and allow some slop. limitC = Box2DXMath.Clamp(limitC + Settings.AngularSlop, -Settings.MaxAngularCorrection, 0.0f); limitImpulse = -_motorMass * limitC; float oldLimitImpulse = _limitPositionImpulse; _limitPositionImpulse = Box2DXMath.Max(_limitPositionImpulse + limitImpulse, 0.0f); limitImpulse = _limitPositionImpulse - oldLimitImpulse; } else if (_limitState == LimitState.AtUpperLimit) { float limitC = angle - _upperAngle; angularError = Box2DXMath.Max(0.0f, limitC); // Prevent large angular corrections and allow some slop. limitC = Box2DXMath.Clamp(limitC - Settings.AngularSlop, 0.0f, Settings.MaxAngularCorrection); limitImpulse = -_motorMass * limitC; float oldLimitImpulse = _limitPositionImpulse; _limitPositionImpulse = Box2DXMath.Min(_limitPositionImpulse + limitImpulse, 0.0f); limitImpulse = _limitPositionImpulse - oldLimitImpulse; } b1._sweep.A -= b1._invI * limitImpulse; b2._sweep.A += b2._invI * limitImpulse; b1.SynchronizeTransform(); b2.SynchronizeTransform(); } return(positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop); }
internal override void SolveVelocityConstraints(TimeStep step) { Body b1 = _body1; Body b2 = _body2; Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter()); Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter()); // Solve point-to-point constraint Vec2 pivotCdot = b2._linearVelocity + Vec2.Cross(b2._angularVelocity, r2) - b1._linearVelocity - Vec2.Cross(b1._angularVelocity, r1); Vec2 pivotForce = -Settings.FORCE_INV_SCALE(step.Inv_Dt) * Box2DXMath.Mul(_pivotMass, pivotCdot); #if B2_TOI_JOINTS if (step.WarmStarting) { _pivotForce += pivotForce; _lastWarmStartingPivotForce = _pivotForce; } else { _pivotForce = _lastWarmStartingPivotForce; //Do not update warm starting value! } #else _pivotForce += pivotForce; #endif Vec2 P = Settings.FORCE_SCALE(step.Dt) * pivotForce; b1._linearVelocity -= b1._invMass * P; b1._angularVelocity -= b1._invI * Vec2.Cross(r1, P); b2._linearVelocity += b2._invMass * P; b2._angularVelocity += b2._invI * Vec2.Cross(r2, P); if (_enableMotor && _limitState != LimitState.EqualLimits) { float motorCdot = b2._angularVelocity - b1._angularVelocity - _motorSpeed; float motorForce = -step.Inv_Dt * _motorMass * motorCdot; float oldMotorForce = _motorForce; _motorForce = Box2DXMath.Clamp(_motorForce + motorForce, -_maxMotorTorque, _maxMotorTorque); motorForce = _motorForce - oldMotorForce; float P_ = step.Dt * motorForce; b1._angularVelocity -= b1._invI * P_; b2._angularVelocity += b2._invI * P_; } if (_enableLimit && _limitState != LimitState.InactiveLimit) { float limitCdot = b2._angularVelocity - b1._angularVelocity; float limitForce = -step.Inv_Dt * _motorMass * limitCdot; if (_limitState == LimitState.EqualLimits) { _limitForce += limitForce; } else if (_limitState == LimitState.AtLowerLimit) { float oldLimitForce = _limitForce; _limitForce = Box2DXMath.Max(_limitForce + limitForce, 0.0f); limitForce = _limitForce - oldLimitForce; } else if (_limitState == LimitState.AtUpperLimit) { float oldLimitForce = _limitForce; _limitForce = Box2DXMath.Min(_limitForce + limitForce, 0.0f); limitForce = _limitForce - oldLimitForce; } float P_ = step.Dt * limitForce; b1._angularVelocity -= b1._invI * P_; b2._angularVelocity += b2._invI * P_; } }
/// <summary> /// Describes whether this instance solve position constraints /// </summary> /// <param name="baumgarte">The baumgarte</param> /// <returns>The bool</returns> internal override bool SolvePositionConstraints(float baumgarte) { // TODO_ERIN block solve with limit. Body body1 = Body1; Body body2 = Body2; float angularError = 0.0f; float positionError = 0.0f; // Solve angular limit constraint. if (IsLimitEnabled && State != LimitState.InactiveLimit) { float angle = body2.Sweep.A - body1.Sweep.A - ReferenceAngle; float limitImpulse = 0.0f; if (State == LimitState.EqualLimits) { // Prevent large angular corrections float c = Box2DXMath.Clamp(angle, -Settings.MaxAngularCorrection, Settings.MaxAngularCorrection); limitImpulse = -MotorMass * c; angularError = Box2DXMath.Abs(c); } else if (State == LimitState.AtLowerLimit) { float c = angle - LowerLimit; angularError = -c; // Prevent large angular corrections and allow some slop. c = Box2DXMath.Clamp(c + Settings.AngularSlop, -Settings.MaxAngularCorrection, 0.0f); limitImpulse = -MotorMass * c; } else if (State == LimitState.AtUpperLimit) { float c = angle - UpperLimit; angularError = c; // Prevent large angular corrections and allow some slop. c = Box2DXMath.Clamp(c - Settings.AngularSlop, 0.0f, Settings.MaxAngularCorrection); limitImpulse = -MotorMass * c; } body1.Sweep.A -= body1.InvI * limitImpulse; body2.Sweep.A += body2.InvI * limitImpulse; body1.SynchronizeTransform(); body2.SynchronizeTransform(); } // Solve point-to-point constraint. { Vec2 mulR1 = Box2DXMath.Mul(body1.GetXForm().R, LocalAnchor1 - body1.GetLocalCenter()); Vec2 mulR2 = Box2DXMath.Mul(body2.GetXForm().R, LocalAnchor2 - body2.GetLocalCenter()); Vec2 body2SweepC = body2.Sweep.C + mulR2 - body1.Sweep.C - mulR1; positionError = body2SweepC.Length(); float invMass1 = body1.InvMass, invMass2 = body2.InvMass; float invI1 = body1.InvI, invI2 = body2.InvI; // Handle large detachment. float kAllowedStretch = 10.0f * Settings.LinearSlop; if (body2SweepC.LengthSquared() > kAllowedStretch * kAllowedStretch) { // Use a particle solution (no rotation). Vec2 sweepC = body2SweepC; sweepC.Normalize(); float mass12 = invMass1 + invMass2; Box2DxDebug.Assert(mass12 > Settings.FltEpsilon); float divideMass12 = 1.0f / mass12; Vec2 impulseLocal = divideMass12 * -body2SweepC; float kBeta = 0.5f; body1.Sweep.C -= kBeta * invMass1 * impulseLocal; body2.Sweep.C += kBeta * invMass2 * impulseLocal; body2SweepC = body2.Sweep.C + mulR2 - body1.Sweep.C - mulR1; } Mat22 k1 = new Mat22 { Col1 = new Vec2(invMass1 + invMass2, 0.0f), Col2 = new Vec2(0.0f, invMass1 + invMass2) }; Mat22 k2 = new Mat22(); k2.Col1.X = invI1 * mulR1.Y * mulR1.Y; k2.Col2.X = -invI1 * mulR1.X * mulR1.Y; k2.Col1.Y = -invI1 * mulR1.X * mulR1.Y; k2.Col2.Y = invI1 * mulR1.X * mulR1.X; Mat22 k3 = new Mat22(); k3.Col1.X = invI2 * mulR2.Y * mulR2.Y; k3.Col2.X = -invI2 * mulR2.X * mulR2.Y; k3.Col1.Y = -invI2 * mulR2.X * mulR2.Y; k3.Col2.Y = invI2 * mulR2.X * mulR2.X; Mat22 k = k1 + k2 + k3; Vec2 impulse = k.Solve(-body2SweepC); body1.Sweep.C -= body1.InvMass * impulse; body1.Sweep.A -= body1.InvI * Vec2.Cross(mulR1, impulse); body2.Sweep.C += body2.InvMass * impulse; body2.Sweep.A += body2.InvI * Vec2.Cross(mulR2, impulse); body1.SynchronizeTransform(); body2.SynchronizeTransform(); } return(positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop); }
/// <summary> /// Solves the velocity constraints using the specified step /// </summary> /// <param name="step">The step</param> internal override void SolveVelocityConstraints(TimeStep step) { Body b1 = Body1; Body b2 = Body2; Vec2 v1 = b1.LinearVelocity; float w1 = b1.AngularVelocity; Vec2 v2 = b2.LinearVelocity; float w2 = b2.AngularVelocity; float m1 = b1.InvMass, m2 = b2.InvMass; float i1 = b1.InvI, i2 = b2.InvI; //Solve motor constraint. if (IsMotorEnabled && State != LimitState.EqualLimits) { float cdot = w2 - w1 - MotorSpeed; float impulse = MotorMass * -cdot; float oldImpulse = MotorTorque; float maxImpulse = step.Dt * MaxMotorTorque; MotorTorque = Box2DXMath.Clamp(MotorTorque + impulse, -maxImpulse, maxImpulse); impulse = MotorTorque - oldImpulse; w1 -= i1 * impulse; w2 += i2 * impulse; } //Solve limit constraint. if (IsLimitEnabled && State != LimitState.InactiveLimit) { Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, LocalAnchor1 - b1.GetLocalCenter()); Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, LocalAnchor2 - b2.GetLocalCenter()); // Solve point-to-point constraint Vec2 cdot1 = v2 + Vec2.Cross(w2, r2) - v1 - Vec2.Cross(w1, r1); float cdot2 = w2 - w1; Vec3 cdot = new Vec3(cdot1.X, cdot1.Y, cdot2); Vec3 impulse = Mass.Solve33(-cdot); if (State == LimitState.EqualLimits) { Impulse += impulse; } else if (State == LimitState.AtLowerLimit) { float newImpulse = Impulse.Z + impulse.Z; if (newImpulse < 0.0f) { Vec2 reduced = Mass.Solve22(-cdot1); impulse.X = reduced.X; impulse.Y = reduced.Y; impulse.Z = -Impulse.Z; Impulse = new Vec3(reduced.X, reduced.Y, 0.0f); } } else if (State == LimitState.AtUpperLimit) { float newImpulse = Impulse.Z + impulse.Z; if (newImpulse > 0.0f) { Vec2 reduced = Mass.Solve22(-cdot1); impulse.X = reduced.X; impulse.Y = reduced.Y; impulse.Z = -Impulse.Z; Impulse = new Vec3(reduced.X, reduced.Y, 0.0f); } } Vec2 p = new Vec2(impulse.X, impulse.Y); v1 -= m1 * p; w1 -= i1 * (Vec2.Cross(r1, p) + impulse.Z); v2 += m2 * p; w2 += i2 * (Vec2.Cross(r2, p) + impulse.Z); } else { Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, LocalAnchor1 - b1.GetLocalCenter()); Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, LocalAnchor2 - b2.GetLocalCenter()); // Solve point-to-point constraint Vec2 cdot = v2 + Vec2.Cross(w2, r2) - v1 - Vec2.Cross(w1, r1); Vec2 impulse = Mass.Solve22(-cdot); Impulse = new Vec3(impulse.X, impulse.Y, Impulse.Z); v1 -= m1 * impulse; w1 -= i1 * Vec2.Cross(r1, impulse); v2 += m2 * impulse; w2 += i2 * Vec2.Cross(r2, impulse); } b1.LinearVelocity = v1; b1.AngularVelocity = w1; b2.LinearVelocity = v2; b2.AngularVelocity = w2; }