|
@@ -49,6 +49,8 @@ b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def)
|
|
|
m_localAnchorA = def->localAnchorA;
|
|
|
m_localAnchorB = def->localAnchorB;
|
|
|
m_referenceAngle = def->referenceAngle;
|
|
|
+ m_frequencyHz = def->frequencyHz;
|
|
|
+ m_dampingRatio = def->dampingRatio;
|
|
|
|
|
|
m_impulse.SetZero();
|
|
|
}
|
|
@@ -91,15 +93,50 @@ void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data)
|
|
|
float32 mA = m_invMassA, mB = m_invMassB;
|
|
|
float32 iA = m_invIA, iB = m_invIB;
|
|
|
|
|
|
- m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
|
|
|
- m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
|
|
|
- m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB;
|
|
|
- m_mass.ex.y = m_mass.ey.x;
|
|
|
- m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
|
|
|
- m_mass.ez.y = m_rA.x * iA + m_rB.x * iB;
|
|
|
- m_mass.ex.z = m_mass.ez.x;
|
|
|
- m_mass.ey.z = m_mass.ez.y;
|
|
|
- m_mass.ez.z = iA + iB;
|
|
|
+ b2Mat33 K;
|
|
|
+ K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
|
|
|
+ K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
|
|
|
+ K.ez.x = -m_rA.y * iA - m_rB.y * iB;
|
|
|
+ K.ex.y = K.ey.x;
|
|
|
+ K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
|
|
|
+ K.ez.y = m_rA.x * iA + m_rB.x * iB;
|
|
|
+ K.ex.z = K.ez.x;
|
|
|
+ K.ey.z = K.ez.y;
|
|
|
+ K.ez.z = iA + iB;
|
|
|
+
|
|
|
+ if (m_frequencyHz > 0.0f)
|
|
|
+ {
|
|
|
+ K.GetInverse22(&m_mass);
|
|
|
+
|
|
|
+ float32 invM = iA + iB;
|
|
|
+ float32 m = invM > 0.0f ? 1.0f / invM : 0.0f;
|
|
|
+
|
|
|
+ float32 C = aB - aA - m_referenceAngle;
|
|
|
+
|
|
|
+ // Frequency
|
|
|
+ float32 omega = 2.0f * b2_pi * m_frequencyHz;
|
|
|
+
|
|
|
+ // Damping coefficient
|
|
|
+ float32 d = 2.0f * m * m_dampingRatio * omega;
|
|
|
+
|
|
|
+ // Spring stiffness
|
|
|
+ float32 k = m * omega * omega;
|
|
|
+
|
|
|
+ // magic formulas
|
|
|
+ float32 h = data.step.dt;
|
|
|
+ m_gamma = h * (d + h * k);
|
|
|
+ m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
|
|
|
+ m_bias = C * h * k * m_gamma;
|
|
|
+
|
|
|
+ invM += m_gamma;
|
|
|
+ m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ K.GetSymInverse33(&m_mass);
|
|
|
+ m_gamma = 0.0f;
|
|
|
+ m_bias = 0.0f;
|
|
|
+ }
|
|
|
|
|
|
if (data.step.warmStarting)
|
|
|
{
|
|
@@ -135,20 +172,47 @@ void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data)
|
|
|
float32 mA = m_invMassA, mB = m_invMassB;
|
|
|
float32 iA = m_invIA, iB = m_invIB;
|
|
|
|
|
|
- b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
|
|
|
- float32 Cdot2 = wB - wA;
|
|
|
- b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
|
|
|
+ if (m_frequencyHz > 0.0f)
|
|
|
+ {
|
|
|
+ float32 Cdot2 = wB - wA;
|
|
|
+
|
|
|
+ float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z);
|
|
|
+ m_impulse.z += impulse2;
|
|
|
+
|
|
|
+ wA -= iA * impulse2;
|
|
|
+ wB += iB * impulse2;
|
|
|
|
|
|
- b2Vec3 impulse = -m_mass.Solve33(Cdot);
|
|
|
- m_impulse += impulse;
|
|
|
+ b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
|
|
|
|
|
|
- b2Vec2 P(impulse.x, impulse.y);
|
|
|
+ b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1);
|
|
|
+ m_impulse.x += impulse1.x;
|
|
|
+ m_impulse.y += impulse1.y;
|
|
|
|
|
|
- vA -= mA * P;
|
|
|
- wA -= iA * (b2Cross(m_rA, P) + impulse.z);
|
|
|
+ b2Vec2 P = impulse1;
|
|
|
|
|
|
- vB += mB * P;
|
|
|
- wB += iB * (b2Cross(m_rB, P) + impulse.z);
|
|
|
+ vA -= mA * P;
|
|
|
+ wA -= iA * b2Cross(m_rA, P);
|
|
|
+
|
|
|
+ vB += mB * P;
|
|
|
+ wB += iB * b2Cross(m_rB, P);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
|
|
|
+ float32 Cdot2 = wB - wA;
|
|
|
+ b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
|
|
|
+
|
|
|
+ b2Vec3 impulse = -b2Mul(m_mass, Cdot);
|
|
|
+ m_impulse += impulse;
|
|
|
+
|
|
|
+ b2Vec2 P(impulse.x, impulse.y);
|
|
|
+
|
|
|
+ vA -= mA * P;
|
|
|
+ wA -= iA * (b2Cross(m_rA, P) + impulse.z);
|
|
|
+
|
|
|
+ vB += mB * P;
|
|
|
+ wB += iB * (b2Cross(m_rB, P) + impulse.z);
|
|
|
+ }
|
|
|
|
|
|
data.velocities[m_indexA].v = vA;
|
|
|
data.velocities[m_indexA].w = wA;
|
|
@@ -171,33 +235,53 @@ bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data)
|
|
|
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
|
|
|
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
|
|
|
|
|
|
- b2Vec2 C1 = cB + rB - cA - rA;
|
|
|
- float32 C2 = aB - aA - m_referenceAngle;
|
|
|
+ float32 positionError, angularError;
|
|
|
|
|
|
- float32 positionError = C1.Length();
|
|
|
- float32 angularError = b2Abs(C2);
|
|
|
+ b2Mat33 K;
|
|
|
+ K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
|
|
|
+ K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
|
|
|
+ K.ez.x = -rA.y * iA - rB.y * iB;
|
|
|
+ K.ex.y = K.ey.x;
|
|
|
+ K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
|
|
|
+ K.ez.y = rA.x * iA + rB.x * iB;
|
|
|
+ K.ex.z = K.ez.x;
|
|
|
+ K.ey.z = K.ez.y;
|
|
|
+ K.ez.z = iA + iB;
|
|
|
|
|
|
- m_mass.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
|
|
|
- m_mass.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
|
|
|
- m_mass.ez.x = -rA.y * iA - rB.y * iB;
|
|
|
- m_mass.ex.y = m_mass.ey.x;
|
|
|
- m_mass.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
|
|
|
- m_mass.ez.y = rA.x * iA + rB.x * iB;
|
|
|
- m_mass.ex.z = m_mass.ez.x;
|
|
|
- m_mass.ey.z = m_mass.ez.y;
|
|
|
- m_mass.ez.z = iA + iB;
|
|
|
+ if (m_frequencyHz > 0.0f)
|
|
|
+ {
|
|
|
+ b2Vec2 C1 = cB + rB - cA - rA;
|
|
|
|
|
|
- b2Vec3 C(C1.x, C1.y, C2);
|
|
|
+ positionError = C1.Length();
|
|
|
+ angularError = 0.0f;
|
|
|
|
|
|
- b2Vec3 impulse = -m_mass.Solve33(C);
|
|
|
+ b2Vec2 P = -K.Solve22(C1);
|
|
|
|
|
|
- b2Vec2 P(impulse.x, impulse.y);
|
|
|
+ cA -= mA * P;
|
|
|
+ aA -= iA * b2Cross(rA, P);
|
|
|
|
|
|
- cA -= mA * P;
|
|
|
- aA -= iA * (b2Cross(rA, P) + impulse.z);
|
|
|
+ cB += mB * P;
|
|
|
+ aB += iB * b2Cross(rB, P);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ b2Vec2 C1 = cB + rB - cA - rA;
|
|
|
+ float32 C2 = aB - aA - m_referenceAngle;
|
|
|
+
|
|
|
+ positionError = C1.Length();
|
|
|
+ angularError = b2Abs(C2);
|
|
|
|
|
|
- cB += mB * P;
|
|
|
- aB += iB * (b2Cross(rB, P) + impulse.z);
|
|
|
+ b2Vec3 C(C1.x, C1.y, C2);
|
|
|
+
|
|
|
+ b2Vec3 impulse = -K.Solve33(C);
|
|
|
+ b2Vec2 P(impulse.x, impulse.y);
|
|
|
+
|
|
|
+ cA -= mA * P;
|
|
|
+ aA -= iA * (b2Cross(rA, P) + impulse.z);
|
|
|
+
|
|
|
+ cB += mB * P;
|
|
|
+ aB += iB * (b2Cross(rB, P) + impulse.z);
|
|
|
+ }
|
|
|
|
|
|
data.positions[m_indexA].c = cA;
|
|
|
data.positions[m_indexA].a = aA;
|
|
@@ -227,3 +311,20 @@ float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const
|
|
|
{
|
|
|
return inv_dt * m_impulse.z;
|
|
|
}
|
|
|
+
|
|
|
+void b2WeldJoint::Dump()
|
|
|
+{
|
|
|
+ int32 indexA = m_bodyA->m_islandIndex;
|
|
|
+ int32 indexB = m_bodyB->m_islandIndex;
|
|
|
+
|
|
|
+ b2Log(" b2WeldJointDef jd;\n");
|
|
|
+ b2Log(" jd.bodyA = bodies[%d];\n", indexA);
|
|
|
+ b2Log(" jd.bodyB = bodies[%d];\n", indexB);
|
|
|
+ b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
|
|
|
+ b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
|
|
|
+ b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
|
|
|
+ b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
|
|
|
+ b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
|
|
|
+ b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
|
|
|
+ b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
|
|
|
+}
|