API Documentation for:
Show:

File:addBox2D\Dynamics\b2World.js

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

// CLASS CONSTRUCTOR

    /**
     * The world class manages all physics entities, dynamic simulation,
     * and asynchronous queries. The world also contains efficient memory
     * management facilities.
     *
     * @class b2World
     * @constructor
     * @param   {b2Vec2=}    [gravity=b2Vec2]
     * @param   {boolean=}   [allowSleep=true]
     * @module Dynamics
     */
    function b2World( gravity, allowSleep ) {

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

     // property DECLARATIONS

        /**
         * The flag that controls automatic clearing of forces after each time step.
         *
         * @public
         * @property     m_flag_clearForces
         * @type        {boolean}
         * @default     true
         */
        // ( this.m_flags & b2World.e_clearForces )
        this.m_flag_clearForces = true;

        /**
         * @public
         * @property  m_contactManager
         * @type      {b2ContactManager}
         */
        this.m_contactManager = new b2ContactManager;

        /**
         * @public
         * @property  m_gravity
         * @type      {b2Vec2}
         * @default   (0,0)
         */
        this.m_gravity = new b2Vec2;

        /**
         * Development profiling data.
         *
         * @public
         * @property  m_profile
         * @type      {b2Profile}
         */
        this.m_profile = new b2Profile();

        /**
         *
         * @public
         * @property  m_groundBody
         * @type      {int}
         * @default   b2Body.
         */
        this.m_groundBody = this.createBody( new b2BodyDef );

     // property INITIALISATIONS

        /**
         * Enable/disable sleep.
         *
         * @public
         * @property  m_allowSleep
         * @type      {boolean}
         */
        this.m_allowSleep = allowSleep || true;


        /**
         * @public
         * @property  m_bodyList
         * @type     {b2Body}
         * @default    null
         */
        this.m_bodyList = null;

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

        /**
         * @public
         * @property  m_destructionListener
         * @type      {?b2DestructionListener|null}
         * @default   null
         */
        this.m_destructionListener = null;

        /**
         * @public
         * @property  m_debugDraw
         * @type      {?b2DebugDraw|null}
         * @default   null
         */
        this.m_debugDraw = null;


        if ( gravity ) {
            if ( gravity.isProxy ) {
                this.m_gravity = gravity;
            }
            else {
                this.m_gravity.copy( gravity )
            }
        }
        //TODO: m_flag -> bitmask
        /**
         * @type {boolean}
         */
        this.m_flag_newFixture = false;
        /**
         * @type {boolean}
         */
        this.m_flag_locked = false;

        /**
         * This is used to compute the time step ratio to support a variable time step.
         *
         * @public
         * @property  m_inv_dt0
         * @type      {float}
         * @default     0.0
         */
        this.m_inv_dt0 = 0;

        /**
         * @public
         * @property  m_island
         * @type      {b2Island}
         */
        this.m_island = new b2Island();

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

        /**
         *
         * @public
         * @property  m_jointList
         * @type      {?b2Joint|null}
         * @default   null
         */
        this.m_jointList = null;

        /**
         * @public
         * @property  s_stack
         * @type      {Array.<?b2Body>}
         */
        this.s_stack = [];

        /**
         * These are for debugging the solver.
         * @type {boolean}
         */
        //TODO: static? b2World.
        this.m_warmStarting = true;
        this.m_continuousPhysics = true;
        this.m_subStepping = false;
        this.m_stepComplete = true;

/*#if EXPORT_PARTICLES */
        /**
         * @public
         * @property  m_particleSystemList
         * @type      {?b2ParticleSystem}
         * @default   null
         */
        this.m_particleSystemList = null;
/*#end EXPORT_PARTICLES */
/*##if EXPORT_CONTROLLERS */
        /**
         * @public
         * @property  m_controllerList
         * @type      {?b2Controller|null}
         * @default   null
         */
        this.m_controllerList = null;

        /**
         * @public
         * @property  m_controllerCount
         * @type      {int}
         * @default   0
         */
        this.m_controllerCount = 0;
/*#end EXPORT_CONTROLLERS */

    } p = b2World.prototype; Box2D.b2World = b2World;

     // STATIC CLASS PROPERTIES

        /**
         * Object pool for memory management.
         */
        b2World._B2VEC2_POOL0 = new b2Vec2;
        b2World._B2VEC2_POOL1 = new b2Vec2;
        b2World._B2VEC2_POOL2 = new b2Vec2;
        b2World._B2VEC2_POOL3 = new b2Vec2;
        b2World._B2AABB_POOL0 = new b2AABB;
        b2World._B2TIMESTEP_POOL0 = new b2TimeStep;
        b2World.B2TIMESTEP_SUB_POOL0 = new b2TimeStep;
        b2World._B2SWEEP_POOL0 = new b2Sweep;
        b2World._B2SWEEP_POOL1 = new b2Sweep;
        b2World._B2SWEEP_POOL2 = new b2Sweep;
        b2World._B2TOI_INPUT_POOL0 = new b2TOIInput;
        b2World._B2TOI_OUTPUT_POOL0 = new b2TOIOutput;
        b2World._B2RAYCAST_INPUT_POOL0 = new b2RayCastInput;
        b2World._B2RAYCAST_OUTPUT_POOL0 = new b2RayCastOutput;
        b2World._B2COLOR_POOL0 = new b2Color( 0.5, 0.8, 0.8 );
        b2World._B2VEC2_VECTOR_4 = b2Vec2.newVector( 4 );
        b2World._B2TRANSFORM_POOL0 = new b2Transform;
        b2World._B2VEC2_VECTOR_MAX_POLYGON_VERTICES = b2Vec2.newVector( b2Settings.b2_maxPolygonVertices );

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

  // STATIC CLASS METHODS

    /**
     * Returns FALSE if the b2World has zero force on BOTH the x and y axis.
     *
     *  NOTE:   <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS</a>
     *          feeds zero force into addBox2D and handles force itself,
     *          which enables its much more advanced, customisable force abilities.
     *          Including multiple force fields.
     *
     * @public
     * @method  hasForce
     * @return  {boolean}       TRUE if force x AND y != 0.0,
     *                          FALSE otherwise.
     */
    b2World.hasForce = function ( force ) {
            return force.y != 0.0 || force.x != 0.0;
    };

// INSTANCE METHODS

    /**
     * Enable/disable allowSleeping.
     *
     * @public
     * @method  setAllowSleeping
     * @param   {boolean}     flag
     * @return  {void}
     */
    p.setAllowSleeping = function ( flag ) {
        if ( flag === this.m_allowSleep ) {
            return;
        }
        this.m_allowSleep = flag;
        if ( !this.m_allowSleep ) {
            for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
                b.setAwake( true );
            }
        }
    };

    /**
     * @public
     * @method  getAllowSleeping
     * @return  {boolean}     flag
     */
    p.getAllowSleeping = function () {
            return this.m_allowSleep;
    };

    /**
     * Enable/disable warm starting. For testing.
     *
     * @public
     * @method  setWarmStarting
     * @param   {boolean}     flag
     * @return  {void}
     */
    p.setWarmStarting = function ( flag ) {
        this.m_warmStarting = flag;
    };

    /**
     * Enable/disable continuous physics. For testing.
     *
     * @public
     * @method  setContinuousPhysics
     * @param   {boolean}   flag
     * @return  {void}
     */
    p.setContinuousPhysics = function ( flag ) {
        this.m_continuousPhysics = flag;
    };

    /**
     * Get continuous physics status. For testing.
     *
     * @public
     * @method  setContinuousPhysics
     * @return  {boolean}
     */
    p.getContinuousPhysics = function () {
        return this.m_continuousPhysics;
    };

    /**
     * Enable/disable single stepped continuous physics. For
     * testing.
     *
     * @public
     * @method  setSubStepping
     * @param   {boolean}     flag
     * @return  {void}
     */
    p.setSubStepping = function ( flag ) {
        this.m_subStepping = flag;
    };

    /**
     * Get single stepped continuous physics status.
     * For testing.
     *
     * @public
     * @method  getSubStepping
     * @return  {boolean}
     */
    p.getSubStepping = function () {
        return this.m_subStepping;
    };

    /**
     * Get the world body list. With the returned body, use
     * b2Body::GetNext to get the next body in the world list. A
     * NULL body indicates the end of the list.
     *
     * @public
     * @method  getBodyList
     * @return  {b2Body}    The head of the world body linked-list.
     */
    p.getBodyList = function () {
        return this.m_bodyList;
    };

    /**
     * Get the world joint list. With the returned joint, use
     * b2Joint.getNext to get the next joint in the world list. A
     * NULL joint indicates the end of the list.
     *
     * @public
     * @method  getJointList
     * @return  {b2Joint}     The head of the world joint linked-list.
     */
    p.getJointList = function () {
        return this.m_jointList;
    };

