All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jbox2d.dynamics.joints.PulleyJoint Maven / Gradle / Ivy

There is a newer version: 1.9.1
Show newest version
/*******************************************************************************
 * 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  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 12:12:02 PM Jan 23, 2011
 */
package org.jbox2d.dynamics.joints;

import org.jbox2d.common.Mat22;
import org.jbox2d.common.MathUtils;
import org.jbox2d.common.Settings;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.TimeStep;
import org.jbox2d.pooling.IWorldPool;

/**
 * @author Daniel Murphy
 */
public class PulleyJoint extends Joint {
	
	public static final float MIN_PULLEY_LENGTH = 2.0f;
	
	private final Vec2 m_groundAnchor1 = new Vec2();
	private final Vec2 m_groundAnchor2 = new Vec2();
	private final Vec2 m_localAnchor1 = new Vec2();
	private final Vec2 m_localAnchor2 = new Vec2();
	
	private final Vec2 m_u1 = new Vec2();
	private final Vec2 m_u2 = new Vec2();
	
	private float m_constant;
	private float m_ratio;
	
	private float m_maxLength1;
	private float m_maxLength2;
	
	// Effective masses
	private float m_pulleyMass;
	private float m_limitMass1;
	private float m_limitMass2;
	
	// Impulses for accumulation/warm starting.
	private float m_impulse;
	private float m_limitImpulse1;
	private float m_limitImpulse2;
	
	private LimitState m_state;
	private LimitState m_limitState1;
	private LimitState m_limitState2;
	
	/**
	 * @param argWorldPool
	 * @param def
	 */
	public PulleyJoint(IWorldPool argWorldPool, PulleyJointDef def) {
		super(argWorldPool, def);
		m_groundAnchor1.set(def.groundAnchorA);
		m_groundAnchor2.set(def.groundAnchorB);
		m_localAnchor1.set(def.localAnchorA);
		m_localAnchor2.set(def.localAnchorB);
		
		assert (def.ratio != 0.0f);
		m_ratio = def.ratio;
		
		m_constant = def.lengthA + m_ratio * def.lengthB;
		
		m_maxLength1 = MathUtils.min(def.maxLengthA, m_constant - m_ratio * MIN_PULLEY_LENGTH);
		m_maxLength2 = MathUtils.min(def.maxLengthB, (m_constant - MIN_PULLEY_LENGTH) / m_ratio);
		
		m_impulse = 0.0f;
		m_limitImpulse1 = 0.0f;
		m_limitImpulse2 = 0.0f;
	}
	
	/**
	 * @see org.jbox2d.dynamics.joints.Joint#getAnchorA(org.jbox2d.common.Vec2)
	 */
	@Override
	public void getAnchorA(Vec2 argOut) {
		m_bodyA.getWorldPointToOut(m_localAnchor1, argOut);
	}
	
	/**
	 * @see org.jbox2d.dynamics.joints.Joint#getAnchorB(org.jbox2d.common.Vec2)
	 */
	@Override
	public void getAnchorB(Vec2 argOut) {
		m_bodyB.getWorldPointToOut(m_localAnchor2, 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_u2).mulLocal(m_impulse).mulLocal(inv_dt);
	}
	
	/**
	 * @see org.jbox2d.dynamics.joints.Joint#getReactionTorque(float)
	 */
	@Override
	public float getReactionTorque(float inv_dt) {
		return 0f;
	}
	
	public Vec2 getGroundAnchorA() {
		return m_groundAnchor1;
	}
	
	public Vec2 getGroundAnchorB() {
		return m_groundAnchor2;
	}
	
	public float getLength1() {
		final Vec2 p = pool.popVec2();
		m_bodyA.getWorldPointToOut(m_localAnchor1, p);
		p.subLocal(m_groundAnchor1);
		
		float len = p.length();
		pool.pushVec2(1);
		return len;
	}
	
	public float getLength2() {
		final Vec2 p = pool.popVec2();
		m_bodyB.getWorldPointToOut(m_localAnchor2, p);
		p.subLocal(m_groundAnchor2);
		
		float len = p.length();
		pool.pushVec2(1);
		return len;
	}
	
	public float getRatio() {
		return m_ratio;
	}
	
