2 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
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.
19 #include "b2DistanceJoint.h"
20 #include "../b2Body.h"
21 #include "../b2World.h"
23 // 1-D constrained system
24 // m (v2 - v1) = lambda
25 // v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
28 // 1-D mass-damper-spring system
29 // m (v2 - v1) + h * d * v2 + h * k *
31 // C = norm(p2 - p1) - L
32 // u = (p2 - p1) / norm(p2 - p1)
33 // Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))
34 // J = [-u -cross(r1, u) u cross(r2, u)]
36 // = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2
38 void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2,
39 const b2Vec2& anchor1, const b2Vec2& anchor2)
43 localAnchor1 = body1->GetLocalPoint(anchor1);
44 localAnchor2 = body2->GetLocalPoint(anchor2);
45 b2Vec2 d = anchor2 - anchor1;
50 b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)
53 m_localAnchor1 = def->localAnchor1;
54 m_localAnchor2 = def->localAnchor2;
55 m_length = def->length;
56 m_frequencyHz = def->frequencyHz;
57 m_dampingRatio = def->dampingRatio;
64 void b2DistanceJoint::InitVelocityConstraints(const b2TimeStep& step)
66 m_inv_dt = step.inv_dt;
71 // Compute the effective mass matrix.
72 b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
73 b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
74 m_u = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
76 // Handle singularity.
77 float32 length = m_u.Length();
78 if (length > b2_linearSlop)
87 float32 cr1u = b2Cross(r1, m_u);
88 float32 cr2u = b2Cross(r2, m_u);
89 float32 invMass = b1->m_invMass + b1->m_invI * cr1u * cr1u + b2->m_invMass + b2->m_invI * cr2u * cr2u;
90 b2Assert(invMass > B2_FLT_EPSILON);
91 m_mass = 1.0f / invMass;
93 if (m_frequencyHz > 0.0f)
95 float32 C = length - m_length;
98 float32 omega = 2.0f * b2_pi * m_frequencyHz;
100 // Damping coefficient
101 float32 d = 2.0f * m_mass * m_dampingRatio * omega;
104 float32 k = m_mass * omega * omega;
107 m_gamma = 1.0f / (step.dt * (d + step.dt * k));
108 m_bias = C * step.dt * k * m_gamma;
110 m_mass = 1.0f / (invMass + m_gamma);
113 if (step.warmStarting)
115 m_impulse *= step.dtRatio;
116 b2Vec2 P = m_impulse * m_u;
117 b1->m_linearVelocity -= b1->m_invMass * P;
118 b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P);
119 b2->m_linearVelocity += b2->m_invMass * P;
120 b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P);
128 void b2DistanceJoint::SolveVelocityConstraints(const b2TimeStep& step)
132 b2Body* b1 = m_body1;
133 b2Body* b2 = m_body2;
135 b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
136 b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
138 // Cdot = dot(u, v + cross(w, r))
139 b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);
140 b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);
141 float32 Cdot = b2Dot(m_u, v2 - v1);
143 float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse);
144 m_impulse += impulse;
146 b2Vec2 P = impulse * m_u;
147 b1->m_linearVelocity -= b1->m_invMass * P;
148 b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P);
149 b2->m_linearVelocity += b2->m_invMass * P;
150 b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P);
153 bool b2DistanceJoint::SolvePositionConstraints()
155 if (m_frequencyHz > 0.0f)
160 b2Body* b1 = m_body1;
161 b2Body* b2 = m_body2;
163 b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
164 b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
166 b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
168 float32 length = d.Normalize();
169 float32 C = length - m_length;
170 C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);
172 float32 impulse = -m_mass * C;
174 b2Vec2 P = impulse * m_u;
176 b1->m_sweep.c -= b1->m_invMass * P;
177 b1->m_sweep.a -= b1->m_invI * b2Cross(r1, P);
178 b2->m_sweep.c += b2->m_invMass * P;
179 b2->m_sweep.a += b2->m_invI * b2Cross(r2, P);
181 b1->SynchronizeTransform();
182 b2->SynchronizeTransform();
184 return b2Abs(C) < b2_linearSlop;
187 b2Vec2 b2DistanceJoint::GetAnchor1() const
189 return m_body1->GetWorldPoint(m_localAnchor1);
192 b2Vec2 b2DistanceJoint::GetAnchor2() const
194 return m_body2->GetWorldPoint(m_localAnchor2);
197 b2Vec2 b2DistanceJoint::GetReactionForce() const
199 b2Vec2 F = (m_inv_dt * m_impulse) * m_u;
203 float32 b2DistanceJoint::GetReactionTorque() const