API Documentation for:
Show:

File:addBox2D\Dynamics\Joints\b2RevoluteJoint.js


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

 // CLASS CONSTRUCTOR

    /**
     * A revolute joint constrains two bodies to share a common
     * point while they are free to rotate about the point. The
     * relative rotation about the shared point is the joint angle.
     * You can limit the relative rotation with a joint limit that
     * specifies a lower and upper angle. You can use a motor to
     * drive the relative rotation about the shared point. A maximum
     * motor torque is provided so that infinite forces are not
     * generated.
     *
     * @class   b2RevoluteJoint
     * @constructor
     * @param   {b2RevoluteJointDef}  revoluteJointDef
     * @extends {b2Joint}
     * @module  Joints
     */
    function b2RevoluteJoint( revoluteJointDef ) {

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

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

     // property DECLARATIONS

        /**
         * @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;

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

        /**
         * @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_localAnchorA
         * @type      {b2Vec2}
         */
        this.m_localAnchorA = new b2Vec2;

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

        /**
         * @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_impulse
         * @type      {b2Vec3}
         */
        this.m_impulse = new b2Vec3;

        /**
         * Effective mass for point-to-point constraint.
         *
         * @public
         * @property  m_mass
         * @type      {b2Mat33}
         */
        this.m_mass = new b2Mat33;

     // property INITIALISATIONS

        this.m_localAnchorA.copy( revoluteJointDef.localAnchorA );
        this.m_localAnchorB.copy( revoluteJointDef.localAnchorB );
        this.m_impulse.setZero();

        /**
         * @public
         * @property  m_referenceAngle
         * @type      {float}
         */
        this.m_referenceAngle = revoluteJointDef.referenceAngle;

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

        /**
         * @public
         * @property  m_lowerAngle
         * @type      {float}
         */
        this.m_lowerAngle = revoluteJointDef.lowerAngle;

        /**
         * @public
         * @property  m_upperAngle
         * @type      {float}
         */
        this.m_upperAngle = revoluteJointDef.upperAngle;

        /**
         * @public
         * @property  m_maxMotorTorque
         * @type      {float}
         */
        this.m_maxMotorTorque = revoluteJointDef.maxMotorTorque;

        /**
         * @public
         * @property  m_motorSpeed
         * @type      {float}
         */
        this.m_motorSpeed = revoluteJointDef.motorSpeed;

        /**
         * @public
         * @property  m_enableLimit
         * @type      {float}
         */
        this.m_enableLimit = revoluteJointDef.enableLimit;

        /**
         * @public
         * @property  m_enableMotor
         * @type      {float}
         */
        this.m_enableMotor = revoluteJointDef.enableMotor;

        /**
         * Effective mass for motor/limit angular constraint.
         *
         * @public
         * @property  m_enableMotor
         * @type      {float}
         * @default    0.0
         */
        this.m_motorMass = 0.0;

        /**
         * @public
         * @property  m_limitState
         * @type      {int}
         * default    b2Joint.e_inactiveLimit
         */
        this.m_limitState = b2Joint.e_inactiveLimit;

        /**
         * @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_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_invMassA
         * @type      {float}
         * @default   0.0
         */
        this.m_invIA = 0.0;

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


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

} b2RevoluteJoint.prototype = p = new b2Joint; Box2D.b2RevoluteJoint = b2RevoluteJoint;

     // STATIC CLASS PROPERTIES

        /**
         * Object pool for memory management.
         */
        b2RevoluteJoint._B2VEC2_POOL0 = new b2Vec2;
        b2RevoluteJoint._B2VEC2_POOL1 = new b2Vec2;
        b2RevoluteJoint._B2VEC2_POOL2 = new b2Vec2;
        b2RevoluteJoint._B2VEC2_POOL3 = new b2Vec2;
        b2RevoluteJoint._B2VEC2_POOL4 = new b2Vec2;
        b2RevoluteJoint._B2VEC2_POOL5 = new b2Vec2;

        b2RevoluteJoint._B2VEC3_POOL0 = new b2Vec3;

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

 // INSTANCE METHODS

    /**
     * @public
     * @method  getAnchorB
     * @param   {b2Vec2|Object=}   [out=b2Vec2]   reusable object
     * @return  {b2Vec2|Object}    out
     */
    p.getAnchorA = function ( out ) {
        out = out || b2RevoluteJoint._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 || b2RevoluteJoint._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 || b2RevoluteJoint._B2VEC2_POOL0;
        return out.set( invDeltaTime * this.m_impulse.x, invDeltaTime * this.m_impulse.y );
    };

    /**
     * Get the reaction torque due to the joint limit given the
     * inverse time step. Unit is N*m.
     *
     * @public
     * @method  getReactionTorque
     * @param   {float}     invDeltaTime
     * @return  {float}
     */
    p.getReactionTorque = function ( invDeltaTime ) {
        return invDeltaTime * this.m_impulse.z;
    };

    /**
     * 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_localAnchorB );
    };

    /**
     * Get the reference angle.
     *
     * @public
     * @method  getReferenceAngle
     * @return  {float}
     */
    p.getReferenceAngle = function () {
        return this.m_referenceAngle;
    };

    /**
     * @public
     * @method  getJointAngle
     * @return  {float}
     */
    p.getJointAngle = function () {
        return this.m_bodyB.m_sweep.a - this.m_bodyA.m_sweep.a - this.m_referenceAngle;
    };

    /**
     * @public
     * @method  getJointSpeed
     * @return  {float}
     */
    p.getJointSpeed = function () {
        return this.m_bodyB.m_angularVelocity - this.m_bodyA.m_angularVelocity;
    };

    /**
     * @public
     * @method  isMotorEnabled
     * @return  {boolean}
     */
    p.isMotorEnabled = function () {
        return this.m_enableMotor;
    };

    /**
     * @public
     * @method  enableMotor
     * @param   {boolean}     flag
     * @return  {void}
     */
    p.enableMotor = function ( flag ) {
        if ( this.m_enableMotor !== flag ) {
            this.m_bodyA.setAwake( true );
            this.m_bodyB.setAwake( true );
            this.m_enableMotor = flag;
        }
    };

    /**
     * Get the current motor torque given the inverse time step.
     * Unit is N*m.
     *
     * @public
     * @method  getMotorTorque
     * @param   {b2Vec2|Object=}   invDeltaTime
     * @return  {float}
     */
    p.getMotorTorque = function ( invDeltaTime ) {
        return invDeltaTime * this.m_motorImpulse;
    };

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

    /**
     * @public
     * @method  setMaxMotorTorque
     * @param   {float} torque
     * @return  {void}
     */
    p.setMaxMotorTorque = function ( torque ) {
        this.m_maxMotorTorque = torque;
    };

    /**
     * Set the maximum friction force in N.
     *
     * @public
     * @method  getMaxMotorTorque
     * @return  {float}
     */
    p.getMaxMotorTorque = function () {
        return this.m_maxMotorTorque;
    };

    /**
     * @public
     * @method  isLimitEnabled
     * @return  {boolean}
     */
    p.isLimitEnabled = function () {
        return this.m_enableLimit;
    };

    /**
     * @public
     * @method  enableLimit
     * @param   {boolean} flag
     * @return  {void}
     */
    p.enableLimit = function ( flag ) {
        if ( flag !== this.m_enableLimit ) {
            this.m_bodyA.setAwake( true );
            this.m_bodyB.setAwake( true );
            this.m_enableLimit = flag;
                this.m_impulse.z = 0.0;
        }
    };

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

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

    /**
     * @public
     * @method  setLimits
     * @param   {number} lower
     * @param   {number} upper
     * @return  {void}
     */
    p.setLimits = function ( lower, upper ) {
        this.m_bodyA.setAwake( true );
        this.m_bodyB.setAwake( true );
            this.m_impulse.z = 0.0;
        this.m_lowerAngle = lower;
        this.m_upperAngle = upper;
    };

    /**
     * @public
     * @method  setMotorSpeed
         * @param   {float} speed
     * @return  {void}
     */
    p.setMotorSpeed = function ( speed ) {
        if ( this.m_motorSpeed !== speed ) {
            this.m_bodyA.setAwake( true );
            this.m_bodyB.setAwake( true );
            this.m_motorSpeed = speed;
        }
    };

    /**
     * @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;

        /*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;

        /*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;

        // b2Rot qA(aA), qB(aB);
        /*b2Rot*/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 );

        // 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]

        /*float32*/var mA = this.m_invMassA, mB = this.m_invMassB;
        /*float32*/var iA = this.m_invIA, iB = this.m_invIB;

        /*bool*/var fixedRotation = (iA + iB === 0);

        this.m_mass.ex.x = mA + mB + this.m_rA.y * this.m_rA.y * iA + this.m_rB.y * this.m_rB.y * iB;
        this.m_mass.ey.x = -this.m_rA.y * this.m_rA.x * iA - this.m_rB.y * this.m_rB.x * iB;
        this.m_mass.ez.x = -this.m_rA.y * iA - this.m_rB.y * iB;
        this.m_mass.ex.y = this.m_mass.ey.x;
        this.m_mass.ey.y = mA + mB + this.m_rA.x * this.m_rA.x * iA + this.m_rB.x * this.m_rB.x * iB;
        this.m_mass.ez.y = this.m_rA.x * iA + this.m_rB.x * iB;
        this.m_mass.ex.z = this.m_mass.ez.x;
        this.m_mass.ey.z = this.m_mass.ez.y;
        this.m_mass.ez.z = iA + iB;

        this.m_motorMass = iA + iB;
        if ( this.m_motorMass > 0 ) {
            this.m_motorMass = 1 / this.m_motorMass;
        }

        if ( !this.m_enableMotor || fixedRotation ) {
                this.m_motorImpulse = 0.0;
        }

        if ( this.m_enableLimit && !fixedRotation ) {
            /*float32*/var jointAngle = aB - aA - this.m_referenceAngle;
            if ( Math.abs( this.m_upperAngle - this.m_lowerAngle ) < 2 * b2Settings.b2_angularSlop ) {
                this.m_limitState = b2Joint.e_equalLimits;
            }
            else if ( jointAngle <= this.m_lowerAngle ) {
                if ( this.m_limitState !== b2Joint.e_atLowerLimit ) {
                    this.m_impulse.z = 0;
                }
                this.m_limitState = b2Joint.e_atLowerLimit;
            }
            else if ( jointAngle >= this.m_upperAngle ) {
                if ( this.m_limitState !== b2Joint.e_atUpperLimit ) {
                    this.m_impulse.z = 0;
                }
                this.m_limitState = b2Joint.e_atUpperLimit;
            }
            else {
                this.m_limitState = b2Joint.e_inactiveLimit;
                this.m_impulse.z = 0;
            }
        }
        else {
            this.m_limitState = b2Joint.e_inactiveLimit;
        }

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

            // b2Vec2 P(m_impulse.x, m_impulse.y);
            var P = b2RevoluteJoint._B2VEC2_POOL0.set( this.m_impulse.x, this.m_impulse.y );

            // vA -= mA * P;
            vA.minusEqualsMul( mA, P );
            wA -= iA * (b2Vec2.cross( this.m_rA, P ) + this.m_motorImpulse + this.m_impulse.z);

            // vB += mB * P;
            vB.plusEqualsMul( mB, P );
            wB += iB * (b2Vec2.cross( this.m_rB, P ) + this.m_motorImpulse + this.m_impulse.z);
        }
        else {
            this.m_impulse.setZero();
                this.m_motorImpulse = 0.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;

        /*float32*/var mA = this.m_invMassA, mB = this.m_invMassB;
        /*float32*/var iA = this.m_invIA, iB = this.m_invIB;

        /*bool*/var fixedRotation = (iA + iB === 0);

        // Solve motor constraint.
        if ( this.m_enableMotor && this.m_limitState !== b2Joint.e_equalLimits && !fixedRotation ) {
            /*float32*/var Cdot = wB - wA - this.m_motorSpeed;
            /*float32*/var impulse = -this.m_motorMass * Cdot;
            /*float32*/var oldImpulse = this.m_motorImpulse;
            /*float32*/var maxImpulse = data.step.dt * this.m_maxMotorTorque;
            this.m_motorImpulse = b2Math.clamp( this.m_motorImpulse + impulse, -maxImpulse, maxImpulse );
            impulse = this.m_motorImpulse - oldImpulse;

            wA -= iA * impulse;
            wB += iB * impulse;
        }

        // Solve limit constraint.
        if ( this.m_enableLimit && this.m_limitState !== b2Joint.e_inactiveLimit && !fixedRotation ) {
            // b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
            var Cdot1 = b2Vec2.subtract(
                b2Vec2.vPlusCrossFV( vB, wB, this.m_rB, b2Vec2.POOL0 ),
                b2Vec2.vPlusCrossFV( vA, wA, this.m_rA, b2Vec2.POOL1 ),
                b2RevoluteJoint._B2VEC2_POOL2 );
            /*float32*/var Cdot2 = wB - wA;
            // b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);

            // b2Vec3 impulse = -this.m_mass.solve33(Cdot);
            var impulse = this.m_mass.solve33( Cdot1.x, Cdot1.y, Cdot2, b2RevoluteJoint._B2VEC3_POOL0 ).negative();

            if ( this.m_limitState === b2Joint.e_equalLimits ) {
                this.m_impulse.plus( impulse );
            }
            else if ( this.m_limitState === b2Joint.e_atLowerLimit ) {
                /*float32*/var newImpulse = this.m_impulse.z + impulse.z;
                if ( newImpulse < 0 ) {
                    // b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
                    var rhs_x = -Cdot1.x + this.m_impulse.z * this.m_mass.ez.x;
                    var rhs_y = -Cdot1.y + this.m_impulse.z * this.m_mass.ez.y;
                    /*b2Vec2*/var reduced = this.m_mass.solve22( rhs_x, rhs_y, b2RevoluteJoint._B2VEC2_POOL3 );
                    impulse.x = reduced.x;
                    impulse.y = reduced.y;
                    impulse.z = -this.m_impulse.z;
                    this.m_impulse.x += reduced.x;
                    this.m_impulse.y += reduced.y;
                    this.m_impulse.z = 0;
                }
                else {
                    this.m_impulse.plus( impulse );
                }
            }
            else if ( this.m_limitState === b2Joint.e_atUpperLimit ) {
                /*float32*/var newImpulse = this.m_impulse.z + impulse.z;
                if ( newImpulse > 0 ) {
                    // b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
                    var rhs_x = -Cdot1.x + this.m_impulse.z * this.m_mass.ez.x;
                    var rhs_y = -Cdot1.y + this.m_impulse.z * this.m_mass.ez.y;
                    /*b2Vec2*/var reduced = this.m_mass.solve22( rhs_x, rhs_y, b2RevoluteJoint._B2VEC2_POOL4 );
                    impulse.x = reduced.x;
                    impulse.y = reduced.y;
                    impulse.z = -this.m_impulse.z;
                    this.m_impulse.x += reduced.x;
                    this.m_impulse.y += reduced.y;
                    this.m_impulse.z = 0;
                }
                else {
                    this.m_impulse.plus( impulse );
                }
            }

            // P(impulse.x, impulse.y);
            var P = b2RevoluteJoint._B2VEC2_POOL0.set( impulse.x, impulse.y );

            // -= mA * P;
            vA.minusEqualsMul( mA, P );
            wA -= iA * (b2Vec2.cross( this.m_rA, P ) + impulse.z);

            //		vB += mB * P;
            vB.plusEqualsMul( mB, P );
            wB += iB * (b2Vec2.cross( this.m_rB, P ) + impulse.z);
        }
        else {
            // Solve point-to-point constraint
            // b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
            var Cdot = b2Vec2.subtract(
                b2Vec2.vPlusCrossFV( vB, wB, this.m_rB, b2Vec2.POOL0 ),
                b2Vec2.vPlusCrossFV( vA, wA, this.m_rA, b2Vec2.POOL1 ),
                b2RevoluteJoint._B2VEC2_POOL1 );
            // b2Vec2 impulse = m_mass.solve22(-Cdot);
            /*b2Vec2*/var impulse = this.m_mass.solve22( -Cdot.x, -Cdot.y, b2RevoluteJoint._B2VEC2_POOL5 );

            this.m_impulse.x += impulse.x;
            this.m_impulse.y += impulse.y;

            // vA -= mA * impulse;
            vA.minusEqualsMul( mA, impulse );
            wA -= iA * b2Vec2.cross( this.m_rA, impulse );

            // vB += mB * impulse;
            vB.plusEqualsMul( mB, impulse );
            wB += iB * b2Vec2.cross( this.m_rB, impulse );
        }

        // 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 ) {
        /*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;

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

        /*float32*/var angularError = 0;
        /*float32*/var positionError = 0;

        /*bool*/var fixedRotation = (this.m_invIA + this.m_invIB === 0);

        // Solve angular limit constraint.
        if ( this.m_enableLimit && this.m_limitState !== b2Joint.e_inactiveLimit && !fixedRotation ) {
            /*float32*/var angle = aB - aA - this.m_referenceAngle;
            /*float32*/var limitImpulse = 0;

            if ( this.m_limitState === b2Joint.e_equalLimits ) {
                // Prevent large angular corrections
                /*float32*/var C = b2Math.clamp( angle - this.m_lowerAngle, -b2Settings.b2_maxAngularCorrection, b2Settings.b2_maxAngularCorrection );
                limitImpulse = -this.m_motorMass * C;
                angularError = Math.abs( C );
            }
            else if ( this.m_limitState === b2Joint.e_atLowerLimit ) {
                /*float32*/var C = angle - this.m_lowerAngle;
                angularError = -C;

                // Prevent large angular corrections and allow some slop.
                C = b2Math.clamp( C + b2Settings.b2_angularSlop, -b2Settings.b2_maxAngularCorrection, 0 );
                limitImpulse = -this.m_motorMass * C;
            }
            else if ( this.m_limitState === b2Joint.e_atUpperLimit ) {
                /*float32*/var C = angle - this.m_upperAngle;
                angularError = C;

                // Prevent large angular corrections and allow some slop.
                C = b2Math.clamp( C - b2Settings.b2_angularSlop, 0, b2Settings.b2_maxAngularCorrection );
                limitImpulse = -this.m_motorMass * C;
            }

            aA -= this.m_invIA * limitImpulse;
            aB += this.m_invIB * limitImpulse;
        }

        // Solve point-to-point constraint.
        {
            qA.setAngle( aA );
            qB.setAngle( aB );
            // b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
            b2Vec2.subtract( this.m_localAnchorA, this.m_localCenterA, this.m_lalcA );
            var rA = b2Rot.timesV2( qA, this.m_lalcA, this.m_rA );
            // b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
            b2Vec2.subtract( this.m_localAnchorB, this.m_localCenterB, this.m_lalcB );
            var rB = b2Rot.timesV2( qB, this.m_lalcB, this.m_rB );

            // b2Vec2 C = cB + rB - cA - rA;
            var C =
                b2Vec2.subtract(
                    b2Vec2.add( cB, rB, b2Vec2.POOL0 ),
                    b2Vec2.add( cA, rA, b2Vec2.POOL1 ),
                    b2RevoluteJoint._B2VEC2_POOL0 );
            positionError = C.length();

            /*float32*/var mA = this.m_invMassA, mB = this.m_invMassB;
            /*float32*/var iA = this.m_invIA, iB = this.m_invIB;

            var K = this.m_K;
            K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y;
            K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y;
            K.ey.x = K.ex.y;
            K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x;

            // b2Vec2 impulse = -K.solve(C);
            /*b2Vec2*/var impulse = K.solve( C.x, C.y, b2RevoluteJoint._B2VEC2_POOL1 ).negative();

            // cA -= mA * impulse;
            cA.minusEqualsMul( mA, impulse );
            aA -= iA * b2Vec2.cross( rA, impulse );

            // cB += mB * impulse;
            cB.plusEqualsMul( mB, impulse );
            aB += iB * b2Vec2.cross( rB, impulse );
        }

        // 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 positionError <= b2Settings.b2_linearSlop && angularError <= b2Settings.b2_angularSlop;
    };