/*#if EXPORT_PARTICLES */
    /**
     * Get the world particle-system list. With the returned body, use
     * b2ParticleSystem::GetNext to get the next particle-system in the world
     * list. A NULL particle-system indicates the end of the list.
     *
     * @public
     * @method  getParticleSystemList
     * @return  {b2ParticleSystem}      The head of the world particle-system list.
     *                                  NULL particle-system indicates the end of the list.
     */
    p.getParticleSystemList = function () {
        return this.m_particleSystemList;
    };
/*#end EXPORT_PARTICLES */

    /**
     * Get the world contact list. With the returned contact, use
     * <a href=../classes/b2Contact.html#method_getNext>b2Contact.getNext()</a>
     * to get the next contact in the world
     * list. A NULL contact indicates the end of the list.
     *
     *  Warning: contacts are created and destroyed in the middle of a
     *  time step. Use
     *  <a href=../classes/b2ContactListener.html>b2ContactListener</a>
     *  to avoid missing contacts.
     *
     * @public
     * @method  getContactList
     * @return  {b2Contact} The head of the world contact linked-list
     */
    p.getContactList = function () {
        return this.m_contactManager.m_contactList;
    };

    /**
     * Get the number of bodies.
     *
     * @public
     * @method  getBodyCount
     * @return  {int}
     */
    p.getBodyCount = function () {
        return this.m_bodyCount;
    };

    /**
     * Get the number of joints.
     *
     * @public
     * @method  getJointCount
     * @return  {int}
     */
    p.getJointCount = function () {
        return this.m_jointCount;
    };

    /**
     * Get the number of contacts (each may have 0 or more contact points).
     *
     * @public
     * @method  getContactCount
     * @return  {int}
     */
    p.getContactCount = function () {
        return this.m_contactManager.m_contactCount;
    };

    /**
     * Change the global gravity vector.
     *
     * @public
     * @method  setGravity
     * @param   {b2Vec2}      gravity
     * @param   {boolean=}    [wake=true]   false lets bodies sleep through this update.
     * @return  {void}
     */
    p.setGravity = function ( gravity, wake ) {
        wake = wake || true;

        if ( (this.m_gravity.x !== gravity.x) || (this.m_gravity.y !== gravity.y) ) {
            this.m_gravity.copy( gravity );

            if ( wake ) {
                for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
                    b.setAwake( true );
                }
            }
        }
    };

    /**
     * Get the global gravity vector.
     *
     *  NOTE:  Unless a reusable object is provided, this returns a permanently
     *         heap allocated b2Vec2 for memory management.
     *         Copy returned values to avoid un expected value changes due to recycling.
     *
     * @public
     * @method  getGravity
     * @param   {b2Vec2|Object=}    [out=b2Vec2]    reusable object
     * @return  {b2Vec2|Object}     out
     */
    p.getGravity = function ( out ) {
        out = out || b2World._B2VEC2_POOL0;
        return out.copy( this.m_gravity );
    };

    /**
     * @public
     * @method  getGroundBody
     * @return  {b2Body}
     */
    p.getGroundBody = function () {
        return this.m_groundBody;
    };

    /**
     * Is the world locked (is it mid time step).
     *
     * @public
     * @method  isLocked
     * @return  {boolean}
     */
    p.isLocked = function () {
        //TODO: isLocked ((this.m_flags & b2World.e_locked) > 0)
        return this.m_flag_locked;
    };

    /**
     * Set the flag that controls automatic clearing of forces after each time step.
     *
     * @public
     * @method  setAutoClearForces
     * @param   {boolean}    flag
     */
    p.setAutoClearForces = function ( flag ) {
        this.m_flag_clearForces = flag;
    };

    /**
     * Get the flag that controls automatic clearing of forces after each time step.
     *
     * @public
     * @method      getAutoClearForces
     * @returns     {boolean}
     */
    p.getAutoClearForces = function () {
        return this.m_flag_clearForces;
    };

    /**
     * Get the contact manager for testing.
     *
     * @public
     * @method  getContactManager
     * @return {b2ContactManager}
     */
    p.getContactManager = function () {
        return this.m_contactManager;
    };

    /**
     * Get the current profile.
     *
     * @public
     * @method  getProfile
     * @return {b2Profile}
     */
    p.getProfile = function () {
        return this.m_profile;
    };

    /**
     * Register a destruction listener. The listener is owned by you and must
     * remain in scope.
     *
     * @public
     * @method  setDestructionListener
     * @return  {void}
     */
    p.setDestructionListener = function ( listener ) {
        this.m_destructionListener = listener;
    };

    /**
     * Register a contact filter to provide specific control over collision.
     * Otherwise the default filter is used (b2_defaultFilter). The listener is
     * owned by you and must remain in scope.
     *
     * @public
     * @method  setContactFilter
     * @param   {b2Filter}      filter      Data to filter contacts by.
     * @return  {void}
     */
    p.setContactFilter = function ( filter ) {
        this.m_contactManager.m_contactFilter = filter;
    };

    /**
     * Register a contact event listener. The listener is owned by you and must
     * remain in scope.
     *
     * @public
     * @method  setContactListener
     * @param   {Function}      listener
     * @return  {void}
     */
    p.setContactListener = function ( listener ) {
        this.m_contactManager.m_contactListener = listener;
    };

    /**
     * Register a routine for debug drawing. The debug draw functions are called
     * inside with b2World::DrawDebugData method. The debug draw object is owned
     * by you and must remain in scope.
     *
     * @public
     * @method  setDebugDraw
     * @param   {b2DebugDraw}    debugDraw      DebugDrawing definition.
     * @return  {void}
     */
    p.setDebugDraw = function ( debugDraw ) {
        this.m_debugDraw = debugDraw;
    };

    /**
     * Create a rigid body given a definition. No reference to the definition is retained.
     *
     *  Warning: This function is locked during callbacks.</br>
     *    NOTE:  However using the
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS framework</a>
     *           event listeners you can do what every you want whenever you want and
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS</a>
     *           manages the locked world problems for you.
     *
     * @public
     * @method  createBody
     * @param   {b2BodyDef}     bodyDef
     * @return  {b2Body}
     */
    p.createBody = function ( bodyDef ) {
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( !this.isLocked() );
        }/*#*/
        if ( this.isLocked() ) {
            return null;
        }

        /** b2Body */ var b = new b2Body( bodyDef, this );

        // Add to world doubly linked list.
        b.m_prev = null;
        b.m_next = this.m_bodyList;
        if ( this.m_bodyList ) {
            this.m_bodyList.m_prev = b;
        }
        this.m_bodyList = b;
        ++this.m_bodyCount;

        return b;
    };

    /**
     * Destroy a rigid body.</br></br>
     *
     *  Warning: This automatically deletes all associated shapes and joints.</br>
     *  Warning: This function is locked during callbacks.</br>
     *    NOTE:  However using the
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS framework</a>
     *           event listeners you can do what every you want whenever you want and
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS</a>
     *           manages the locked world problems for you.
     *
     * @public
     * @method  destroyBody
     * @param   {b2Body}    body
     * @return  {void}
     */
    p.destroyBody = function ( body ) {
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( this.m_bodyCount > 0 );
            b2Assert( !this.isLocked() );
        }/*#*/
        if ( this.isLocked() ) {
            return;
        }

        // Delete the attached joints.
        /** b2JointEdge */ var je = body.m_jointList;
        while (je) {
            /** b2JointEdge */ var je0 = je;
            je = je.next;

            if ( this.m_destructionListener ) {
                this.m_destructionListener.sayGoodbyeJoint( je0.joint );
            }

            this.destroyJoint( je0.joint );

            body.m_jointList = je;
        }
        body.m_jointList = null;

/*##if EXPORT_CONTROLLERS */
        /// @see b2Controller list
        /** b2ControllerEdge */ var coe = body.m_controllerList;
        while (coe) {
            /** b2ControllerEdge */ var coe0 = coe;
            coe = coe.nextController;
            coe0.controller.removeBody( body );
        }
