1 | /* |
2 | * Copyright (c) 2007-2011 Erin Catto http://www.box2d.org |
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 <Box2D/Dynamics/Joints/b2RopeJoint.h> |
20 | #include <Box2D/Dynamics/b2Body.h> |
21 | #include <Box2D/Dynamics/b2TimeStep.h> |
22 | |
23 | |
24 | // Limit: |
25 | // C = norm(pB - pA) - L |
26 | // u = (pB - pA) / norm(pB - pA) |
27 | // Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA)) |
28 | // J = [-u -cross(rA, u) u cross(rB, u)] |
29 | // K = J * invM * JT |
30 | // = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2 |
31 | |
32 | b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def) |
33 | : b2Joint(def) |
34 | { |
35 | m_localAnchorA = def->localAnchorA; |
36 | m_localAnchorB = def->localAnchorB; |
37 | |
38 | m_maxLength = def->maxLength; |
39 | |
40 | m_mass = 0.0f; |
41 | m_impulse = 0.0f; |
42 | m_state = e_inactiveLimit; |
43 | m_length = 0.0f; |
44 | } |
45 | |
46 | void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data) |
47 | { |
48 | m_indexA = m_bodyA->m_islandIndex; |
49 | m_indexB = m_bodyB->m_islandIndex; |
50 | m_localCenterA = m_bodyA->m_sweep.localCenter; |
51 | m_localCenterB = m_bodyB->m_sweep.localCenter; |
52 | m_invMassA = m_bodyA->m_invMass; |
53 | m_invMassB = m_bodyB->m_invMass; |
54 | m_invIA = m_bodyA->m_invI; |
55 | m_invIB = m_bodyB->m_invI; |
56 | |
57 | b2Vec2 cA = data.positions[m_indexA].c; |
58 | float32 aA = data.positions[m_indexA].a; |
59 | b2Vec2 vA = data.velocities[m_indexA].v; |
60 | float32 wA = data.velocities[m_indexA].w; |
61 | |
62 | b2Vec2 cB = data.positions[m_indexB].c; |
63 | float32 aB = data.positions[m_indexB].a; |
64 | b2Vec2 vB = data.velocities[m_indexB].v; |
65 | float32 wB = data.velocities[m_indexB].w; |
66 | |
67 | b2Rot qA(aA), qB(aB); |
68 | |
69 | m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); |
70 | m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); |
71 | m_u = cB + m_rB - cA - m_rA; |
72 | |
73 | m_length = m_u.Length(); |
74 | |
75 | float32 C = m_length - m_maxLength; |
76 | if (C > 0.0f) |
77 | { |
78 | m_state = e_atUpperLimit; |
79 | } |
80 | else |
81 | { |
82 | m_state = e_inactiveLimit; |
83 | } |
84 | |
85 | if (m_length > b2_linearSlop) |
86 | { |
87 | m_u *= 1.0f / m_length; |
88 | } |
89 | else |
90 | { |
91 | m_u.SetZero(); |
92 | m_mass = 0.0f; |
93 | m_impulse = 0.0f; |
94 | return; |
95 | } |
96 | |
97 | // Compute effective mass. |
98 | float32 crA = b2Cross(m_rA, m_u); |
99 | float32 crB = b2Cross(m_rB, m_u); |
100 | float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB; |
101 | |
102 | m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; |
103 | |
104 | if (data.step.warmStarting) |
105 | { |
106 | // Scale the impulse to support a variable time step. |
107 | m_impulse *= data.step.dtRatio; |
108 | |
109 | b2Vec2 P = m_impulse * m_u; |
110 | vA -= m_invMassA * P; |
111 | wA -= m_invIA * b2Cross(m_rA, P); |
112 | vB += m_invMassB * P; |
113 | wB += m_invIB * b2Cross(m_rB, P); |
114 | } |
115 | else |
116 | { |
117 | m_impulse = 0.0f; |
118 | } |
119 | |
120 | data.velocities[m_indexA].v = vA; |
121 | data.velocities[m_indexA].w = wA; |
122 | data.velocities[m_indexB].v = vB; |
123 | data.velocities[m_indexB].w = wB; |
124 | } |
125 | |
126 | void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data) |
127 | { |
128 | b2Vec2 vA = data.velocities[m_indexA].v; |
129 | float32 wA = data.velocities[m_indexA].w; |
130 | b2Vec2 vB = data.velocities[m_indexB].v; |
131 | float32 wB = data.velocities[m_indexB].w; |
132 | |
133 | // Cdot = dot(u, v + cross(w, r)) |
134 | b2Vec2 vpA = vA + b2Cross(wA, m_rA); |
135 | b2Vec2 vpB = vB + b2Cross(wB, m_rB); |
136 | float32 C = m_length - m_maxLength; |
137 | float32 Cdot = b2Dot(m_u, vpB - vpA); |
138 | |
139 | // Predictive constraint. |
140 | if (C < 0.0f) |
141 | { |
142 | Cdot += data.step.inv_dt * C; |
143 | } |
144 | |
145 | float32 impulse = -m_mass * Cdot; |
146 | float32 oldImpulse = m_impulse; |
147 | m_impulse = b2Min(0.0f, m_impulse + impulse); |
148 | impulse = m_impulse - oldImpulse; |
149 | |
150 | b2Vec2 P = impulse * m_u; |
151 | vA -= m_invMassA * P; |
152 | wA -= m_invIA * b2Cross(m_rA, P); |
153 | vB += m_invMassB * P; |
154 | wB += m_invIB * b2Cross(m_rB, P); |
155 | |
156 | data.velocities[m_indexA].v = vA; |
157 | data.velocities[m_indexA].w = wA; |
158 | data.velocities[m_indexB].v = vB; |
159 | data.velocities[m_indexB].w = wB; |
160 | } |
161 | |
162 | bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data) |
163 | { |
164 | b2Vec2 cA = data.positions[m_indexA].c; |
165 | float32 aA = data.positions[m_indexA].a; |
166 | b2Vec2 cB = data.positions[m_indexB].c; |
167 | float32 aB = data.positions[m_indexB].a; |
168 | |
169 | b2Rot qA(aA), qB(aB); |
170 | |
171 | b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); |
172 | b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); |
173 | b2Vec2 u = cB + rB - cA - rA; |
174 | |
175 | float32 length = u.Normalize(); |
176 | float32 C = length - m_maxLength; |
177 | |
178 | C = b2Clamp(C, 0.0f, b2_maxLinearCorrection); |
179 | |
180 | float32 impulse = -m_mass * C; |
181 | b2Vec2 P = impulse * u; |
182 | |
183 | cA -= m_invMassA * P; |
184 | aA -= m_invIA * b2Cross(rA, P); |
185 | cB += m_invMassB * P; |
186 | aB += m_invIB * b2Cross(rB, P); |
187 | |
188 | data.positions[m_indexA].c = cA; |
189 | data.positions[m_indexA].a = aA; |
190 | data.positions[m_indexB].c = cB; |
191 | data.positions[m_indexB].a = aB; |
192 | |
193 | return length - m_maxLength < b2_linearSlop; |
194 | } |
195 | |
196 | b2Vec2 b2RopeJoint::GetAnchorA() const |
197 | { |
198 | return m_bodyA->GetWorldPoint(m_localAnchorA); |
199 | } |
200 | |
201 | b2Vec2 b2RopeJoint::GetAnchorB() const |
202 | { |
203 | return m_bodyB->GetWorldPoint(m_localAnchorB); |
204 | } |
205 | |
206 | b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const |
207 | { |
208 | b2Vec2 F = (inv_dt * m_impulse) * m_u; |
209 | return F; |
210 | } |
211 | |
212 | float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const |
213 | { |
214 | B2_NOT_USED(inv_dt); |
215 | return 0.0f; |
216 | } |
217 | |
218 | float32 b2RopeJoint::GetMaxLength() const |
219 | { |
220 | return m_maxLength; |
221 | } |
222 | |
223 | b2LimitState b2RopeJoint::GetLimitState() const |
224 | { |
225 | return m_state; |
226 | } |
227 | |
228 | void b2RopeJoint::Dump() |
229 | { |
230 | int32 indexA = m_bodyA->m_islandIndex; |
231 | int32 indexB = m_bodyB->m_islandIndex; |
232 | |
233 | b2Log(" b2RopeJointDef jd;\n" ); |
234 | b2Log(" jd.bodyA = bodies[%d];\n" , indexA); |
235 | b2Log(" jd.bodyB = bodies[%d];\n" , indexB); |
236 | b2Log(" jd.collideConnected = bool(%d);\n" , m_collideConnected); |
237 | b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n" , m_localAnchorA.x, m_localAnchorA.y); |
238 | b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n" , m_localAnchorB.x, m_localAnchorB.y); |
239 | b2Log(" jd.maxLength = %.15lef;\n" , m_maxLength); |
240 | b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n" , m_index); |
241 | } |
242 | |