/*******************************************************************************
* Copyright (c) 2011, Daniel Murphy
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL MURPHY BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
/**
* Created at 3:38:38 AM Jan 15, 2011
*/
package org.jbox2d.dynamics.joints;
import org.jbox2d.common.Mat22;
import org.jbox2d.common.Mat33;
import org.jbox2d.common.MathUtils;
import org.jbox2d.common.Settings;
import org.jbox2d.common.Vec2;
import org.jbox2d.common.Vec3;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.TimeStep;
import org.jbox2d.pooling.IWorldPool;
/**
* @author Daniel Murphy
*/
public class WeldJoint extends Joint {
private final Vec2 m_localAnchorA;
private final Vec2 m_localAnchorB;
private float m_referenceAngle;
private final Vec3 m_impulse;
private final Mat33 m_mass;
/**
* @param argWorld
* @param def
*/
protected WeldJoint(IWorldPool argWorld, WeldJointDef def) {
super(argWorld, def);
m_localAnchorA = new Vec2(def.localAnchorA);
m_localAnchorB = new Vec2(def.localAnchorB);
m_referenceAngle = def.referenceAngle;
m_impulse = new Vec3();
m_impulse.setZero();
m_mass = new Mat33();
}
/**
* @see org.jbox2d.dynamics.joints.Joint#getAnchorA(org.jbox2d.common.Vec2)
*/
@Override
public void getAnchorA(Vec2 argOut) {
m_bodyA.getWorldPointToOut(m_localAnchorA, argOut);
}
/**
* @see org.jbox2d.dynamics.joints.Joint#getAnchorB(org.jbox2d.common.Vec2)
*/
@Override
public void getAnchorB(Vec2 argOut) {
m_bodyB.getWorldPointToOut(m_localAnchorB, argOut);
}
/**
* @see org.jbox2d.dynamics.joints.Joint#getReactionForce(float, org.jbox2d.common.Vec2)
*/
@Override
public void getReactionForce(float inv_dt, Vec2 argOut) {
argOut.set(m_impulse.x, m_impulse.y);
argOut.mulLocal(inv_dt);
}
/**
* @see org.jbox2d.dynamics.joints.Joint#getReactionTorque(float)
*/
@Override
public float getReactionTorque(float inv_dt) {
return inv_dt * m_impulse.z;
}
/**
* @see org.jbox2d.dynamics.joints.Joint#initVelocityConstraints(org.jbox2d.dynamics.TimeStep)
*/
@Override
public void initVelocityConstraints(TimeStep step) {
Body bA = m_bodyA;
Body bB = m_bodyB;
// Compute the effective mass matrix.
final Vec2 rA = pool.popVec2();
final Vec2 rB = pool.popVec2();
rA.set(m_localAnchorA).subLocal(bA.getLocalCenter());
rB.set(m_localAnchorB).subLocal(bB.getLocalCenter());
Mat22.mulToOut(bA.getTransform().R, rA, rA);
Mat22.mulToOut(bB.getTransform().R, rB, rB);
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
// r_skew = [-ry; rx]
// Matlab
// K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
// [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
// [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
float mA = bA.m_invMass, mB = bB.m_invMass;
float iA = bA.m_invI, iB = bB.m_invI;
m_mass.col1.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
m_mass.col2.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
m_mass.col3.x = -rA.y * iA - rB.y * iB;
m_mass.col1.y = m_mass.col2.x;
m_mass.col2.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
m_mass.col3.y = rA.x * iA + rB.x * iB;
m_mass.col1.z = m_mass.col3.x;
m_mass.col2.z = m_mass.col3.y;
m_mass.col3.z = iA + iB;
if (step.warmStarting)
{
// Scale impulses to support a variable time step.
m_impulse.mulLocal(step.dtRatio);
final Vec2 P = pool.popVec2();
final Vec2 temp = pool.popVec2();
P.set(m_impulse.x, m_impulse.y);
temp.set(P).mulLocal(mA);
bA.m_linearVelocity.subLocal(temp);
bA.m_angularVelocity -= iA * (Vec2.cross(rA, P) + m_impulse.z);
temp.set(P).mulLocal(mB);
bB.m_linearVelocity.addLocal(temp);
bB.m_angularVelocity += iB * (Vec2.cross(rB, P) + m_impulse.z);
pool.pushVec2(2);
}
else
{
m_impulse.setZero();
}
pool.pushVec2(2);
}
/**
* @see org.jbox2d.dynamics.joints.Joint#solveVelocityConstraints(org.jbox2d.dynamics.TimeStep)
*/
@Override
public void solveVelocityConstraints(TimeStep step) {
Body bA = m_bodyA;
Body bB = m_bodyB;
Vec2 vA = bA.m_linearVelocity;
float wA = bA.m_angularVelocity;
Vec2 vB = bB.m_linearVelocity;
float wB = bB.m_angularVelocity;
float mA = bA.m_invMass, mB = bB.m_invMass;
float iA = bA.m_invI, iB = bB.m_invI;
final Vec2 rA = pool.popVec2();
final Vec2 rB = pool.popVec2();
rA.set(m_localAnchorA).subLocal(bA.getLocalCenter());
rB.set(m_localAnchorB).subLocal(bB.getLocalCenter());
Mat22.mulToOut(bA.getTransform().R, rA, rA);
Mat22.mulToOut(bB.getTransform().R, rB, rB);
final Vec2 Cdot1 = pool.popVec2();
final Vec2 temp = pool.popVec2();
// Solve point-to-point finalraint
Vec2.crossToOut(wA, rA, temp);
Vec2.crossToOut(wB, rB, Cdot1);
Cdot1.addLocal(vB).subLocal(vA).subLocal(temp);
float Cdot2 = wB - wA;
final Vec3 Cdot = pool.popVec3();
Cdot.set(Cdot1.x, Cdot1.y, Cdot2);
final Vec3 impulse = pool.popVec3();
m_mass.solve33ToOut(Cdot.negateLocal(), impulse); // just leave Cdot negated..
m_impulse.addLocal(impulse);
final Vec2 P = pool.popVec2();
P.set(impulse.x, impulse.y);
temp.set(P).mulLocal(mA);
vA.subLocal(temp);
wA -= iA * (Vec2.cross(rA, P) + impulse.z);
temp.set(P).mulLocal(mB);
vB.addLocal(temp);
wB += iB * (Vec2.cross(rB, P) + impulse.z);
bA.m_linearVelocity.set(vA);
bA.m_angularVelocity = wA;
bB.m_linearVelocity.set(vB);
bB.m_angularVelocity = wB;
pool.pushVec2(5);
pool.pushVec3(2);
}
/**
* @see org.jbox2d.dynamics.joints.Joint#solvePositionConstraints(float)
*/
@Override
public boolean solvePositionConstraints(float baumgarte) {
Body bA = m_bodyA;
Body bB = m_bodyB;
float mA = bA.m_invMass, mB = bB.m_invMass;
float iA = bA.m_invI, iB = bB.m_invI;
final Vec2 rA = pool.popVec2();
final Vec2 rB = pool.popVec2();
rA.set(m_localAnchorA).subLocal(bA.getLocalCenter());
rB.set(m_localAnchorB).subLocal(bB.getLocalCenter());
Mat22.mulToOut(bA.getTransform().R, rA, rA);
Mat22.mulToOut(bB.getTransform().R, rB, rB);
final Vec2 C1 = pool.popVec2();
C1.set(bB.m_sweep.c).addLocal(rB).subLocal(bA.m_sweep.c).subLocal(rA);
float C2 = bB.m_sweep.a - bA.m_sweep.a - m_referenceAngle;
// Handle large detachment.
final float k_allowedStretch = 10.0f * Settings.linearSlop;
float positionError = C1.length();
float angularError = MathUtils.abs(C2);
if (positionError > k_allowedStretch){
iA *= 1.0f;
iB *= 1.0f;
}
m_mass.col1.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
m_mass.col2.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
m_mass.col3.x = -rA.y * iA - rB.y * iB;
m_mass.col1.y = m_mass.col2.x;
m_mass.col2.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
m_mass.col3.y = rA.x * iA + rB.x * iB;
m_mass.col1.z = m_mass.col3.x;
m_mass.col2.z = m_mass.col3.y;
m_mass.col3.z = iA + iB;
final Vec3 C = pool.popVec3();
final Vec3 impulse = pool.popVec3();
C.set(C1.x, C1.y, C2);
m_mass.solve33ToOut(C.negateLocal(), impulse); // just leave c negated..
final Vec2 P = pool.popVec2();
final Vec2 temp = pool.popVec2();
P.set(impulse.x, impulse.y);
temp.set(P).mulLocal(mA);
bA.m_sweep.c.subLocal(temp);
bA.m_sweep.a -= iA * (Vec2.cross(rA, P) + impulse.z);
temp.set(P).mulLocal(mB);
bB.m_sweep.c.addLocal(temp);
bB.m_sweep.a += iB * (Vec2.cross(rB, P) + impulse.z);
bA.synchronizeTransform();
bB.synchronizeTransform();
pool.pushVec2(5);
pool.pushVec3(2);
return positionError <= Settings.linearSlop && angularError <= Settings.angularSlop;
}
}