2
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
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 <Box2D/Dynamics/Joints/b2MouseJoint.h>
20
#include <Box2D/Dynamics/b2Body.h>
21
#include <Box2D/Dynamics/b2TimeStep.h>
23
// p = attached point, m = mouse point
29
// w k % (rx i + ry j) = w * (-ry i + rx j)
31
b2MouseJoint::b2MouseJoint(const b2MouseJointDef* def)
34
b2Assert(def->target.IsValid());
35
b2Assert(b2IsValid(def->maxForce) && def->maxForce >= 0.0f);
36
b2Assert(b2IsValid(def->frequencyHz) && def->frequencyHz >= 0.0f);
37
b2Assert(b2IsValid(def->dampingRatio) && def->dampingRatio >= 0.0f);
39
m_targetA = def->target;
40
m_localAnchorB = b2MulT(m_bodyB->GetTransform(), m_targetA);
42
m_maxForce = def->maxForce;
45
m_frequencyHz = def->frequencyHz;
46
m_dampingRatio = def->dampingRatio;
52
void b2MouseJoint::SetTarget(const b2Vec2& target)
54
if (m_bodyB->IsAwake() == false)
56
m_bodyB->SetAwake(true);
61
const b2Vec2& b2MouseJoint::GetTarget() const
66
void b2MouseJoint::SetMaxForce(float32 force)
71
float32 b2MouseJoint::GetMaxForce() const
76
void b2MouseJoint::SetFrequency(float32 hz)
81
float32 b2MouseJoint::GetFrequency() const
86
void b2MouseJoint::SetDampingRatio(float32 ratio)
88
m_dampingRatio = ratio;
91
float32 b2MouseJoint::GetDampingRatio() const
93
return m_dampingRatio;
96
void b2MouseJoint::InitVelocityConstraints(const b2SolverData& data)
98
m_indexB = m_bodyB->m_islandIndex;
99
m_localCenterB = m_bodyB->m_sweep.localCenter;
100
m_invMassB = m_bodyB->m_invMass;
101
m_invIB = m_bodyB->m_invI;
103
b2Vec2 cB = data.positions[m_indexB].c;
104
float32 aB = data.positions[m_indexB].a;
105
b2Vec2 vB = data.velocities[m_indexB].v;
106
float32 wB = data.velocities[m_indexB].w;
110
float32 mass = m_bodyB->GetMass();
113
float32 omega = 2.0f * b2_pi * m_frequencyHz;
115
// Damping coefficient
116
float32 d = 2.0f * mass * m_dampingRatio * omega;
119
float32 k = mass * (omega * omega);
122
// gamma has units of inverse mass.
123
// beta has units of inverse time.
124
float32 h = data.step.dt;
125
b2Assert(d + h * k > b2_epsilon);
126
m_gamma = h * (d + h * k);
129
m_gamma = 1.0f / m_gamma;
131
m_beta = h * k * m_gamma;
133
// Compute the effective mass matrix.
134
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
136
// K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
137
// = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]
138
// [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x]
140
K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma;
141
K.ex.y = -m_invIB * m_rB.x * m_rB.y;
143
K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma;
145
m_mass = K.GetInverse();
147
m_C = cB + m_rB - m_targetA;
150
// Cheat with some damping
153
if (data.step.warmStarting)
155
m_impulse *= data.step.dtRatio;
156
vB += m_invMassB * m_impulse;
157
wB += m_invIB * b2Cross(m_rB, m_impulse);
164
data.velocities[m_indexB].v = vB;
165
data.velocities[m_indexB].w = wB;
168
void b2MouseJoint::SolveVelocityConstraints(const b2SolverData& data)
170
b2Vec2 vB = data.velocities[m_indexB].v;
171
float32 wB = data.velocities[m_indexB].w;
173
// Cdot = v + cross(w, r)
174
b2Vec2 Cdot = vB + b2Cross(wB, m_rB);
175
b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse));
177
b2Vec2 oldImpulse = m_impulse;
178
m_impulse += impulse;
179
float32 maxImpulse = data.step.dt * m_maxForce;
180
if (m_impulse.LengthSquared() > maxImpulse * maxImpulse)
182
m_impulse *= maxImpulse / m_impulse.Length();
184
impulse = m_impulse - oldImpulse;
186
vB += m_invMassB * impulse;
187
wB += m_invIB * b2Cross(m_rB, impulse);
189
data.velocities[m_indexB].v = vB;
190
data.velocities[m_indexB].w = wB;
193
bool b2MouseJoint::SolvePositionConstraints(const b2SolverData& data)
199
b2Vec2 b2MouseJoint::GetAnchorA() const
204
b2Vec2 b2MouseJoint::GetAnchorB() const
206
return m_bodyB->GetWorldPoint(m_localAnchorB);
209
b2Vec2 b2MouseJoint::GetReactionForce(float32 inv_dt) const
211
return inv_dt * m_impulse;
214
float32 b2MouseJoint::GetReactionTorque(float32 inv_dt) const
216
return inv_dt * 0.0f;