	/**
	 * @see org.jbox2d.dynamics.joints.Joint#initVelocityConstraints(org.jbox2d.dynamics.TimeStep)
	 */
	@Override
	public void initVelocityConstraints(TimeStep step) {
		Body b1 = m_bodyA;
		Body b2 = m_bodyB;
		
		final Vec2 r1 = pool.popVec2();
		final Vec2 r2 = pool.popVec2();
		final Vec2 p1 = pool.popVec2();
		final Vec2 p2 = pool.popVec2();
		final Vec2 s1 = pool.popVec2();
		final Vec2 s2 = pool.popVec2();
		
		r1.set(m_localAnchor1).subLocal(b1.getLocalCenter());
		r2.set(m_localAnchor2).subLocal(b2.getLocalCenter());
		
		Mat22.mulToOut(b1.getTransform().R, r1, r1);
		Mat22.mulToOut(b2.getTransform().R, r2, r2);
		
		p1.set(b1.m_sweep.c).addLocal(r1);
		p2.set(b2.m_sweep.c).addLocal(r2);
		
		s1.set(m_groundAnchor1);
		s2.set(m_groundAnchor2);
		
		// Get the pulley axes.
		m_u1.set(p1).subLocal(s1);
		m_u2.set(p2).subLocal(s2);
		
		float length1 = m_u1.length();
		float length2 = m_u2.length();
		
		if (length1 > Settings.linearSlop) {
			m_u1.mulLocal(1.0f / length1);
		}
		else {
			m_u1.setZero();
		}
		
		if (length2 > Settings.linearSlop) {
			m_u2.mulLocal(1.0f / length2);
		}
		else {
			m_u2.setZero();
		}
		
		float C = m_constant - length1 - m_ratio * length2;
		if (C > 0.0f) {
			m_state = LimitState.INACTIVE;
			m_impulse = 0.0f;
		}
		else {
			m_state = LimitState.AT_UPPER;
		}
		
		if (length1 < m_maxLength1) {
			m_limitState1 = LimitState.INACTIVE;
			m_limitImpulse1 = 0.0f;
		}
		else {
			m_limitState1 = LimitState.AT_UPPER;
		}
		
		if (length2 < m_maxLength2) {
			m_limitState2 = LimitState.INACTIVE;
			m_limitImpulse2 = 0.0f;
		}
		else {
			m_limitState2 = LimitState.AT_UPPER;
		}
		
		// Compute effective mass.
		float cr1u1 = Vec2.cross(r1, m_u1);
		float cr2u2 = Vec2.cross(r2, m_u2);
		
		m_limitMass1 = b1.m_invMass + b1.m_invI * cr1u1 * cr1u1;
		m_limitMass2 = b2.m_invMass + b2.m_invI * cr2u2 * cr2u2;
		m_pulleyMass = m_limitMass1 + m_ratio * m_ratio * m_limitMass2;
		assert (m_limitMass1 > Settings.EPSILON);
		assert (m_limitMass2 > Settings.EPSILON);
		assert (m_pulleyMass > Settings.EPSILON);
		m_limitMass1 = 1.0f / m_limitMass1;
		m_limitMass2 = 1.0f / m_limitMass2;
		m_pulleyMass = 1.0f / m_pulleyMass;
		
		if (step.warmStarting) {
			// Scale impulses to support variable time steps.
			m_impulse *= step.dtRatio;
			m_limitImpulse1 *= step.dtRatio;
			m_limitImpulse2 *= step.dtRatio;
			
			final Vec2 P1 = pool.popVec2();
			final Vec2 P2 = pool.popVec2();
			final Vec2 temp = pool.popVec2();
			
			// Warm starting.
			P1.set(m_u1).mulLocal(-(m_impulse + m_limitImpulse1));
			P2.set(m_u2).mulLocal(-m_ratio * m_impulse - m_limitImpulse2);
			
			temp.set(P1).mulLocal(b1.m_invMass);
			b1.m_linearVelocity.addLocal(temp);
			b1.m_angularVelocity += b1.m_invI * Vec2.cross(r1, P1);
			
			temp.set(P2).mulLocal(b2.m_invMass);
			b2.m_linearVelocity.addLocal(temp);
			b2.m_angularVelocity += b2.m_invI * Vec2.cross(r2, P2);
			
			pool.pushVec2(3);
		}
		else {
			m_impulse = 0.0f;
			m_limitImpulse1 = 0.0f;
			m_limitImpulse2 = 0.0f;
		}
		
		pool.pushVec2(6);
	}
	
