API Documentation for:
Show:

File:addBox2D\Dynamics\Joints\b2MouseJoint.js

//################################################################################################//
//################################################################################################//
//                                                                                                //
//            ██    ██████ ██   ██                            ██       ██        ██               //
//            ██        ██ ███ ███                            ██                 ██               //
//            █████     ██ ███████ █████ ██ ██ █████ █████    ██ █████ ██ █████ █████             //
//            ██ ██ ██████ ██ █ ██ ██ ██ ██ ██ ██    ██ ██    ██ ██ ██ ██ ██ ██  ██               //
//            ██ ██ ██     ██   ██ ██ ██ ██ ██ █████ █████    ██ ██ ██ ██ ██ ██  ██               //
//            ██ ██ ██     ██   ██ ██ ██ ██ ██    ██ ██       ██ ██ ██ ██ ██ ██  ██               //
//            █████ ██████ ██   ██ █████ █████ █████ █████ █████ █████ ██ ██ ██  ████             //
//                                                                                                //
//################################################################################################//
//################################################################################################//

 // CLASS CONSTRUCTOR

    /**
     * A mouse joint is used to make a point on a body track a
     * specified world point. This a soft constraint with a maximum
     * force. This allows the constraint to stretch and without
     * applying huge forces.
     *
     * NOTE: this joint is not documented in the manual because it
     * was developed to be used in the testbed. If you want to learn
     * how to use the mouse joint, look at the testbed.
     *
     * @class   b2MouseJoint
     * @constructor
     * @param   {b2MouseJointDef}  mouseJointDef
     * @extends {b2Joint}
     * @module  Joints
     */
    function b2MouseJoint( mouseJointDef ) {

        /**
         *Invoke parent class constructor function reference.
         */
        this.constructor( mouseJointDef );

////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                //
//                  ██████                              ██   ██                                   //
//                  ██  ██                              ██                                        //
//                  ██  ██ ████ █████ █████ █████ ████ █████ ██ █████ █████                       //
//                  ██████ ██   ██ ██ ██ ██ ██ ██ ██    ██   ██ ██ ██ ██                          //
//                  ██     ██   ██ ██ ██ ██ █████ ██    ██   ██ █████ █████                       //
//                  ██     ██   ██ ██ ██ ██ ██    ██    ██   ██ ██       ██                       //
//                  ██     ██   █████ █████ █████ ██    ████ ██ █████ █████                       //
//                                    ██                                                          //
//                                    ██                                                          //
//                                                                                                //
////////////////////////////////////////////////////////////////////////////////////////////////////

     // property DECLARATIONS

        /**
         *
         * @public
         * @property  m_K
         * @type      {b2Mat22}
         */
        this.m_K = new b2Mat22;

        /**
         *
         * @public
         * @property  m_mass
         * @type      {b2Mat22}
         */
        this.m_mass = new b2Mat22;

        /**
         *
         * @public
         * @property  m_localAnchorB
         * @type      {b2Vec2}
         */
        this.m_localAnchorB = new b2Vec2;

        /**
         *
         * @public
         * @property  m_targetA
         * @type      {b2Vec2}
         */
        this.m_targetA = new b2Vec2;

        /**
         *
         * @public
         * @property  m_impulse
         * @type      {b2Vec2}
         */
        this.m_impulse = new b2Vec2;

        /**
         *
         * @public
         * @property  m_rB
         * @type      {b2Vec2}
         */
        this.m_rB = new b2Vec2;

        /**
         *
         * @public
         * @property  m_localCenterB
         * @type      {b2Vec2}
         */
        this.m_localCenterB = new b2Vec2;

        /**
         *
         * @public
         * @property  m_C
         * @type      {b2Vec2}
         */
        this.m_C = new b2Vec2;

        /**
         *
         * @public
         * @property  m_qB
         * @type      {b2Rot}
         */
        this.m_qB = new b2Rot();

        /**
         *
         * @public
         * @property  m_lalcB
         * @type      {b2Vec2}
         */
        this.m_lalcB = new b2Vec2;
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( mouseJointDef.target.isValid() );
            b2Assert( isFinite( mouseJointDef.maxForce ) && mouseJointDef.maxForce >= 0 );
            b2Assert( isFinite( mouseJointDef.frequencyHz ) && mouseJointDef.frequencyHz >= 0 );
            b2Assert( isFinite( mouseJointDef.dampingRatio ) && mouseJointDef.dampingRatio >= 0 );
        }/*#*/

     // property INITIALISATIONS

        this.m_targetA.copy( mouseJointDef.target );
        b2Transform.tTimesV2( this.m_bodyB.getTransform(), this.m_targetA, this.m_localAnchorB );
        this.m_impulse.setZero();

        /**
         *
         * @public
         * @property  m_maxForce
         * @type      {float}
         */
        this.m_maxForce = mouseJointDef.maxForce;

        /**
         *
         * @public
         * @property  m_frequencyHz
         * @type      {float}
         */
        this.m_frequencyHz = mouseJointDef.frequencyHz;

        /**
         *
         * @public
         * @property  m_dampingRatio
         * @type      {float}
         */
        this.m_dampingRatio = mouseJointDef.dampingRatio;

        /**
         *
         * @public
         * @property  m_beta
         * @type      {float}
         * @default   0.0
         */
        this.m_beta = 0.0;

        /**
         *
         * @public
         * @property  m_gamma
         * @type      {float}
         * @default   0.0
         */
        this.m_gamma = 0.0;

        /**
         *
         * @public
         * @property  m_indexA
         * @type      {int}
         * @default   0
         */
        this.m_indexA = 0;

        /**
         *
         * @public
         * @property  m_indexB
         * @type      {int}
         * @default   0
         */
        this.m_indexB = 0;

        /**
         *
         * @public
         * @property  m_invMassB
         * @type      {float}
         * @default   0.0
         */
        this.m_invMassB = 0.0;

        /**
         *
         * @public
         * @property  m_invIB
         * @type      {float}
         * @default   0.0
         */
        this.m_invIB = 0.0;


