API Documentation for:
Show:

File:addBox2D\Dynamics\Joints\b2DistanceJoint.js

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

 // CLASS CONSTRUCTOR

    /**
     * A distance joint constrains two points on two bodies to
     * remain at a fixed distance from each other. You can view this
     * as a massless, rigid rod.
     *
     * @class   b2DistanceJoint
     * @constructor
     * @extends {b2Joint}
     * @param   {B2DistanceJointDef}  distanceJointDef
     * @module  Joints
     */
    function b2DistanceJoint( distanceJointDef ) {

    /**
     * Invokes parent class constructor function reference.
     */
    this.constructor( distanceJointDef );

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

 // property DECLARATIONS

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

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

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

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

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

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

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

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

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

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

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


       // property INITIALISATIONS

        this.m_localAnchorA.copy( distanceJointDef.localAnchorA );
        this.m_localAnchorB.copy( distanceJointDef.localAnchorB );

        /**
         *
         * @public
         * @property  m_length
         * @type      {float}
         */
        this.m_length = distanceJointDef.length;

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

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

        /**
         *
         * @public
         * @property  m_impulse
         * @type      {number}
         * @default   0.0
         */
        this.m_impulse = 0.0;

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

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

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

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

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

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

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

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

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


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

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

     // STATIC CLASS PROPERTIES

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

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

 // INSTANCE METHODS

    /**
     * @public
     * @method  getAnchorA
     * @param   {b2Vec2|Object=}   [out=b2Vec2]   reusable object
     * @return  {b2Vec2|Object}    out
     */
    p.getAnchorA = function ( out ) {
        out = out || b2DistanceJoint._B2VEC2_POOL0;
        return this.m_bodyA.getWorldPoint( this.m_localAnchorA, out );
    };

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

    /**
     * The local anchor point relative to bodyA's origin.
     *
     * @public
     * @method  getLocalAnchorA
     * @param   {b2Vec2|Object=}   [out=b2Vec2]   reusable object
     * @return  {b2Vec2|Object}    out
     */
    p.getLocalAnchorA = function ( out ) {
        out = out || b2DistanceJoint._B2VEC2_POOL0;
        return out.copy( this.m_localAnchorA );
    };

    /**
     * The local anchor point relative to bodyA's origin.
     *
     * @public
     * @method  getLocalAnchorB
     * @param   {b2Vec2|Object=}   [out=b2Vec2]   reusable object
     * @return  {b2Vec2|Object}    out
     */
    p.getLocalAnchorB = function ( out ) {
        out = out || b2DistanceJoint._B2VEC2_POOL0;
        return out.copy( this.m_localAnchorA );
    };

    /**
     * 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 || b2DistanceJoint._B2VEC2_POOL0;
        return out.set( invDeltaTime * this.m_impulse * this.m_u.x, invDeltaTime * this.m_impulse * this.m_u.y );
    };

    /**
     * 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.0;
    };

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

    /**
     * @public
     * @method  setLength
     * @return  {void}
     */
    p.setLength = function ( length ) {
        length = length || 0;
        this.m_length = length;
    };

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

    /**
     * Set frequency in Hz.
     *
     * @public
     * @method  setFrequency
     * @param   {float}     hz
     * @return  {void}
     */
    p.setFrequency = function ( hz ) {
        hz = hz || 0.0;
        this.m_frequencyHz = hz;
    };

    /**
     * Get damping ratio.
     *
     * @public
     * @method  getDampingRatio
     * @return  {float}
     */
    p.getDampingRatio = function () {
        return this.m_dampingRatio;
    };

    /**
     * Set damping ratio.
     *
     * @public
     * @method  setDampingRatio
     * @return  {float}
     */
    p.setDampingRatio = function ( ratio ) {
        ratio = ratio || 0;
        this.m_dampingRatio = ratio;
    };

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

        /*b2Vec2&*/var cA = data.positions[this.m_indexA].c;
        /*float32*/var aA = data.positions[this.m_indexA].a;
        /*b2Vec2&*/var vA = data.velocities[this.m_indexA].v;
        /*float32*/var wA = data.velocities[this.m_indexA].w;

        /*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 qA = new b2Rot(aA), qB = new b2Rot(aB);
        var qA = this.m_qA.setAngle( aA ), qB = this.m_qB.setAngle( aB );

        //	m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
        b2Vec2.subtract( this.m_localAnchorA, this.m_localCenterA, this.m_lalcA );
        b2Rot.timesV2( qA, this.m_lalcA, this.m_rA );
        //	m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
        b2Vec2.subtract( this.m_localAnchorB, this.m_localCenterB, this.m_lalcB );
        b2Rot.timesV2( qB, this.m_lalcB, this.m_rB );
        //	m_u = cB + m_rB - cA - m_rA;
        this.m_u.x = cB.x + this.m_rB.x - cA.x - this.m_rA.x;
        this.m_u.y = cB.y + this.m_rB.y - cA.y - this.m_rA.y;

        // Handle singularity.
        var length = this.m_u.length();
        if ( length > b2Settings.b2_linearSlop ) {
            this.m_u.times( 1 / length );
        }
        else {
            this.m_u.setZero();
        }

        //	float32 crAu = b2Cross(m_rA, m_u);
        var crAu = b2Vec2.cross( this.m_rA, this.m_u );
        //	float32 crBu = b2Cross(m_rB, m_u);
        var crBu = b2Vec2.cross( this.m_rB, this.m_u );
        //	float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu;
        var invMass = this.m_invMassA + this.m_invIA * crAu * crAu + this.m_invMassB + this.m_invIB * crBu * crBu;

        // Compute the effective mass matrix.
        this.m_mass = invMass !== 0 ? 1 / invMass : 0;

        if ( this.m_frequencyHz > 0 ) {
            var C = length - this.m_length;

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

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

            // Spring stiffness
            var k = this.m_mass * omega * omega;

            // magic formulas
            /*float32*/var h = data.step.dt;
            this.m_gamma = h * (d + h * k);
            this.m_gamma = this.m_gamma !== 0 ? 1 / this.m_gamma : 0;
            this.m_bias = C * h * k * this.m_gamma;

            invMass += this.m_gamma;
            this.m_mass = invMass !== 0 ? 1 / invMass : 0;
        }
        else {
            this.m_gamma = 0;
            this.m_bias = 0;
        }

        if ( data.step.warmStarting ) {
            // Scale the impulse to support a variable time step.
            this.m_impulse *= data.step.dtRatio;

            // b2Vec2 P = m_impulse * m_u;
            var P = b2Vec2.numTimes( this.m_impulse, this.m_u, b2DistanceJoint._B2VEC2_POOL0 );

            // vA -= m_invMassA * P;
            vA.minusEqualsMul( this.m_invMassA, P );
            // wA -= m_invIA * b2Cross(m_rA, P);
            wA -= this.m_invIA * b2Vec2.cross( this.m_rA, P );
            // vB += m_invMassB * P;
            vB.plusEqualsMul( this.m_invMassB, P );
            // wB += m_invIB * b2Cross(m_rB, P);
            wB += this.m_invIB * b2Vec2.cross( this.m_rB, P );
        }
        else {
            this.m_impulse = 0;
        }

        // data.velocities[this.m_indexA].v = vA;
        data.velocities[this.m_indexA].w = wA;
        // 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 vA = data.velocities[this.m_indexA].v;
        /*float32*/var wA = data.velocities[this.m_indexA].w;
        /*b2Vec2&*/var vB = data.velocities[this.m_indexB].v;
        /*float32*/var wB = data.velocities[this.m_indexB].w;

        //	b2Vec2 vpA = vA + b2Cross(wA, m_rA);
        var vpA = b2Vec2.vPlusCrossFV( vA, wA, this.m_rA, b2DistanceJoint._B2VEC2_POOL0 );
        //	b2Vec2 vpB = vB + b2Cross(wB, m_rB);
        var vpB = b2Vec2.vPlusCrossFV( vB, wB, this.m_rB, b2DistanceJoint._B2VEC2_POOL1 );
        //	float32 Cdot = b2Dot(m_u, vpB - vpA);
        var Cdot = b2Vec2.dot( this.m_u, b2Vec2.subtract( vpB, vpA, b2Vec2.POOL0 ) );

        var impulse = (-this.m_mass * (Cdot + this.m_bias + this.m_gamma * this.m_impulse));
        this.m_impulse += impulse;

        //	b2Vec2 P = impulse * m_u;
        var P = b2Vec2.numTimes( impulse, this.m_u, b2DistanceJoint._B2VEC2_POOL2 );

        //	vA -= m_invMassA * P;
        vA.minusEqualsMul( this.m_invMassA, P );
        //	wA -= m_invIA * b2Cross(m_rA, P);
        wA -= this.m_invIA * b2Vec2.cross( this.m_rA, P );
        //	vB += m_invMassB * P;
        vB.plusEqualsMul( this.m_invMassB, P );
        //	wB += m_invIB * b2Cross(m_rB, P);
        wB += this.m_invIB * b2Vec2.cross( this.m_rB, P );

        //	data.velocities[this.m_indexA].v = vA;
        data.velocities[this.m_indexA].w = wA;
        //	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 ) {
        if ( this.m_frequencyHz > 0 ) {
            // There is no position correction for soft distance constraints.
            return true;
        }
        /*b2Vec2&*/var cA = data.positions[this.m_indexA].c;
        /*float32*/var aA = data.positions[this.m_indexA].a;
        /*b2Vec2&*/var cB = data.positions[this.m_indexB].c;
        /*float32*/var aB = data.positions[this.m_indexB].a;

        //	var qA = new b2Rot(aA), qB = new b2Rot(aB);
        var qA = this.m_qA.setAngle( aA ), qB = this.m_qB.setAngle( aB );

        //	b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
        var rA = b2Rot.timesV2( this.m_qA, this.m_lalcA, this.m_rA ); // use m_rA
        //	b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
        var rB = b2Rot.timesV2( this.m_qB, this.m_lalcB, this.m_rB ); // use m_rB
        //	b2Vec2 u = cB + rB - cA - rA;
        var u = this.m_u; // use m_u
        u.x = cB.x + rB.x - cA.x - rA.x;
        u.y = cB.y + rB.y - cA.y - rA.y;

        //	float32 length = u.norm();
        var length = this.m_u.norm();
        //	float32 C = length - m_length;
        var C = length - this.m_length;
        C = b2Math.clamp( C, (-b2Settings.b2_maxLinearCorrection), b2Settings.b2_maxLinearCorrection );

        var impulse = (-this.m_mass * C);
        //	b2Vec2 P = impulse * u;
        var P = b2Vec2.numTimes( impulse, u, b2DistanceJoint._B2VEC2_POOL0 );

        //	cA -= m_invMassA * P;
        cA.minusEqualsMul( this.m_invMassA, P );
        //	aA -= m_invIA * b2Cross(rA, P);
        aA -= this.m_invIA * b2Vec2.cross( rA, P );
        //	cB += m_invMassB * P;
        cB.plusEqualsMul( this.m_invMassB, P );
        //	aB += m_invIB * b2Cross(rB, P);
        aB += this.m_invIB * b2Vec2.cross( rB, P );

        //	data.positions[this.m_indexA].c = cA;
        data.positions[this.m_indexA].a = aA;
        //	data.positions[this.m_indexB].c = cB;
        data.positions[this.m_indexB].a = aB;

        return Math.abs( C ) < b2Settings.b2_linearSlop;
    };