	/**
	 * @see org.jbox2d.dynamics.joints.Joint#solveVelocityConstraints(org.jbox2d.dynamics.TimeStep)
	 */
	@Override
	public void solveVelocityConstraints(TimeStep step) {
		Body b1 = m_bodyA;
		Body b2 = m_bodyB;
		
		final Vec2 r1 = pool.popVec2();
		final Vec2 r2 = pool.popVec2();
		
		r1.set(m_localAnchor1).subLocal(b1.getLocalCenter());
		r2.set(m_localAnchor2).subLocal(b2.getLocalCenter());
		
		Mat22.mulToOut(b1.getTransform().R, r1, r1);
		Mat22.mulToOut(b2.getTransform().R, r2, r2);
		
		if (m_state == LimitState.AT_UPPER) {
			final Vec2 v1 = pool.popVec2();
			final Vec2 v2 = pool.popVec2();
			
			Vec2.crossToOut(b1.m_angularVelocity, r1, v1);
			Vec2.crossToOut(b2.m_angularVelocity, r2, v2);
			
			v1.addLocal(b1.m_linearVelocity);
			v2.addLocal(b2.m_linearVelocity);
			
			float Cdot = -Vec2.dot(m_u1, v1) - m_ratio * Vec2.dot(m_u2, v2);
			float impulse = m_pulleyMass * (-Cdot);
			float oldImpulse = m_impulse;
			m_impulse = MathUtils.max(0.0f, m_impulse + impulse);
			impulse = m_impulse - oldImpulse;
			
			final Vec2 P1 = pool.popVec2();
			final Vec2 P2 = pool.popVec2();
			final Vec2 temp = pool.popVec2();
			
			P1.set(m_u1).mulLocal(-impulse);
			P2.set(m_u2).mulLocal(-m_ratio * impulse);
			
			temp.set(P1).mulLocal(b1.m_invMass);
			b1.m_linearVelocity.addLocal(temp);
			b1.m_angularVelocity += b1.m_invI * Vec2.cross(r1, P1);
			
			temp.set(P2).mulLocal(b2.m_invMass);
			b2.m_linearVelocity.addLocal(temp);
			b2.m_angularVelocity += b2.m_invI * Vec2.cross(r2, P2);
			
			pool.pushVec2(5);
		}
		
		if (m_limitState1 == LimitState.AT_UPPER) {
			final Vec2 v1 = pool.popVec2();
			
			Vec2.crossToOut(b1.m_angularVelocity, r1, v1);
			v1.addLocal(b1.m_linearVelocity);
			
			float Cdot = -Vec2.dot(m_u1, v1);
			float impulse = -m_limitMass1 * Cdot;
			float oldImpulse = m_limitImpulse1;
			m_limitImpulse1 = MathUtils.max(0.0f, m_limitImpulse1 + impulse);
			impulse = m_limitImpulse1 - oldImpulse;
			
			final Vec2 P1 = pool.popVec2();
			final Vec2 temp = pool.popVec2();
			
			P1.set(m_u1).mulLocal(-impulse);
			
			temp.set(P1).mulLocal(b1.m_invMass);
			b1.m_linearVelocity.addLocal(temp);
			b1.m_angularVelocity += b1.m_invI * Vec2.cross(r1, P1);
			
			pool.pushVec2(3);
		}
		
		if (m_limitState2 == LimitState.AT_UPPER) {
			
			final Vec2 v2 = pool.popVec2();
			Vec2.crossToOut(b2.m_angularVelocity, r2, v2);
			v2.addLocal(b2.m_linearVelocity);
			
			float Cdot = -Vec2.dot(m_u2, v2);
			float impulse = -m_limitMass2 * Cdot;
			float oldImpulse = m_limitImpulse2;
			m_limitImpulse2 = MathUtils.max(0.0f, m_limitImpulse2 + impulse);
			impulse = m_limitImpulse2 - oldImpulse;
			
			final Vec2 P2 = pool.popVec2();
			final Vec2 temp = pool.popVec2();
			
			P2.set(m_u2).mulLocal(-impulse);
			
			temp.set(P2).mulLocal(b2.m_invMass);
			b2.m_linearVelocity.addLocal(temp);
			b2.m_angularVelocity += b2.m_invI * Vec2.cross(r2, P2);
			
			pool.pushVec2(3);
		}
		
		pool.pushVec2(2);
	}
	
