- var Vec3 = require('../math/Vec3');
-
- module.exports = Spring;
-
- /**
- * A spring, connecting two bodies.
- *
- * @class Spring
- * @constructor
- * @param {Body} bodyA
- * @param {Body} bodyB
- * @param {Object} [options]
- * @param {number} [options.restLength] A number > 0. Default: 1
- * @param {number} [options.stiffness] A number >= 0. Default: 100
- * @param {number} [options.damping] A number >= 0. Default: 1
- * @param {Vec3} [options.worldAnchorA] Where to hook the spring to body A, in world coordinates.
- * @param {Vec3} [options.worldAnchorB]
- * @param {Vec3} [options.localAnchorA] Where to hook the spring to body A, in local body coordinates.
- * @param {Vec3} [options.localAnchorB]
- */
- function Spring(bodyA,bodyB,options){
- options = options || {};
-
- /**
- * Rest length of the spring.
- * @property restLength
- * @type {number}
- */
- this.restLength = typeof(options.restLength) === "number" ? options.restLength : 1;
-
- /**
- * Stiffness of the spring.
- * @property stiffness
- * @type {number}
- */
- this.stiffness = options.stiffness || 100;
-
- /**
- * Damping of the spring.
- * @property damping
- * @type {number}
- */
- this.damping = options.damping || 1;
-
- /**
- * First connected body.
- * @property bodyA
- * @type {Body}
- */
- this.bodyA = bodyA;
-
- /**
- * Second connected body.
- * @property bodyB
- * @type {Body}
- */
- this.bodyB = bodyB;
-
- /**
- * Anchor for bodyA in local bodyA coordinates.
- * @property localAnchorA
- * @type {Vec3}
- */
- this.localAnchorA = new Vec3();
-
- /**
- * Anchor for bodyB in local bodyB coordinates.
- * @property localAnchorB
- * @type {Vec3}
- */
- this.localAnchorB = new Vec3();
-
- if(options.localAnchorA){
- this.localAnchorA.copy(options.localAnchorA);
- }
- if(options.localAnchorB){
- this.localAnchorB.copy(options.localAnchorB);
- }
- if(options.worldAnchorA){
- this.setWorldAnchorA(options.worldAnchorA);
- }
- if(options.worldAnchorB){
- this.setWorldAnchorB(options.worldAnchorB);
- }
- }
-
- /**
- * Set the anchor point on body A, using world coordinates.
- * @method setWorldAnchorA
- * @param {Vec3} worldAnchorA
- */
- Spring.prototype.setWorldAnchorA = function(worldAnchorA){
- this.bodyA.pointToLocalFrame(worldAnchorA,this.localAnchorA);
- };
-
- /**
- * Set the anchor point on body B, using world coordinates.
- * @method setWorldAnchorB
- * @param {Vec3} worldAnchorB
- */
- Spring.prototype.setWorldAnchorB = function(worldAnchorB){
- this.bodyB.pointToLocalFrame(worldAnchorB,this.localAnchorB);
- };
-
- /**
- * Get the anchor point on body A, in world coordinates.
- * @method getWorldAnchorA
- * @param {Vec3} result The vector to store the result in.
- */
- Spring.prototype.getWorldAnchorA = function(result){
- this.bodyA.pointToWorldFrame(this.localAnchorA,result);
- };
-
- /**
- * Get the anchor point on body B, in world coordinates.
- * @method getWorldAnchorB
- * @param {Vec3} result The vector to store the result in.
- */
- Spring.prototype.getWorldAnchorB = function(result){
- this.bodyB.pointToWorldFrame(this.localAnchorB,result);
- };
-
- var applyForce_r = new Vec3(),
- applyForce_r_unit = new Vec3(),
- applyForce_u = new Vec3(),
- applyForce_f = new Vec3(),
- applyForce_worldAnchorA = new Vec3(),
- applyForce_worldAnchorB = new Vec3(),
- applyForce_ri = new Vec3(),
- applyForce_rj = new Vec3(),
- applyForce_ri_x_f = new Vec3(),
- applyForce_rj_x_f = new Vec3(),
- applyForce_tmp = new Vec3();
-
- /**
- * Apply the spring force to the connected bodies.
- * @method applyForce
- */
- Spring.prototype.applyForce = function(){
- var k = this.stiffness,
- d = this.damping,
- l = this.restLength,
- bodyA = this.bodyA,
- bodyB = this.bodyB,
- r = applyForce_r,
- r_unit = applyForce_r_unit,
- u = applyForce_u,
- f = applyForce_f,
- tmp = applyForce_tmp;
-
- var worldAnchorA = applyForce_worldAnchorA,
- worldAnchorB = applyForce_worldAnchorB,
- ri = applyForce_ri,
- rj = applyForce_rj,
- ri_x_f = applyForce_ri_x_f,
- rj_x_f = applyForce_rj_x_f;
-
- // Get world anchors
- this.getWorldAnchorA(worldAnchorA);
- this.getWorldAnchorB(worldAnchorB);
-
- // Get offset points
- worldAnchorA.vsub(bodyA.position,ri);
- worldAnchorB.vsub(bodyB.position,rj);
-
- // Compute distance vector between world anchor points
- worldAnchorB.vsub(worldAnchorA,r);
- var rlen = r.norm();
- r_unit.copy(r);
- r_unit.normalize();
-
- // Compute relative velocity of the anchor points, u
- bodyB.velocity.vsub(bodyA.velocity,u);
- // Add rotational velocity
-
- bodyB.angularVelocity.cross(rj,tmp);
- u.vadd(tmp,u);
- bodyA.angularVelocity.cross(ri,tmp);
- u.vsub(tmp,u);
-
- // F = - k * ( x - L ) - D * ( u )
- r_unit.mult(-k*(rlen-l) - d*u.dot(r_unit), f);
-
- // Add forces to bodies
- bodyA.force.vsub(f,bodyA.force);
- bodyB.force.vadd(f,bodyB.force);
-
- // Angular force
- ri.cross(f,ri_x_f);
- rj.cross(f,rj_x_f);
- bodyA.torque.vsub(ri_x_f,bodyA.torque);
- bodyB.torque.vadd(rj_x_f,bodyB.torque);
- };
-
-