/*#end EXPORT_CONTROLLERS */
        // Delete the attached contacts.
        /** b2ContactEdge */ var ce = body.m_contactList;
        while (ce) {
            /** b2ContactEdge */ var ce0 = ce;
            ce = ce.next;
            this.m_contactManager.destroy( ce0.contact );
        }
        body.m_contactList = null;

        // Delete the attached fixtures. This destroys broad-phase proxies.
        /** b2Fixture */ var f = body.m_fixtureList;
        while (f) {
            /** b2Fixture */ var f0 = f;
            f = f.m_next;

            if ( this.m_destructionListener ) {
                this.m_destructionListener.sayGoodbyeFixture( f0 );
            }

            f0.destroyProxies( this.m_contactManager.m_broadPhase );
            f0.destroy();


            body.m_fixtureList = f;
            body.m_fixtureCount -= 1;
        }
        body.m_fixtureList = null;
        body.m_fixtureCount = 0;

        // Remove world body list.
        if ( body.m_prev ) {
            body.m_prev.m_next = body.m_next;
        }

        if ( body.m_next ) {
            body.m_next.m_prev = body.m_prev;
        }

        if ( body === this.m_bodyList ) {
            this.m_bodyList = body.m_next;
        }

        --this.m_bodyCount;
    };

    /**
     * Create a joint to constrain bodies together. No reference to the definition
     * is retained. This may cause the connected bodies to cease colliding.</br></br>
     *
     *  Warning: This function is locked during callbacks.</br>
     *    NOTE:  However using the
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS framework</a>
     *           event listeners you can do what every you want whenever you want and
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS</a>
     *           manages the locked world problems for you.
     *
     * @public
     * @method  createJoint
     * @param   {b2JointDef}  jointDef
     * @return  {b2Joint}
     */
    p.createJoint = function ( jointDef ) {
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( !this.isLocked() );
        }/*#*/
        if ( this.isLocked() ) {
            return null;
        }

        /** b2Joint */ var j = b2JointFactory.create( jointDef, null );

        // Connect to the world list.
        j.m_prev = null;
        j.m_next = this.m_jointList;
        if ( this.m_jointList ) {
            this.m_jointList.m_prev = j;
        }
        this.m_jointList = j;
        ++this.m_jointCount;

        // Connect to the bodies' doubly linked lists.
        j.m_edgeA.joint = j;
        j.m_edgeA.other = j.m_bodyB;
        j.m_edgeA.prev = null;
        j.m_edgeA.next = j.m_bodyA.m_jointList;
        if ( j.m_bodyA.m_jointList ) j.m_bodyA.m_jointList.prev = j.m_edgeA;
        j.m_bodyA.m_jointList = j.m_edgeA;

        j.m_edgeB.joint = j;
        j.m_edgeB.other = j.m_bodyA;
        j.m_edgeB.prev = null;
        j.m_edgeB.next = j.m_bodyB.m_jointList;
        if ( j.m_bodyB.m_jointList ) j.m_bodyB.m_jointList.prev = j.m_edgeB;
        j.m_bodyB.m_jointList = j.m_edgeB;

        /** b2Body */ var bodyA = jointDef.bodyA;
        /** b2Body */ var bodyB = jointDef.bodyB;

        // If the joint prevents collisions, then flag any contacts for filtering.
        if ( !jointDef.collideConnected ) {
            /** b2ContactEdge */ var edge = bodyB.getContactList();
            while (edge) {
                if ( edge.other === bodyA ) {
                    // Flag the contact for filtering at the next time step (where either
                    // body is awake).
                    edge.contact.flagForFiltering();
                }

                edge = edge.next;
            }
        }

        // Note: creating a joint doesn't wake the bodies.

        return j;
    };

    /**
     *  Destroy a joint. This may cause the connected bodies to begin colliding.</br></br>
     *
     *  Warning: This function is locked during callbacks.</br>
     *    NOTE:  However using the
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS framework</a>
     *           event listeners you can do what every you want whenever you want and
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS</a>
     *           manages the locked world problems for you.
     *
     * @public
     * @method  destroyJoint
     * @param   {b2Joint}   joint
     * @return  {void}
     */
    p.destroyJoint = function ( joint ) {
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( !this.isLocked() );
        }/*#*/
        if ( this.isLocked() ) {
            return;
        }

        /** boolean */ var collideConnected = joint.m_collideConnected;

        // Remove from the doubly linked list.
        if ( joint.m_prev ) {
            joint.m_prev.m_next = joint.m_next;
        }

        if ( joint.m_next ) {
            joint.m_next.m_prev = joint.m_prev;
        }

        if ( joint === this.m_jointList ) {
            this.m_jointList = joint.m_next;
        }

        // Disconnect from island graph.
        /** b2Body */ var bodyA = joint.m_bodyA;
        /** b2Body */ var bodyB = joint.m_bodyB;

        // Wake up connected bodies.
        bodyA.setAwake( true );
        bodyB.setAwake( true );

        // Remove from body 1.
        if ( joint.m_edgeA.prev ) {
            joint.m_edgeA.prev.next = joint.m_edgeA.next;
        }

        if ( joint.m_edgeA.next ) {
            joint.m_edgeA.next.prev = joint.m_edgeA.prev;
        }

        if ( joint.m_edgeA === bodyA.m_jointList ) {
            bodyA.m_jointList = joint.m_edgeA.next;
        }

        joint.m_edgeA.prev = null;
        joint.m_edgeA.next = null;

        // Remove from body 2
        if ( joint.m_edgeB.prev ) {
            joint.m_edgeB.prev.next = joint.m_edgeB.next;
        }

        if ( joint.m_edgeB.next ) {
            joint.m_edgeB.next.prev = joint.m_edgeB.prev;
        }

        if ( joint.m_edgeB === bodyB.m_jointList ) {
            bodyB.m_jointList = joint.m_edgeB.next;
        }

        joint.m_edgeB.prev = null;
        joint.m_edgeB.next = null;

        b2JointFactory.destroy( joint, null );
       /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( this.m_jointCount > 0 );
        }/*#*/
        --this.m_jointCount;

        // If the joint prevents collisions, then flag any contacts for filtering.
        if ( !collideConnected ) {
            /** b2ContactEdge */ var edge = bodyB.getContactList();
            while (edge) {
                if ( edge.other === bodyA ) {
                    // Flag the contact for filtering at the next time step (where either
                    // body is awake).
                    edge.contact.flagForFiltering();
                }

                edge = edge.next;
            }
        }
    };

/*#if EXPORT_PARTICLES */
    /**
     * Create a particle system given a definition. No reference to the
     * definition is retained.
     *
     *  Warning: This function is locked during callbacks.</br>
     *    NOTE:  However using the
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS framework</a>
     *           event listeners you can do what every you want whenever you want and
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS</a>
     *           manages the locked world problems for you.
     *
     * @public
     * @method  createParticleSystem
     * @param   {b2ParticleSystemDef}  systemDef
     * @return {b2ParticleSystem}
     */
    p.createParticleSystem = function ( systemDef ) {
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( !this.isLocked() );
        }/*#*/
        if ( this.isLocked() ) {
            return null;
        }

        var p = new b2ParticleSystem( systemDef, this );

        // Add to world doubly linked list.
        p.m_prev = null;
        p.m_next = this.m_particleSystemList;
        if ( this.m_particleSystemList ) {
            this.m_particleSystemList.m_prev = p;
        }
        this.m_particleSystemList = p;

        return p;
    };

    /**
     * Destroy a particle system.
     *
     *  Warning: This function is locked during callbacks.</br>
     *    NOTE:  However using the
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS framework</a>
     *           event listeners you can do what every you want whenever you want and
     *           <a href=https://github.com/SmartArtsStudio/addPhysicsJS>addPhysicsJS</a>
     *           manages the locked world problems for you.
     *
     * @public
     * @method  destroyParticleSystem
     * @param   {b2ParticleSystem}    system
     * @return  {void}
     */
    p.destroyParticleSystem = function ( system ) {
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( !this.isLocked() );
        }/*#*/
        if ( this.isLocked() ) {
            return;
        }

        // Remove world particleSystem list.
        if ( system.m_prev ) {
            system.m_prev.m_next = system.m_next;
        }

        if ( system.m_next ) {
            system.m_next.m_prev = system.m_prev;
        }

        if ( system === this.m_particleSystemList ) {
            this.m_particleSystemList = system.m_next;
        }
    };
/*#end EXPORT_PARTICLES */

    /**
     * Find islands, integrate and solve constraints, solve position constraints.
     *
     * @public
     * @method  solve
     * @param   {b2TimeStep} step
     * @return  {void}
     */
    p.solve = function ( step ) {

/*#if EXPORT_PARTICLES */
        // update previous transforms
        for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
            b.m_xf0.copy( b.m_xf );
        }
/*#end EXPORT_PARTICLES */
/*##if EXPORT_CONTROLLERS */
        /// @see b2Controller list
        for (/** b2Controller */ var controller = this.m_controllerList; controller; controller = controller.m_next) {
            controller.step( step );
        }