	/**
	 * @see org.jbox2d.dynamics.joints.Joint#solvePositionConstraints(float)
	 */
	@Override
	public boolean solvePositionConstraints(float baumgarte) {
		Body b1 = m_bodyA;
		Body b2 = m_bodyB;
		
		final Vec2 s1 = pool.popVec2();
		final Vec2 s2 = pool.popVec2();
		
		s1.set(m_groundAnchor1);
		s2.set(m_groundAnchor2);
		
		float linearError = 0.0f;
		
		if (m_state == LimitState.AT_UPPER) {
			final Vec2 r1 = pool.popVec2();
			final Vec2 r2 = pool.popVec2();
			final Vec2 p1 = pool.popVec2();
			final Vec2 p2 = pool.popVec2();
			
			r1.set(m_localAnchor1).subLocal(b1.getLocalCenter());
			r2.set(m_localAnchor2).subLocal(b2.getLocalCenter());
			
			Mat22.mulToOut(b1.getTransform().R, r1, r1);
			Mat22.mulToOut(b2.getTransform().R, r2, r2);
			
			p1.set(b1.m_sweep.c).addLocal(r1);
			p2.set(b2.m_sweep.c).addLocal(r2);
			
			// Get the pulley axes.
			m_u1.set(p1).subLocal(s1);
			m_u2.set(p2).subLocal(s2);
			
			float length1 = m_u1.length();
			float length2 = m_u2.length();
			
			if (length1 > Settings.linearSlop) {
				m_u1.mulLocal(1.0f / length1);
			}
			else {
				m_u1.setZero();
			}
			
			if (length2 > Settings.linearSlop) {
				m_u2.mulLocal(1.0f / length2);
			}
			else {
				m_u2.setZero();
			}
			
			float C = m_constant - length1 - m_ratio * length2;
			linearError = MathUtils.max(linearError, -C);
			
			C = MathUtils.clamp(C + Settings.linearSlop, -Settings.maxLinearCorrection, 0.0f);
			float impulse = -m_pulleyMass * C;
			
			final Vec2 P1 = pool.popVec2();
			final Vec2 P2 = pool.popVec2();
			final Vec2 temp = pool.popVec2();
			
			P1.set(m_u1).mulLocal(-impulse);
			P2.set(m_u2).mulLocal(-m_ratio * impulse);
			
			temp.set(P1).mulLocal(b1.m_invMass);
			b1.m_sweep.c.addLocal(temp);
			b1.m_sweep.a += b1.m_invI * Vec2.cross(r1, P1);
			
			temp.set(P2).mulLocal(b2.m_invMass);
			b2.m_sweep.c.addLocal(temp);
			b2.m_sweep.a += b2.m_invI * Vec2.cross(r2, P2);
			
			b1.synchronizeTransform();
			b2.synchronizeTransform();
			
			pool.pushVec2(7);
		}
		
		if (m_limitState1 == LimitState.AT_UPPER) {
			final Vec2 r1 = pool.popVec2();
			final Vec2 p1 = pool.popVec2();
			
			r1.set(m_localAnchor1).subLocal(b1.getLocalCenter());
			
			Mat22.mulToOut(b1.getTransform().R, r1, r1);
			
			p1.set(b1.m_sweep.c).addLocal(r1);
			
			m_u1.set(p1).subLocal(s1);
			
			float length1 = m_u1.length();
			
			if (length1 > Settings.linearSlop) {
				m_u1.mulLocal(1.0f / length1);
			}
			else {
				m_u1.setZero();
			}
			
			float C = m_maxLength1 - length1;
			linearError = MathUtils.max(linearError, -C);
			C = MathUtils.clamp(C + Settings.linearSlop, -Settings.maxLinearCorrection, 0.0f);
			float impulse = -m_limitMass1 * C;
			
			final Vec2 P1 = pool.popVec2();
			final Vec2 temp = pool.popVec2();
			
			P1.set(m_u1).mulLocal(-impulse);
			
			temp.set(P1).mulLocal(b1.m_invMass);
			b1.m_sweep.c.addLocal(temp);
			b1.m_sweep.a += b1.m_invI * Vec2.cross(r1, P1);
			
			b1.synchronizeTransform();
			
			pool.pushVec2(4);
		}
		
		if (m_limitState2 == LimitState.AT_UPPER) {
			final Vec2 r2 = pool.popVec2();
			final Vec2 p2 = pool.popVec2();
			
			r2.set(m_localAnchor2).subLocal(b2.getLocalCenter());
			
			Mat22.mulToOut(b2.getTransform().R, r2, r2);
			
			p2.set(b2.m_sweep.c).addLocal(r2);
			
			// Get the pulley axes.
			m_u2.set(p2).subLocal(s2);
			
			float length2 = m_u2.length();
			
			if (length2 > Settings.linearSlop) {
				m_u2.mulLocal(1.0f / length2);
			}
			else {
				m_u2.setZero();
			}
			
			float C = m_maxLength2 - length2;
			linearError = MathUtils.max(linearError, -C);
			C = MathUtils.clamp(C + Settings.linearSlop, -Settings.maxLinearCorrection, 0.0f);
			float impulse = -m_limitMass2 * C;
			
			final Vec2 P2 = pool.popVec2();
			final Vec2 temp = pool.popVec2();
			
			P2.set(m_u2).mulLocal(-impulse);
			
			temp.set(P2).mulLocal(b2.m_invMass);
			b2.m_sweep.c.addLocal(temp);
			b2.m_sweep.a += b2.m_invI * Vec2.cross(r2, P2);
			
			b2.synchronizeTransform();
			
			pool.pushVec2(4);
		}
		pool.pushVec2(2);
		
		return linearError < Settings.linearSlop;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy