API Documentation for:
Show:

File:addBox2D\Dynamics\Joints\b2GearJoint.js

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

 // CLASS CONSTRUCTOR

    /**
     * A gear joint is used to connect two joints together. Either
     * joint can be a revolute or prismatic joint. You specify a
     * gear ratio to bind the motions together:
     * coordinateA + ratio * coordinateB = constant
     * The ratio can be negative or positive. If one joint is a
     * revolute joint and the other joint is a prismatic joint, then
     * the ratio will have units of length or units of 1/length.
     * warning You have to manually destroy the gear joint if jointA
     * or jointB is destroyed.
     *
     * @class   b2GearJoint
     * @constructor
     * @extends {b2Joint}
     * @param   {b2GearJointDef}  gearJointDef
     * @module  Joints
     */
    //TODO: test b2GearJoint. Ported but not yet tested.
    function b2GearJoint( gearJointDef ) {

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

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

     // property DECLARATIONS

        // Solver shared

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

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

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

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

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

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

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

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

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

        /**
         * @public
         * @property  m_JvBD
         * @type      {b2Vec2}
         */
        this.m_JvBD = 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_qC
         * @type      {b2Rot}
         */
        this.m_qC = new b2Rot;

        /**
         * @public
         * @property  m_qD
         * @type      {b2Rot}
         */
        this.m_qD = 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_lalcC
         * @type      {b2Vec2}
         */
        this.m_lalcC = new b2Vec2;

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


     // property INITIALISATIONS

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

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

        /**
         * @public
         * @property  m_referenceAngleB
         * @type      {float}
         * @default     0.0
         */
        this.m_constant = 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_indexC
         * @type      {int}
         * @default     0
         */
        this.m_indexC = 0;

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

        /**
         * @public
         * @property  m_mA
         * @type      {int}
         * @default     0.0
         */
        this.m_mA = 0.0;

        /**
         * @public
         * @property  m_mB
         * @type      {int}
         * @default     0.0
         */
        this.m_mB = 0.0;

        /**
         * @public
         * @property  m_mC
         * @type      {int}
         * @default     0.0
         */
        this.m_mC = 0.0;

        /**
         * @public
         * @property  m_mD
         * @type      {int}
         * @default     0.0
         */
        this.m_mD = 0.0;

        /**
         * @public
         * @property  m_iA
         * @type      {int}
         * @default     0.0
         */
        this.m_iA = 0.0;

        /**
         * @public
         * @property  m_iB
         * @type      {int}
         * @default     0.0
         */
        this.m_iB = 0.0;

        /**
         * @public
         * @property  m_iB
         * @type      {int}
         * @default     0.0
         */
        this.m_iB = 0.0;

        /**
         * @public
         * @property  m_iC
         * @type      {int}
         * @default     0.0
         */
        this.m_iC = 0.0;

        /**
         * @public
         * @property  m_iD
         * @type      {int}
         * @default     0.0
         */
        this.m_iD = 0.0;

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

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

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

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

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

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

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

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

        /**
         * @public
         * @property  m_qB
         * @type      {b2Rot}
         * @default     0.0
         */
        this.m_qB = 0.0;

        /**
         * @public
         * @property  m_qC
         * @type      {b2Rot}
         * @default     0.0
         */
        this.m_qC = 0.0;

        /**
         * @public
         * @property  m_qD
         * @type      {b2Rot}
         * @default     0.0
         */
        this.m_qD = 0.0;

        /**
         * @public
         * @property  m_joint1
         * @type      {b2Joint}
         */
        this.m_joint1 = gearJointDef.joint1;

        /**
         * @public
         * @property  m_joint1
         * @type      {b2Joint}
         */
        this.m_joint2 = gearJointDef.joint2;

        /**
         *
         * @public
         * @property  m_bodyA
         * @type      {b2Body}
         */
        this.m_bodyA = gearJointDef.joint1.getBodyB();

        /**
         *
         * @public
         * @property  m_ratio
         * @type      {float}
         */
        this.m_ratio = gearJointDef.ratio;

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

     // constructor LOGIC

        /**
         * @public
         * @property  m_typeA
         * @type      {int}
         */
        this.m_typeA = this.m_joint1.joint1.m_type;

        /**
         * @public
         * @property  m_typeA
         * @type      {int}
         */
        this.m_typeB = this.m_joint2.joint1.m_type;

        /**
         * Body A is connected to body C.
         *
         * @public
         * @property  m_bodyC
         * @type      {b2Body}
         * @default
         */
        this.m_bodyC = this.m_joint1.m_bodyB;

        /**
         * Body A is connected to body C.
         *
         * @public
         * @property  m_bodyA
         * @type      {b2Body}
         * @default
         */
        this.m_bodyA = this.m_joint1.m_bodyB;

        /**
         * Body B is connected to body D.
         *
         * @public
         * @property  m_bodyD
         * @type      {b2Body}
         * @default
         */
        this.m_bodyD = this.m_joint2.m_bodyA;

        /**
         * Body B is connected to body D.
         *
         * @public
         * @property  m_bodyB
         * @type      {b2Body}
         * @default
         */
        this.m_bodyB = this.m_joint2.m_bodyB;
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( this.m_typeA === b2Joint.e_revoluteJoint || this.m_typeA === b2Joint.e_prismaticJoint );
            b2Assert( this.m_typeB === b2Joint.e_revoluteJoint || this.m_typeB === b2Joint.e_prismaticJoint );
        }/*#*/
        /*float32*/var coordinateA;
        /*float32*/var coordinateB;

        // TODO_ERIN there might be some problem with the joint edges in b2Joint.

        // Get geometry of joint1
        /**b2Transform*/var xfA = this.m_bodyA.m_xf;
            /**float32*/var aA = this.m_bodyA.m_sweep.a;
        /**b2Transform*/var xfC = this.m_bodyC.m_xf;
            /**float32*/var aC = this.m_bodyC.m_sweep.a;

        if ( this.m_typeA === b2Joint.e_revoluteJoint ) {
            /**b2RevoluteJoint*/var revolute = gearJointDef.joint1;
            this.m_localAnchorC.copy( revolute.m_localAnchorA );
            this.m_localAnchorA.copy( revolute.m_localAnchorB );
            this.m_referenceAngleA = revolute.m_referenceAngle;
            this.m_localAxisC.setZero();

            coordinateA = aA - aC - this.m_referenceAngleA;
        }
        else {
            /*b2PrismaticJoint*/var prismatic = gearJointDef.joint1;
            this.m_localAnchorC.copy( prismatic.m_localAnchorA );
            this.m_localAnchorA.copy( prismatic.m_localAnchorB );
            this.m_referenceAngleA = prismatic.m_referenceAngle;
            this.m_localAxisC.copy( prismatic.m_localXAxisA );

            // b2Vec2 pC = m_localAnchorC;
            var pC = this.m_localAnchorC;
            // b2Vec2 pA = b2MulT(xfC.q, b2Mul(xfA.q, m_localAnchorA) + (xfA.p - xfC.p));
            var pA = b2Rot.invRotV2(
                xfC.q,
                b2Vec2.add(
                    b2Rot.timesV2( xfA.q, this.m_localAnchorA, b2Vec2.POOL0 ),
                    b2Vec2.subtract( xfA.p, xfC.p, b2Vec2.POOL1 ),
                    b2Vec2.POOL0 ),
                b2Vec2.POOL0 ); // pA uses s_t0
            //		coordinateA = b2Dot(pA - pC, m_localAxisC);
            coordinateA = b2Vec2.dot( b2Vec2.subtract( pA, pC, b2Vec2.POOL0 ), this.m_localAxisC );
        }

        // Get geometry of joint2
        /*b2Transform*/var xfB = this.m_bodyB.m_xf;
            /*float32*/var aB = this.m_bodyB.m_sweep.a;
        /*b2Transform*/var xfD = this.m_bodyD.m_xf;
            /*float32*/var aD = this.m_bodyD.m_sweep.a;

        if ( this.m_typeB === b2Joint.e_revoluteJoint ) {
            /*b2RevoluteJoint*/var revolute = gearJointDef.joint2;
            this.m_localAnchorD.copy( revolute.m_localAnchorA );
            this.m_localAnchorB.copy( revolute.m_localAnchorB );
            this.m_referenceAngleB = revolute.m_referenceAngle;
            this.m_localAxisD.setZero();
            coordinateB = aB - aD - this.m_referenceAngleB;
        }
        else {
            /*b2PrismaticJoint*/var prismatic = gearJointDef.joint2;
            this.m_localAnchorD.copy( prismatic.m_localAnchorA );
            this.m_localAnchorB.copy( prismatic.m_localAnchorB );
            this.m_referenceAngleB = prismatic.m_referenceAngle;
            this.m_localAxisD.copy( prismatic.m_localXAxisA );

            // b2Vec2 pD = m_localAnchorD;
            var pD = this.m_localAnchorD;
            // b2Vec2 pB = b2MulT(xfD.q, b2Mul(xfB.q, m_localAnchorB) + (xfB.p - xfD.p));
            var pB = b2Rot.invRotV2(
                xfD.q,
                b2Vec2.add(
                    b2Rot.timesV2( xfB.q, this.m_localAnchorB, b2Vec2.POOL0 ),
                    b2Vec2.subtract( xfB.p, xfD.p, b2Vec2.POOL1 ),
                    b2Vec2.POOL0 ),
                b2Vec2.POOL0 );
            // coordinateB = b2Dot(pB - pD, m_localAxisD);
            coordinateB = b2Vec2.dot( b2Vec2.subtract( pB, pD, b2Vec2.POOL0 ), this.m_localAxisD );
        }
        this.m_ratio = gearJointDef.ratio;
        this.m_constant = coordinateA + this.m_ratio * coordinateB;
        this.m_impulse = 0;

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

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

 // STATIC CLASS PROPERTIES

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

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

 // INSTANCE METHODS

    /**
     * @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_indexC = this.m_bodyC.m_islandIndex;
        this.m_indexD = this.m_bodyD.m_islandIndex;
        this.m_lcA.copy( this.m_bodyA.m_sweep.localCenter );
        this.m_lcB.copy( this.m_bodyB.m_sweep.localCenter );
        this.m_lcC.copy( this.m_bodyC.m_sweep.localCenter );
        this.m_lcD.copy( this.m_bodyD.m_sweep.localCenter );
        this.m_mA = this.m_bodyA.m_invMass;
        this.m_mB = this.m_bodyB.m_invMass;
        this.m_mC = this.m_bodyC.m_invMass;
        this.m_mD = this.m_bodyD.m_invMass;
        this.m_iA = this.m_bodyA.m_invI;
        this.m_iB = this.m_bodyB.m_invI;
        this.m_iC = this.m_bodyC.m_invI;
        this.m_iD = this.m_bodyD.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;

        /**float32*/var aC = data.positions[this.m_indexC].a;
        /**b2Vec2&*/var vC = data.velocities[this.m_indexC].v;
        /**float32*/var wC = data.velocities[this.m_indexC].w;

        /**float32*/var aD = data.positions[this.m_indexD].a;
        /**b2Vec2&*/var vD = data.velocities[this.m_indexD].v;
        /**float32*/var wD = data.velocities[this.m_indexD].w;

        // b2Rot qA(aA), qB(aB), qC(aC), qD(aD);
        var qA = this.m_qA.setAngle( aA ),
            qB = this.m_qB.setAngle( aB ),
            qC = this.m_qC.setAngle( aC ),
            qD = this.m_qD.setAngle( aD );

        this.m_mass = 0;

        if ( this.m_typeA === b2Joint.e_revoluteJoint ) {
            this.m_JvAC.setZero();
            this.m_JwA = 1;
            this.m_JwC = 1;
            this.m_mass += this.m_iA + this.m_iC;
        }
        else {
            // b2Vec2 u = b2Mul(qC, m_localAxisC);
            var u = b2Rot.timesV2( qC, this.m_localAxisC, b2GearJoint._B2VEC2_POOL1 );
            // b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC);
            b2Vec2.subtract( this.m_localAnchorC, this.m_lcC, this.m_lalcC );
            var rC = b2Rot.timesV2( qC, this.m_lalcC, b2GearJoint._B2VEC2_POOL2 );
            // b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA);
            b2Vec2.subtract( this.m_localAnchorA, this.m_lcA, this.m_lalcA );
            var rA = b2Rot.timesV2( qA, this.m_lalcA, b2GearJoint._B2VEC2_POOL2 );
            // m_JvAC = u;
            this.m_JvAC.copy( u );
            // m_JwC = b2Cross(rC, u);
            this.m_JwC = b2Vec2.cross( rC, u );
            // m_JwA = b2Cross(rA, u);
            this.m_JwA = b2Vec2.cross( rA, u );
            this.m_mass += this.m_mC + this.m_mA + this.m_iC * this.m_JwC * this.m_JwC + this.m_iA * this.m_JwA * this.m_JwA;
        }

        if ( this.m_typeB === b2Joint.e_revoluteJoint ) {
            this.m_JvBD.setZero();
            this.m_JwB = this.m_ratio;
            this.m_JwD = this.m_ratio;
            this.m_mass += this.m_ratio * this.m_ratio * (this.m_iB + this.m_iD);
        }
        else {
            // b2Vec2 u = b2Mul(qD, m_localAxisD);
            var u = b2Rot.timesV2( qD, this.m_localAxisD, b2GearJoint._B2VEC2_POOL3 );
            // b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD);
            b2Vec2.subtract( this.m_localAnchorD, this.m_lcD, this.m_lalcD );
            var rD = b2Rot.timesV2( qD, this.m_lalcD, b2GearJoint._B2VEC2_POOL4 );
            // b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB);
            b2Vec2.subtract( this.m_localAnchorB, this.m_lcB, this.m_lalcB );
            var rB = b2Rot.timesV2( qB, this.m_lalcB, b2GearJoint._B2VEC2_POOL5 );
            // m_JvBD = m_ratio * u;
            b2Vec2.numTimes( this.m_ratio, u, this.m_JvBD );
            // m_JwD = m_ratio * b2Cross(rD, u);
            this.m_JwD = this.m_ratio * b2Vec2.cross( rD, u );
            // m_JwB = m_ratio * b2Cross(rB, u);
            this.m_JwB = this.m_ratio * b2Vec2.cross( rB, u );
            this.m_mass += this.m_ratio * this.m_ratio * (this.m_mD + this.m_mB) + this.m_iD * this.m_JwD * this.m_JwD + this.m_iB * this.m_JwB * this.m_JwB;
        }

        // Compute effective mass.
        this.m_mass = this.m_mass > 0 ? 1 / this.m_mass : 0;

        if ( data.step.warmStarting ) {
            // vA += (m_mA * m_impulse) * m_JvAC;
            vA.plusEqualsMul( this.m_mA * this.m_impulse, this.m_JvAC );
            wA += this.m_iA * this.m_impulse * this.m_JwA;
            // vB += (m_mB * m_impulse) * m_JvBD;
            vB.plusEqualsMul( this.m_mB * this.m_impulse, this.m_JvBD );
            wB += this.m_iB * this.m_impulse * this.m_JwB;
            // vC -= (m_mC * m_impulse) * m_JvAC;
            vC.minusEqualsMul( this.m_mC * this.m_impulse, this.m_JvAC );
            wC -= this.m_iC * this.m_impulse * this.m_JwC;
            // vD -= (m_mD * m_impulse) * m_JvBD;
            vD.minusEqualsMul( this.m_mD * this.m_impulse, this.m_JvBD );
            wD -= this.m_iD * this.m_impulse * this.m_JwD;
        }
        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;
        // data.velocities[this.m_indexC].v = vC;
        data.velocities[this.m_indexC].w = wC;
        // data.velocities[this.m_indexD].v = vD;
        data.velocities[this.m_indexD].w = wD;
    };

    /**
     *
     * @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&*/var vC = data.velocities[this.m_indexC].v;
        /*float32*/var wC = data.velocities[this.m_indexC].w;
        /*b2Vec2&*/var vD = data.velocities[this.m_indexD].v;
        /*float32*/var wD = data.velocities[this.m_indexD].w;

        //	float32 Cdot = b2Dot(m_JvAC, vA - vC) + b2Dot(m_JvBD, vB - vD);
        var Cdot =
            b2Vec2.dot( this.m_JvAC, b2Vec2.subtract( vA, vC, b2Vec2.POOL0 ) ) +
            b2Vec2.dot( this.m_JvBD, b2Vec2.subtract( vB, vD, b2Vec2.POOL0 ) );
        Cdot += (this.m_JwA * wA - this.m_JwC * wC) + (this.m_JwB * wB - this.m_JwD * wD);

        /*float32*/var impulse = -this.m_mass * Cdot;
        this.m_impulse += impulse;

        //	vA += (m_mA * impulse) * m_JvAC;
        vA.plusEqualsMul( (this.m_mA * impulse), this.m_JvAC );
        wA += this.m_iA * impulse * this.m_JwA;
        //	vB += (m_mB * impulse) * m_JvBD;
        vB.plusEqualsMul( (this.m_mB * impulse), this.m_JvBD );
        wB += this.m_iB * impulse * this.m_JwB;
        //	vC -= (m_mC * impulse) * m_JvAC;
        vC.minusEqualsMul( (this.m_mC * impulse), this.m_JvAC );
        wC -= this.m_iC * impulse * this.m_JwC;
        //	vD -= (m_mD * impulse) * m_JvBD;
        vD.minusEqualsMul( (this.m_mD * impulse), this.m_JvBD );
        wD -= this.m_iD * impulse * this.m_JwD;

        //	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;
        //	data.velocities[this.m_indexC].v = vC;
        data.velocities[this.m_indexC].w = wC;
        //	data.velocities[this.m_indexD].v = vD;
        data.velocities[this.m_indexD].w = wD;
    };

    /**
     * @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;
        /*b2Vec2&*/var cC = data.positions[this.m_indexC].c;
        /*float32*/var aC = data.positions[this.m_indexC].a;
        /*b2Vec2&*/var cD = data.positions[this.m_indexD].c;
        /*float32*/var aD = data.positions[this.m_indexD].a;

        // b2Rot qA(aA), qB(aB), qC(aC), qD(aD);
        var qA = this.m_qA.setAngle( aA ),
            qB = this.m_qB.setAngle( aB ),
            qC = this.m_qC.setAngle( aC ),
            qD = this.m_qD.setAngle( aD );

        /*float32*/var linearError = 0;
        /*float32*/var coordinateA, coordinateB;
        /*b2Vec2*/var JvAC = this.m_JvAC, JvBD = this.m_JvBD;
        /*float32*/var JwA, JwB, JwC, JwD;
        /*float32*/var mass = 0;

        if ( this.m_typeA === b2Joint.e_revoluteJoint ) {
            JvAC.setZero();
            JwA = 1;
            JwC = 1;
            mass += this.m_iA + this.m_iC;

            coordinateA = aA - aC - this.m_referenceAngleA;
        }
        else {
            // b2Vec2 u = b2Mul(qC, m_localAxisC);
            var u = b2Rot.timesV2( qC, this.m_localAxisC, b2GearJoint._B2VEC2_POOL0 );
            // b2Vec2 rC = b2Mul(qC, m_localAnchorC - m_lcC);
            var rC = b2Rot.timesV2( qC, this.m_lalcC, b2GearJoint._B2VEC2_POOL1 );
            // b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_lcA);
            var rA = b2Rot.timesV2( qA, this.m_lalcA, b2GearJoint._B2VEC2_POOL2 );
            // JvAC = u;
            JvAC.copy( u );
            // JwC = b2Cross(rC, u);
            JwC = b2Vec2.cross( rC, u );
            // JwA = b2Cross(rA, u);
            JwA = b2Vec2.cross( rA, u );
            mass += this.m_mC + this.m_mA + this.m_iC * JwC * JwC + this.m_iA * JwA * JwA;

            // b2Vec2 pC = m_localAnchorC - m_lcC;
            var pC = this.m_lalcC;
            // b2Vec2 pA = b2MulT(qC, rA + (cA - cC));
            var pA = b2Rot.invRotV2(
                qC,
                b2Vec2.add(
                    rA,
                    b2Vec2.subtract( cA, cC, b2Vec2.POOL0 ),
                    b2Vec2.POOL0 ),
                b2Vec2.POOL0 ); // pA uses s_t0
            // coordinateA = b2Dot(pA - pC, m_localAxisC);
            coordinateA = b2Vec2.dot( b2Vec2.subtract( pA, pC, b2Vec2.POOL0 ), this.m_localAxisC );
        }

        if ( this.m_typeB === b2Joint.e_revoluteJoint ) {
            JvBD.setZero();
            JwB = this.m_ratio;
            JwD = this.m_ratio;
            mass += this.m_ratio * this.m_ratio * (this.m_iB + this.m_iD);

            coordinateB = aB - aD - this.m_referenceAngleB;
        }
        else {
            // b2Vec2 u = b2Mul(qD, m_localAxisD);
            var u = b2Rot.timesV2( qD, this.m_localAxisD, b2GearJoint._B2VEC2_POOL3 );
            // b2Vec2 rD = b2Mul(qD, m_localAnchorD - m_lcD);
            var rD = b2Rot.timesV2( qD, this.m_lalcD, b2GearJoint._B2VEC2_POOL4 );
            // b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_lcB);
            var rB = b2Rot.timesV2( qB, this.m_lalcB, b2GearJoint._B2VEC2_POOL5 );
            // JvBD = m_ratio * u;
            b2Vec2.numTimes( this.m_ratio, u, JvBD );
            // JwD = m_ratio * b2Cross(rD, u);
            JwD = this.m_ratio * b2Vec2.cross( rD, u );
            // JwB = m_ratio * b2Cross(rB, u);
            JwB = this.m_ratio * b2Vec2.cross( rB, u );
            mass += this.m_ratio * this.m_ratio * (this.m_mD + this.m_mB) + this.m_iD * JwD * JwD + this.m_iB * JwB * JwB;

            // b2Vec2 pD = m_localAnchorD - m_lcD;
            var pD = this.m_lalcD;
            // b2Vec2 pB = b2MulT(qD, rB + (cB - cD));
            var pB = b2Rot.invRotV2(
                qD,
                b2Vec2.add(
                    rB,
                    b2Vec2.subtract( cB, cD, b2Vec2.POOL0 ),
                    b2Vec2.POOL0 ),
                b2Vec2.POOL0 ); // pB uses s_t0
            // coordinateB = b2Dot(pB - pD, m_localAxisD);
            coordinateB = b2Vec2.dot( b2Vec2.subtract( pB, pD, b2Vec2.POOL0 ), this.m_localAxisD );
        }

        /*float32*/var C = (coordinateA + this.m_ratio * coordinateB) - this.m_constant;

        /*float32*/var impulse = 0;
        if ( mass > 0 ) {
            impulse = -C / mass;
        }

        //	cA += m_mA * impulse * JvAC;
        cA.plusEqualsMul( this.m_mA * impulse, JvAC );
        aA += this.m_iA * impulse * JwA;
        //	cB += m_mB * impulse * JvBD;
        cB.plusEqualsMul( this.m_mB * impulse, JvBD );
        aB += this.m_iB * impulse * JwB;
        //	cC -= m_mC * impulse * JvAC;
        cC.minusEqualsMul( this.m_mC * impulse, JvAC );
        aC -= this.m_iC * impulse * JwC;
        //	cD -= m_mD * impulse * JvBD;
        cD.minusEqualsMul( this.m_mD * impulse, JvBD );
        aD -= this.m_iD * impulse * JwD;

        //	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;
        //	data.positions[this.m_indexC].c = cC;
        data.positions[this.m_indexC].a = aC;
        //	data.positions[this.m_indexD].c = cD;
        data.positions[this.m_indexD].a = aD;

        // TODO_ERIN not implemented
        return linearError < b2Settings.b2_linearSlop;
    };

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

    /**
     * Get the first joint.
     *
     * @public
     * @method  getJoint1
     * @return  {b2Joint}
     */
    p.getJoint1 = function () {
        return this.m_joint1;
    };

    /**
     * Get the second joint.
     *
     * @public
     * @method  getJoint1
     * @return  {b2Joint}
     */
    p.getJoint2 = function () {
        return this.m_joint2;
    };

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

    /**
     * @public
     * @method  setRatio
     * @param   {float}     ratio
     * @return  {float}
     */
    p.setRatio = function ( ratio ) {
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) { b2Assert( isFinite( ratio ) ); }
        /*#end EXPORT_ASSERTS */
        this.m_ratio = ratio;
    };