////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                //
//                  ██       ██               ██  ██                                              //
//                  ██       ██                   ██                                              //
//                  ██ █████ █████ █████ ████ ██ █████ █████ █████ █████ █████                    //
//                  ██ ██ ██ ██ ██ ██ ██ ██   ██  ██      ██ ██ ██ ██    ██ ██                    //
//                  ██ ██ ██ ██ ██ █████ ██   ██  ██   █████ ██ ██ ██    █████                    //
//                  ██ ██ ██ ██ ██ ██    ██   ██  ██   ██ ██ ██ ██ ██    ██                       //
//                  ██ ██ ██ ██ ██ █████ ██   ██  ████ █████ ██ ██ █████ █████                    //
//                                                                                                //
////////////////////////////////////////////////////////////////////////////////////////////////////

    } b2MouseJoint.prototype = p = new b2Joint(); Box2D.b2MouseJoint = b2MouseJoint;

     // STATIC CLASS PROPERTIES

        /**
         * Object pool for memory management.
         */
        b2MouseJoint._B2VEC2_POOL0 = new b2Vec2;
        b2MouseJoint._B2VEC2_POOL1 = new b2Vec2;
        b2MouseJoint._B2VEC2_POOL2 = new b2Vec2;

////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                //
//                       ██   ██        ██   ██             ██                                    //
//                       ███ ███        ██   ██             ██                                    //
//                       ███████ █████ █████ █████ █████ █████ █████                              //
//                       ██ █ ██ ██ ██  ██   ██ ██ ██ ██ ██ ██ ██                                 //
//                       ██   ██ █████  ██   ██ ██ ██ ██ ██ ██ █████                              //
//                       ██   ██ ██     ██   ██ ██ ██ ██ ██ ██    ██                              //
//                       ██   ██ █████  ████ ██ ██ █████ █████ █████                              //
//                                                                                                //
////////////////////////////////////////////////////////////////////////////////////////////////////


 // INSTANCE METHODS

    /**
     * @public
     * @method  getAnchorB
     * @param   {b2Vec2|Object=}   [out=b2Vec2]   reusable object
     * @return  {b2Vec2|Object}    out
     */
    p.getAnchorA = function ( out ) {
        out = out || b2MouseJoint._B2VEC2_POOL0;
        return out.copy( this.m_targetA );
    };

    /**
     * @public
     * @method  getAnchorB
     * @param   {b2Vec2|Object=}   [out=b2Vec2]   reusable object
     * @return  {b2Vec2|Object}    out
     */
    p.getAnchorB = function ( out ) {
        out = out || b2MouseJoint._B2VEC2_POOL0;
        return this.m_bodyB.getWorldPoint( this.m_localAnchorB, out );
    };

    /**
     * Get the reaction force given the inverse time step.
     * Unit is N.
     *
     * @public
     * @method  getReactionForce
     * @param   {float}     invDeltaTime
     * @param   {b2Vec2|Object=}   [out=b2Vec2]   reusable object
     * @return  {b2Vec2|Object}    out
     */
    p.getReactionForce = function ( invDeltaTime, out ) {
        out = out || b2MouseJoint._B2VEC2_POOL0;
        return b2Vec2.numTimes( invDeltaTime, this.m_impulse, out );
    };

    /**
     * Get the reaction torque given the inverse time step.
     * Unit is N*m. This is always zero for a distance joint.
     *
     * @public
     * @method  getReactionTorque
     * @param   {float}     invDeltaTime
     * @return  {float}
     */
    p.getReactionTorque = function ( invDeltaTime ) {
        return 0;
    };

    /**
     * @public
     * @method  setTarget
     * @param   {float}     target
     * @return  {float}
     */
    p.setTarget = function ( target ) {
        if ( !this.m_bodyB.isAwake() ) {
            this.m_bodyB.setAwake( true );
        }
        this.m_targetA.copy( target );
    };

    /**
     * @public
     * @method  getTarget
     * @param   {b2Vec2|Object=}   [out=b2Vec2]   reusable object
     * @return  {b2Vec2|Object}    out
     */
    p.getTarget = function ( out ) {
        out = out || b2MouseJoint._B2VEC2_POOL0;
        return out.copy( this.m_targetA );
    };

    /**
     * Set the target angular offset, in radians.
     *
     * @public
     * @method  setDampingRatio
     * @param   {float}     ratio
     * @return  {float}
     */
    p.setDampingRatio = function ( ratio ) {
        this.m_dampingRatio = ratio;
    };

    /**
     * Get the target angular offset, in radians.
     *
     * @public
     * @method  getDampingRatio
     * @return  {float}
     */
    p.getDampingRatio = function () {
        return this.m_dampingRatio;
    };

    /**
     * @public
     * @method  setMaxForce
     * @param   {float}     maxForce
     * @return  {float}
     */
    p.setMaxForce = function ( maxForce ) {
        this.m_maxForce = maxForce;
    };

    /**
     * Get the maximum friction force in N.
     *
     * @public
     * @method  getMaxForce
     * @return  {float}
     */
    p.getMaxForce = function () {
        return this.m_maxForce;
    };

    /**
     * @public
     * @method  setFrequency
     * @param   {float}     hz
     * @return  {float}
     */
    p.setFrequency = function ( hz ) {
        this.m_frequencyHz = hz;
    };

    /**
     * @public
     * @method  getFrequency
     * @return  {float}
     */
    p.getFrequency = function () {
        return this.m_frequencyHz;
    };

    /**
     * @public
     * @method  shiftOrigin
     * @param   {float}     newOrigin
     * @return  {float}
     */
        // Implement b2Joint.shiftOrigin
    p.shiftOrigin = function ( newOrigin ) {
        this.m_targetA.minus( newOrigin );
    };

    /**
     * @public
     * @override
     * @method  initVelocityConstraints
     * @param   {b2SolverData} data
     * @return  {void}
     */
    // Implement b2Joint.initVelocityConstraints
    p.initVelocityConstraints = function ( data ) {
        	this.m_indexB = this.m_bodyB.m_islandIndex;
        	this.m_localCenterB.copy(this.m_bodyB.m_sweep.localCenter);
        	this.m_invMassB = this.m_bodyB.m_invMass;
        	this.m_invIB = this.m_bodyB.m_invI;

        	/*b2Vec2&*/ var cB = data.positions[this.m_indexB].c;
        	/*float32*/ var aB = data.positions[this.m_indexB].a;
        	/*b2Vec2&*/ var vB = data.velocities[this.m_indexB].v;
        	/*float32*/ var wB = data.velocities[this.m_indexB].w;

        	var qB = this.m_qB.setAngle(aB);

        	/*float32*/ var mass = this.m_bodyB.getMass();

        	// Frequency
        	/*float32*/ var omega = 2 * Math.PI * this.m_frequencyHz;

        	// Damping coefficient
        	/*float32*/ var d = 2 * mass * this.m_dampingRatio * omega;

        	// Spring stiffness
        	/*float32*/ var k = mass * (omega * omega);

        	// magic formulas
        	// gamma has units of inverse mass.
        	// beta has units of inverse time.
        	/*float32*/ var h = data.step.dt;
        	/*##if EXPORT_ASSERTS */
        	if (b2Settings.ASSERTS_ENABLED) { b2Assert(d + h * k > b2Settings.b2_epsilon); }
            /*#end EXPORT_ASSERTS */
        	this.m_gamma = h * (d + h * k);
        	if (this.m_gamma !== 0)
        	{
        		this.m_gamma = 1 / this.m_gamma;
        	}
        	this.m_beta = h * k * this.m_gamma;

        	// Compute the effective mass matrix.
        	b2Vec2.subtract(this.m_localAnchorB, this.m_localCenterB, this.m_lalcB);
        	b2Rot.timesV2(qB, this.m_lalcB, this.m_rB);

        	// K    = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
        	//      = [1/m1+1/m2     0    ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]
        	//        [    0     1/m1+1/m2]           [-r1.x*r1.y r1.x*r1.x]           [-r1.x*r1.y r1.x*r1.x]
        	var K = this.m_K;
        	K.ex.x = this.m_invMassB + this.m_invIB * this.m_rB.y * this.m_rB.y + this.m_gamma;
        	K.ex.y = -this.m_invIB * this.m_rB.x * this.m_rB.y;
        	K.ey.x = K.ex.y;
        	K.ey.y = this.m_invMassB + this.m_invIB * this.m_rB.x * this.m_rB.x + this.m_gamma;

        	K.getInverse(this.m_mass);

            // m_C = cB + m_rB - m_targetA;
        	this.m_C.x = cB.x + this.m_rB.x - this.m_targetA.x;
        	this.m_C.y = cB.y + this.m_rB.y - this.m_targetA.y;
            // m_C *= m_beta;
        	this.m_C.times(this.m_beta);

        	// Cheat with some damping
        	wB *= 0.98;

        	if (data.step.warmStarting)
        	{
        		this.m_impulse.times(data.step.dtRatio);
            // vB += m_invMassB * m_impulse;
        		vB.x += this.m_invMassB * this.m_impulse.x;
        		vB.y += this.m_invMassB * this.m_impulse.y;
        		wB += this.m_invIB * b2Vec2.cross(this.m_rB, this.m_impulse);
        	}
        	else
        	{
        		this.m_impulse.setZero();
        	}

            // data.velocities[this.m_indexB].v = vB;
        	data.velocities[this.m_indexB].w = wB;
    };

    /**
     *
     * @public
     * @override
     * @method  solveVelocityConstraints
     * @param   {b2SolverData} data
     * @return  {void}
     */
    // Implement b2Joint.solveVelocityConstraints
    p.solveVelocityConstraints = function ( data ) {
        	/*b2Vec2&*/ var vB = data.velocities[this.m_indexB].v;
        	/*float32*/ var wB = data.velocities[this.m_indexB].w;

        	// Cdot = v + cross(w, r)
        //	b2Vec2 Cdot = vB + b2Cross(wB, m_rB);
        	var Cdot = b2Vec2.vPlusCrossFV(vB, wB, this.m_rB, b2MouseJoint._B2VEC2_POOL0);
        //	b2Vec2 impulse = b2Mul(m_mass, -(Cdot + m_C + m_gamma * m_impulse));
        	var impulse = b2Mat22.timesV2(
        		this.m_mass,
        		b2Vec2.add(
        			Cdot,
        			b2Vec2.add(this.m_C,
        				b2Vec2.numTimes(this.m_gamma, this.m_impulse, b2Vec2.POOL0),
        				b2Vec2.POOL0),
        			b2Vec2.POOL0).negative(),
                b2MouseJoint._B2VEC2_POOL1);

        //	b2Vec2 oldImpulse = m_impulse;
        	var oldImpulse = b2MouseJoint._B2VEC2_POOL2.copy(this.m_impulse);
        //	m_impulse += impulse;
        	this.m_impulse.plus(impulse);
        	/*float32*/ var maxImpulse = data.step.dt * this.m_maxForce;
        	if (this.m_impulse.lengthSquared() > maxImpulse * maxImpulse)
        	{
        		this.m_impulse.times(maxImpulse / this.m_impulse.length());
        	}
        //	impulse = m_impulse - oldImpulse;
        	b2Vec2.subtract(this.m_impulse, oldImpulse, impulse);

        //	vB += m_invMassB * impulse;
        vB.plusEqualsMul( this.m_invMassB, impulse );
        wB += this.m_invIB * b2Vec2.cross( this.m_rB, impulse );

        //	data.velocities[this.m_indexB].v = vB;
        data.velocities[this.m_indexB].w = wB;
    };

    /**
     * @public
     * @override
     * @method  solvePositionConstraints
     * @param   {b2SolverData} data
     * @return  {void}
     */
    // Implement b2Joint.solvePositionConstraints
    p.solvePositionConstraints = function ( data ) {
        return true;
    };