/*#end EXPORT_CONTROLLERS */
        this.m_profile.solveInit = 0;
        this.m_profile.solveVelocity = 0;
        this.m_profile.solvePosition = 0;

        // Size the island for the worst case.
        /** b2Island */ var island = this.m_island;
        island.initialize( this.m_bodyCount,
            this.m_contactManager.m_contactCount,
            this.m_jointCount,
            null, // this.m_stackAllocator,
            this.m_contactManager.m_contactListener );

        // Clear all the island flags.
        for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
            b.m_flag_islandFlag = false;
        }
        for (/** b2Contact */ var c = this.m_contactManager.m_contactList; c; c = c.m_next) {
            c.m_flag_islandFlag = false;
        }
        for (/** b2Joint */ var j = this.m_jointList; j; j = j.m_next) {
            j.m_islandFlag = false;
        }

        // Build and simulate all awake islands.
        /** number */ var stackSize = this.m_bodyCount;
        /** @type {Array.<?b2Body>} */ var stack = this.s_stack;
        for (/** b2Body */ var seed = this.m_bodyList; seed; seed = seed.m_next) {
            if ( seed.m_flag_islandFlag ) {
                continue;
            }

            if ( !seed.isAwake() || !seed.isActive() ) {
                continue;
            }

            // The seed can be dynamic or kinematic.
            if ( seed.getType() === b2Body.b2_staticBody ) {
                continue;
            }

            // Reset island and stack.
            island.clear();
            /** number */ var stackCount = 0;
            stack[stackCount++] = seed;
            seed.m_flag_islandFlag = true;

            // Perform a depth first search (DFS) on the constraint graph.
            while (stackCount > 0) {
                // Grab the next body off the stack and add it to the island.
                /** b2Body */
                var b = stack[--stackCount];
                /*##if EXPORT_ASSERTS */
                if ( b2Settings.ASSERTS_ENABLED ) {
                    b2Assert( b.isActive() );
                }/*#*/
                island.addBody( b );

                // Make sure the body is awake.
                b.setAwake( true );

                // To keep islands as small as possible, we don't
                // propagate islands across static bodies.
                if ( b.getType() === b2Body.b2_staticBody ) {
                    continue;
                }

                // Search all contacts connected to this body.
                for (/** b2ContactEdge */ var ce = b.m_contactList; ce; ce = ce.next) {
                    /** b2Contact */ var contact = ce.contact;

                    // Has this contact already been added to an island?
                    if ( contact.m_flag_islandFlag ) {
                        continue;
                    }

                    // Is this contact solid and touching?
                    if ( !contact.isEnabled() || !contact.isTouching() ) {
                        continue;
                    }

                    // Skip sensors.
                    /** boolean */ var sensorA = contact.m_fixtureA.m_isSensor;
                    /** boolean */ var sensorB = contact.m_fixtureB.m_isSensor;
                    if ( sensorA || sensorB ) {
                        continue;
                    }

                    island.addContact( contact );
                    contact.m_flag_islandFlag = true;

                    /** b2Body */ var other = ce.other;

                    // Was the other body already added to this island?
                    if ( other.m_flag_islandFlag ) {
                        continue;
                    }
                    /*##if EXPORT_ASSERTS */
                    if ( b2Settings.ASSERTS_ENABLED ) {
                        b2Assert( stackCount < stackSize );
                    }/*#*/
                    stack[stackCount++] = other;
                    other.m_flag_islandFlag = true;
                }

                // Search all joints connect to this body.
                for (/** b2JointEdge */ var je = b.m_jointList; je; je = je.next) {
                    if ( je.joint.m_islandFlag ) {
                        continue;
                    }

                    /** b2Body */
                    var other = je.other;

                    // Don't simulate joints connected to inactive bodies.
                    if ( !other.isActive() ) {
                        continue;
                    }

                    island.addJoint( je.joint );
                    je.joint.m_islandFlag = true;

                    if ( other.m_flag_islandFlag ) {
                        continue;
                    }
                   /*##if EXPORT_ASSERTS */
                    if ( b2Settings.ASSERTS_ENABLED ) {
                        b2Assert( stackCount < stackSize );
                    }/*#*/
                    stack[stackCount++] = other;
                    other.m_flag_islandFlag = true;
                }
            }

            /** b2Profile */ var profile = new b2Profile();
            island.solve( profile, step, this.m_gravity, this.m_allowSleep );
            this.m_profile.solveInit += profile.solveInit;
            this.m_profile.solveVelocity += profile.solveVelocity;
            this.m_profile.solvePosition += profile.solvePosition;

            // Post solve cleanup.
            for (/** number */ var i = 0; i < island.m_bodyCount; ++i) {
                // Allow static bodies to participate in other islands.
                /** b2Body */
                var b = island.m_bodies[i];
                if ( b.getType() === b2Body.b2_staticBody ) {
                    b.m_flag_islandFlag = false;
                }
            }
        }

        for (/** number */ var i = 0; i < stack.length; ++i) {
            if ( !stack[i] ) break;
            stack[i] = null;
        }

        {
            /** b2Timer */ var timer = new b2Timer();

            // Synchronize fixtures, check for out of range bodies.
            for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
                // If a body was not in an island then it did not move.
                if ( !b.m_flag_islandFlag ) {
                    continue;
                }

                if ( b.getType() === b2Body.b2_staticBody ) {
                    continue;
                }

                // Update fixtures (for broad-phase).
                b.synchronizeFixtures();
            }

            // Look for new contacts.
            this.m_contactManager.findNewContacts();
            this.m_profile.broadphase = timer.getMilliseconds();
        }
    };

    /**
     * Find Time Of Impact contacts and solve them.
     *
     * @public
     * @method  solveTOI
     * @param   {b2TimeStep} step
     * @return  {void}
     */
    p.solveTOI = function ( step ) {
        //	b2Island island(2 * b2Settings.b2_maxTOIContactsPerIsland, b2Settings.b2_maxTOIContactsPerIsland, 0, &m_stackAllocator, m_contactManager.m_contactListener);
        /** b2Island */ var island = this.m_island;
        island.initialize( 2 * b2Settings.b2_maxTOIContactsPerIsland, b2Settings.b2_maxTOIContactsPerIsland, 0, null, this.m_contactManager.m_contactListener );

        if ( this.m_stepComplete ) {
            for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
                b.m_flag_islandFlag = false;
                b.m_sweep.alpha0 = 0;
            }

            for (/** b2Contact */ var c = this.m_contactManager.m_contactList; c; c = c.m_next) {
                // Invalidate TOI
                c.m_flag_toiFlag = c.m_flag_islandFlag = false;
                c.m_toiCount = 0;
                c.m_toi = 1;
            }
        }

        // Find TOI events and solve them.
        for (; ;) {
            // Find the first TOI.
            /** b2Contact */ var minContact = null;
            /** number */ var minAlpha = 1;

            for (/** b2Contact */ var c = this.m_contactManager.m_contactList; c; c = c.m_next) {
                // Is this contact disabled?
                if ( !c.isEnabled() ) {
                    continue;
                }

                // Prevent excessive sub-stepping.
                if ( c.m_toiCount > b2Settings.b2_maxSubSteps ) {
                    continue;
                }

                /** number */ var alpha = 1;
                if ( c.m_flag_toiFlag ) {
                    // This contact has a valid cached TOI.
                    alpha = c.m_toi;
                }
                else {
                    /** b2Fixture */ var fA = c.getFixtureA();
                    /** b2Fixture */ var fB = c.getFixtureB();

                    // Is there a sensor?
                    if ( fA.isSensor() || fB.isSensor() ) {
                        continue;
                    }

                    /** b2Body */ var bA = fA.getBody();
                    /** b2Body */ var bB = fB.getBody();

                    /** int */ var typeA = bA.m_type;
                    /** int */ var typeB = bB.m_type;
                    /*##if EXPORT_ASSERTS */
                    if ( b2Settings.ASSERTS_ENABLED ) {
                        b2Assert( typeA === b2Body.b2_dynamicBody || typeB === b2Body.b2_dynamicBody );
                    }
                    /*#end EXPORT_ASSERTS */
                    /** boolean */ var activeA = bA.isAwake() && typeA !== b2Body.b2_staticBody;
                    /** boolean */ var activeB = bB.isAwake() && typeB !== b2Body.b2_staticBody;

                    // Is at least one body active (awake and dynamic or kinematic)?
                    if ( !activeA && !activeB ) {
                        continue;
                    }

                    /** boolean */ var collideA = bA.isBullet() || typeA !== b2Body.b2_dynamicBody;
                    /** boolean */ var collideB = bB.isBullet() || typeB !== b2Body.b2_dynamicBody;

                    // Are these two non-bullet dynamic bodies?
                    if ( !collideA && !collideB ) {
                        continue;
                    }

                    // Compute the TOI for this contact.
                    // Put the sweeps onto the same time interval.
                    /** number */ var alpha0 = bA.m_sweep.alpha0;

                    if ( bA.m_sweep.alpha0 < bB.m_sweep.alpha0 ) {
                        alpha0 = bB.m_sweep.alpha0;
                        bA.m_sweep.advance( alpha0 );
                    }
                    else if ( bB.m_sweep.alpha0 < bA.m_sweep.alpha0 ) {
                        alpha0 = bA.m_sweep.alpha0;
                        bB.m_sweep.advance( alpha0 );
                    }
                    /*##if EXPORT_ASSERTS */
                    if ( b2Settings.ASSERTS_ENABLED ) {
                        b2Assert( alpha0 < 1 );
                    }
                    /*#end EXPORT_ASSERTS */
                    /** number */ var indexA = c.getChildIndexA();
                    /** number */ var indexB = c.getChildIndexB();

                    // Compute the time of impact in interval [0, minTOI]
                    /** b2TOIInput */ var input = b2World._B2TOI_INPUT_POOL0;
                    input.proxyA.setShape( fA.getShape(), indexA );
                    input.proxyB.setShape( fB.getShape(), indexB );
                    input.sweepA.copy( bA.m_sweep );
                    input.sweepB.copy( bB.m_sweep );
                    input.tMax = 1;

                    /** b2TOIOutput */ var output = b2World._B2TOI_OUTPUT_POOL0;
                    b2Collision.timeOfImpact( output, input );

                    // Beta is the fraction of the remaining portion of the .
                    /** number */ var beta = output.t;
                    if ( output.state === b2TOIOutput.e_touching ) {
                        alpha = Math.min( alpha0 + (1 - alpha0) * beta, 1 );
                    }
                    else {
                        alpha = 1;
                    }

                    c.m_toi = alpha;
                    c.m_flag_toiFlag = true;
                }

                if ( alpha < minAlpha ) {
                    // This is the minimum TOI found so far.
                    minContact = c;
                    minAlpha = alpha;
                }
            }

            if ( minContact === null || 1 - 10 * b2Settings.b2_epsilon < minAlpha ) {
                // No more TOI events. Done!
                this.m_stepComplete = true;
                break;
            }

            // Advance the bodies to the TOI.
            /** b2Fixture */var fA = minContact.getFixtureA();
            /** b2Fixture */var fB = minContact.getFixtureB();
            /** b2Body */var bA = fA.getBody();
            /** b2Body */var bB = fB.getBody();

            /** b2Sweep */ var backup1 = b2World._B2SWEEP_POOL1.copy( bA.m_sweep );
            /** b2Sweep */ var backup2 = b2World._B2SWEEP_POOL2.copy( bB.m_sweep );

            bA.advance( minAlpha );
            bB.advance( minAlpha );

            // The TOI contact likely has some new contact points.
            minContact.update( this.m_contactManager.m_contactListener );
            minContact.m_flag_toiFlag = false;
            ++minContact.m_toiCount;

            // Is the contact solid?
            if ( !minContact.isEnabled() || !minContact.isTouching() ) {
                // Restore the sweeps.
                minContact.setEnabled( false );
                bA.m_sweep.copy( backup1 );
                bB.m_sweep.copy( backup2 );
                bA.synchronizeTransform();
                bB.synchronizeTransform();
                continue;
            }

            bA.setAwake( true );
            bB.setAwake( true );

            // Build the island
            island.clear();
            island.addBody( bA );
            island.addBody( bB );
            island.addContact( minContact );

            bA.m_flag_islandFlag = true;
            bB.m_flag_islandFlag = true;
            minContact.m_flag_islandFlag = true;

            // Get contacts on bodyA and bodyB.
            //** b2Body */ var bodies = [bA, bB];
            for (/** number */ var i = 0; i < 2; ++i) {
                /** b2Body */ var body = (i === 0) ? (bA) : (bB);//bodies[i];
                if ( body.m_type === b2Body.b2_dynamicBody ) {
                    for (/** b2ContactEdge */ var ce = body.m_contactList; ce; ce = ce.next) {
                        if ( island.m_bodyCount === island.m_bodyCapacity ) {
                            break;
                        }

                        if ( island.m_contactCount === island.m_contactCapacity ) {
                            break;
                        }

                        /** b2Contact */ var contact = ce.contact;

                        // Has this contact already been added to the island?
                        if ( contact.m_flag_islandFlag ) {
                            continue;
                        }

                        // Only add static, kinematic, or bullet bodies.
                        /** b2Body */ var other = ce.other;
                        if ( other.m_type === b2Body.b2_dynamicBody && !body.isBullet() && !other.isBullet() ) {
                            continue;
                        }

                        // Skip sensors.
                        /** boolean */ var sensorA = contact.m_fixtureA.m_isSensor;
                        /** boolean */ var sensorB = contact.m_fixtureB.m_isSensor;
                        if ( sensorA || sensorB ) {
                            continue;
                        }

                        // Tentatively advance the body to the TOI.
                        /** b2Sweep */ var backup = b2World._B2SWEEP_POOL0.copy( other.m_sweep );
                        if ( !other.m_flag_islandFlag ) {
                            other.advance( minAlpha );
                        }

                        // Update the contact points
                        contact.update( this.m_contactManager.m_contactListener );

                        // Was the contact disabled by the user?
                        if ( !contact.isEnabled() ) {
                            other.m_sweep.copy( backup );
                            other.synchronizeTransform();
                            continue;
                        }

                        // Are there contact points?
                        if ( !contact.isTouching() ) {
                            other.m_sweep.copy( backup );
                            other.synchronizeTransform();
                            continue;
                        }

                        // Add the contact to the island
                        contact.m_flag_islandFlag = true;
                        island.addContact( contact );

                        // Has the other body already been added to the island?
                        if ( other.m_flag_islandFlag ) {
                            continue;
                        }

                        // Add the other body to the island.
                        other.m_flag_islandFlag = true;

                        if ( other.m_type !== b2Body.b2_staticBody ) {
                            other.setAwake( true );
                        }

                        island.addBody( other );
                    }
                }
            }

            /** b2TimeStep */ var subStep = b2World.B2TIMESTEP_SUB_POOL0;
            subStep.dt = (1 - minAlpha) * step.dt;
            subStep.inv_dt = 1 / subStep.dt;
            subStep.dtRatio = 1;
            subStep.positionIterations = step.positionIterations;
            subStep.velocityIterations = step.velocityIterations;
/*#if EXPORT_PARTICLES */
            subStep.particleIterations = step.particleIterations;
/*#end EXPORT_PARTICLES */
            subStep.warmStarting = false;
            island.solveTOI( subStep, bA.m_islandIndex, bB.m_islandIndex );

            // Reset island flags and synchronize broad-phase proxies.
            for (/** number */ var i = 0; i < island.m_bodyCount; ++i) {
                /** b2Body */
                var body = island.m_bodies[i];
                body.m_flag_islandFlag = false;

                if ( body.m_type !== b2Body.b2_dynamicBody ) {
                    continue;
                }

                body.synchronizeFixtures();

                // Invalidate all contact TOIs on this displaced body.
                for (/** b2ContactEdge */ var ce = body.m_contactList; ce; ce = ce.next) {
                    ce.contact.m_flag_toiFlag = ce.contact.m_flag_islandFlag = false;
                }
            }

            // Commit fixture proxy movements to the broad-phase so that new contacts are created.
            // Also, some contacts can be destroyed.
            this.m_contactManager.findNewContacts();

            if ( this.m_subStepping ) {
                this.m_stepComplete = false;
                break;
            }
        }
    };

    /**
     * Take a time step. This performs collision detection,
     * integration, and constraint solution.
     *
     * For the numerical stability of particles, minimize the following
     * dimensionless gravity acceleration:
     *     gravity / particleRadius * (timeStep / particleIterations)^2
     * b2ParticleSystem.b2CalculateParticleIterations() or
     * CalculateReasonableParticleIterations() help to determine the optimal
     * particleIterations.
     *
     *
     * @public
     * @method  step
     * @param   {number}    deltaTime           The amount of time to simulate, this should not vary.
     * @param   {number}    velocityIterations  For the velocity constraint solver.
     * @param   {number}    positionIterations  For the position constraint solver.
     * @param   {number=}   particleIterations  For the particle constraint solver. (Only if particle module included.)
     * @return  {void}
     */
    p.step = function ( deltaTime, velocityIterations, positionIterations/*#if EXPORT_PARTICLES */, particleIterations/*#end EXPORT_PARTICLES */ ){
/*#if EXPORT_PARTICLES */
        particleIterations = particleIterations || this.calculateReasonableParticleIterations( deltaTime );
/*#end EXPORT_PARTICLES */
        /** b2Timer */ var stepTimer = new b2Timer();

        // If new fixtures were added, we need to find the new contacts.
        if ( this.m_flag_newFixture ) {
            this.m_contactManager.findNewContacts();
            this.m_flag_newFixture = false;
        }

        this.m_flag_locked = true;

        /** b2TimeStep */ var step = b2World._B2TIMESTEP_POOL0;
        step.dt = deltaTime;
        step.velocityIterations = velocityIterations;
        step.positionIterations = positionIterations;
/*#if EXPORT_PARTICLES */
        step.particleIterations = particleIterations;
/*#end EXPORT_PARTICLES */
        if ( deltaTime > 0 ) {
            step.inv_dt = 1 / deltaTime;
        }
        else {
            step.inv_dt = 0;
        }

        step.dtRatio = this.m_inv_dt0 * deltaTime;

        step.warmStarting = this.m_warmStarting;

        // Update contacts. This is where some contacts are destroyed.
        {
            /**b2Timer*/ var timer = new b2Timer();
            this.m_contactManager.collide();
            this.m_profile.collide = timer.getMilliseconds();
        }

        // Integrate velocities, solve velocity constraints, and integrate positions.
        if ( this.m_stepComplete && step.dt > 0.0 ) {
            timer = new b2Timer();
/*#if EXPORT_PARTICLES */
            for (/** b2ParticleSystem */ var p = this.m_particleSystemList; p; p = p.m_next) {
                p.solve( step ); // Particle Simulation
            }
/*#end EXPORT_PARTICLES */
            this.solve( step );
            this.m_profile.solve = timer.getMilliseconds();
        }

        // Handle TOI events.
        if ( this.m_continuousPhysics && step.dt > 0 ) {
            timer = new b2Timer();
            this.solveTOI( step );
            this.m_profile.solveTOI = timer.getMilliseconds();
        }

        if ( step.dt > 0 ) {
            this.m_inv_dt0 = step.inv_dt;
        }

        if ( this.m_flag_clearForces ) {
            this.clearForces();
        }

        this.m_flag_locked = false;

        this.m_profile.step = stepTimer.getMilliseconds();
    };

    /**
     * Manually clear the force buffer on all bodies. By default, forces are cleared automatically
     * after each call to Step. The default behavior is modified by calling
     * <a href=../classes/b2World.html#method_setAutoClearForces>b2World.setAutoClearForces()</a>.
     * The purpose of this function is to support sub-stepping. Sub-stepping is often used to maintain
     * a fixed sized time step under a variable frame-rate.
     * When you perform sub-stepping you will disable auto clearing of forces and instead call
     * <a href=../classes/b2World.html#method_clearForces>b2World.clearForces()</a>
     * after all sub-steps are complete in one pass of your game loop. See
     * <a href=../classes/b2World.html#method_setAutoClearForces>b2World.setAutoClearForces()</a>
     *
     * @public
     * @method  clearForces
     * @return  {void}
     */
    p.clearForces = function () {
        for (/** b2Body */ var body = this.m_bodyList; body; body = body.m_next) {
            body.m_force.setZero();
            body.m_torque = 0;
        }
    };

    /**
     * Query the world for all fixtures that potentially overlap the provided AABB.
     *
     * @public
     * @method  queryAABB
     * @param   {b2QueryCallback|function(b2Fixture):boolean}   callback    A user implemented callback class.
     * @param   {b2AABB}        aabb    The query box.
     * @return  {void}
     */
    p.queryAABB = function ( callback, aabb ) {
        /** b2BroadPhase */ var broadPhase = this.m_contactManager.m_broadPhase;

        /**
         * @return {boolean}
         * @param {b2TreeNode} proxy
         */
        var WorldQueryAABBWrapper = function ( proxy ) {
            /** b2FixtureProxy */var fixture_proxy = broadPhase.getUserData( proxy );
            /*##if EXPORT_ASSERTS */
            if ( b2Settings.ASSERTS_ENABLED ) {
                b2Assert( fixture_proxy instanceof b2FixtureProxy );
            }/*#*/
            /** b2Fixture */var fixture = fixture_proxy.fixture;
            if ( callback instanceof b2QueryCallback ) {
                return callback.reportFixture( fixture );
            }
            else if (typeof(callback) === 'function')
            {
                return callback( fixture );
            }
        };

        broadPhase.query( WorldQueryAABBWrapper, aabb );
/*#if EXPORT_PARTICLES */
        if ( callback instanceof b2QueryCallback ) {
            for (/** b2ParticleSystem */ var p = this.m_particleSystemList; p; p = p.m_next) {
                if ( callback.shouldQueryParticleSystem( p ) ) {
                    p.queryAABB( callback, aabb );
                }
            }
        }
/*#end EXPORT_PARTICLES */
    };

    /**
     * Query the world for all fixtures that potentially overlap the
     * provided shape's AABB. Calls
     * <a href=../classes/b2World.html#method_queryAABB>b2World.queryAABB()</a>
     * internally.
     *
     * @public
     * @method  queryShape
     * @param   {b2QueryCallback|function(b2Fixture):boolean}   callback
     * @param   {b2Shape}                                       shape
     * @param   {b2Transform}                                   transform
     * @param   {int}                                           childIndex
     * @return  {void}
     */
    p.queryShape = function ( callback, shape, transform, childIndex ) {
        /** b2BroadPhase */ var broadPhase = this.m_contactManager.m_broadPhase;

        /**
         * @return {boolean}
         * @param {b2TreeNode} proxy
         */
        var WorldQueryShapeWrapper = function ( proxy ) {
            /** b2FixtureProxy */
            var fixture_proxy = broadPhase.getUserData( proxy );
            /*##if EXPORT_ASSERTS */
            if ( b2Settings.ASSERTS_ENABLED ) {
                b2Assert( fixture_proxy instanceof b2FixtureProxy );
            }/*#*/
            /** b2Fixture */ var fixture = fixture_proxy.fixture;
            if ( b2Collision.testOverlapShape( shape, 0, fixture.getShape(), 0, transform, fixture.getBody().getTransform() ) ) {
                if ( callback instanceof b2QueryCallback ) {
                    return callback.reportFixture( fixture );
                }
                else if (typeof(callback) === 'function')
                {
                    return callback( fixture );
                }
            }
            return true;
        };

        childIndex = childIndex || 0;
        /** b2AABB */ var aabb = b2World._B2AABB_POOL0;
        shape.computeAABB( aabb, transform, childIndex );
        broadPhase.query( WorldQueryShapeWrapper, aabb );
/*#if EXPORT_PARTICLES */
        if ( callback instanceof b2QueryCallback ) {
            for (/** b2ParticleSystem */ var p = this.m_particleSystemList; p; p = p.m_next) {
                if ( callback.shouldQueryParticleSystem( p ) ) {
                    p.queryAABB( callback, aabb );
                }
            }
        }
/*#end EXPORT_PARTICLES */
    };

    /**
     * @public
     * @method  queryPoint
     * @param   {b2QueryCallback|function(b2Fixture):boolean}   callback
     * @param   {b2Vec2}    point   Point in world to test.
     * @param   {float=}    [slop]
     * @return  {void}
     */
    p.queryPoint = function ( callback, point, slop ) {
        /** b2BroadPhase */ var broadPhase = this.m_contactManager.m_broadPhase;

        /**
         * @return {boolean}
         * @param {b2TreeNode} proxy
         */
        var WorldQueryWrapper = function ( proxy ) {
            /** b2FixtureProxy */
            var fixture_proxy = broadPhase.getUserData( proxy );
            /*##if EXPORT_ASSERTS */
            if ( b2Settings.ASSERTS_ENABLED ) {
                b2Assert( fixture_proxy instanceof b2FixtureProxy );
            }/*#*/
            /** b2Fixture */ var fixture = fixture_proxy.fixture;
            if ( fixture.testPoint( point ) ) {
                if ( callback instanceof b2QueryCallback ) {
                    return callback.reportFixture( fixture );
                }
                else if (typeof(callback) === 'function')
                {
                    return callback( fixture );
                }
            }
            return true;
        };

        slop = (typeof(slop) === 'number') ? (slop) : (b2Settings.b2_linearSlop);
        /** b2AABB */ var aabb = b2World._B2AABB_POOL0;
        aabb.lowerBound.set( point.x - slop, point.y - slop );
        aabb.upperBound.set( point.x + slop, point.y + slop );
        broadPhase.query( WorldQueryWrapper, aabb );
/*#if EXPORT_PARTICLES */
        if ( callback instanceof b2QueryCallback ) {
            for (/** b2ParticleSystem */ var p = this.m_particleSystemList; p; p = p.m_next) {
                if ( callback.shouldQueryParticleSystem( p ) ) {
                    p.queryAABB( callback, aabb );
                }
            }
        }
/*#end EXPORT_PARTICLES */
    };

    /**
     * Ray-cast the world for all fixtures in the path of the ray.
     * Your callback controls whether you get the closest point, any
     * point, or n-points. The ray-cast ignores shapes that contain
     * the starting point.
     *
     * @public
     * @method  rayCast
     * @param {b2RayCastCallback|function(b2Fixture,b2Vec2,b2Vec2,number):number}  callback     A user implemented callback class.
     * @param {b2Vec2}      point1  The ray starting point
     * @param {b2Vec2}      point2  The ray ending point
     * @return  {void}
     */
    p.rayCast = function ( callback, point1, point2 ) {
        /** b2BroadPhase */ var broadPhase = this.m_contactManager.m_broadPhase;

        /**
         * @return {number}
         * @param {b2RayCastInput} input
         * @param {b2TreeNode} proxy
         */
        var WorldRayCastWrapper = function ( input, proxy ) {
            /** b2FixtureProxy */
            var fixture_proxy = broadPhase.getUserData( proxy );
            /*##if EXPORT_ASSERTS */
            if ( b2Settings.ASSERTS_ENABLED ) {
                b2Assert( fixture_proxy instanceof b2FixtureProxy );
            }/*#*/
            /** b2Fixture */ var fixture = fixture_proxy.fixture;
            /** number */ var index = fixture_proxy.childIndex;
            /** b2RayCastOutput */ var output = b2World._B2RAYCAST_OUTPUT_POOL0;
            /** boolean */ var hit = fixture.rayCast( output, input, index );

            if ( hit ) {
                /** number */ var fraction = output.fraction;
                /** b2Vec2 */ var point = b2World._B2VEC2_POOL0;
                point.set( (1 - fraction) * point1.x + fraction * point2.x, (1 - fraction) * point1.y + fraction * point2.y );

                if ( callback instanceof b2RayCastCallback ) {
                    return callback.reportFixture( fixture, point, output.normal, fraction );
                }
                else if (typeof(callback) === 'function')
                {
                    return callback( fixture, point, output.normal, fraction );
                }
            }
            return input.maxFraction;
        };

        /** b2RayCastInput */ var input = b2World._B2RAYCAST_INPUT_POOL0;
        input.maxFraction = 1;
        input.p1.copy( point1 );
        input.p2.copy( point2 );
        broadPhase.rayCast( WorldRayCastWrapper, input );
/*#if EXPORT_PARTICLES */
        if ( callback instanceof b2RayCastCallback ) {
            for (/** b2ParticleSystem */ var p = this.m_particleSystemList; p; p = p.m_next) {
                if ( callback.shouldQueryParticleSystem( p ) ) {
                    p.rayCast( callback, point1, point2 );
                }
            }
        }
/*#end EXPORT_PARTICLES */
    };

    /**
     * Return first fixture to intersect raycast.
     *
     * @public
     * @method  rayCastOne
     * @param   {b2Vec2}    point1  The ray starting point.
     * @param   {b2Vec2}    point2  The ray ending point.
     * @return  {b2Fixture}
     */
    p.rayCastOne = function ( point1, point2 ) {
        /** b2Fixture */ var result = null;
        /** number */ var min_fraction = 1;

        /**
         * @private
         * @method  worldRayCastOneWrapper
         * @param {b2Fixture} fixture
         * @param {b2Vec2} point
         * @param {b2Vec2} normal
         * @param {number} fraction
         * @return {number}
         */
        function WorldRayCastOneWrapper( fixture, point, normal, fraction ) {
            if ( fraction < min_fraction ) {
                min_fraction = fraction;
                result = fixture;
            }

            return min_fraction;
        };

        this.rayCast( WorldRayCastOneWrapper, point1, point2 );

        return result;
    };

    /**
     * Return all fixtures to intersect raycast.
     *
     * @public
     * @method  rayCastAll
     * @param   {b2Vec2}            point1
     * @param   {b2Vec2}            point2
     * @param   {Array.<b2Fixture>} out
     * @return  {Array.<b2Fixture>} out
     */
    p.rayCastAll = function ( point1, point2, out ) {
        out.length = 0;

        /**
         * @private
         * @method  worldRayCastOneWrapper
         * @param {b2Fixture} fixture
         * @param {b2Vec2} point
         * @param {b2Vec2} normal
         * @param {number} fraction
         * @return {number}
         */
        function WorldRayCastAllWrapper( fixture, point, normal, fraction ) {
            out.push( fixture );
            return 1;
        }
        this.rayCast( WorldRayCastAllWrapper, point1, point2 );

        return out;
    };

    /**
     * @public
     * @method  drawShape
     * @param   {b2Fixture}     fixture
     * @param   {b2Transform}   transform
     * @param   {b2Color}       color
     * @return  {void}
     */
    p.drawShape = function ( fixture, transform, color ) {
        /** b2Shape */ var shape = fixture.getShape();

        switch (shape.m_type) {
            case b2Shape.e_circleShape:
            {
                /** b2CircleShape */ var circle = shape instanceof b2CircleShape ? shape : null;

                /** b2Vec2 */ var center = b2Transform.timesV2( transform, circle.m_p, b2World._B2VEC2_POOL0 );
                /** number */ var radius = circle.m_radius;
                /** b2Vec2 */ var axis = b2Vec2._UNITX;

                this.m_debugDraw.drawSolidCircle( center, radius, axis, color );
            }
                break;

            case b2Shape.e_edgeShape:
            {
                /** b2EdgeShape */ var edge = shape instanceof b2EdgeShape ? shape : null;
                /** b2Vec2 */ var v1 = b2Transform.timesV2( transform, edge.m_vertex1, b2World._B2VEC2_POOL0 );
                /** b2Vec2 */ var v2 = b2Transform.timesV2( transform, edge.m_vertex2, b2World._B2VEC2_POOL1 );
                ///** b2Vec2 */ var v1 = edge.m_vertex1;
                ///** b2Vec2 */ var v2 = edge.m_vertex2;
                this.m_debugDraw.drawSegment( v1, v2, color );
            }
                break;

            case b2Shape.e_chainShape:
            {
                /** b2ChainShape */ var chain = shape instanceof b2ChainShape ? shape : null;
                /** number */ var count = chain.m_count;
                /** Array.<b2Vec2> */var vertices = chain.m_vertices;

                /** Array.<b2Vec2> */var v1 = b2Transform.timesV2( transform, vertices[0], b2World._B2VEC2_POOL0 );
                /** b2Vec2 */var v2 = b2World._B2VEC2_POOL1;
                this.m_debugDraw.drawCircle( v1, 0.05, color );
                for (/** number */ var i = 1; i < count; ++i) {
                    /** b2Vec2 */v2.equals( b2Transform.timesV2( transform, vertices[i] ) );
                    this.m_debugDraw.drawSegment( v1, v2, color );
                    this.m_debugDraw.drawCircle( v2, 0.05, color );
                    v1.equals( v2 );
                }
            }
                break;

            case b2Shape.e_polygonShape:
            {
                /** b2PolygonShape */ var poly = shape instanceof b2PolygonShape ? shape : null;
                /** number */ var vertexCount = poly.m_count;
                /** @type {Array.<b2Vec2>} */var localVertices = poly.m_vertices;
                /** @type {Array.<b2Vec2>} */var vertices = b2World._B2VEC2_VECTOR_MAX_POLYGON_VERTICES;

                for (i = 0; i < vertexCount; ++i) {
                    vertices[i].equals( b2Transform.timesV2( transform, localVertices[i] ) );
                }
                this.m_debugDraw.drawSolidPolygon( vertices, vertexCount, color );
            }
                break;
        }
    };

    /**
     * @public
     * @method  drawJoint
     * @param   {b2Joint} joint
     * @return  {void}
     */
    p.drawJoint = function ( joint ) {
        /** b2Body */ var bodyA = joint.getBodyA();
        /** b2Body */ var bodyB = joint.getBodyB();
        /** b2Transform */ var xf1 = bodyA.m_xf;
        /** b2Transform */ var xf2 = bodyB.m_xf;
        /** b2Vec2 */ var x1 = xf1.p;
        /** b2Vec2 */ var x2 = xf2.p;
        /** b2Vec2 */ var p1 = joint.getAnchorA( b2World._B2VEC2_POOL0 );
        /** b2Vec2 */ var p2 = joint.getAnchorB( b2World._B2VEC2_POOL1 );

        /** b2Color */ var color = b2World._B2COLOR_POOL0;
        color.setRGBA( 0.5, 0.8, 0.8 );

        switch (joint.m_type) {
            case b2Joint.e_distanceJoint:
                this.m_debugDraw.drawSegment( p1, p2, color );
                break;

            case b2Joint.e_pulleyJoint:{
                /** b2PulleyJoint */ var pulley = joint instanceof b2PulleyJoint ? joint : null;
                /** b2Vec2 */ var s1 = pulley.getGroundAnchorA( b2World._B2VEC2_POOL2 );
                /** b2Vec2 */ var s2 = pulley.getGroundAnchorB( b2World._B2VEC2_POOL3 );
                this.m_debugDraw.drawSegment( s1, p1, color );
                this.m_debugDraw.drawSegment( s2, p2, color );
                this.m_debugDraw.drawSegment( s1, s2, color );
            }
                break;

            case b2Joint.e_mouseJoint:
                // don't draw this
                this.m_debugDraw.drawSegment( p1, p2, color );
                break;

            default:
                if ( bodyA != this.m_groundBody ) {
                    this.m_debugDraw.drawSegment( x1, p1, color );
                }

                this.m_debugDraw.drawSegment( p1, p2, color );

                if ( bodyB != this.m_groundBody ) {
                    this.m_debugDraw.drawSegment( x2, p2, color );
                }
        };
    };

