first commit
[blok] / Box2D / Source / Dynamics / Joints / b2DistanceJoint.cpp
1 /*
2 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
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 "b2DistanceJoint.h"
20 #include "../b2Body.h"
21 #include "../b2World.h"
22
23 // 1-D constrained system
24 // m (v2 - v1) = lambda
25 // v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
26 // x2 = x1 + h * v2
27
28 // 1-D mass-damper-spring system
29 // m (v2 - v1) + h * d * v2 + h * k * 
30
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)]
35 // K = J * invM * JT
36 //   = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2
37
38 void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2,
39                                                                         const b2Vec2& anchor1, const b2Vec2& anchor2)
40 {
41         body1 = b1;
42         body2 = b2;
43         localAnchor1 = body1->GetLocalPoint(anchor1);
44         localAnchor2 = body2->GetLocalPoint(anchor2);
45         b2Vec2 d = anchor2 - anchor1;
46         length = d.Length();
47 }
48
49
50 b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)
51 : b2Joint(def)
52 {
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;
58         m_impulse = 0.0f;
59         m_gamma = 0.0f;
60         m_bias = 0.0f;
61         m_inv_dt = 0.0f;
62 }
63
64 void b2DistanceJoint::InitVelocityConstraints(const b2TimeStep& step)
65 {
66         m_inv_dt = step.inv_dt;
67
68         b2Body* b1 = m_body1;
69         b2Body* b2 = m_body2;
70
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;
75
76         // Handle singularity.
77         float32 length = m_u.Length();
78         if (length > b2_linearSlop)
79         {
80                 m_u *= 1.0f / length;
81         }
82         else
83         {
84                 m_u.Set(0.0f, 0.0f);
85         }
86
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;
92
93         if (m_frequencyHz > 0.0f)
94         {
95                 float32 C = length - m_length;
96
97                 // Frequency
98                 float32 omega = 2.0f * b2_pi * m_frequencyHz;
99
100                 // Damping coefficient
101                 float32 d = 2.0f * m_mass * m_dampingRatio * omega;
102
103                 // Spring stiffness
104                 float32 k = m_mass * omega * omega;
105
106                 // magic formulas
107                 m_gamma = 1.0f / (step.dt * (d + step.dt * k));
108                 m_bias = C * step.dt * k * m_gamma;
109
110                 m_mass = 1.0f / (invMass + m_gamma);
111         }
112
113         if (step.warmStarting)
114         {
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);
121         }
122         else
123         {
124                 m_impulse = 0.0f;
125         }
126 }
127
128 void b2DistanceJoint::SolveVelocityConstraints(const b2TimeStep& step)
129 {
130         B2_NOT_USED(step);
131
132         b2Body* b1 = m_body1;
133         b2Body* b2 = m_body2;
134
135         b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
136         b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
137
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);
142
143         float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse);
144         m_impulse += impulse;
145
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);
151 }
152
153 bool b2DistanceJoint::SolvePositionConstraints()
154 {
155         if (m_frequencyHz > 0.0f)
156         {
157                 return true;
158         }
159
160         b2Body* b1 = m_body1;
161         b2Body* b2 = m_body2;
162
163         b2Vec2 r1 = b2Mul(b1->GetXForm().R, m_localAnchor1 - b1->GetLocalCenter());
164         b2Vec2 r2 = b2Mul(b2->GetXForm().R, m_localAnchor2 - b2->GetLocalCenter());
165
166         b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1;
167
168         float32 length = d.Normalize();
169         float32 C = length - m_length;
170         C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);
171
172         float32 impulse = -m_mass * C;
173         m_u = d;
174         b2Vec2 P = impulse * m_u;
175
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);
180
181         b1->SynchronizeTransform();
182         b2->SynchronizeTransform();
183
184         return b2Abs(C) < b2_linearSlop;
185 }
186
187 b2Vec2 b2DistanceJoint::GetAnchor1() const
188 {
189         return m_body1->GetWorldPoint(m_localAnchor1);
190 }
191
192 b2Vec2 b2DistanceJoint::GetAnchor2() const
193 {
194         return m_body2->GetWorldPoint(m_localAnchor2);
195 }
196
197 b2Vec2 b2DistanceJoint::GetReactionForce() const
198 {
199         b2Vec2 F = (m_inv_dt * m_impulse) * m_u;
200         return F;
201 }
202
203 float32 b2DistanceJoint::GetReactionTorque() const
204 {
205         return 0.0f;
206 }