/*#if EXPORT_PARTICLES */
    /**
     * @public
     * @override
     * @method  drawParticleSystem
     * @param   {b2ParticleSystem} system
     * @return  {void}
     */
    p.drawParticleSystem = function ( system ) {
        var particleCount = system.getParticleCount();
        if ( particleCount ) {
            var radius = system.getRadius();
            var positionBuffer = system.getPositionBuffer();
            if ( system.m_colorBuffer.data ) {
                var colorBuffer = system.getColorBuffer();
                this.m_debugDraw.drawParticles( positionBuffer, radius, colorBuffer, particleCount );
            }
            else {
                this.m_debugDraw.drawParticles( positionBuffer, radius, null, particleCount );
            }
        }
    };
/*#end EXPORT_PARTICLES */

    /**
     * Call this to draw shapes and other debug draw data. This is intentionally non-const.
     *
     * @public
     * @method  drawDebugData
     * @return  {void}
     */
    p.drawDebugData = function () {
        if ( this.m_debugDraw === null ) {
            return;
        }
        this.m_debugDraw.clear();
        /** number */ var flags = this.m_debugDraw.getFlags();
        //** b2Color */ var color = b2World._B2COLOR_POOL0;

        if ( flags & b2Draw.e_shapeBit ) {
            for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
                /** b2Transform */ var xf = b.m_xf;

                for (/** b2Fixture */ var f = b.getFixtureList(); f; f = f.m_next) {
                    if ( !b.isActive() ) {
                        color.setRGBA( 0.5, 0.5, 0.3 );
                        this.drawShape( f, xf, color );
                    }
                    else if ( b.getType() === b2Body.b2_staticBody ) {
                        color.setRGBA( 0.5, 0.9, 0.5 );
                        this.drawShape( f, xf, color );
                    }
                    else if ( b.getType() === b2Body.b2_kinematicBody ) {
                        color.setRGBA( 0.5, 0.5, 0.9 );
                        this.drawShape( f, xf, color );
                    }
                    else if ( !b.isAwake() ) {
                        color.setRGBA( 0.6, 0.6, 0.6 );
                        this.drawShape( f, xf, color );
                    }
                    else {
                        color.setRGBA( 0.9, 0.7, 0.7 );
                        this.drawShape( f, xf, color );
                    }
                }
            }
        }
/*#if EXPORT_PARTICLES */
        if ( flags & b2Draw.e_particleBit ) {
            for (/** b2ParticleSystem */ var p = this.m_particleSystemList; p; p = p.m_next) {
                this.drawParticleSystem( p );
            }
        }
/*#end EXPORT_PARTICLES */

        if ( flags & b2Draw.e_jointBit ) {
            for (/** b2Joint */ var j = this.m_jointList; j; j = j.m_next) {
                this.drawJoint( j );
            }
        }

        /*
         if (flags & b2DrawFlags.e_pairBit)
         {
         color.setRGB(0.3, 0.9, 0.9);
         for (var contact = this.m_contactManager.m_contactList; contact; contact = contact.m_next)
         {
         var fixtureA = contact.getFixtureA();
         var fixtureB = contact.getFixtureB();

         var cA = fixtureA.getAABB().getCenter();
         var cB = fixtureB.getAABB().getCenter();

         this.m_debugDraw.drawSegment(cA, cB, color);
         }
         }
         */

        if ( flags & b2Draw.e_aabbBit ) {
            color.setRGB( 0.9, 0.3, 0.9 );
            /** b2BroadPhase */ var bp = this.m_contactManager.m_broadPhase;
            /** @type {Array.<b2Vec2>} */ var vs = b2World._B2VEC2_VECTOR_4;

            for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
                if ( !b.isActive() ) {
                    continue;
                }

                for (/** b2Fixture */ var f = b.getFixtureList(); f; f = f.m_next) {
                    for (/** number */ var i = 0; i < f.m_proxyCount; ++i) {
                        /** b2FixtureProxy */ var proxy = f.m_proxies[i];

                        /** b2AABB */ var aabb = bp.getFatAABB( proxy.proxy );
                        vs[0].set( aabb.lowerBound.x, aabb.lowerBound.y );
                        vs[1].set( aabb.upperBound.x, aabb.lowerBound.y );
                        vs[2].set( aabb.upperBound.x, aabb.upperBound.y );
                        vs[3].set( aabb.lowerBound.x, aabb.upperBound.y );

                        this.m_debugDraw.drawPolygon( vs, 4, color );
                    }
                }
            }
        }

        if ( flags & b2Draw.e_centerOfMassBit ) {
            for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
                /** b2Transform */
                var xf = b2World._B2TRANSFORM_POOL0;
                xf.q.copy( b.m_xf.q );
                xf.p.copy( b.getWorldCenter() );
                this.m_debugDraw.drawTransform( xf );
            }
        }
/*##if EXPORT_CONTROLLERS */
        /// @see b2Controller list
        if ( flags & b2Draw.e_controllerBit ) {
            for (/** b2Controller */ var c = this.m_controllerList; c; c = c.m_next) {
                c.draw( this.m_debugDraw );
            }
        }
/*#end EXPORT_CONTROLLERS */
    };

    /**
     *
     * @public
     * @method  setBroadPhase
     * @param   {b2BroadPhase} broadPhase
     * @return  {void}
     */
    p.setBroadPhase = function ( broadPhase ) {
        var oldBroadPhase = this.m_contactManager.m_broadPhase;

        this.m_contactManager.m_broadPhase = broadPhase;

        for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
            for (/** b2Fixture */ var f = b.m_fixtureList; f; f = f.m_next) {
                f.m_proxy = broadPhase.createProxy( oldBroadPhase.getFatAABB( f.m_proxy ), f );
            }
        }
    };

/*#if EXPORT_PARTICLES */
    /**
     * Recommend a value to be used in `Step` for `particleIterations`.
     * This calculation is necessarily a simplification and should only be
     * used as a starting point. Please see "Particle Iterations" in the
     * Programmer's Guide for details.
     *
     * @public
     * @method   calculateReasonableParticleIterations
     * @param    {float} timeStep   Is the value to be passed into `Step`.
     * @return   {int}              Reasonable particle iterations
     */
    p.calculateReasonableParticleIterations = function ( timeStep ) {
        if ( this.m_particleSystemList === null ) {
            return 1;
        }

        function GetSmallestRadius( world ) {
            var smallestRadius = b2Settings.b2_maxFloat;
            /**b2ParticleSystem*/var system = world.getParticleSystemList();
            for ( ; system !== null; system = system.m_next) {
                smallestRadius = Math.min( smallestRadius, system.getRadius() );
            }
            return smallestRadius;
        }

        // Use the smallest radius, since that represents the worst-case.
        return b2Particle.b2CalculateParticleIterations( this.m_gravity.length(), GetSmallestRadius( this ), timeStep );
    };
/*#end EXPORT_PARTICLES */

    /**
     * Get the number of broad-phase proxies.
     *
     * @public
     * @method  getProxyCount
     * @return  {int}
     */
    p.getProxyCount = function () {
        return this.m_contactManager.m_broadPhase.getProxyCount();
    };

    /**
     * Get the height of the dynamic tree.
     *
     * @public
     * @method  getTreeHeight
     * @return {float}
     */
    p.getTreeHeight = function () {
        return this.m_contactManager.m_broadPhase.getTreeHeight();
    };

    /**
     * Get the balance of the dynamic tree.
     *
     * @public
     * @method  getTreeBalance
     * @return {float}
     */
    p.getTreeBalance = function () {
        return this.m_contactManager.m_broadPhase.getTreeBalance();
    };

    /**
     * Get the quality metric of the dynamic tree. The smaller the
     * better. The minimum is 1.
     *
     * @public
     * @method  getTreeQuality
     * @return {float}
     */
    p.getTreeQuality = function () {
        return this.m_contactManager.m_broadPhase.getTreeQuality();
    };

    /**
     * Shift the world origin. Useful for large worlds.
     * The body shift formula is: position -= newOrigin.
     *
     * @public
     * @method  shiftOrigin
     * @param   {b2Vec2}    newOrigin   The new origin with respect to the old origin.
     * @return  {void}
     */
    p.shiftOrigin = function ( newOrigin ) {
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( !this.isLocked() );
        }/*#*/
        if ( this.isLocked() ) {
            return;
        }

        for (/** b2Body */ var b = this.m_bodyList; b; b = b.m_next) {
            b.m_xf.p.minus( newOrigin );
            b.m_sweep.c0.minus( newOrigin );
            b.m_sweep.c.minus( newOrigin );
        }

        for (/** b2Joint */ var j = this.m_jointList; j; j = j.m_next) {
            j.shiftOrigin( newOrigin );
        }

        this.m_contactManager.m_broadPhase.shiftOrigin( newOrigin );
    };

/*##if EXPORT_CONTROLLERS */
    /**
     * See
     * <a href=../classes/b2Controller.html>b2Controller</a>
     * list.
     *
     * @public
     * @method  addController
     * @param   {b2Controller}  controller
     * @return  {b2Controller}
     */
    p.addController = function ( controller ) {
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( controller.m_world === null, "Controller can only be a member of one world" );
        }/*#*/
        controller.m_world = this;
        controller.m_next = this.m_controllerList;
        controller.m_prev = null;
        if ( this.m_controllerList ) {
            this.m_controllerList.m_prev = controller;
        }
        this.m_controllerList = controller;
        ++this.m_controllerCount;
        return controller;
    };

    /**
     * See
     * <a href=../classes/b2Controller.html>b2Controller</a>
     * list.
     *
     * @public
     * @method  removeController
     * @return  {b2Controller}
     */
    p.removeController = function ( controller ) {
        /*##if EXPORT_ASSERTS */
        if ( b2Settings.ASSERTS_ENABLED ) {
            b2Assert( controller.m_world === this, "Controller is not a member of this world" );
        }/*#*/
        if ( controller.m_prev ) {
            controller.m_prev.m_next = controller.m_next;
        }
        if ( controller.m_next ) {
            controller.m_next.m_prev = controller.m_prev;
        }
        if ( this.m_controllerList === controller ) {
            this.m_controllerList = controller.m_next;
        }
        --this.m_controllerCount;
        controller.m_prev = null;
        controller.m_next = null;
        controller.m_world = null;
    };
/*#end EXPORT_CONTROLLERS */