diff --git a/sites/all/modules/figli/edlp_corpus/assets/dist/bower/physics.js b/sites/all/modules/figli/edlp_corpus/assets/dist/bower/physics.js
new file mode 100644
index 000000000..c3ddff68c
--- /dev/null
+++ b/sites/all/modules/figli/edlp_corpus/assets/dist/bower/physics.js
@@ -0,0 +1,1153 @@
+/**
+ * Physics
+ * A requirified port of Traer Physics from Processing to JavaScript.
+ * Copyright (C) 2012 jonobr1
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o this.originalPositions.length) {
+ this.originalPositions.push(new Vector());
+ this.originalVelocities.push(new Vector());
+ this.k1Forces.push(new Vector());
+ this.k1Velocities.push(new Vector());
+ this.k2Forces.push(new Vector());
+ this.k2Velocities.push(new Vector());
+ this.k3Forces.push(new Vector());
+ this.k3Velocities.push(new Vector());
+ this.k4Forces.push(new Vector());
+ this.k4Velocities.push(new Vector());
+ }
+
+ return this;
+
+ },
+
+ step: function(dt) {
+
+ var s = this.s;
+ var p, x, y;
+
+ this.allocateParticles();
+
+ _.each(s.particles, function(p, i) {
+ if (!p.fixed) {
+ this.originalPositions[i].copy(p.position);
+ this.originalVelocities[i].copy(p.velocity);
+ }
+ p.force.clear();
+ }, this);
+
+ // K1
+
+ s.applyForces();
+
+ _.each(s.particles, function(p, i) {
+ if (!p.fixed) {
+ this.k1Forces[i].copy(p.force);
+ this.k1Velocities[i].copy(p.velocity);
+ }
+ p.force.clear();
+ }, this);
+
+ // K2
+
+ _.each(s.particles, function(p, i) {
+ if (!p.fixed) {
+
+ var op = this.originalPositions[i];
+ var k1v = this.k1Velocities[i];
+ x = op.x + k1v.x * 0.5 * dt;
+ y = op.y + k1v.y * 0.5 * dt;
+ p.position.set(x, y);
+
+ var ov = this.originalVelocities[i];
+ var k1f = this.k1Forces[i];
+ x = ov.x + k1f.x * 0.5 * dt / p.mass;
+ y = ov.y + k1f.y * 0.5 * dt / p.mass;
+ p.velocity.set(x, y);
+
+ }
+ }, this);
+
+ s.applyForces();
+
+ _.each(s.particles, function(p, i) {
+ if (!p.fixed) {
+ this.k2Forces[i].copy(p.force);
+ this.k2Velocities[i].copy(p.velocity);
+ }
+ p.force.clear();
+ }, this);
+
+ // K3
+
+ _.each(s.particles, function(p, i) {
+ if (!p.fixed) {
+
+ var op = this.originalPositions[i];
+ var k2v = this.k2Velocities[i];
+ p.position.set(op.x + k2v.x * 0.5 * dt, op.y + k2v.y * 0.5 * dt);
+
+ var ov = this.originalVelocities[i];
+ var k2f = this.k2Forces[i];
+ p.velocity.set(ov.x + k2f.x * 0.5 * dt / p.mass, ov.y + k2f.y * 0.5 * dt / p.mass);
+ }
+ }, this);
+
+ s.applyForces();
+
+ _.each(s.particles, function(p, i) {
+ if (!p.fixed) {
+ this.k3Forces[i].copy(p.force);
+ this.k3Velocities[i].copy(p.velocity);
+ }
+ p.force.clear();
+ }, this);
+
+ // K4
+
+ _.each(s.particles, function(p, i) {
+ if (!p.fixed) {
+
+ var op = this.originalPositions[i];
+ var k3v = this.k3Velocities[i];
+ p.position.set(op.x + k3v.x * dt, op.y + k3v.y * dt)
+
+ var ov = this.originalVelocities[i];
+ var k3f = this.k3Forces[i];
+ p.velocity.set(ov.x + k3f.x * dt / p.mass, ov.y + k3f.y * dt / p.mass);
+ }
+ }, this);
+
+ s.applyForces();
+
+ _.each(s.particles, function(p, i) {
+ if (!p.fixed) {
+ this.k4Forces[i].copy(p.force);
+ this.k4Velocities[i].copy(p.velocity);
+ }
+ }, this);
+
+ // TOTAL
+
+ _.each(s.particles, function(p, i) {
+
+ p.age += dt;
+
+ if (!p.fixed) {
+
+ var op = this.originalPositions[i];
+ var k1v = this.k1Velocities[i];
+ var k2v = this.k2Velocities[i];
+ var k3v = this.k3Velocities[i];
+ var k4v = this.k4Velocities[i];
+
+ var x = op.x + dt / 6.0 * (k1v.x + 2.0 * k2v.x + 2.0 * k3v.x + k4v.x);
+ var y = op.y + dt / 6.0 * (k1v.y + 2.0 * k2v.y + 2.0 * k3v.y + k4v.y);
+
+ p.position.set(x, y);
+
+ var ov = this.originalVelocities[i];
+ var k1f = this.k1Forces[i];
+ var k2f = this.k2Forces[i];
+ var k3f = this.k3Forces[i];
+ var k4f = this.k4Forces[i];
+
+ x = ov.x + dt / (6.0 * p.mass) * (k1f.x + 2.0 * k2f.x + 2.0 * k3f.x + k4f.x);
+ y = ov.y + dt / (6.0 * p.mass) * (k1f.y + 2.0 * k2f.y + 2.0 * k3f.y + k4f.y);
+
+ p.velocity.set(x, y);
+
+ }
+
+ }, this);
+
+ return this;
+
+ }
+
+ });
+
+ module.exports = Integrator;
+
+},{"./common":8,"./vector":12}],3:[function(require,module,exports){
+var _ = require('./common')
+, Vector = require('./vector')
+;
+
+ function Particle(mass) {
+
+ this.position = new Vector();
+ this.velocity = new Vector();
+ this.force = new Vector();
+ this.mass = mass;
+ this.fixed = false;
+ this.age = 0;
+ this.dead = false;
+
+ }
+
+ _.extend(Particle.prototype, {
+
+ /**
+ * Get the distance between two particles.
+ */
+ distanceTo: function(p) {
+ return this.position.distanceTo(p.position);
+ },
+
+ /**
+ * Make the particle fixed in 2D space.
+ */
+ makeFixed: function() {
+ this.fixed = true;
+ this.velocity.clear();
+ return this;
+ },
+
+ /**
+ * Reset a particle.
+ */
+ reset: function() {
+
+ this.age = 0;
+ this.dead = false;
+ this.position.clear();
+ this.velocity.clear();
+ this.force.clear();
+ this.mass = 1.0;
+
+ return this;
+ },
+
+ /**
+ * Returns a boolean describing whether the particle is in movement.
+ */
+ resting: function() {
+ return this.fixed || this.velocity.isZero() && this.force.isZero();
+ }
+
+ });
+
+ module.exports = Particle;
+
+},{"./common":8,"./vector":12}],4:[function(require,module,exports){
+var _ = require('./common')
+, Vector = require('./Vector')
+, Particle = require('./Particle')
+, Spring = require('./Spring')
+, Attraction = require('./Attraction')
+, Integrator = require('./Integrator')
+;
+
+ /**
+ * traer.js
+ * A particle-based physics engine ported from Jeff Traer's Processing
+ * library to JavaScript. This version is intended for use with the
+ * HTML5 canvas element. It is dependent on Three.js' Vector2 class,
+ * but can be overridden with any Vector2 class with the methods included.
+ *
+ * @author Jeffrey Traer Bernstein (original Java library)
+ * @author Adam Saponara (JavaScript port)
+ * @author Jono Brandel (requirified/optimization port)
+ * @author David Schoonover (Node/CommonJS/Browserify port)
+ *
+ * @version 0.3
+ * @date March 25, 2012
+ */
+
+ /**
+ * The whole kit and kaboodle.
+ *
+ * @class
+ */
+ function ParticleSystem() {
+
+ this.__equilibriumCriteria = { particles: true, springs: true, attractions: true };
+ this.__equilibrium = false; // are we at equilibrium?
+ this.__optimized = false;
+
+ this.particles = [];
+ this.springs = [];
+ this.attractions = [];
+ this.forces = [];
+ this.integrator = new Integrator(this);
+ this.hasDeadParticles = false;
+
+ var args = arguments.length;
+
+ if (args === 1) {
+ this.gravity = new Vector(0, arguments[0]);
+ this.drag = ParticleSystem.DEFAULT_DRAG;
+ } else if (args === 2) {
+ this.gravity = new Vector(0, arguments[0]);
+ this.drag = arguments[1];
+ } else if (args === 3) {
+ this.gravity = new Vector(arguments[0], arguments[1]);
+ this.drag = arguments[3];
+ } else {
+ this.gravity = new Vector(0, ParticleSystem.DEFAULT_GRAVITY);
+ this.drag = ParticleSystem.DEFAULT_DRAG;
+ }
+
+ }
+
+ _.extend(ParticleSystem, {
+
+ DEFAULT_GRAVITY: 0,
+
+ DEFAULT_DRAG: 0.001,
+
+ Attraction: Attraction,
+
+ Integrator: Integrator,
+
+ Particle: Particle,
+
+ Spring: Spring,
+
+ Vector: Vector
+
+ });
+
+ _.extend(ParticleSystem.prototype, {
+
+ /**
+ * Set whether to optimize the simulation. This enables the check of whether
+ * particles are moving.
+ */
+ optimize: function(b) {
+ this.__optimized = !!b;
+ return this;
+ },
+
+ /**
+ * Set the gravity of the ParticleSystem.
+ */
+ setGravity: function(x, y) {
+ this.gravity.set(x, y);
+ return this;
+ },
+
+ /**
+ * Sets the criteria for equilibrium
+ */
+ setEquilibriumCriteria: function(particles, springs, attractions) {
+ this.__equilibriumCriteria.particles = !!particles;
+ this.__equilibriumCriteria.springs = !!springs;
+ this.__equilibriumCriteria.attractions = !!attractions;
+ },
+
+ /**
+ * Update the integrator
+ */
+ tick: function() {
+ this.integrator.step(arguments.length === 0 ? 1 : arguments[0]);
+ if (this.__optimized) {
+ this.__equilibrium = !this.needsUpdate();
+ }
+ return this;
+ },
+
+ /**
+ * Checks all springs and attractions to see if the contained particles are
+ * inert / resting and returns a boolean.
+ */
+ needsUpdate: function() {
+ var i = 0;
+
+ if(this.__equilibriumCriteria.particles) {
+ for (i = 0, l = this.particles.length; i < l; i++) {
+ if (!this.particles[i].resting()) {
+ return true;
+ }
+ }
+ }
+
+ if(this.__equilibriumCriteria.springs) {
+ for (i = 0, l = this.springs.length; i < l; i++) {
+ if (!this.springs[i].resting()) {
+ return true;
+ }
+ }
+ }
+
+ if(this.__equilibriumCriteria.attractions) {
+ for (i = 0, l = this.attractions.length; i < l; i++) {
+ if (!this.attractions[i].resting()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+
+ },
+
+ /**
+ * Add a particle to the ParticleSystem.
+ */
+ addParticle: function(p) {
+
+ this.particles.push(p);
+ return this;
+
+ },
+
+ /**
+ * Add a spring to the ParticleSystem.
+ */
+ addSpring: function(s) {
+
+ this.springs.push(s);
+ return this;
+
+ },
+
+ /**
+ * Add an attraction to the ParticleSystem.
+ */
+ addAttraction: function(a) {
+
+ this.attractions.push(a);
+ return this;
+
+ },
+
+ /**
+ * Makes and then adds Particle to ParticleSystem.
+ */
+ makeParticle: function(m, x, y) {
+
+ var mass = _.isNumber(m) ? m : 1.0;
+ var x = x || 0;
+ var y = y || 0;
+
+ var p = new Particle(mass);
+ p.position.set(x, y);
+ this.addParticle(p);
+ return p;
+
+ },
+
+ /**
+ * Makes and then adds Spring to ParticleSystem.
+ */
+ makeSpring: function(a, b, k, d, l) {
+
+ var s = new Spring(a, b, k, d, l);
+ this.addSpring(s);
+ return s;
+
+ },
+
+ /**
+ * Makes and then adds Attraction to ParticleSystem.
+ */
+ makeAttraction: function(a, b, k, d) {
+
+ var a = new Attraction(a, b, k, d);
+ this.addAttraction(a);
+ return a;
+
+ },
+
+ /**
+ * Wipe the ParticleSystem clean.
+ */
+ clear: function() {
+
+ this.particles.length = 0;
+ this.springs.length = 0;
+ this.attractions.length = 0;
+
+ },
+
+ /**
+ * Calculate and apply forces.
+ */
+ applyForces: function() {
+
+ if (!this.gravity.isZero()) {
+ _.each(this.particles, function(p) {
+ p.force.addSelf(this.gravity);
+ }, this);
+ }
+
+ var t = new Vector();
+
+ _.each(this.particles, function(p) {
+ t.set(p.velocity.x * -1 * this.drag, p.velocity.y * -1 * this.drag);
+ p.force.addSelf(t);
+ }, this);
+
+ _.each(this.springs, function(s) {
+ s.update();
+ });
+
+ _.each(this.attractions, function(a) {
+ a.update();
+ });
+
+ _.each(this.forces, function(f) {
+ f.update();
+ });
+
+ return this;
+
+ },
+
+ /**
+ * Clear all particles in the system.
+ */
+ clearForces: function() {
+ _.each(this.particles, function(p) {
+ p.clear();
+ });
+ return this;
+ }
+
+ });
+
+ module.exports = ParticleSystem;
+
+},{"./Attraction":1,"./Integrator":2,"./Particle":3,"./Spring":6,"./Vector":7,"./common":8}],5:[function(require,module,exports){
+var _ = require('./common')
+, raf = require('./requestAnimationFrame')
+, ParticleSystem = require('./ParticleSystem')
+;
+
+ var updates = [];
+
+ /**
+ * Extended singleton instance of ParticleSystem with convenience methods for
+ * Request Animation Frame.
+ * @class
+ */
+ function Physics() {
+
+ var _this = this;
+
+ this.playing = false;
+
+ ParticleSystem.apply(this, arguments);
+
+ this.animations = [];
+
+ this.equilibriumCallbacks = [];
+
+ update.call(this);
+
+ }
+
+ _.extend(Physics, ParticleSystem, {
+
+ superclass: ParticleSystem
+
+ });
+
+ _.extend(Physics.prototype, ParticleSystem.prototype, {
+
+ /**
+ * Play the animation loop. Doesn't affect whether in equilibrium or not.
+ */
+ play: function() {
+
+ if (this.playing) {
+ return this;
+ }
+
+ this.playing = true;
+ this.__equilibrium = false;
+ update.call(this);
+
+ return this;
+
+ },
+
+ /**
+ * Pause the animation loop. Doesn't affect whether in equilibrium or not.
+ */
+ pause: function() {
+
+ this.playing = false;
+ return this;
+
+ },
+
+ /**
+ * Toggle between playing and pausing the simulation.
+ */
+ toggle: function() {
+
+ if (this.playing) {
+ this.pause();
+ } else {
+ this.play();
+ }
+
+ return this;
+
+ },
+
+ onUpdate: function(func) {
+
+ if (_.indexOf(this.animations, func) >= 0 || !_.isFunction(func)) {
+ return this;
+ }
+
+ this.animations.push(func);
+
+ return this;
+
+ },
+
+ onEquilibrium: function(func) {
+
+ if (_.indexOf(this.equilibriumCallbacks, func) >= 0 || !_.isFunction(func)) {
+ return this;
+ }
+
+ this.equilibriumCallbacks.push(func);
+
+ return this;
+
+ },
+
+ /**
+ * Call update after values in the system have changed and this will fire
+ * it's own Request Animation Frame to update until things have settled
+ * to equilibrium — at which point the system will stop updating.
+ */
+ update: function() {
+
+ if (!this.__equilibrium) {
+ return this;
+ }
+
+ this.__equilibrium = false;
+ if (this.playing) {
+ update.call(this);
+ }
+
+ return this;
+
+ }
+
+ });
+
+ function update() {
+
+ var _this = this;
+
+ this.tick();
+
+ _.each(this.animations, function(a) {
+ a();
+ });
+
+ if ((this.__optimized && !this.__equilibrium || !this.__optimized) && this.playing) {
+
+ raf(function() {
+ update.call(_this);
+ });
+
+ }
+
+ if (this.__optimized && this.__equilibrium){
+
+ _.each(this.equilibriumCallbacks, function(a) {
+ a();
+ });
+
+ }
+
+ }
+
+ module.exports = Physics;
+
+
+},{"./ParticleSystem":4,"./common":8,"./requestAnimationFrame":11}],6:[function(require,module,exports){
+var _ = require('./common')
+, Vector = require('./vector')
+;
+
+ function Spring(a, b, k, d, l) {
+
+ this.constant = k;
+ this.damping = d;
+ this.length = l;
+ this.a = a;
+ this.b = b;
+ this.on = true;
+
+ }
+
+ _.extend(Spring.prototype, {
+
+ /**
+ * Returns the distance between particle a and particle b
+ * in 2D space.
+ */
+ currentLength: function() {
+ return this.a.position.distanceTo(this.b.position);
+ },
+
+ /**
+ * Update spring logic.
+ */
+ update: function() {
+
+ var a = this.a;
+ var b = this.b;
+ if (!(this.on && (!a.fixed || !b.fixed))) return this;
+
+ var a2b = new Vector().sub(a.position, b.position);
+ var d = a2b.length();
+
+ if (d === 0) {
+ a2b.clear();
+ } else {
+ a2b.divideScalar(d); // Essentially normalize
+ }
+
+ var fspring = -1 * (d - this.length) * this.constant;
+
+ var va2b = new Vector().sub(a.velocity, b.velocity);
+
+ var fdamping = -1 * this.damping * va2b.dot(a2b);
+
+ var fr = fspring + fdamping;
+
+ a2b.multiplyScalar(fr);
+
+ if (!a.fixed) {
+ a.force.addSelf(a2b);
+ }
+ if (!b.fixed) {
+ b.force.subSelf(a2b);
+ }
+
+ return this;
+
+ },
+
+ /**
+ * Returns a boolean describing whether the spring is resting or not.
+ * Convenient for knowing whether or not the spring needs another update
+ * tick.
+ */
+ resting: function() {
+
+ var a = this.a;
+ var b = this.b;
+ var l = this.length;
+
+ return !this.on || (a.fixed && b.fixed)
+ || (a.fixed && (l === 0 ? b.position.equals(a.position) : b.position.distanceTo(a.position) <= l) && b.resting())
+ || (b.fixed && (l === 0 ? a.position.equals(b.position) : a.position.distanceTo(b.position) <= l) && a.resting());
+
+ }
+
+ });
+
+ module.exports = Spring;
+
+
+},{"./common":8,"./vector":12}],7:[function(require,module,exports){
+/**
+ * @author mr.doob / http://mrdoob.com/
+ * @author philogb / http://blog.thejit.org/
+ * @author egraether / http://egraether.com/
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ * @author jonobr1 / http://jonobr1.com/
+ */
+
+var _ = require('./common');
+
+ /**
+ * A two dimensional vector.
+ */
+ function Vector(x, y) {
+
+ this.x = x || 0;
+ this.y = y || 0;
+
+ }
+
+ _.extend(Vector.prototype, {
+
+ set: function(x, y) {
+ this.x = x;
+ this.y = y;
+ return this;
+ },
+
+ copy: function(v) {
+ this.x = v.x;
+ this.y = v.y;
+ return this;
+ },
+
+ clear: function() {
+ this.x = 0;
+ this.y = 0;
+ return this;
+ },
+
+ clone: function() {
+ return new Vector(this.x, this.y);
+ },
+
+ add: function(v1, v2) {
+ this.x = v1.x + v2.x;
+ this.y = v1.y + v2.y;
+ return this;
+ },
+
+ addSelf: function(v) {
+ this.x += v.x;
+ this.y += v.y;
+ return this;
+ },
+
+ sub: function(v1, v2) {
+ this.x = v1.x - v2.x;
+ this.y = v1.y - v2.y;
+ return this;
+ },
+
+ subSelf: function(v) {
+ this.x -= v.x;
+ this.y -= v.y;
+ return this;
+ },
+
+ multiplySelf: function(v) {
+ this.x *= v.x;
+ this.y *= v.y;
+ return this;
+ },
+
+ multiplyScalar: function(s) {
+ this.x *= s;
+ this.y *= s;
+ return this;
+ },
+
+ multiplyScalarXY: function(sx,sy) {
+ this.x *= sx;
+ this.y *= sy;
+ return this;
+ },
+
+ divideScalar: function(s) {
+ if (s) {
+ this.x /= s;
+ this.y /= s;
+ } else {
+ this.set(0, 0);
+ }
+ return this;
+ },
+
+ negate: function() {
+ return this.multiplyScalar(-1);
+ },
+
+ dot: function(v) {
+ return this.x * v.x + this.y * v.y;
+ },
+
+ lengthSquared: function() {
+ return this.x * this.x + this.y * this.y;
+ },
+
+ length: function() {
+ return Math.sqrt(this.lengthSquared());
+ },
+
+ normalize: function() {
+ return this.divideScalar(this.length());
+ },
+
+ distanceTo: function(v) {
+ return Math.sqrt(this.distanceToSquared(v));
+ },
+
+ distanceToSquared: function(v) {
+ var dx = this.x - v.x, dy = this.y - v.y;
+ return dx * dx + dy * dy;
+ },
+
+ setLength: function(l) {
+ return this.normalize().multiplyScalar(l);
+ },
+
+ equals: function(v) {
+ return (this.distanceTo(v) < 0.0001 /* almost same position */);
+ },
+
+ lerp: function(v, t) {
+ var x = (v.x - this.x) * t + this.x;
+ var y = (v.y - this.y) * t + this.y;
+ return this.set(x, y);
+ },
+
+ isZero: function() {
+ return (this.length() < 0.0001 /* almost zero */ );
+ }
+
+ });
+
+ module.exports = Vector;
+
+},{"./common":8}],8:[function(require,module,exports){
+
+ /**
+ * Pulled only what's needed from:
+ *
+ * Underscore.js 1.3.3
+ * (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
+ * http://documentcloud.github.com/underscore
+ */
+
+ var breaker = {};
+ var ArrayProto = Array.prototype;
+ var ObjProto = Object.prototype;
+ var hasOwnProperty = ObjProto.hasOwnProperty;
+ var slice = ArrayProto.slice;
+ var nativeForEach = ArrayProto.forEach;
+ var nativeIndexOf = ArrayProto.indexOf;
+ var toString = ObjProto.toString;
+
+ var has = function(obj, key) {
+ return hasOwnProperty.call(obj, key);
+ };
+
+ var each = function(obj, iterator, context) {
+
+ if (obj == null) return;
+ if (nativeForEach && obj.forEach === nativeForEach) {
+ obj.forEach(iterator, context);
+ } else if (obj.length === +obj.length) {
+ for (var i = 0, l = obj.length; i < l; i++) {
+ if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
+ }
+ } else {
+ for (var key in obj) {
+ if (_.has(obj, key)) {
+ if (iterator.call(context, obj[key], key, obj) === breaker) return;
+ }
+ }
+ }
+
+ };
+
+ var identity = function(value) {
+ return value;
+ };
+
+ var sortedIndex = function(array, obj, iterator) {
+ iterator || (iterator = identity);
+ var low = 0, high = array.length;
+ while (low < high) {
+ var mid = (low + high) >> 1;
+ iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
+ }
+ return low;
+ };
+
+ module.exports = {
+
+ has: has,
+
+ each: each,
+
+ extend: function(obj) {
+ each(slice.call(arguments, 1), function(source) {
+ for (var prop in source) {
+ obj[prop] = source[prop];
+ }
+ });
+ return obj;
+ },
+
+ indexOf: function(array, item, isSorted) {
+ if (array == null) return -1;
+ var i, l;
+ if (isSorted) {
+ i = sortedIndex(array, item);
+ return array[i] === item ? i : -1;
+ }
+ if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
+ for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
+ return -1;
+ },
+
+ sortedIndex: sortedIndex,
+
+ identity: identity,
+
+ isNumber: function(obj) {
+ return toString.call(obj) == '[object Number]';
+ },
+
+ isFunction: function(obj) {
+ return toString.call(obj) == '[object Function]' || typeof obj == 'function';
+ },
+
+ isUndefined: function(obj) {
+ return obj === void 0;
+ },
+
+ isNull: function(obj) {
+ return obj === null;
+ }
+
+ };
+
+
+},{}],"H99CHA":[function(require,module,exports){
+var root = (function(){ return this; })()
+, previousShortcut = root.Physics
+;
+
+module.exports = root.Physics = require('./Physics');
+
+},{"./Physics":5}],"physics":[function(require,module,exports){
+module.exports=require('H99CHA');
+},{}],11:[function(require,module,exports){
+ /*
+ * Requirified version of Paul Irish's request animation frame.
+ * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+ */
+module.exports =
+ window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function (callback) {
+ window.setTimeout(callback, 1000 / 60);
+ };
+
+},{}],12:[function(require,module,exports){
+module.exports=require(7)
+},{"./common":8}]},{},["H99CHA"])
diff --git a/sites/all/modules/figli/edlp_corpus/assets/dist/bower/physicsjs-full.js b/sites/all/modules/figli/edlp_corpus/assets/dist/bower/physicsjs-full.js
deleted file mode 100644
index 963098617..000000000
--- a/sites/all/modules/figli/edlp_corpus/assets/dist/bower/physicsjs-full.js
+++ /dev/null
@@ -1,11963 +0,0 @@
-/**
- * PhysicsJS v0.7.0 - 2014-12-08
- * A modular, extendable, and easy-to-use physics engine for javascript
- * http://wellcaffeinated.net/PhysicsJS
- *
- * Copyright (c) 2014 Jasper Palfree
- * Licensed MIT
- */
-
-// ---
-// inside: src/intro.js
-
-(function (root, factory) {
- if (typeof exports === 'object') {
- // Node.
- module.exports = factory.call(root);
- } else if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module.
- define(function(){ return factory.call(root) });
- } else {
- // Browser globals (root is window)
- root.Physics = factory.call(root);
- }
-}(typeof window !== 'undefined' ? window : this, function () {
-
-'use strict';
-
-var window = this;
-var document = window.document;
-
-/** related to: Physics.world
- * Physics
- *
- * The top-level namespace. All of PhysicsJS is contained in
- * the `Physics` namespace.
- *
- * It may (and should) be invoked as a function to create a world instance. For all intensive purposes, [[Physics]] and [[Physics.world]] are the same thing.
- *
- * See [[new Physics.world]] for config options and function signature.
- *
- * Example:
- *
- * ```javascript
- * Physics( cfg, function( world ) {
- * // use world
- * }); // -> world
- * ```
- **/
-var Physics = function Physics(){
-
- return Physics.world.apply(Physics, arguments);
-};
-
-/**
- * Physics.util
- *
- * Namespace for utility functions.
- **/
-Physics.util = {};
-
-/**
- * == Special ==
- *
- * This section contains miscellaneous functionality.
- **/
-
-
-// ---
-// inside: src/math/aabb.js
-
-(function(){
-
- /**
- * Physics.aabb( minX, minY, maxX, maxY ) -> Object
- * Physics.aabb( pt1, pt2 ) -> Object
- * Physics.aabb( width, height[, pt] ) -> Object
- * - minX (Number): The x coord of the "top left" point
- * - minY (Number): The y coord of the "top left" point
- * - maxX (Number): The x coord of the "bottom right" point
- * - maxY (Number): The y coord of the "bottom right" point
- * - pt1 (Vectorish): The first corner
- * - pt2 (Vectorish): The opposite corner
- * - width (Number): The width of the bounding box
- * - height (Number): The height of the bounding box
- * - pt (Vectorish): The center point of the bounding box
- *
- * Create an Axis Aligned Bounding Box.
- *
- * Signature:
- *
- * ```javascript
- * {
- * x: Number, // the x coord of the center point
- * y: Number, // the y coord of the center point
- * hw: Number, // the half-width
- * hh: Number, // the half-height
- * }
- * ```
- **/
- Physics.aabb = function( minX, minY, maxX, maxY ){
-
- var aabb = { x: 0, y: 0, hw: 0, hh: 0 };
-
- if ( minX === undefined ){
- return aabb;
- }
-
- if ( minX && minX.x !== undefined ){
- // we have a point specified as first arg
- maxX = minY.x;
- maxY = minY.y;
- minY = minX.y;
- minX = minX.x;
- }
-
- if ( maxY === undefined && minX !== undefined && minY !== undefined ){
-
- aabb.hw = minX * 0.5;
- aabb.hh = minY * 0.5;
-
- if ( maxX && maxX.x !== undefined ){
- // we have a point specified as the third arg
- // so we assume it's the center point
- aabb.x = maxX.x;
- aabb.y = maxX.y;
- }
-
- return aabb;
- }
-
- // here, we should have all the arguments as numbers
- aabb.hw = Math.abs(maxX - minX) * 0.5;
- aabb.hh = Math.abs(maxY - minY) * 0.5;
- aabb.x = (maxX + minX) * 0.5;
- aabb.y = (maxY + minY) * 0.5;
-
- return aabb;
- };
-
- /**
- * Physics.aabb.contains( aabb, pt ) -> Boolean
- * - aabb (Object): The aabb
- * - pt (Vectorish): The point
- * + (Boolean): `true` if `pt` is inside `aabb`, `false` otherwise
- *
- * Check if a point is inside an aabb.
- **/
- Physics.aabb.contains = function contains( aabb, pt ){
-
- return (pt.x > (aabb.x - aabb.hw)) &&
- (pt.x < (aabb.x + aabb.hw)) &&
- (pt.y > (aabb.y - aabb.hh)) &&
- (pt.y < (aabb.y + aabb.hh));
- };
-
- /**
- * Physics.aabb.clone( aabb ) -> Object
- * - aabb (Object): The aabb to clone
- * + (Object): The clone
- *
- * Clone an aabb.
- **/
- Physics.aabb.clone = function( aabb ){
- return {
- x: aabb.x,
- y: aabb.y,
- hw: aabb.hw,
- hh: aabb.hh
- };
- };
-
- /**
- * Physics.aabb.union( aabb1, aabb2[, modify] ) -> Object
- * - aabb1 (Object): The first aabb (returned if modify is `true`)
- * - aabb2 (Object): The second aabb
- * + (Object): The union of two aabbs. If modify is `true`, then the first aabb will be modified and returned.
- *
- * Get the union of two aabbs.
- **/
- Physics.aabb.union = function( aabb1, aabb2, modify ){
-
- var ret = modify === true ? aabb1 : {}
- ,maxX = Math.max( aabb1.x + aabb1.hw, aabb2.x + aabb2.hw )
- ,maxY = Math.max( aabb1.y + aabb1.hh, aabb2.y + aabb2.hh )
- ,minX = Math.min( aabb1.x - aabb1.hw, aabb2.x - aabb2.hw )
- ,minY = Math.min( aabb1.y - aabb1.hh, aabb2.y - aabb2.hh )
- ;
-
- ret.hw = Math.abs(maxX - minX) * 0.5;
- ret.hh = Math.abs(maxY - minY) * 0.5;
- ret.x = (maxX + minX) * 0.5;
- ret.y = (maxY + minY) * 0.5;
-
- return ret;
- };
-
-
- /**
- * Physics.aabb.overlap( aabb1, aabb2 ) -> Boolean
- * - aabb1 (Object): The first aabb
- * - aabb2 (Object): The second aabb
- * + (Boolean): `true` if they overlap, `false` otherwise
- *
- * Check if two AABBs overlap.
- **/
- Physics.aabb.overlap = function( aabb1, aabb2 ){
-
- var min1 = aabb1.x - aabb1.hw
- ,min2 = aabb2.x - aabb2.hw
- ,max1 = aabb1.x + aabb1.hw
- ,max2 = aabb2.x + aabb2.hw
- ;
-
- // first check x-axis
-
- if ( (min2 <= max1 && max1 <= max2) || (min1 <= max2 && max2 <= max1) ){
- // overlap in x-axis
- // check y...
- min1 = aabb1.y - aabb1.hh;
- min2 = aabb2.y - aabb2.hh;
- max1 = aabb1.y + aabb1.hh;
- max2 = aabb2.y + aabb2.hh;
-
- return (min2 <= max1 && max1 <= max2) || (min1 <= max2 && max2 <= max1);
- }
-
- // they don't overlap
- return false;
- };
-
-}());
-
-
-// ---
-// inside: src/math/gjk.js
-
-(function(){
-
- // the algorithm doesn't always converge for curved shapes.
- // need these constants to dictate how accurate we want to be.
- var gjkAccuracy = 0.0001;
- var gjkMaxIterations = 100;
-
- // get the next search direction from two simplex points
- var getNextSearchDir = function getNextSearchDir( ptA, ptB, dir ){
-
- var ABdotB = ptB.normSq() - ptB.dot( ptA )
- ,ABdotA = ptB.dot( ptA ) - ptA.normSq()
- ;
-
- // if the origin is farther than either of these points
- // get the direction from one of those points to the origin
- if ( ABdotB < 0 ){
-
- return dir.clone( ptB ).negate();
-
- } else if ( ABdotA > 0 ){
-
- return dir.clone( ptA ).negate();
-
- // otherwise, use the perpendicular direction from the simplex
- } else {
-
- // dir = AB = B - A
- dir.clone( ptB ).vsub( ptA );
- // if (left handed coordinate system)
- // A cross AB < 0 then get perpendicular counterclockwise
- return dir.perp( (ptA.cross( dir ) > 0) );
- }
- };
-
- /** hide
- * getClosestPoints( simplex ) -> Object
- * - simplex (Array): The simplex
- *
- * Figure out the closest points on the original objects
- * from the last two entries of the simplex
- **/
- var getClosestPoints = function getClosestPoints( simplex ){
-
- // see http://www.codezealot.org/archives/153
- // for algorithm details
-
- // we know that the position of the last point
- // is very close to the previous. (by nature of the distance test)
- // this won't give great results for the closest
- // points algorithm, so let's use the previous two
- var len = simplex.length
- ,last = simplex[ len - 2 ]
- ,prev = simplex[ len - 3 ]
- ,scratch = Physics.scratchpad()
- ,A = scratch.vector().clone( last.pt )
- // L = B - A
- ,L = scratch.vector().clone( prev.pt ).vsub( A )
- ,lambdaB
- ,lambdaA
- ;
-
- if ( L.equals(Physics.vector.zero) ){
-
- // oh.. it's a zero vector. So A and B are both the closest.
- // just use one of them
- return scratch.done({
-
- a: last.a,
- b: last.b
- });
- }
-
- lambdaB = - L.dot( A ) / L.normSq();
- lambdaA = 1 - lambdaB;
-
- if ( lambdaA <= 0 ){
- // woops.. that means the closest simplex point
- // isn't on the line it's point B itself
- return scratch.done({
- a: prev.a,
- b: prev.b
- });
- } else if ( lambdaB <= 0 ){
- // vice versa
- return scratch.done({
- a: last.a,
- b: last.b
- });
- }
-
- // guess we'd better do the math now...
- return scratch.done({
- // a closest = lambdaA * Aa + lambdaB * Ba
- a: A.clone( last.a ).mult( lambdaA ).vadd( L.clone( prev.a ).mult( lambdaB ) ).values(),
- // b closest = lambdaA * Ab + lambdaB * Bb
- b: A.clone( last.b ).mult( lambdaA ).vadd( L.clone( prev.b ).mult( lambdaB ) ).values()
- });
- };
-
- /**
- * Physics.gjk( support(axis)[, seed, checkOverlapOnly, debugFn] ) -> Object
- * - support (Function): The support function. Must return an object containing
- the witness points (`.a`, `.b`) and the support point (`.pt`).
- Recommended to use simple objects.
- Eg:
- ```javascript
- return {
- a: { x: 1, y:2 },
- b: { x: 3, y: 4 },
- pt: { x: 2, y: 2 }
- };
- ```
- * - axis (Physics.vector): The axis to search
- * - seed (Physics.vector): The starting direction for the simplex (defaults to x-axis)
- * - checkOverlapOnly (Boolean): only check whether there is an overlap, don't calculate the depth
- * - debugFn (Function): For debugging. Called at every iteration with the current simplex.
- *
- * Implementation agnostic GJK function.
- *
- * Gilbert–Johnson–Keerthi object collison algorithm
- * For general information about GJK see:
- * - [www.codezealot.org/archives/88](http://www.codezealot.org/archives/88)
- * - [mollyrocket.com/849](http://mollyrocket.com/849)
- *
- * The algorithm information returned:
- * ```javascript
- * {
- * overlap: Boolean,
- * simplex: [] // array containing simplex points as simple x/y objects
- * }
- * ```
- **/
- var gjk = function gjk( support, seed, checkOverlapOnly, debugFn ){
-
- var overlap = false
- ,noOverlap = false // if we're sure we're not overlapping
- ,distance = false
- ,simplex = []
- ,simplexLen = 1
- // setup a scratchpad of temporary cheap objects
- ,scratch = Physics.scratchpad()
- // use seed as starting direction or use x axis
- ,dir = scratch.vector().clone(seed || Physics.vector.axis[ 0 ])
- ,last = scratch.vector()
- ,lastlast = scratch.vector()
- // some temp vectors
- ,v1 = scratch.vector()
- ,v2 = scratch.vector()
- ,ab
- ,ac
- ,sign
- ,tmp
- ,iterations = 0
- ;
-
- // get the first Minkowski Difference point
- tmp = support( dir );
- simplexLen = simplex.push( tmp );
- last.clone( tmp.pt );
- // negate d for the next point
- dir.negate();
-
- // start looping
- while ( ++iterations ) {
-
- // swap last and lastlast, to save on memory/speed
- last.swap(lastlast);
- // push a new point to the simplex because we haven't terminated yet
- tmp = support( dir );
- simplexLen = simplex.push( tmp );
- last.clone( tmp.pt );
-
- if ( debugFn ){
- debugFn( simplex );
- }
-
- if ( last.equals(Physics.vector.zero) ){
- // we happened to pick the origin as a support point... lucky.
- overlap = true;
- break;
- }
-
- // check if the last point we added actually passed the origin
- if ( !noOverlap && last.dot( dir ) <= 0.0 ) {
- // if the point added last was not past the origin in the direction of d
- // then the Minkowski difference cannot possibly contain the origin since
- // the last point added is on the edge of the Minkowski Difference
-
- // if we just need the overlap...
- if ( checkOverlapOnly ){
- break;
- }
-
- noOverlap = true;
- }
-
- // if it's a line...
- if ( simplexLen === 2 ){
-
- // otherwise we need to determine if the origin is in
- // the current simplex and act accordingly
-
- dir = getNextSearchDir( last, lastlast, dir );
- // continue...
-
- // if it's a triangle... and we're looking for the distance
- } else if ( noOverlap ){
-
- // if we know there isn't any overlap and
- // we're just trying to find the distance...
- // make sure we're getting closer to the origin
- dir.normalize();
- tmp = lastlast.dot( dir );
- if ( Math.abs(tmp - last.dot( dir )) < gjkAccuracy ){
-
- distance = -tmp;
- break;
- }
-
- // if we are still getting closer then only keep
- // the points in the simplex that are closest to
- // the origin (we already know that last is closer
- // than the previous two)
- // the norm is the same as distance(origin, a)
- // use norm squared to avoid the sqrt operations
- if (lastlast.normSq() < v1.clone(simplex[ 0 ].pt).normSq()) {
-
- simplex.shift();
-
- } else {
-
- simplex.splice(1, 1);
- }
-
- dir = getNextSearchDir( v1.clone(simplex[ 1 ].pt), v2.clone(simplex[ 0 ].pt), dir );
- // continue...
-
- // if it's a triangle
- } else {
-
- // we need to trim the useless point...
-
- ab = ab || scratch.vector();
- ac = ac || scratch.vector();
-
- // get the edges AB and AC
- ab.clone( lastlast ).vsub( last );
- ac.clone( simplex[ 0 ].pt ).vsub( last );
-
- // here normally people think about this as getting outward facing
- // normals and checking dot products. Since we're in 2D
- // we can be clever...
- sign = ab.cross( ac ) > 0;
-
- if ( sign ^ (last.cross( ab ) > 0) ){
-
- // ok... so there's an XOR here... don't freak out
- // remember last = A = -AO
- // if AB cross AC and AO cross AB have the same sign
- // then the origin is along the outward facing normal of AB
- // so if AB cross AC and A cross AB have _different_ (XOR) signs
- // then this is also the case... so we proceed...
-
- // point C is dead to us now...
- simplex.shift();
-
- // if we haven't deduced that we've enclosed the origin
- // then we know which way to look...
- // morph the ab vector into its outward facing normal
- ab.perp( !sign );
-
- // swap
- dir.swap( ab );
-
- // continue...
-
- // if we get to this if, then it means we can continue to look along
- // the other outward normal direction (ACperp)
- // if we don't see the origin... then we must have it enclosed
- } else if ( sign ^ (ac.cross( last ) > 0) ){
- // then the origin is along the outward facing normal
- // of AC; (ACperp)
-
- // point B is dead to us now...
- simplex.splice(1, 1);
-
- ac.perp( sign );
-
- // swap
- dir.swap( ab );
-
- // continue...
-
- } else {
-
- // we have enclosed the origin!
- overlap = true;
- // fewf... take a break
- break;
- }
- }
-
- // woah nelly... that's a lot of iterations.
- // Stop it!
- if (iterations > gjkMaxIterations){
- scratch.done();
- return {
- simplex: simplex,
- iterations: iterations,
- distance: 0,
- maxIterationsReached: true
- };
- }
- }
-
- // free workspace
- scratch.done();
-
- tmp = {
- overlap: overlap,
- simplex: simplex,
- iterations: iterations
- };
-
- if ( distance !== false ){
-
- tmp.distance = distance;
- tmp.closest = getClosestPoints( simplex );
- }
-
- return tmp;
- };
-
- Physics.gjk = gjk;
-
-})();
-
-
-// ---
-// inside: src/math/statistics.js
-
-(function(){
-
- Physics.statistics = {
- /**
- * Physics.statistics.pushRunningAvg( v, k, m, s ) -> Array
- * - v (Number): is value to push
- * - k (Number): is num elements
- * - m (Number): is current mean
- * - s (Number): is current s value
- * + (Array): Returns a 2 element array containing the next mean, and s value
- *
- * Push a value to a running average calculation.
- * see [http://www.johndcook.com/blog/standard_deviation]
- *
- * Note: variance can be calculated from the "s" value by multiplying it by `1/(k-1)`
- **/
- pushRunningAvg: function( v, k, m, s ){
-
- var x = v - m;
-
- // Mk = Mk-1+ (xk – Mk-1)/k
- // Sk = Sk-1 + (xk – Mk-1)*(xk – Mk).
- m += x / k;
- s += x * (v - m);
- return [m, s];
- },
-
- /**
- * Physics.statistics.pushRunningVectorAvg( v, k, m[, s] )
- * - v (Physics.vector): is vector to push
- * - k (Number): is num elements
- * - m (Physics.vector): is current mean
- * - s (Physics.vector): is current s value
- *
- * Push a vector to a running vector average calculation.
- * see [http://www.johndcook.com/blog/standard_deviation]
- *
- * Calculations are done in place. The `m` and `s` parameters are altered.
- *
- * Note: variance can be calculated from the "s" vector by multiplying it by `1/(k-1)`
- *
- * If s value is ommitted it won't be used.
- **/
- pushRunningVectorAvg: function( v, k, m, s ){
- var invK = 1/k
- ,x = v.get(0) - m.get(0)
- ,y = v.get(1) - m.get(1)
- ;
-
- // Mk = Mk-1+ (xk – Mk-1)/k
- // Sk = Sk-1 + (xk – Mk-1)*(xk – Mk).
- m.add( x * invK, y * invK );
-
- if ( s ){
- x *= v.get(0) - m.get(0);
- y *= v.get(1) - m.get(1);
-
- s.add( x, y );
- }
- }
- };
-})();
-
-
-// ---
-// inside: src/math/transform.js
-
-(function(){
-
- /**
- * class Physics.transform
- *
- * Vector Transformations class for rotating and translating vectors
- **/
-
- /**
- * new Physics.transform( [vect, angle, origin] )
- * new Physics.transform( transform )
- * - vect (Vectorish): Translation vector
- * - transform (Physics.transform): Transform to copy
- * - angle (Number): Angle (radians) to use for rotation
- * - origin (Vectorish): Origin of the rotation
- *
- * Transform Constructor / Factory
- **/
- var Transform = function Transform( vect, angle, origin ) {
-
- if (!(this instanceof Transform)){
- return new Transform( vect, angle );
- }
-
- this.v = new Physics.vector();
- this.o = new Physics.vector(); // origin of rotation
-
- if ( vect instanceof Transform ){
-
- this.clone( vect );
- return;
- }
-
- if (vect){
- this.setTranslation( vect );
- }
-
- this.setRotation( angle || 0, origin );
- };
-
- /**
- * Physics.transform#setTranslation( vect ) -> this
- * - vect (Vectorish): The translation vector
- *
- * Set the translation portion of the transform.
- **/
- Transform.prototype.setTranslation = function( vect ){
-
- this.v.clone( vect );
- return this;
- };
-
- /**
- * Physics.transform#setRotation( angle[, origin ] ) -> this
- * - angle (Number): Angle (radians) to use for rotation
- * - origin (Vectorish): Origin of the rotation
- *
- * Set the rotation portion of the transform
- **/
- Transform.prototype.setRotation = function( angle, origin ){
-
- this.cosA = Math.cos( angle );
- this.sinA = Math.sin( angle );
-
- if ( origin ){
- this.o.clone( origin );
- } else {
- this.o.zero();
- }
-
- return this;
- };
-
- /**
- * Physics.transform#clone( [transform] ) -> this|Physics.transform
- * - transform (Physics.transform): Transform to copy
- * + (this): For chaining
- * + (Physics.transform): New copy of `this` if none is specified as an argument
- *
- * Clone another transform. Or clone self into new transform.
- **/
- Transform.prototype.clone = function( t ){
-
- if ( t ){
-
- this.setTranslation( t.v );
- this.cosA = t.cosA;
- this.sinA = t.sinA;
- this.o.clone( t.o );
-
- return this;
- }
-
- return new Transform( this );
- };
-
- Physics.transform = Transform;
-
-})();
-
-// ---
-// inside: src/math/vector.js
-
-(function(window){
-
- // http://jsperf.com/vector-storage-test/2
-
- // cached math functions
- // TODO: might be faster not to do this???
- var sqrt = Math.sqrt
- ,min = Math.min
- ,max = Math.max
- ,acos = Math.acos
- ,atan2 = Math.atan2
- ,TWOPI = Math.PI * 2
- ,typedArrays = !!window.Float64Array
- ;
-
- /**
- * class Physics.vector
- *
- * The vector class and factory function.
- *
- * Call `Physics.vector` with the same arguments as
- * [[new Physics.vector]] to create an instance.
- *
- * The vector methods mostly modify the vector instance.
- * This makes computations faster because creating vectors
- * is avoided.
- *
- * Creating vectors is generally an expensive operation
- * so try to avoid doing this in the simulation loop.
- * Instead you can use [[Physics.scratchpad]] to get
- * temporary vectors for use in performance critical
- * code.
- *
- * _Note_: The coordinate system is left-handed, meaning that
- * the clockwise angular direction is positive. This has implications
- * for the cross-product rule.
- **/
-
- /** section: Special
- * class Vectorish
- *
- * Any object with `.x` and `.y` properties.
- *
- * A `Vectorish` isn't really a class. In this documentation, when
- * an argument is specified as a `Vectorish` it means either a true
- * [[Physics.vector]] instance, or an object literal with `.x` and `.y`
- * properties.
- **/
-
- /**
- * new Physics.vector( x, y )
- * new Physics.vector( vect )
- * - x (Number): The x coordinate
- * - y (Number): The y coordinate
- * - vect (Vectorish): A vector-like object to clone
- *
- * Vector Constructor.
- **/
- var Vector = function Vector( x, y ) {
-
- // enforce instantiation
- if ( !(this instanceof Vector) ){
-
- return new Vector( x, y );
- }
-
- // arrays to store values
- // x = _[0]
- // y = _[1]
- // norm = _[3]
- // normsq = _[4]
-
- /** internal
- * Physics.vector#_
- *
- * Private storage array for data.
- *
- * Do not access this directly. Private. Keep out.
- **/
- if (typedArrays){
- this._ = new Float64Array(5);
- } else {
- this._ = [];
- }
-
- if (x && (x.x !== undefined || x._ && x._.length)){
-
- this.clone( x );
-
- } else {
-
- this.recalc = true; //whether or not recalculate norms
- this.set( x, y );
- }
- };
-
- Object.defineProperties( Vector.prototype, {
- /**
- * Physics.vector#x
- *
- * Getter/setter property for the x coordinate.
- **/
- x: {
- get: function(){
- return +this._[0];
- },
- set: function( x ){
- x = +x || 0;
- this.recalc = ( x === this._[0] );
- this._[0] = x;
- }
- },
- /**
- * Physics.vector#y
- *
- * Getter/setter property for the y coordinate.
- **/
- y: {
- get: function(){
- return +this._[1];
- },
- set: function( y ){
- y = +y || 0;
- this.recalc = ( y === this._[1] );
- this._[1] = y;
- }
- }
- });
-
- //
- // Methods
- //
-
- /**
- * Physics.vector#set( x, y ) -> this
- * - x (Number): x coordinate
- * - y (Number): y coordinate
- *
- * Sets the x and y components of this vector.
- **/
- Vector.prototype.set = function( x, y ) {
-
- this.recalc = true;
-
- this._[0] = +x || 0;
- this._[1] = +y || 0;
- return this;
- };
-
- /** deprecated: 0.6.0..1.0.0
- * Physics.vector#get( idx ) -> Number
- * - idx (Number): The coordinate index (0 or 1)
- *
- * Get the x or y component by index.
- **/
- Vector.prototype.get = function( n ){
-
- return this._[ n ];
- };
-
- /**
- * Physics.vector#vadd( v ) -> this
- * - v (Physics.vector): vector to add
- *
- * Add a [[Physics.vector]] to `this`.
- **/
- Vector.prototype.vadd = function( v ) {
-
- this.recalc = true;
-
- this._[0] += v._[0];
- this._[1] += v._[1];
- return this;
- };
-
- /**
- * Physics.vector#vsub( v ) -> this
- * - v (Physics.vector): vector to subtract
- *
- * Subtract a [[Physics.vector]] from `this`.
- **/
- Vector.prototype.vsub = function( v ) {
-
- this.recalc = true;
-
- this._[0] -= v._[0];
- this._[1] -= v._[1];
- return this;
- };
-
- /**
- * Physics.vector#add( x, y ) -> this
- * - x (Number): amount to add to the x coordinate
- * - y (Number): amount to add to the y coordinate
- *
- * Add scalars [[Physics.vector]] to the coordinates.
- **/
- Vector.prototype.add = function( x, y ){
-
- this.recalc = true;
-
- this._[0] += +x || 0;
- this._[1] += +y || 0;
- return this;
- };
-
- /**
- * Physics.vector#sub( x, y ) -> this
- * - x (Number): amount to subtract from the x coordinate
- * - y (Number): amount to subtract from the y coordinate
- *
- * Subtract scalars [[Physics.vector]] from the coordinates.
- **/
- Vector.prototype.sub = function( x, y ){
-
- this.recalc = true;
-
- this._[0] -= x;
- this._[1] -= y === undefined? 0 : y;
- return this;
- };
-
- /**
- * Physics.vector#mult( m ) -> this
- * - m (Number): amount to multiply this vector by
- *
- * Multiply this by a scalar quantity.
- *
- * Same as scaling the vector by an amount `m`.
- **/
- Vector.prototype.mult = function( m ) {
-
- if ( !this.recalc ){
-
- this._[4] *= m * m;
- this._[3] *= m;
- }
-
- this._[0] *= m;
- this._[1] *= m;
- return this;
- };
-
- /**
- * Physics.vector#dot( v ) -> Number
- * - v (Physics.vector): The other vector
- *
- * Compute the dot product of this vector with `v`.
- **/
- Vector.prototype.dot = function( v ) {
-
- return (this._[0] * v._[0]) + (this._[1] * v._[1]);
- };
-
- /**
- * Physics.vector#cross( v ) -> Number
- * - v (Physics.vector): The other vector
- *
- * Compute the (left-handed) cross product of this vector with `v`.
- **/
- Vector.prototype.cross = function( v ) {
-
- return ( - this._[0] * v._[1]) + (this._[1] * v._[0]);
- };
-
- /**
- * Physics.vector#proj( v ) -> Number
- * - v (Physics.vector): The other vector
- *
- * Compute the [scalar projection](http://en.wikipedia.org/wiki/Vector_projection#Scalar_projection_2) of this along `v`.
- **/
- Vector.prototype.proj = function( v ){
-
- return this.dot( v ) / v.norm();
- };
-
-
- /**
- * Physics.vector#vproj( v ) -> this
- * - v (Physics.vector): The other vector
- *
- * Compute the [vector projection](http://en.wikipedia.org/wiki/Vector_projection#Vector_projection_2) of this along `v` and copy the result into this vector.
- **/
- Vector.prototype.vproj = function( v ){
-
- var m = this.dot( v ) / v.normSq();
- return this.clone( v ).mult( m );
- };
-
- /**
- * Physics.vector#angle( [v] ) -> Number
- * - v (Physics.vector): The other vector
- * + (Number): The angle in radians between this vector and the x-axis OR `v` if specified
- *
- * Compute the angle between `this` and vector `v` or this and x axis.
- **/
- Vector.prototype.angle = function( v ){
-
- var ang;
-
- if ( this.equals( Vector.zero ) ){
-
- if ( v ){
- return v.angle();
- } else {
- return NaN;
- }
-
- } else {
-
- if ( v && !v.equals( Vector.zero ) ){
- ang = atan2( this._[1] * v._[0] - this._[0] * v._[1], this._[0] * v._[0] + this._[1] * v._[1]);
- } else {
- ang = atan2( this._[ 1 ], this._[ 0 ] );
- }
- }
-
- while (ang > Math.PI){
- ang -= TWOPI;
- }
-
- while (ang < -Math.PI){
- ang += TWOPI;
- }
-
- return ang;
- };
-
- /**
- * Physics.vector#angle2( left, right ) -> Number
- * - left (Physics.vector): The position on the left
- * - right (Physics.vector): The position on the right
- *
- * Compute the angle created between three points; left -> this -> right.
- **/
- Vector.prototype.angle2 = function( left, right ){
-
- var x1 = left._[0] - this._[0]
- ,y1 = left._[1] - this._[1]
- ,x2 = right._[0] - this._[0]
- ,y2 = right._[1] - this._[1]
- ,ang = atan2( y1 * x2 - x1 * y2, x1 * x2 + y1 * y2)
- ;
-
- while (ang > Math.PI){
- ang -= TWOPI;
- }
-
- while (ang < -Math.PI){
- ang += TWOPI;
- }
-
- return ang;
- };
-
- /**
- * Physics.vector#norm() -> Number
- *
- * Compute the norm (length) of this vector.
- **/
- Vector.prototype.norm = function() {
-
- if (this.recalc){
- this.recalc = false;
- this._[4] = (this._[0] * this._[0] + this._[1] * this._[1]);
- this._[3] = sqrt( this._[4] );
- }
-
- return this._[3];
- };
-
- /**
- * Physics.vector#normSq() -> Number
- *
- * Compute the norm (length) squared of this vector.
- **/
- Vector.prototype.normSq = function() {
-
- if (this.recalc){
- this.recalc = false;
- this._[4] = (this._[0] * this._[0] + this._[1] * this._[1]);
- this._[3] = sqrt( this._[4] );
- }
-
- return this._[4];
- };
-
- /**
- * Physics.vector#dist( v ) -> Number
- * - v (Physics.vector): The other vector
- *
- * Compute the distance from this vector to another vector `v`.
- **/
- Vector.prototype.dist = function( v ) {
-
- var dx, dy;
- return sqrt(
- (dx = (v._[0] - this._[0])) * dx +
- (dy = (v._[1] - this._[1])) * dy
- );
- };
-
- /**
- * Physics.vector#distSq( v ) -> Number
- * - v (Physics.vector): The other vector
- *
- * Compute the distance squared from this vector to another vector `v`.
- **/
- Vector.prototype.distSq = function( v ) {
-
- var dx, dy;
- return (
- (dx = (v._[0] - this._[0])) * dx +
- (dy = (v._[1] - this._[1])) * dy
- );
- };
-
- /**
- * Physics.vector#perp( [ccw] ) -> this
- * - ccw (Boolean): flag to indicate that we should rotate counterclockwise
- *
- * Change this vector into a vector that will be perpendicular.
- *
- * In other words, rotate by (+-) 90 degrees.
- **/
- Vector.prototype.perp = function( ccw ) {
-
- var tmp = this._[0]
- ;
-
- if ( ccw ){
-
- // x <-> y
- // negate y
- this._[0] = this._[1];
- this._[1] = -tmp;
-
- } else {
-
- // x <-> y
- // negate x
- this._[0] = -this._[1];
- this._[1] = tmp;
- }
-
- return this;
- };
-
- /**
- * Physics.vector#normalize() -> this
- *
- * Normalise this vector, making it a unit vector.
- **/
- Vector.prototype.normalize = function() {
-
- var m = this.norm();
-
- // means it's a zero Vector
- if ( m === 0 ){
- return this;
- }
-
- m = 1/m;
-
- this._[0] *= m;
- this._[1] *= m;
-
- this._[3] = 1.0;
- this._[4] = 1.0;
-
- return this;
- };
-
- /**
- * Physics.vector#transform( t ) -> this
- * - t (Physics.transform): The transformation to apply
- *
- * Apply a [[Physics.transform]] to this vector.
- **/
- Vector.prototype.transform = function( t ){
-
- var sinA = t.sinA
- ,cosA = t.cosA
- ,x = t.o._[ 0 ]
- ,y = t.o._[ 1 ]
- ;
-
- this._[ 0 ] -= x;
- this._[ 1 ] -= y;
-
- // rotate about origin "o" then translate
- return this.set(
- this._[ 0 ] * cosA - this._[ 1 ] * sinA + x + t.v._[ 0 ],
- this._[ 0 ] * sinA + this._[ 1 ] * cosA + y + t.v._[ 1 ]
- );
- };
-
- /**
- * Physics.vector#transformInv( t ) -> this
- * - t (Physics.transform): The transformation to apply the inverse of
- *
- * Apply an inverse [[Physics.transform]] to this vector.
- **/
- Vector.prototype.transformInv = function( t ){
-
- var sinA = t.sinA
- ,cosA = t.cosA
- ,x = t.o._[ 0 ]
- ,y = t.o._[ 1 ]
- ;
-
- this._[ 0 ] -= x + t.v._[ 0 ];
- this._[ 1 ] -= y + t.v._[ 1 ];
-
- // inverse translate then inverse rotate about origin "o"
- return this.set(
- this._[ 0 ] * cosA + this._[ 1 ] * sinA + x,
- - this._[ 0 ] * sinA + this._[ 1 ] * cosA + y
- );
- };
-
- /**
- * Physics.vector#rotate( t ) -> this
- * Physics.vector#rotate( ang[, o] ) -> this
- * - t (Physics.transform): The transformation to apply the rotational part of
- * - ang (Number): The angle (in radians), to rotate by
- * - o (Vectorish): The point of origin of the rotation
- *
- * Rotate this vector.
- *
- * An angle and rotation origin can be specified,
- * or a transform can be specified and only the rotation
- * portion of that transform will be applied
- **/
- Vector.prototype.rotate = function( t, o ){
-
- var sinA
- ,cosA
- ,x = 0
- ,y = 0
- ;
-
- if ( typeof t === 'number' ){
- sinA = Math.sin( t );
- cosA = Math.cos( t );
-
- if ( o ){
- x = o.x;
- y = o.y;
- }
- } else {
- sinA = t.sinA;
- cosA = t.cosA;
-
- x = t.o._[ 0 ];
- y = t.o._[ 1 ];
- }
-
- this._[ 0 ] -= x;
- this._[ 1 ] -= y;
-
- return this.set(
- this._[ 0 ] * cosA - this._[ 1 ] * sinA + x,
- this._[ 0 ] * sinA + this._[ 1 ] * cosA + y
- );
- };
-
- /**
- * Physics.vector#rotateInv( t ) -> this
- * - t (Physics.transform): The transformation to apply the inverse rotational part of
- *
- * Apply the inverse rotation of a transform.
- *
- * Only the inverse rotation portion of
- * that transform will be applied.
- **/
- Vector.prototype.rotateInv = function( t ){
-
- return this.set(
- (this._[ 0 ] - t.o._[ 0 ]) * t.cosA + (this._[ 1 ] - t.o._[ 1 ]) * t.sinA + t.o._[ 0 ],
- -(this._[ 0 ] - t.o._[ 0 ]) * t.sinA + (this._[ 1 ] - t.o._[ 1 ]) * t.cosA + t.o._[ 1 ]
- );
- };
-
- /**
- * Physics.vector#translate( t ) -> this
- * - t (Physics.transform): The transformation to apply the translational part of
- *
- * Apply the translation of a transform.
- *
- * Only the translation portion of
- * that transform will be applied.
- **/
- Vector.prototype.translate = function( t ){
-
- return this.vadd( t.v );
- };
-
- /**
- * Physics.vector#translateInv( t ) -> this
- * - t (Physics.transform): The transformation to apply the inverse translational part of
- *
- * Apply the inverse translation of a transform.
- *
- * Only the inverse translation portion of
- * that transform will be applied.
- **/
- Vector.prototype.translateInv = function( t ){
-
- return this.vsub( t.v );
- };
-
-
- /**
- * Physics.vector#clone( [v] ) -> this|Physics.vector
- * - v (Vectorish): The vector-like object to clone
- * + (this): If `v` is specified as an argument
- * + (Physics.vector): A new vector instance that clones this vector, if no argument is specified
- *
- * Create a clone of this vector, or clone another vector into this instance.
- *
- * This is especially useful in vector algorithms
- * that use temporary vectors (which most should).
- * You can create temporary vectors and then do things like...
- * ```
- * temp.clone( otherVector );
- * // compute things with temp...
- * // then save the result
- * result.clone( tmp );
- * ```
- **/
- Vector.prototype.clone = function( v ) {
-
- // http://jsperf.com/vector-storage-test
-
- if ( v ){
-
- if (!v._){
-
- return this.set( v.x, v.y );
- }
-
- this.recalc = v.recalc;
-
- if (!v.recalc){
- this._[3] = v._[3];
- this._[4] = v._[4];
- }
-
- this._[0] = v._[0];
- this._[1] = v._[1];
-
- return this;
- }
-
- return new Vector( this );
- };
-
- /**
- * Physics.vector#swap( v ) -> this
- * - v (Physics.vector): The other vector
- *
- * Swap values with other vector.
- **/
- Vector.prototype.swap = function( v ){
-
- var _ = this._;
- this._ = v._;
- v._ = _;
-
- _ = this.recalc;
- this.recalc = v.recalc;
- v.recalc = _;
- return this;
- };
-
- /**
- * Physics.vector#values() -> Object
- *
- * Get the coordinate values as an object literal.
- **/
- Vector.prototype.values = function(){
-
- return {
- x: this._[0],
- y: this._[1]
- };
- };
-
-
- /**
- * Physics.vector#zero() -> this
- *
- * Set the coordinates of this vector to zero.
- **/
- Vector.prototype.zero = function() {
-
- this._[3] = 0.0;
- this._[4] = 0.0;
-
- this._[0] = 0.0;
- this._[1] = 0.0;
- return this;
- };
-
- /**
- * Physics.vector#negate() -> this
- *
- * Flip this vector in the opposite direction.
- **/
- Vector.prototype.negate = function( component ){
-
- if (component !== undefined){
-
- this._[ component ] = -this._[ component ];
- return this;
- }
-
- this._[0] = -this._[0];
- this._[1] = -this._[1];
- return this;
- };
-
- /**
- * Physics.vector#clamp( minV, maxV ) -> this
- * - minV (Vectorish): The minimum vector
- * - maxV (Vectorish): The maximum vector
- *
- * Constrain vector components to minima and maxima.
- *
- * The vector analog of [scalar clamping](http://en.wikipedia.org/wiki/Clamping_(graphics)).
- **/
- Vector.prototype.clamp = function( minV, maxV ){
-
- this._[0] = min(max(this._[0], minV.x), maxV.x);
- this._[1] = min(max(this._[1], minV.y), maxV.y);
- this.recalc = true;
- return this;
- };
-
- /**
- * Physics.vector#toString() -> String
- *
- * Get a formatted string of this vector's coordinates.
- **/
- Vector.prototype.toString = function(){
-
- return '('+this._[0] + ', ' + this._[1]+')';
- };
-
-
- /**
- * Physics.vector#equals( v ) -> Boolean
- * - v (Physics.vector): The other vector
- *
- * Determine if this vector equals another.
- **/
- Vector.prototype.equals = function( v ){
-
- return this._[0] === v._[0] &&
- this._[1] === v._[1] &&
- this._[2] === v._[2];
- };
-
- /**
- * Physics.vector.axis = Array
- *
- * Read-only axis vectors for general reference.
- *
- * Example:
- *
- * ```javascript
- * Physics.vector.axis[0]; // The x axis unit vector
- * Physics.vector.axis[1]; // The y axis unit vector
- * ```
- **/
- Vector.axis = [
- new Vector(1.0, 0.0),
- new Vector(0.0, 1.0)
- ];
-
- /**
- * Physics.vector.zero = zeroVector
- *
- * Read-only zero vector for reference
- **/
- Vector.zero = new Vector(0, 0);
-
- // assign
- Physics.vector = Vector;
-
-}(this)); // end Vector class
-
-
-// ---
-// inside: src/util/noconflict.js
-
-(function( window ){
-
- var _Physics = window.Physics;
-
- /**
- * Physics.noConflict() -> Physics
- *
- * Restore the original reference to the global window.Physics variable.
- *
- * Does nothing if PhysicsJS doesn't have a reference in global scope
- **/
- Physics.noConflict = function(){
-
- if ( window.Physics === Physics ) {
- window.Physics = _Physics;
- }
-
- return Physics;
- };
-
-})( this );
-
-// ---
-// inside: src/util/decorator.js
-
-/** related to: factory
- * Physics.util.decorator( type [, protoDef ] ) -> Function
- * - type (String): The name of the factory you are creating
- * - protoDef (Object): The top-level prototype
- * + (Function): The factory function
- *
- * Facilitates creation of decorator factory functions.
- *
- * See the [[factory]] definition for the factory signatures.
- * [For full documentation and examples, please visit the wiki](https://github.com/wellcaffeinated/PhysicsJS/wiki/Fundamentals#the-factory-pattern).
- *
- * Example:
- *
- * ```javascript
- * var factory = Physics.util.decorator('factory', {
- * // prototype methods...
- * method: function( args ){
- * }
- * });
- *
- * // define
- * factory( 'name', 'parent-name', function( parent ){
- *
- * // extend further...
- * return {
- * // overrides
- * init: function( cfg ){
- * parent.init.call(this, cfg);
- * }
- * };
- * });
- *
- * // instantiate
- * var options = { key: 'val' };
- * var instance = factory( 'name', options );
- * ```
- **/
-var Decorator = Physics.util.decorator = function Decorator( type, baseProto ){
-
- var registry = {}
- ,proto = {}
- ;
-
- // extend that supports getters/setters
- // only extends functions
- var extend = function extend( to, from ){
- var desc, key;
- for ( key in from ){
- desc = Object.getOwnPropertyDescriptor( from, key );
- if ( desc.get || desc.set ){
-
- Object.defineProperty( to, key, desc );
-
- } else if ( Physics.util.isFunction( desc.value ) ){
-
- to[ key ] = desc.value;
- }
- }
- return to;
- };
-
- // http://ejohn.org/blog/objectgetprototypeof/
- /* jshint -W103 */
- var getProto = Object.getPrototypeOf;
- if ( typeof getProto !== 'function' ) {
- if ( typeof 'test'.__proto__ === 'object' ) {
- getProto = function(object){
- return object.__proto__;
- };
- } else {
- getProto = function(object){
- // May break if the constructor has been tampered with
- return object.constructor.prototype;
- };
- }
- }
- /* jshint +W103 */
-
- var objectCreate = Object.create;
- if (typeof objectCreate !== 'function') {
- objectCreate = function (o) {
- function F() {}
- F.prototype = o;
- return new F();
- };
- }
-
- /*
- * mixin( key, val )
- * mixin( obj )
- * - key (String): The method name
- * - val (Function): The function to assign
- * - obj (Object): object with many `key: fn` pairs
- *
- * Apply mixin methods to decorator base.
- */
- var mixin = function mixin( key, val ){
-
- if ( typeof key === 'object' ){
- proto = extend(proto, key);
- proto.type = type;
- return;
- }
-
- if ( key !== 'type' && Physics.util.isFunction( val ) ){
- proto[ key ] = val;
- }
- };
-
- // @TODO: not sure of the best way to make the constructor names
- // transparent and readable in debug consoles...
- mixin( baseProto );
-
- /** belongs to: Physics.util.decorator
- * factory( name[, parentName], decorator[, cfg] )
- * factory( name, cfg ) -> Object
- * - name (String): The class name
- * - parentName (String): The name of parent class to extend
- * - decorator (Function): The decorator function that should define and return methods to extend (decorate) the base class
- * - cfg (Object): The configuration to pass to the class initializer
- *
- * Factory function for definition and instantiation of subclasses.
- *
- * Use the first signature (once) to define it first.
- * If defining without the "cfg" parameter, void will be returned. Otherwise the class instance will be returned.
- *
- * See [[Physics.util.decorator]] for more information.
- **/
- var factory = function factory( name, parentName, decorator, cfg ){
-
- var instance
- ,result
- ,parent = proto
- ,tmp
- ;
-
- // set parent if specified
- if ( typeof parentName !== 'string' ){
-
- // ... otherwise reassign parameters
- cfg = decorator;
- decorator = parentName;
-
- } else {
-
- // extend the specified module
- parent = registry[ parentName ];
-
- if ( !parent ){
-
- throw 'Error: "' + parentName + '" ' + type + ' not defined';
- }
-
- parent = parent.prototype;
- }
-
- if ( typeof decorator === 'function' ){
-
- result = registry[ name ];
-
- if ( result ){
-
- result.prototype = extend(result.prototype, decorator( getProto(result.prototype) ));
-
- } else {
- // newly defined
- // store the new class
- result = registry[ name ] = function constructor( opts ){
- if (this.init){
- this.init( opts );
- }
- };
-
- result.prototype = objectCreate( parent );
- result.prototype = extend(result.prototype, decorator( parent, result.prototype ));
- }
-
- result.prototype.type = type;
- result.prototype.name = name;
-
- } else {
-
- cfg = decorator || {};
- result = registry[ name ];
- if (!result){
-
- throw 'Error: "' + name + '" ' + type + ' not defined';
- }
- }
-
- if ( cfg ) {
-
- // create a new instance from the provided decorator
- return new result( cfg );
- }
- };
-
- factory.mixin = mixin;
-
- return factory;
-};
-
-
-// ---
-// inside: src/util/helpers.js
-
-/**
- * Physics.util.indexOf( arr, value ) -> Number
- * - arr (Array): The array to search
- * - value (Mixed): The value to find
- * + (Number): The index of `value` in the array OR `-1` if not found
- *
- * Fast indexOf implementation.
- **/
-Physics.util.indexOf = function indexOf(arr, value) {
- var fr = 0, bk = arr.length;
- while (fr < bk) {
- bk--;
- if (arr[ fr ] === value) {
- return fr;
- }
- if (arr[ bk ] === value) {
- return bk;
- }
- fr++;
- }
- return -1;
-};
-
-
-// http://jsperf.com/array-destroy/87
-/**
- * Physics.util.clearArray( arr ) -> Array
- * - arr (Array): The array to clear
- * + (Array): The array passed in
- *
- * Quickly clear an array.
- **/
-Physics.util.clearArray = function clearArray(arr){
- var l = arr.length;
- while( l-- ){
- arr.pop();
- }
- return arr;
-};
-
-/**
- * Physics.util.throttle( fn, delay ) -> Function
- * - fn (Function): The function to throttle
- * - delay (Number): Time in milliseconds
- *
- * Ensure a function is only called once every specified time span.
- **/
-Physics.util.throttle = function throttle( fn, delay, scope ){
- var to
- ,call = false
- ,args
- ,cb = function(){
- clearTimeout( to );
- if ( call ){
- call = false;
- to = setTimeout(cb, delay);
- fn.apply(scope, args);
- } else {
- to = false;
- }
- }
- ;
-
- scope = scope || null;
-
- return function(){
- call = true;
- args = arguments;
- if ( !to ){
- cb();
- }
- };
-};
-
-/**
- * Physics.util.options( def[, target] ) -> Function
- * - def (Object): Default options to set
- * - target (Object): Where to copy the options to. Defaults to the returned function.
- * + (Function): The options function
- *
- * Options helper to keep track of options. Call it with a config object. Access options directly on the function.
- *
- * Example:
- *
- * ```javascript
- * this.options = Physics.util.options({ foo: 'bar', opt: 'def' });
- * this.options({ opt: 'myVal' });
- *
- * this.options.foo; // === 'bar'
- * this.options.def; // === 'myVal'
- *
- * // can also change defaults later
- * this.options.defaults({ foo: 'baz' });
- *
- * // can add a change callback
- * this.options.onChange(function( opts ){
- * // some option changed
- * // opts is the target
- * });
- * ```
- **/
-// deep copy callback to extend deeper into options
-var deepCopyFn = function( a, b ){
-
- if ( Physics.util.isPlainObject( b ) ){
-
- return Physics.util.extend({}, a, b, deepCopyFn );
- }
-
- return b !== undefined ? b : a;
-};
-Physics.util.options = function( def, target ){
-
- var _def = {}
- ,fn
- ,callbacks = []
- ;
-
- // set options
- fn = function fn( options, deep ){
-
- Physics.util.extend(target, options, deep ? deepCopyFn : null);
- for ( var i = 0, l = callbacks.length; i < l; ++i ){
- callbacks[ i ]( target );
- }
- return target;
- };
-
- // add defaults
- fn.defaults = function defaults( def, deep ){
- Physics.util.extend( _def, def, deep ? deepCopyFn : null );
- Physics.util.defaults( target, _def, deep ? deepCopyFn : null );
- return _def;
- };
-
- fn.onChange = function( cb ){
- callbacks.push( cb );
- };
-
- target = target || fn;
-
- fn.defaults( def );
-
- return fn;
-};
-
-/**
- * Physics.util.pairHash( id1, id2 ) -> Number
- * - id1 (Number): The id of the first thing
- * - id2 (Number): The id of the second thing
- * + (Number): A unique numeric hash (valid for values < 2^16)
- *
- * Generate a unique numeric hash from two input IDs.
- *
- * Useful for speedy indexing of pairs.
- **/
-Physics.util.pairHash = function( id1, id2 ){
- id1 = id1|0;
- id2 = id2|0;
-
- if ( (id1|0) === (id2|0) ){
-
- return -1;
- }
-
- // valid for values < 2^16
- return ((id1|0) > (id2|0) ?
- (id1 << 16) | (id2 & 0xFFFF) :
- (id2 << 16) | (id1 & 0xFFFF))|0
- ;
-};
-
-/**
- * Physics.util.bind( fn, scope[, args... ] ) -> Function
- * - fn (Function): The function to bind scope to
- * - scope (Object): The scope to give to `fn`
- * - args (Mixed): Arguments to send to `fn`
- *
- * Bind a scope to a function.
- *
- * Basically the same functionality as [Function.prototype.bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
- **/
-if ( !Function.prototype.bind ){
- Physics.util.bind = function( fn, scope, args ){
- args = Array.prototype.slice.call( arguments, 2 );
- return function(){
- return fn.apply( scope, args.concat( Array.prototype.slice.call(arguments) ) );
- };
- };
-} else {
- Physics.util.bind = function( fn, scope, args ){
- args = Array.prototype.slice.call( arguments, 1 );
- return Function.prototype.bind.apply( fn, args );
- };
-}
-
-/**
- * Physics.util.find( collection, fn( value, index, collection ) ) -> Mixed
- * - collection (Array): Collection of values to test
- * - fn (Function): The test function
- * - value (Mixed): The value to test
- * - index (Number): The index of value in collection
- * - collection (Array): The input collection
- *
- * Test an array of values against a test function
- * and return the first value for which the function
- * returns true.
- **/
-Physics.util.find = function( collection, fn ){
- var i
- ,l = collection.length
- ,val
- ;
-
- for ( i = 0; i < l; i++ ){
- val = collection[ i ];
- if ( fn( val, i, collection ) ){
- return val;
- }
- }
-};
-
-/**
- * Physics.util.filter( collection, fn( value, index, collection ) ) -> Array
- * - collection (Array): Collection of values to test
- * - fn (Function): The test function
- * - value (Mixed): The value to test
- * - index (Number): The index of value in collection
- * - collection (Array): The input collection
- *
- * Test an array of values against a test function
- * and return another array of values for which
- * the test function returns true.
- **/
-Physics.util.filter = function( collection, fn ){
- var i
- ,l = collection.length
- ,val
- ,matches = []
- ;
-
- for ( i = 0; i < l; i++ ){
- val = collection[ i ];
- if ( fn( val, i, collection ) ){
- matches.push( val );
- }
- }
-
- return matches;
-};
-
-// lodash methods
-
-(function(){
-/*
- * @license
- * Modified version of:
- * Lo-Dash 2.4.1 (Custom Build)
- * Copyright 2012-2013 The Dojo Foundation
- * Based on Underscore.js 1.5.2
- * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license
- */
-
-/* Used to determine if values are of the language type Object */
-var objectTypes = {
- 'boolean': false,
- 'function': true,
- 'object': true,
- 'number': false,
- 'string': false,
- 'undefined': false
-};
-var identity = function(a){ return a; };
-var arrayClass = '[object Array]';
-var objectClass = '[object Object]';
-var nativeKeys = Object.keys;
-var toString = Object.prototype.toString;
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-/* Used as the size when optimizations are enabled for large arrays */
-var largeArraySize = 75;
-/* Used to pool arrays and objects used internally */
-var arrayPool = [],
- objectPool = [];
-/* Used as the max size of the `arrayPool` and `objectPool` */
-var maxPoolSize = 40;
-var keyPrefix = +new Date() + '';
-
-function releaseArray(array) {
- Physics.util.clearArray( array );
- if (arrayPool.length < maxPoolSize) {
- arrayPool.push(array);
- }
-}
-
-function releaseObject(object) {
- var cache = object.cache;
- if (cache) {
- releaseObject(cache);
- }
- object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
- if (objectPool.length < maxPoolSize) {
- objectPool.push(object);
- }
-}
-
-function getObject() {
- return objectPool.pop() || {
- 'array': null,
- 'cache': null,
- 'criteria': null,
- 'false': false,
- 'index': 0,
- 'null': false,
- 'number': null,
- 'object': null,
- 'push': null,
- 'string': null,
- 'true': false,
- 'undefined': false,
- 'value': null
- };
-}
-
-function getArray() {
- return arrayPool.pop() || [];
-}
-
-function cacheIndexOf(cache, value) {
- var type = typeof value;
- cache = cache.cache;
-
- if (type === 'boolean' || value == null) {
- return cache[value] ? 0 : -1;
- }
- if (type !== 'number' && type !== 'string') {
- type = 'object';
- }
- var key = type === 'number' ? value : keyPrefix + value;
- cache = (cache = cache[type]) && cache[key];
-
- return type === 'object' ?
- (cache && Physics.util.indexOf(cache, value) > -1 ? 0 : -1) :
- (cache ? 0 : -1);
-}
-
-function cachePush(value) {
- var cache = this.cache,
- type = typeof value;
-
- if (type === 'boolean' || value == null) {
- cache[value] = true;
- } else {
- if (type !== 'number' && type !== 'string') {
- type = 'object';
- }
- var key = type === 'number' ? value : keyPrefix + value,
- typeCache = cache[type] || (cache[type] = {});
-
- if (type === 'object') {
- (typeCache[key] || (typeCache[key] = [])).push(value);
- } else {
- typeCache[key] = true;
- }
- }
-}
-
-function createCache(array) {
- var index = -1,
- length = array.length,
- first = array[0],
- mid = array[(length / 2) | 0],
- last = array[length - 1];
-
- if (first && typeof first === 'object' &&
- mid && typeof mid === 'object' && last && typeof last === 'object') {
- return false;
- }
- var cache = getObject();
- cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
-
- var result = getObject();
- result.array = array;
- result.cache = cache;
- result.push = cachePush;
-
- while (++index < length) {
- result.push(array[index]);
- }
- return result;
-}
-
-var shimKeys = function(object) {
- var index, iterable = object, result = [];
- if (!iterable){ return result; }
- if (!(objectTypes[typeof object])){ return result; }
- for (index in iterable) {
- if (hasOwnProperty.call(iterable, index)) {
- result.push(index);
- }
- }
- return result;
-};
-
-var keys = !nativeKeys ? shimKeys : function(object) {
- if (!Physics.util.isObject(object)) {
- return [];
- }
- return nativeKeys(object);
-};
-
-var idCounter = 0;
-/**
- * Physics.util.uniqueId( [prefix] ) -> String
- * - prefix (String): Prefix to the id
- *
- * Generate a unique id, optionally prefixed.
- **/
-Physics.util.uniqueId = function uniqueId(prefix) {
- var id = ++idCounter;
- return '' + (prefix || '') + id;
-};
-
-/*
- * The base implementation of `_.random` without argument juggling or support
- * for returning floating-point numbers.
- *
- * @private
- * @param {number} min The minimum possible value.
- * @param {number} max The maximum possible value.
- * @returns {number} Returns a random number.
- */
-function baseRandom(min, max) {
- return min + Math.floor(Math.random() * (max - min + 1));
-}
-
-/*
- * Creates an array of shuffled values, using a version of the Fisher-Yates
- * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
- *
- * @static
- * @memberOf _
- * @category Collections
- * @param {Array|Object|string} collection The collection to shuffle.
- * @returns {Array} Returns a new shuffled collection.
- * @example
- *
- * _.shuffle([1, 2, 3, 4, 5, 6]);
- * // => [4, 1, 6, 3, 5, 2]
- */
-Physics.util.shuffle = function(collection) {
- var index = -1
- ,length = collection ? collection.length : 0
- ,result = Array(typeof length === 'number' ? length : 0)
- ,i
- ,l
- ,value
- ,rand
- ;
-
- for ( i = 0, l = collection.length; i < l; i++ ){
- value = collection[ i ];
- rand = baseRandom(0, ++index);
- result[index] = result[rand];
- result[rand] = value;
- }
- return result;
-};
-
-/**
- * Physics.util.isObject( val ) -> Boolean
- * - val (Mixed): The value to test
- *
- * Test if a value is an object.
- **/
-Physics.util.isObject = function isObject(value) {
- // check if the value is the ECMAScript language type of Object
- // http://es5.github.io/#x8
- // and avoid a V8 bug
- // http://code.google.com/p/v8/issues/detail?id=2291
- return !!(value && objectTypes[typeof value]);
-};
-
-function isFunction(value) {
- return typeof value === 'function';
-}
-
-/**
- * Physics.util.isFunction( val ) -> Boolean
- * - val (Mixed): The value to test
- *
- * Test if a value is a function.
- **/
-Physics.util.isFunction = isFunction;
-
-/**
- * Physics.util.isArray( val ) -> Boolean
- * - val (Mixed): The value to test
- *
- * Test if a value is an array.
- **/
-Physics.util.isArray = Array.isArray || function(value) {
- return value && typeof value === 'object' && typeof value.length === 'number' &&
- toString.call(value) === arrayClass || false;
-};
-
-var reNative = RegExp('^' +
- String(toString)
- .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
- .replace(/toString| for [^\]]+/g, '.*?') + '$'
-);
-function isNative(value) {
- return typeof value === 'function' && reNative.test(value);
-}
-
-function shimIsPlainObject(value) {
- var ctor,
- result;
-
- // avoid non Object objects, `arguments` objects, and DOM elements
- if (!(value && toString.call(value) === objectClass) ||
- (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
- return false;
- }
- // In most environments an object's own properties are iterated before
- // its inherited properties. If the last iterated property is an object's
- // own property then there are no inherited enumerable properties.
- for (var key in value){
- result = key;
- }
- return typeof result === 'undefined' || hasOwnProperty.call(value, result);
-}
-
-/**
- * Physics.util.isPlainObject( val ) -> Boolean
- * - val (Mixed): The value to test
- *
- * Test if a value is a plain javascript object.
- **/
-Physics.util.isPlainObject = !Object.getPrototypeOf ? shimIsPlainObject : function(value) {
- if (!(value && toString.call(value) === objectClass)) {
- return false;
- }
- var valueOf = value.valueOf,
- objProto = isNative(valueOf) && (objProto = Object.getPrototypeOf(valueOf)) && Object.getPrototypeOf(objProto);
-
- return objProto ?
- (value === objProto || Object.getPrototypeOf(value) === objProto) :
- shimIsPlainObject(value);
-};
-
-function baseUniq(array, isSorted, callback) {
- var index = -1,
- indexOf = Physics.util.indexOf,
- length = array ? array.length : 0,
- result = [];
-
- var isLarge = !isSorted && length >= largeArraySize && indexOf === Physics.util.indexOf,
- seen = (callback || isLarge) ? getArray() : result;
-
- if (isLarge) {
- var cache = createCache(seen);
- indexOf = cacheIndexOf;
- seen = cache;
- }
- while (++index < length) {
- var value = array[index],
- computed = callback ? callback(value, index, array) : value;
-
- if (isSorted ?
- !index || seen[seen.length - 1] !== computed :
- indexOf(seen, computed) < 0
- ) {
- if (callback || isLarge) {
- seen.push(computed);
- }
- result.push(value);
- }
- }
- if (isLarge) {
- releaseArray(seen.array);
- releaseObject(seen);
- } else if (callback) {
- releaseArray(seen);
- }
- return result;
-}
-
-/**
- * Physics.util.uniq( array, [isSorted, callback] ) -> Array
- * - array (Array): The array
- * - isSorted (Boolean): Flag to indicate the array is sorted
- * - callback (Function): Mapping function
- *
- * Create an array without duplicates.
- **/
-Physics.util.uniq = function uniq(array, isSorted, callback) {
- // juggle arguments
- if (typeof isSorted !== 'boolean' && isSorted != null) {
- callback = isSorted;
- isSorted = false;
- }
- return baseUniq(array, isSorted, callback);
-};
-
-var assign = function(object, source, guard) {
- var index, iterable = object, result = iterable;
- if (!iterable) { return result; }
- var args = arguments,
- argsIndex = 0,
- callback,
- argsLength = typeof guard === 'number' ? 2 : args.length;
- if (argsLength > 2 && typeof args[argsLength - 1] === 'function') {
- callback = args[--argsLength];
- }
- while (++argsIndex < argsLength) {
- iterable = args[argsIndex];
- if (iterable && objectTypes[typeof iterable]) {
- var ownIndex = -1,
- ownProps = objectTypes[typeof iterable] && keys(iterable),
- length = ownProps ? ownProps.length : 0;
-
- while (++ownIndex < length) {
- index = ownProps[ownIndex];
- result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
- }
- }
- }
- return result;
-};
-
-/**
- * Physics.util.extend( object, source...[, callback] ) -> Object
- * - object (Object): The destination object
- * - source (Object): The source objects
- * - callback (Function): The function to customize assigning values
- *
- * Implementation of [lodash.extend](http://lodash.com/docs#assign)
- **/
-Physics.util.extend = assign;
-
-/**
- * Physics.util.defaults( object, source...[, callback] ) -> Object
- * - object (Object): The destination object
- * - source (Object): The source objects
- * - callback (Function): The function to customize assigning values
- *
- * Implementation of [lodash.defaults](http://lodash.com/docs#defaults).
- **/
-Physics.util.defaults = function(object, source, guard) {
- var index, iterable = object, result = iterable;
- if (!iterable){ return result; }
- var args = arguments,
- argsIndex = 0,
- argsLength = typeof guard === 'number' ? 2 : args.length;
- while (++argsIndex < argsLength) {
- iterable = args[argsIndex];
- if (iterable && objectTypes[typeof iterable]) {
- var ownIndex = -1,
- ownProps = objectTypes[typeof iterable] && keys(iterable),
- length = ownProps ? ownProps.length : 0;
-
- while (++ownIndex < length) {
- index = ownProps[ownIndex];
- if (typeof result[index] === 'undefined') {
- result[index] = iterable[index];
- }
- }
- }
- }
- return result;
-};
-
-/**
- * Physics.util.sortedIndex( array, value[, callback] ) -> Number
- * - array (Array): The array to inspect
- * - value (Mixed): The value to evaluate
- * - callback (Function): Function called per iteration
- *
- * Implementation of [lodash.sortedIndex](http://lodash.com/docs#sortedIndex).
- **/
-Physics.util.sortedIndex = function sortedIndex(array, value, callback) {
- var low = 0,
- high = array ? array.length : low;
-
- // explicitly reference `identity` for better inlining in Firefox
- callback = callback || identity;
- value = callback(value);
-
- /* jshint -W030 */
- while (low < high) {
- var mid = (low + high) >>> 1;
- (callback(array[mid]) < value) ?
- low = mid + 1 :
- high = mid;
- }
- /* jshint +W030 */
- return low;
-};
-
-})();
-
-
-// ---
-// inside: src/util/scratchpad.js
-
-/*
- * scratchpad
- * thread-safe management of temporary (voletile)
- * objects for use in calculations
- * https://github.com/wellcaffeinated/scratchpad.js
- */
-Physics.scratchpad = (function(){
-
- // Errors
- var SCRATCH_USAGE_ERROR = 'Error: Scratchpad used after .done() called. (Could it be unintentionally scoped?)';
- var SCRATCH_INDEX_OUT_OF_BOUNDS = 'Error: Scratchpad usage space out of bounds. (Did you forget to call .done()?)';
- var SCRATCH_MAX_REACHED = 'Error: Too many scratchpads created. (Did you forget to call .done()?)';
- var ALREADY_DEFINED_ERROR = 'Error: Object is already registered.';
-
- // cache previously created scratches
- var scratches = [];
- var numScratches = 0;
- var Scratch, Scratchpad;
-
- var regIndex = 0;
-
-
- /** belongs to: Physics.scratchpad
- * class Scratch
- *
- * A scratchpad session.
- *
- * This class keeps track of temporary objects used
- * in this session and releases them when finished (call to `.done()`).
- *
- * Use this to retrieve temporary objects:
- * - `.vector()`: retrieve a temporary [[Physics.vector]]
- * - `.transform()`: retrieve a temporary [[Physics.transform]]
- *
- * See [[Physics.scratchpad]] for more info.
- **/
- Scratch = function Scratch(){
-
- // private variables
- this._active = false;
- this._indexArr = [];
-
- if (++numScratches >= Scratchpad.maxScratches){
- throw SCRATCH_MAX_REACHED;
- }
- };
-
- Scratch.prototype = {
-
- /**
- * Scratch#done( [val] ) -> Mixed
- * - val (Mixed): No effect on this method, just passed on to the return value so you can do things like:
- return scratch.done( myReturnVal );
- * + (Mixed): Whatever you specified as `val`
- *
- * Declare that your work is finished.
- *
- * Release temp objects for use elsewhere. Must be called when immediate work is done.
- *
- * You can wrap the return value in scratch.done() so that you don't forget to call it.
- *
- * Example:
- *
- * ```javascript
- * return scratch.done( myReturnValue );
- * ```
- **/
- done: function( val ){
-
- this._active = false;
- var s;
- for ( var i = 0; i < regIndex; ++i ){
-
- this[ i ] = 0;
- }
-
- // add it back to the scratch stack for future use
- scratches.push( this );
- return val;
- }
- };
-
-
- // API
-
- /**
- * Physics.scratchpad( [fn] ) -> Scratch|Function
- * - fn (Function): Some function you'd like to wrap in a scratch session. First argument is the scratch instance.
- * + (Function): The wrapped function (if `fn` arg specified) that can be reused like the original minus the first (scratch) parameter.
- * + (Scratch): The scratch session.
- *
- * Get a new scratch session to work from or wrap a function in a scratch session.
- *
- * Call `.done()` on it when finished.
- *
- * Example:
- *
- * ```javascript
- * // get a scratch session manually
- * var myAlg = function( scratch, arg1, arg2, ... ){
- * var scratch = Physics.scratchpad()
- * ,vec = scratch.vector().set( 0, 0 ) // need to reinitialize... it's recycled!
- * ;
- * // ...
- * return scratch.done( result );
- * };
- * // later...
- * while( awesome ){
- * myAlg( arg1, arg2, ... );
- * }
- * ```
- *
- * Example:
- *
- * ```javascript
- * // wrap a function in a scratch session
- * var myAlg = Physics.scratchpad(function( scratch, arg1, arg2, ... ){
- * var vec = scratch.vector().set( 0, 0 ); // need to reinitialize... it's recycled!
- * //...
- * return result;
- * });
- * // later...
- * while( awesome ){
- * myAlg( arg1, arg2, ... );
- * }
- * ```
- **/
- Scratchpad = function Scratchpad( fn ){
-
- if ( fn ){
- return Scratchpad.fn( fn );
- }
-
- var scratch = scratches.pop() || new Scratch();
- scratch._active = true;
- return scratch;
- };
-
- // options
- Scratchpad.maxScratches = 100; // maximum number of scratches
- Scratchpad.maxIndex = 20; // maximum number of any type of temp objects
-
- /**
- * Physics.scratchpad.fn( fn ) -> Function
- * - fn (Function): Some function you'd like to wrap in a scratch session. First argument is the scratch instance. See [[Physics.scratchpad]].
- * + (Function): The wrapped function that can be reused like the original minus the first (scratch) parameter.
- *
- * Wrap a function in a scratch session.
- *
- * Same as calling `Physics.scratchpad( fn )` with a function specified.
- **/
- Scratchpad.fn = function( fn ){
-
- var args = [];
- for ( var i = 0, l = fn.length; i < l; i++ ){
- args.push( i );
- }
-
- args = 'a' + args.join(',a');
- /* jshint -W054 */
- var handle = new Function('fn, scratches, Scratch', 'return function('+args+'){ '+
- 'var scratch = scratches.pop() || new Scratch( scratches );'+
- 'scratch._active = true;'+
- 'return scratch.done( fn(scratch, '+args+') );'+
- '};'
- );
- /* jshint +W054 */
-
- return handle(fn, scratches, Scratch);
- };
-
- /**
- * Physics.scratchpad.register( name, constructor )
- * - name (String): Name of the object class
- * - constructor (Function): The object constructor
- *
- * Register a new object to be included in scratchpads.
- *
- * Example:
- *
- * ```javascript
- * // register a hypothetical vector class...
- * Physics.scratchpad.register('vector', Vector);
- * ```
- **/
- Scratchpad.register = function register( name, constructor, options ){
-
- var proto = Scratch.prototype
- ,idx = regIndex++ // increase the scratch type index
- ,stackname = '_' + name + 'Stack' // the name of the array stack
- ,useFactory = options && options.useFactory
- ;
-
- if ( name in proto ) {
- throw ALREADY_DEFINED_ERROR;
- }
-
- // create a new function on the prototype
- Scratch.prototype[ name ] = function(){
-
- // get the stack (or initialize it)
- var stack = this[ stackname ] || (this[ stackname ] = [])
- // we increase this index every time a voletile object is requested
- // seems weird to store it on this as a number (ie: this.0, this.1)...
- // but actually it's faster...
- ,stackIndex = this[ idx ] | 0
- ;
-
- this[ idx ] = stackIndex + 1;
-
- // if used after calling done...
- if (!this._active){
- throw SCRATCH_USAGE_ERROR;
- }
-
- // if too many objects created...
- if (stackIndex >= Scratchpad.maxIndex){
- throw SCRATCH_INDEX_OUT_OF_BOUNDS;
- }
-
- // return or create new instance
- return stack[ stackIndex ] ||
- (stack[ stackIndex ] = useFactory ? constructor() : new constructor() );
- };
-
- };
-
- // register some classes
- Scratchpad.register('vector', Physics.vector);
- Scratchpad.register('transform', Physics.transform);
-
- return Scratchpad;
-
-})();
-
-
-// ---
-// inside: src/util/pubsub.js
-
-(function(){
-
- var defaultPriority = 1;
-
- function getPriority( val ){
- return val._priority_;
- }
-
- // register a new scratch object so we can reuse event data
- Physics.scratchpad.register('event', function(){ return {}; }, { useFactory: true });
-
- /**
- * class Physics.util.pubsub
- *
- * Fast pubsub implementation.
- *
- * Can be mixed into other classes easily.
- **/
- var PubSub = function PubSub(){
-
- if (!(this instanceof PubSub)){
- return new PubSub();
- }
- };
-
- PubSub.prototype = {
-
- /**
- * Physics.util.pubsub#on( topic, fn( data, event )[, scope, priority] ) -> this
- * Physics.util.pubsub#on( topicConfig[, scope, priority] ) -> this
- * - topic (String): The topic name
- * - topicConfig (Object): A config with key/value pairs of `{ topic: callbackFn, ... }`
- * - fn (Function): The callback function (if not using Object as previous argument)
- * - data (Mixed): The data sent from the call to `.emit()`
- * - event (Object): Event data, holding `.topic`, the topic, and `.handler`, the `fn` callback.
- * - scope (Object): The scope to bind callback to
- * - priority (Number): The priority of the callback (higher is earlier)
- *
- * Subscribe callback(s) to a topic(s).
- **/
- on: function( topic, fn, scope, priority ){
-
- var listeners
- ,orig
- ,idx
- ;
-
- // ensure topics hash is initialized
- this._topics = this._topics || (this._topics = {});
-
- // check if we're subscribing to multiple topics
- // with an object
- if ( Physics.util.isObject( topic ) ){
-
- for ( var t in topic ){
-
- this.on( t, topic[ t ], fn, scope );
- }
-
- return this;
- }
-
- listeners = this._topics[ topic ] || (this._topics[ topic ] = []);
- orig = fn;
-
- if ( Physics.util.isObject( scope ) ){
-
- fn = Physics.util.bind( fn, scope );
- fn._bindfn_ = orig;
- fn._one_ = orig._one_;
- fn._scope_ = scope;
-
- } else if ( priority === undefined ) {
-
- priority = scope;
- }
-
- fn._priority_ = priority === undefined ? defaultPriority : priority;
-
- idx = Physics.util.sortedIndex( listeners, fn, getPriority );
-
- listeners.splice( idx, 0, fn );
- return this;
- },
-
- /**
- * Physics.util.pubsub#off( topic, fn[, scope] ) -> this
- * Physics.util.pubsub#off( topicCfg ) -> this
- * - topic (String): topic The topic name. Specify `true` to remove all listeners for all topics
- * - topicCfg (Object): A config with key/value pairs of `{ topic: callbackFn, ... }`
- * - fn (Function): The original callback function. Specify `true` to remove all listeners for specified topic
- * - scope (Object): The scope the callback was bound to. This is important if you are binding methods that come from object prototypes.
- *
- * Unsubscribe callback(s) from topic(s).
- **/
- off: function( topic, fn, scope ){
-
- var listeners
- ,listn
- ;
-
- if ( !this._topics ){
- // nothing subscribed
- return this;
- }
-
- if ( topic === true ){
- // purge all listeners
- this._topics = {};
- return this;
- }
-
- // check if we're subscribing to multiple topics
- // with an object
- if ( Physics.util.isObject( topic ) ){
-
- for ( var t in topic ){
-
- this.off( t, topic[ t ] );
- }
-
- return this;
- }
-
- listeners = this._topics[ topic ];
-
- if (!listeners){
- return this;
- }
-
- if ( fn === true ){
- // purge all listeners for topic
- this._topics[ topic ] = [];
- return this;
- }
-
- for ( var i = 0, l = listeners.length; i < l; i++ ){
-
- listn = listeners[ i ];
-
- if (
- (listn._bindfn_ === fn || listn === fn) &&
- ( (!scope) || listn._scope_ === scope) // check the scope too if specified
- ){
- listeners.splice( i, 1 );
- break;
- }
- }
-
- return this;
- },
-
- /**
- * Physics.util.pubsub#emit( topic[, data] ) -> this
- * - topic (String): The topic name
- * - data (Mixed): The data to send
- *
- * Publish data to a topic.
- **/
- emit: function( topic, data ){
-
- if ( !this._topics ){
- // nothing subscribed
- return this;
- }
-
- var listeners = this._topics[ topic ]
- ,l = listeners && listeners.length
- ,handler
- ,e
- ,scratch = Physics.scratchpad()
- ;
-
- if ( !l ){
- return scratch.done(this);
- }
-
- e = scratch.event();
- // event data
- e.topic = topic;
- e.handler = handler;
-
- // reverse iterate so priorities work out correctly
- while ( l-- ){
-
- handler = listeners[ l ];
- handler( data, e );
-
- // if _one_ flag is set, the unsubscribe
- if ( handler._one_ ){
- listeners.splice( l, 1 );
- }
- }
-
- return scratch.done(this);
- },
-
- /**
- * Physics.util.pubsub#one( topic, fn( data, event )[, scope, priority] ) -> this
- * Physics.util.pubsub#one( topicConfig[, scope, priority] ) -> this
- * - topic (String): The topic name
- * - topicConfig (Object): A config with key/value pairs of `{ topic: callbackFn, ... }`
- * - fn (Function): The callback function (if not using Object as previous argument)
- * - data (Mixed): The data sent from the call to `.emit()`
- * - event (Object): Event data, holding `.topic`, the topic, and `.handler`, the `fn` callback.
- * - scope (Object): The scope to bind callback to
- * - priority (Number): The priority of the callback (higher is earlier)
- *
- * Subscribe callback(s) to a topic(s), but only ONCE.
- **/
- one: function( topic, fn, scope ){
-
- // check if we're subscribing to multiple topics
- // with an object
- if ( Physics.util.isObject( topic ) ){
-
- for ( var t in topic ){
-
- this.one( t, topic[ t ], fn, scope );
- }
-
- return this;
- }
-
- // set the _one_ flag
- fn._one_ = true;
- this.on( topic, fn, scope );
-
- return this;
- }
- };
-
- Physics.util.pubsub = PubSub;
-})();
-
-
-// ---
-// inside: src/util/ticker.js
-
-/**
- * class Physics.util.ticker
- *
- * The Ticker _singleton_ for easily binding callbacks to animation loops (requestAnimationFrame).
- *
- * Requires window.requestAnimationFrame... so polyfill it if you need to.
- **/
-(function(window){
-
- var active = true
- ,ps = Physics.util.pubsub()
- ,perf = window.performance
- ;
-
- function now(){
- // http://updates.html5rocks.com/2012/05/requestAnimationFrame-API-now-with-sub-millisecond-precision
- return (perf && perf.now) ?
- (perf.now() + perf.timing.navigationStart) :
- Date.now();
- }
-
- /*
- * step( time )
- * - time (Number): The current time
- *
- * Publish a tick to subscribed callbacks
- */
- function step(){
-
- var time;
-
- window.requestAnimationFrame( step );
-
- if (!active){
- return;
- }
-
- time = now();
-
- if (!time){
- return;
- }
-
- ps.emit( 'tick', time );
- }
-
- // start stepping if we can
- if ( window.requestAnimationFrame ){
- step();
- } else {
- active = false;
- }
-
- /**
- * Physics.util.ticker.start() -> this
- *
- * Start the ticker
- **/
- function start(){
-
- active = true;
- return this;
- }
-
- /**
- * Physics.util.ticker.stop() -> this
- *
- * Stop the ticker
- **/
- function stop(){
-
- active = false;
- return this;
- }
-
- /**
- * Physics.util.ticker.on( listener( time ) ) -> this
- * - listener (Function): The callback function
- * - time (Number): The current timestamp
- *
- * Subscribe a callback to the ticker.
- **/
- function on( listener ){
-
- ps.on('tick', listener);
- return this;
- }
-
- /**
- * Physics.util.ticker.off( listener ) -> this
- * - listener (Function): The callback function previously bound
- *
- * Unsubscribe a callback from the ticker.
- **/
- function off( listener ){
-
- ps.off('tick', listener);
- return this;
- }
-
- /**
- * Physics.util.ticker.isActive() -> Boolean
- * + (Boolean): `true` if running, `false` otherwise.
- *
- * Determine if ticker is currently running.
- **/
- function isActive(){
-
- return !!active;
- }
-
- // API
- Physics.util.ticker = {
- now: now,
- start: start,
- stop: stop,
- on: on,
- off: off,
- isActive: isActive
- };
-
-}(this));
-
-
-// ---
-// inside: src/core/query.js
-
-(function (window) {
-
- /*
- * Group helpers
- */
- var fnTrue = function(){ return !0; }; // return true
-
- var indexOf = Physics.util.indexOf;
-
- /** hide
- * wrapRule( fn( propVal ), prop ) -> Function
- * - fn (Function): The test function
- * - prop (String): The property name to test
- * - propVal (Mixed): The property value
- *
- * Get test function to test on sub property.
- **/
- var wrapRule = function wrapRule( fn, prop ){
- return function( thing ){
- return fn( thing[ prop ] );
- };
- };
-
- /** hide
- * $eq( toMatch[, prop] ) -> Function
- * - toMatch (Mixed): The value to match
- * - prop (String): The property name to test
- *
- * Get an equality test function.
- **/
- var $eq = function $eq( toMatch, prop ){
- return function( thing ){
-
- thing = prop ? thing[ prop ] : thing;
-
- var fr = 0
- ,bk
- ;
-
- if ( Physics.util.isArray( thing ) ){
-
- if ( Physics.util.isArray( toMatch ) ){
- // match all
- bk = thing.length;
-
- // check lengths
- if ( bk !== toMatch.length ){
- return false;
- }
-
- while ( fr < bk ){
- bk--;
- if (
- // check front
- (indexOf(toMatch, thing[ fr ]) === -1) ||
- // check back
- (indexOf(toMatch, thing[ bk ]) === -1)
- ) {
- return false;
- }
- fr++;
- }
- return true;
- } else {
- // find in array
- return (indexOf( thing, toMatch ) > -1);
- }
- }
-
- // exact match
- return (thing === toMatch);
- };
- };
-
- /** hide
- * $ne( toMatch[, prop] ) -> Function
- * - toMatch (Mixed): The value to match
- * - prop (String): The property name to test
- *
- * Get a NOT equality test function.
- **/
- var $ne = function $ne( toMatch, prop ){
- var fn = $eq( toMatch, prop );
- return function( thing ){
- return !fn( thing );
- };
- };
-
- /** hide
- * $in( toMatch[, prop] ) -> Function
- * - toMatch (Array): The array to match
- * - prop (String): The property name to test
- *
- * Get a test function for matching ANY in array
- **/
- var $in = function $in( toMatch, prop ){
- return function( thing ){
-
- thing = prop ? thing[ prop ] : thing;
-
- var fr = 0
- ,bk
- ;
-
- if ( Physics.util.isArray( thing ) ){
- bk = thing.length;
-
- while( fr < bk ){
- bk--;
- if (
- // check front
- (indexOf(toMatch, thing[ fr ]) > -1) ||
- // check back
- (indexOf(toMatch, thing[ bk ]) > -1)
- ) {
- return true;
- }
- fr++;
- }
- return false;
- }
-
- // if thing matches any in array
- return (indexOf(toMatch, thing) > -1);
- };
- };
-
- /** hide
- * $nin( toMatch[, prop] ) -> Function
- * - toMatch (Array): The array to match
- * - prop (String): The property name to test
- *
- * Get a test function for matching NOT ANY in array
- **/
- var $nin = function $nin( toMatch, prop ){
- var fn = $in( toMatch, prop );
- return function( thing ){
- return !fn( thing );
- };
- };
-
- /** hide
- * $at( point ) -> Function
- * - point (Vectorish): The point to check
- *
- * Get a test function to match any body who's aabb intersects point
- **/
- var $at = function $at( point ){
- point = new Physics.vector( point );
- return function( body ){
- var aabb = body.aabb();
- return Physics.aabb.contains( aabb, point );
- };
- };
-
- /** hide
- * $and( first ) -> Function
- * - first (Function): First function node. `first.next` should have the next function, and so on.
- *
- * Get an AND test function.
- **/
- var $and = function $and( first ){
- return first.next ? function( thing ){
- var fn = first;
- while ( fn ){
-
- if ( !fn( thing ) ){
- return false;
- }
- fn = fn.next;
- }
- return true;
- } : first;
- };
-
- /** hide
- * $or( first ) -> Function
- * - first (Function): First function node. `first.next` should have the next function, and so on.
- *
- * Get an OR test function.
- **/
- var $or = function $or( first ){
- return first.next ? function( thing ){
- var fn = first;
- while ( fn ){
-
- if ( fn( thing ) ){
- return true;
- }
- fn = fn.next;
- }
- return false;
- } : first;
- };
-
- // operation hash
- var operations = {
- // $and and $or are separate
- $eq: $eq
- ,$ne: $ne
- ,$in: $in
- ,$nin: $nin
- ,$at: $at
- };
-
- /** related to: Physics.world#find
- * Physics.query( rules ) -> Function
- * - rules (Object): The mongodb-like search rules. (See description).
- * + (Function): The test function
- *
- * Creates a function that can be used to perform tests on objects.
- *
- * The test function will return a [[Boolean]]; `true` if the object matches the tests.
- *
- * Query rules are mongodb-like. You can specify a hash of values to match like this:
- *
- * ```javascript
- * {
- * foo: 'bar',
- * baz: 2,
- * some: {
- * nested: 'value'
- * }
- * }
- * ```
- *
- * And they will all need to match (it's an AND rule).
- *
- * You can also use operators for more versatility. The operators you can use include:
- *
- * - $eq: Test if some property is equal to a value (this is done by default, and is thus redundant)
- * - $ne: Test if some property is _NOT_ equal to a value
- * - $in: Test if some value (or array of values) is one of the specified array of values
- * - $nin: Test if some value (or array of values) is _NOT_ one of the specified array of values
- * - $at: Test if a body's [[Physics.aabb]] includes specified point. It's a primative hit-test.
- *
- * Example:
- *
- * ```javascript
- * var wheelsArray = [];
- *
- * var queryFn = Physics.query({
- * name: 'circle', // only circles
- * $nin: wheelsArray, // not in the wheelsArray
- * labels: { $in: [ 'player', 'monster' ] } // that have player OR monster labels
- * });
- *
- * var obj = {
- * name: 'circle',
- * labels: [ 'round' ]
- * };
- *
- * queryFn( obj ); // -> false
- * // give it a player tag
- * obj.labels.push('player');
- * queryFn( obj ); // -> true
- * // put it inside the wheelsArray
- * wheelsArray.push( obj );
- * queryFn( obj ); // -> false
- * ```
- **/
- var Query = function Query( rules, /* internal use */ $op ){
-
- var op
- ,l
- ,rule
- ,first
- ,list
- ,fn
- ;
-
- if ( $op ){
-
- // parse operation choice
- if ( $op === '$or' || $op === '$and' ){
-
- // expect a rules array
- for ( op = 0, l = rules.length; op < l; ++op ){
-
- fn = Query( rules[ op ] );
- // if first hasn't been set yet, set it and start the list there
- // otherwise set the next node of the list
- list = list ? list.next = fn : first = fn;
- }
-
- return ($op === '$or') ? $or( first ) : $and( first );
- } else if ( op = operations[ $op ] ){
-
- return op( rules );
-
- } else {
- // does not compute...
- throw 'Unknown query operation: ' + $op;
- }
- }
-
- // loop through rules
- for ( op in rules ){
- rule = rules[ op ];
-
- if ( op[0] === '$' ){
- // it's an operation rule
- fn = Query( rule, op );
-
- } else if ( Physics.util.isPlainObject( rule ) ) {
- // it's an object so parse subrules
- fn = wrapRule( Query( rule ), op );
- } else {
- // simple equality rule
- fn = $eq( rule, op );
- }
-
- // if first hasn't been set yet, set it and start the list there
- // otherwise set the next node of the list
- list = list ? list.next = fn : first = fn;
- }
-
- // return the rules test
- return $and( first || fnTrue );
- };
-
- Physics.query = Query;
-
-})(this);
-
-
-// ---
-// inside: src/core/behavior.js
-
-(function(){
-
- var defaults = {
- priority: 0
- };
-
- /** related to: Physics.util.decorator
- * Physics.behavior( name[, options] ) -> Behavior
- * - name (String): The name of the behavior to create
- * - options (Object): The configuration for that behavior ( depends on behavior ).
- Available options and defaults:
-
- ```javascript
- {
- priority: 0 // the priority of this body
- }
- ```
- *
- * Factory function for creating Behaviors.
- *
- * Visit [the PhysicsJS wiki on Behaviors](https://github.com/wellcaffeinated/PhysicsJS/wiki/Behaviors)
- * for usage documentation.
- **/
- Physics.behavior = Decorator('behavior', {
-
- /** belongs to: Physics.behavior
- * class Behavior
- *
- * The base class for behaviors created by [[Physics.behavior]] factory function.
- **/
-
- /** internal
- * Behavior#init( options )
- * - options (Object): The configuration options passed by the factory
- *
- * Initialization. Internal use.
- **/
- init: function( options ){
-
- /** related to: Physics.util.options
- * Behavior#options( options ) -> Object
- * - options (Object): The options to set as an object
- * + (Object): The options
- *
- * Set options on this instance.
- *
- * Access options directly from the options object.
- *
- * Example:
- *
- * ```javascript
- * this.options.someOption;
- * ```
- *
- **/
- this.options = Physics.util.options( defaults );
- this.options( options );
- },
-
- /**
- * Behavior#applyTo( arr ) -> this
- * - arr (Array): Array of bodies to apply this behavior to. Specify `true` for all objects in world.
- *
- * Apply the behavior to a group of bodies.
- **/
- applyTo: function( arr ){
-
- if ( arr === true ){
- this._targets = null;
- } else {
- this._targets = Physics.util.uniq( arr );
- }
- return this;
- },
-
- /**
- * Behavior#getTargets() -> Array
- * + (Array): The array of bodies (by reference!) this behavior is applied to.
- *
- * Get the array of bodies (by reference!) this behavior is applied to.
- **/
- getTargets: function(){
-
- return this._targets || ( this._world ? this._world._bodies : [] );
- },
-
- /**
- * Behavior#setWorld( world ) -> this
- * - world (Object): The world (or null)
- *
- * Set which world to apply to.
- *
- * Usually this is called internally. Shouldn't be a need to call this yourself usually.
- **/
- setWorld: function( world ){
-
- if ( this.disconnect && this._world ){
- this.disconnect( this._world );
- }
-
- this._world = world;
-
- if ( this.connect && world ){
- this.connect( world );
- }
-
- return this;
- },
-
- /**
- * Behavior#connect( world )
- * - world (Physics.world): The world to connect to
- *
- * Connect to a world.
- *
- * Extend this when creating behaviors if you need to specify pubsub management.
- * Automatically called when added to world by the [[Behavior#setWorld]] method.
- **/
- connect: function( world ){
-
- if (this.behave){
- world.on('integrate:positions', this.behave, this, this.options.priority);
- }
- },
-
- /**
- * Behavior#disconnect( world )
- * - world (Physics.world): The world to disconnect from
- *
- * Disconnect from a world.
- *
- * Extend this when creating behaviors if you need to specify pubsub management.
- * Automatically called when added to world by the [[Behavior#setWorld]] method.
- **/
- disconnect: function( world ){
-
- if (this.behave){
- world.off('integrate:positions', this.behave, this);
- }
- },
-
- /**
- * Behavior#behave( data )
- * - data (Object): The pubsub `integrate:positions` event data
- *
- * Default method run on every world integration.
- *
- * You _must_ extend this when creating a behavior,
- * unless you extend the [[Behavior#connect]] and [[Behavior#disconnect]] methods.
- **/
- behave: null
- });
-
-}());
-
-// ---
-// inside: src/core/body.js
-
-(function(){
-
- var defaults = {
-
- // is the body hidden (not to be rendered)?
- hidden: false,
- // is the body `dynamic`, `kinematic` or `static`?
- // http://www.box2d.org/manual.html#_Toc258082973
- treatment: 'dynamic',
- // body mass
- mass: 1.0,
- // body restitution. How "bouncy" is it?
- restitution: 1.0,
- // what is its coefficient of friction with another surface with COF = 1?
- cof: 0.8,
- // what is the view object (mixed) that should be used when rendering?
- view: null
- };
-
- var uidGen = 1;
-
- var Pi2 = Math.PI * 2;
- function cycleAngle( ang ){
- return ((ang % Pi2) + Pi2) % Pi2;
- }
-
- /** related to: Physics.util.decorator
- * Physics.body( name[, options] ) -> Body
- * - name (String): The name of the body to create
- * - options (Object): The configuration for that body ( depends on body ).
- Available options and defaults:
-
- ```javascript
- {
- // is the body hidden (not to be rendered)?
- hidden: false,
- // is the body `dynamic`, `kinematic` or `static`?
- // http://www.box2d.org/manual.html#_Toc258082973
- treatment: 'dynamic',
- // body mass
- mass: 1.0,
- // body restitution. How "bouncy" is it?
- restitution: 1.0,
- // what is its coefficient of friction with another surface with COF = 1?
- cof: 0.8,
- // what is the view object (mixed) that should be used when rendering?
- view: null,
- // the vector offsetting the geometry from its center of mass
- offset: Physics.vector(0,0)
- }
- ```
- *
- * Factory function for creating Bodies.
- *
- * Visit [the PhysicsJS wiki on Bodies](https://github.com/wellcaffeinated/PhysicsJS/wiki/Bodies)
- * for usage documentation.
- **/
- Physics.body = Decorator('body', {
-
- /** belongs to: Physics.body
- * class Body
- *
- * The base class for bodies created by [[Physics.body]] factory function.
- **/
-
- /** internal
- * Body#init( options )
- * - options (Object): The configuration options passed by the factory
- *
- * Initialization. Internal use.
- **/
- init: function( options ){
-
- var self = this;
- var vector = Physics.vector;
-
- /** related to: Physics.util.options
- * Body#options( options ) -> Object
- * - options (Object): The options to set as an object
- * + (Object): The options
- *
- * Set options on this instance.
- *
- * Access options directly from the options object.
- *
- * Example:
- *
- * ```javascript
- * this.options.someOption;
- * ```
- *
- **/
- // all options get copied onto the body.
- this.options = Physics.util.options( defaults, this );
- this.options.onChange(function( opts ){
- self.offset = new vector( opts.offset );
- });
- this.options( options );
-
- /**
- * Body#state
- *
- * The physical state container.
- *
- * - ``this.state.pos`` ([[Physics.vector]]) The position vector.
- * - ``this.state.vel`` ([[Physics.vector]]) The velocity vector.
- * - ``this.state.acc`` ([[Physics.vector]]) The acceleration vector.
- * - ``this.state.angular.pos`` ([[Number]]) The angular position (in radians, positive is clockwise starting along the x axis)
- * - ``this.state.angular.vel`` ([[Number]]) The angular velocity
- * - ``this.state.angular.acc`` ([[Number]]) The angular acceleration
- *
- * Properties from the previous timestep are stored in:
- * ```javascript
- * this.state.old; // .pos, .vel, ...
- * ```
- **/
- this.state = {
- pos: new vector( this.x, this.y ),
- vel: new vector( this.vx, this.vy ),
- acc: new vector(),
- angular: {
- pos: this.angle || 0.0,
- vel: this.angularVelocity || 0.0,
- acc: 0.0
- },
- old: {
- pos: new vector(),
- vel: new vector(),
- acc: new vector(),
- angular: {
- pos: 0.0,
- vel: 0.0,
- acc: 0.0
- }
- }
- };
-
- // private storage for sleeping
- this._sleepAngPosMean = 0;
- this._sleepAngPosVariance = 0;
- this._sleepPosMean = new vector();
- this._sleepPosVariance = new vector();
- this._sleepMeanK = 0;
-
- // cleanup
- delete this.x;
- delete this.y;
- delete this.vx;
- delete this.vy;
- delete this.angle;
- delete this.angularVelocity;
-
- if (this.mass === 0){
- throw "Error: Bodies must have non-zero mass";
- }
-
- /**
- * Body#uid = Number
- *
- * The unique id for the body
- **/
- this.uid = uidGen++;
-
- /** related to: Physics.geometry
- * Body#geometry
- *
- * The geometry for this body.
- *
- * By default it is a `point` geometry which gets overridden.
- **/
- this.geometry = Physics.geometry('point');
-
- /**
- * Body#mass = 1.0
- *
- * The mass.
- **/
-
- /**
- * Body#offset
- *
- * The vector offsetting the body's shape from its center of mass.
- **/
-
- /**
- * Body#restitution = 1.0
- *
- * The restitution.
- *
- * This is the "bounciness" of the body.
- * It's a number between `0` and `1`.
- *
- * A restitution of 1 is the bounciest.
- *
- * A restitution of 0 is not bouncy.
- *
- * When colliding the restitutions of bodies are
- * multiplied together to get the restitution between two
- * bodies.
- *
- **/
-
- /**
- * Body#cof = 0.8
- *
- * The coefficient of friction of the body.
- *
- * It's how much "slide" it has during collisions.
- *
- * A `cof` of `0` will really slidy.
- *
- * A `cof` of `1` has no slide.
- *
- * This is a very simplistic implementation at the moment.
- * What would be better is to have both static and kinetic
- * friction. But that's not done yet.
- **/
-
- /**
- * Body#treatment = String
- *
- * How the body is treated by the simulation.
- *
- * The body can be `dynamic`, `kinematic` or `static` as
- * described by the [analogous box2d docs](http://www.box2d.org/manual.html#_Toc258082973).
- *
- * * _dynamic_ bodies are treated "normally". They are integrated, and collide, and all that.
- * * _kinematic_ bodies are bodies that move at a specified velocity. Other bodies collide with them, but they don't bounce off of other bodies.
- * * _static_ bodies just stand still. They are like obstacles.
- **/
-
- /**
- * Body#hidden = false
- *
- * Determines whether the body should be hidden by the renderer.
- **/
-
- /** related to: Physics.renderer
- * Body#view = it_depends
- *
- * Storage for use by the renderer.
- *
- * The type of renderer will put different things in the view property.
- * Basically, this is how the body "looks". It could be a HTMLElement, or
- * an Image, etc...
- *
- * If your body changes appearance (shape), you should modify this somehow
- * otherwise the renderer will keep using this same view. If you're letting
- * the renderer create the view for you, just set this to `undefined` if the
- * body gets modified in shape during the simulation.
- **/
-
- /** related to: Physics.renderer
- * Body#styles
- *
- * The styles the renderer should use for creating the view.
- *
- * The styles depend on the renderer. See [[Renderer#createView]] for style options.
- **/
- },
-
- /**
- * Body#sleep( [dt] ) -> Boolean
- * - dt (Number): Time to advance the idle time
- * - dt (Boolean): If `true`, the body will be forced to sleep. If `false`, the body will be forced to awake.
- *
- * Get and/or set whether the body is asleep.
- *
- * If called with a time (in ms), the time will be added to the idle time and sleep conditions will be checked.
- **/
- sleep: function( dt ){
-
- if ( dt === true ){
- // force sleep
- this.asleep = true;
-
- } else if ( dt === false ){
- // force wakup
- this.asleep = false;
- this._sleepMeanK = 0;
- this._sleepAngPosMean = 0;
- this._sleepAngPosVariance = 0;
- this._sleepPosMean.zero();
- this._sleepPosVariance.zero();
- this.sleepIdleTime = 0;
-
- } else if ( dt && !this.asleep ) {
-
- this.sleepCheck( dt );
- }
-
- return this.asleep;
- },
-
- /**
- * Body#sleepCheck( [dt] )
- * - dt (Number): Time to advance the idle time
- *
- * Check if the body should be sleeping.
- *
- * Call with no arguments if some event could possibly wake up the body. This will force the body to recheck.
- **/
- sleepCheck: function( dt ){
-
- var opts = this._world && this._world.options;
-
- // if sleeping disabled. stop.
- if ( this.sleepDisabled || (opts && opts.sleepDisabled) ){
- return;
- }
-
- var limit
- ,v
- ,d
- ,r
- ,aabb
- ,scratch = Physics.scratchpad()
- ,diff = scratch.vector()
- ,diff2 = scratch.vector()
- ,kfac
- ,stats
- ;
-
- dt = dt || 0;
- aabb = this.geometry.aabb();
- r = Math.max(aabb.hw, aabb.hh);
-
- if ( this.asleep ){
- // check velocity
- v = this.state.vel.norm() + Math.abs(r * this.state.angular.vel);
- limit = this.sleepSpeedLimit || (opts && opts.sleepSpeedLimit) || 0;
-
- if ( v >= limit ){
- this.sleep( false );
- return scratch.done();
- }
- }
-
- this._sleepMeanK++;
- kfac = this._sleepMeanK > 1 ? 1/(this._sleepMeanK - 1) : 0;
- Physics.statistics.pushRunningVectorAvg( this.state.pos, this._sleepMeanK, this._sleepPosMean, this._sleepPosVariance );
- // we take the sin because that maps the discontinuous angle to a continuous value
- // then the statistics calculations work better
- stats = Physics.statistics.pushRunningAvg( Math.sin(this.state.angular.pos), this._sleepMeanK, this._sleepAngPosMean, this._sleepAngPosVariance );
- this._sleepAngPosMean = stats[0];
- this._sleepAngPosVariance = stats[1];
- v = this._sleepPosVariance.norm() + Math.abs(r * Math.asin(stats[1]));
- v *= kfac;
- limit = this.sleepVarianceLimit || (opts && opts.sleepVarianceLimit) || 0;
- // console.log(v, limit, kfac, this._sleepPosVariance.norm(), stats[1])
- if ( v <= limit ){
- // check idle time
- limit = this.sleepTimeLimit || (opts && opts.sleepTimeLimit) || 0;
- this.sleepIdleTime = (this.sleepIdleTime || 0) + dt;
-
- if ( this.sleepIdleTime > limit ){
- this.asleep = true;
- }
- } else {
- this.sleep( false );
- }
-
- scratch.done();
- },
-
- /**
- * Body#setWorld( world ) -> this
- * - world (Object): The world (or null)
- *
- * Set which world to apply to.
- *
- * Usually this is called internally. Shouldn't be a need to call this yourself usually.
- **/
- setWorld: function( world ){
-
- if ( this.disconnect && this._world ){
- this.disconnect( this._world );
- }
-
- this._world = world;
-
- if ( this.connect && world ){
- this.connect( world );
- }
-
- return this;
- },
-
- /**
- * Body#accelerate( acc ) -> this
- * - acc (Physics.vector): The acceleration vector
- *
- * Accelerate the body by adding supplied vector to its current acceleration
- **/
- accelerate: function( acc ){
-
- if ( this.treatment === 'dynamic' ){
- this.state.acc.vadd( acc );
- }
-
- return this;
- },
-
- /**
- * Body#applyForce( force[, p] ) -> this
- * - force (Vectorish): The force vector
- * - p (Vectorish): The point vector from the COM at which to apply the force
- *
- * Apply a force at center of mass, or at point `p` relative to the center of mass
- **/
- applyForce: function( force, p ){
-
- if ( this.treatment !== 'dynamic' ){
- return this;
- }
-
- var scratch = Physics.scratchpad()
- ,r = scratch.vector()
- ,state
- ;
-
- // if no point at which to apply the force... apply at center of mass
- if ( p && this.moi ){
-
- // apply torques
- state = this.state;
- r.clone( p );
- // r cross F
- this.state.angular.acc -= r.cross( force ) / this.moi;
- }
-
- this.accelerate( r.clone( force ).mult( 1/this.mass ) );
-
- scratch.done();
- return this;
- },
-
- /** related to: Body#offset
- * Body#getGlobalOffset( [out] ) -> Physics.vector
- * - out (Physics.vector): A vector to use to put the result into. One is created if `out` isn't specified.
- * + (Physics.vector): The offset in global coordinates
- *
- * Get the body offset vector (from the center of mass) for the body's shape in global coordinates.
- **/
- getGlobalOffset: function( out ){
-
- out = out || new Physics.vector();
- out.clone( this.offset ).rotate( this.state.angular.pos );
- return out;
- },
-
- /** related to: Physics.aabb
- * Body#aabb() -> Object
- * + (Object): The aabb of this body
- *
- * Get the Axis aligned bounding box for the body in its current position and rotation
- **/
- aabb: function(){
-
- var angle = this.state.angular.pos
- ,scratch = Physics.scratchpad()
- ,v = scratch.vector()
- ,aabb = this.geometry.aabb( angle )
- ;
-
- this.getGlobalOffset( v );
-
- aabb.x += this.state.pos._[0] + v._[0];
- aabb.y += this.state.pos._[1] + v._[1];
-
- return scratch.done( aabb );
- },
-
- /**
- * Body#toBodyCoords( v ) -> Physics.vector
- * - v (Physics.vector): The vector to transform
- * + (Physics.vector): The transformed vector
- *
- * Transform a vector into coordinates relative to this body.
- **/
- toBodyCoords: function( v ){
- return v.vsub( this.state.pos ).rotate( -this.state.angular.pos );
- },
-
- /**
- * Body#toWorldCoords( v ) -> Physics.vector
- * - v (Physics.vector): The vector to transform
- * + (Physics.vector): The transformed vector
- *
- * Transform a vector from body coordinates into world coordinates.
- **/
- toWorldCoords: function( v ){
- return v.rotate( this.state.angular.pos ).vadd( this.state.pos );
- },
-
- /**
- * Body#recalc() -> this
- *
- * Recalculate properties.
- *
- * Intended to be overridden by subclasses. Call when body physical properties are changed.
- **/
- recalc: function(){
- // override to recalculate properties
- return this;
- }
- });
-
- /**
- * Body.getCOM( bodies[, com] ) -> Physics.vector
- * - bodies (Array): The list of bodies
- * - com (Physics.vector): The vector to put result into. A new vector will be created if not provided.
- * + (Physics.vector): The center of mass position
- *
- * Get center of mass position from list of bodies.
- **/
- Physics.body.getCOM = function( bodies, com ){
- // @TODO add a test for this fn
- var b
- ,pos
- ,i
- ,l = bodies && bodies.length
- ,M = 0
- ;
-
- com = com || new Physics.vector();
-
- if ( !l ){
- return com.zero();
- }
-
- if ( l === 1 ){
- return com.clone( bodies[0].state.pos );
- }
-
- com.zero();
-
- for ( i = 0; i < l; i++ ){
- b = bodies[ i ];
- pos = b.state.pos;
- com.add( pos._[0] * b.mass, pos._[1] * b.mass );
- M += b.mass;
- }
-
- com.mult( 1 / M );
-
- return com;
- };
-
-}());
-
-
-// ---
-// inside: src/core/geometry.js
-
-(function(){
- /** related to: Physics.util.decorator
- * Physics.geometry( name[, options] ) -> Geometry
- * - name (String): The name of the geometry to create
- * - options (Object): The configuration for that geometry ( depends on geometry ).
- *
- * Factory function for creating Geometries.
- *
- * Visit [the PhysicsJS wiki on Geometries](https://github.com/wellcaffeinated/PhysicsJS/wiki/Geometries)
- * for usage documentation.
- **/
- Physics.geometry = Decorator('geometry', {
-
- /** belongs to: Physics.geometry
- * class Geometry
- *
- * The base class for geometries created by [[Physics.geometry]] factory function.
- **/
-
- /** internal
- * Geometry#init( options )
- * - options (Object): The configuration options passed by the factory
- *
- * Initialization. Internal use.
- **/
- init: function( options ){
-
- /** related to: Physics.util.options
- * Geometry#options( options ) -> Object
- * - options (Object): The options to set as an object
- * + (Object): The options
- *
- * Set options on this instance.
- *
- * Access options directly from the options object.
- *
- * Example:
- *
- * ```javascript
- * this.options.someOption;
- * ```
- *
- **/
- this.options = Physics.util.options();
- this.options( options );
-
- this._aabb = new Physics.aabb();
- },
-
- /** related to: Physics.aabb
- * Geometry#aabb( angle ) -> Object
- * - angle (Number): The angle to rotate the geometry
- * + (Object): Bounding box values
- *
- * Get axis-aligned bounding box for this object (rotated by angle if specified).
- **/
- aabb: function( angle ){
-
- return Physics.aabb.clone(this._aabb);
- },
-
- /**
- * Geometry#getFarthestHullPoint( dir[, result] ) -> Physics.vector
- * - dir (Physics.vector): Direction to look
- * - result (Physics.vector): A vector to write result to. Speeds up calculations.
- * + (Physics.vector): The farthest hull point in local coordinates
- *
- * Get farthest point on the hull of this geometry
- * along the direction vector `dir`
- * returns local coordinates. Replaces result if provided.
- *
- * Assume all coordinates are relative to the geometry
- * centroid (IE: in the body frame).
- *
- * This should take a direction vector then it should
- * calculate the location (in that frame of reference)
- * of the point on the perimeter (hull) if you traveled
- * in a straight line from the centroid in the provided
- * direction. The result should be returned/set just like
- * it is in the other geometries.
- **/
- getFarthestHullPoint: function( dir, result ){
-
- result = result || new Physics.vector();
-
- // not implemented.
- return result.set( 0, 0 );
- },
-
- /** related to: Geometry#getFarthestHullPoint
- * Geometry#getFarthestCorePoint( dir[, result] ) -> Physics.vector
- * - dir (Physics.vector): Direction to look
- * - result (Physics.vector): A vector to write result to. Speeds up calculations.
- * + (Physics.vector): The farthest hull point in local coordinates
- *
- * Get farthest point on the core shape of this geometry
- * along the direction vector `dir`
- * returns local coordinates. Replaces result if provided.
- *
- * This does almost the same thing as [[Geometry#getFarthestHullPoint]]
- * but shrinks the shape by subtracting "margin" from it.
- * Return the position of the point on the "core" shape.
- **/
- getFarthestCorePoint: function( dir, result, margin ){
-
- result = result || new Physics.vector();
-
- // not implemented.
- return result.set( 0, 0 );
- }
- });
-
-}());
-
-// ---
-// inside: src/core/geometry-helpers.js
-
-/*
- * Geometry helper functions
- */
-
-/**
- * Physics.geometry.regularPolygonVertices( sides, radius ) -> Array
- * - sides (Number): Number of sides the polygon has
- * - radius (Number): Size from center to a vertex
- * + (Array): A list of [[Vectorish]] objects representing the vertices
- *
- * Generate a list of vertices for a regular polygon of any number of sides.
- **/
-Physics.geometry.regularPolygonVertices = function( sides, radius ){
- var verts = []
- ,angle = Math.PI * 2 / sides
- ,a = 0
- ,i
- ;
-
- for ( i = 0; i < sides; i++ ){
- verts.push({
- x: radius * Math.cos( a )
- ,y: radius * Math.sin( a )
- });
-
- a += angle;
- }
-
- return verts;
-};
-
-/**
- * Physics.geometry.isPolygonConvex( hull ) -> Boolean
- * - hull (Array): Array of ([[Vectorish]]) vertices
- * + (Boolean): `true` if the polygon is convex. `false` otherwise.
- *
- * Determine if polygon hull is convex
- **/
-Physics.geometry.isPolygonConvex = function( hull ){
-
- var scratch = Physics.scratchpad()
- ,prev = scratch.vector()
- ,next = scratch.vector()
- ,tmp = scratch.vector()
- ,ret = true
- ,sign = false
- ,l = hull.length
- ;
-
- if ( !hull || !l ){
- return false;
- }
-
- if ( l < 3 ){
- // it must be a point or a line...
- // which are convex
- scratch.done();
- return ret;
- }
-
- prev.clone( hull[ 0 ] ).vsub( tmp.clone( hull[ l - 1 ] ) );
-
- // loop over the edges of the hull and construct vectors of the current
- // edge and retain the last edge
- // add two to the length to do a full cycle
- for ( var i = 1; i <= l; ++i ){
-
- next.clone( hull[ i % l ] ).vsub( tmp.clone( hull[ (i - 1) % l ] ) );
-
- if ( sign === false ){
-
- // first check the sign of the first cross product
- sign = prev.cross( next );
-
- } else if ( (sign > 0) ^ (prev.cross( next ) > 0) ){
-
- // if the cross products are different signs it's not convex
- ret = false;
- break;
- }
-
- // remember the last edge
- next.swap( prev );
- }
-
- scratch.done();
- return ret;
-};
-
-/**
- * Physics.geometry.getPolygonMOI( hull ) -> Number
- * - hull (Array): Array of ([[Vectorish]]) vertices
- * + (Number): The polygon's moment of inertia
- *
- * Gets the moment of inertia of a convex polygon
- *
- * See [List of moments of inertia](http://en.wikipedia.org/wiki/List_of_moments_of_inertia)
- * for more information.
- *
- * _Note_: we make the following assumpations:
- * * mass is unitary (== 1)
- * * axis of rotation is the origin
- **/
-Physics.geometry.getPolygonMOI = function( hull ){
-
- var scratch = Physics.scratchpad()
- ,prev = scratch.vector()
- ,next = scratch.vector()
- ,num = 0
- ,denom = 0
- ,tmp
- ,l = hull.length
- ;
-
- if ( l < 2 ){
- // it must be a point
- // moi = 0
- scratch.done();
- return 0;
- }
-
- if ( l === 2 ){
- // it's a line
- // get length squared
- tmp = next.clone( hull[ 1 ] ).distSq( prev.clone( hull[ 0 ] ) );
- scratch.done();
- return tmp / 12;
- }
-
- prev.clone( hull[ 0 ] );
-
- for ( var i = 1; i < l; ++i ){
-
- next.clone( hull[ i ] );
-
- tmp = Math.abs( next.cross( prev ) );
- num += tmp * ( next.normSq() + next.dot( prev ) + prev.normSq() );
- denom += tmp;
-
- prev.swap( next );
- }
-
- scratch.done();
- return num / ( 6 * denom );
-};
-
-/**
- * Physics.geometry.isPointInPolygon( pt, hull ) -> Boolean
- * - pt (Vectorish): The point to test
- * - hull (Array): Array of ([[Vectorish]]) vertices
- * + (Boolean): `true` if point `pt` is inside the polygon
- *
- * Check if point is inside polygon hull.
- **/
-Physics.geometry.isPointInPolygon = function( pt, hull ){
-
- var scratch = Physics.scratchpad()
- ,point = scratch.vector().clone( pt )
- ,prev = scratch.vector()
- ,next = scratch.vector()
- ,ang = 0
- ,l = hull.length
- ;
-
- if ( l < 2 ){
- // it's a point...
- ang = point.equals( prev.clone( hull[ 0 ] ));
- scratch.done();
- return ang;
- }
-
- if ( l === 2 ){
- // it's a line
- ang = point.angle( prev.clone( hull[ 0 ] ));
- ang += point.angle( prev.clone( hull[ 1 ] ));
- scratch.done();
- return ( Math.abs(ang) === Math.PI );
- }
-
- prev.clone( hull[ 0 ] ).vsub( point );
-
- // calculate the sum of angles between vector pairs
- // from point to vertices
- for ( var i = 1; i <= l; ++i ){
-
- next.clone( hull[ i % l ] ).vsub( point );
- ang += next.angle( prev );
- prev.swap( next );
- }
-
- scratch.done();
- return ( Math.abs(ang) > 1e-6 );
-};
-
-/**
- * Physics.geometry.getPolygonArea( hull ) -> Number
- * - hull (Array): Array of ([[Vectorish]]) vertices
- * + (Number): The area (positive for clockwise ordering)
- *
- * Get the signed area of the polygon.
- **/
-Physics.geometry.getPolygonArea = function getPolygonArea( hull ){
-
- var scratch = Physics.scratchpad()
- ,prev = scratch.vector()
- ,next = scratch.vector()
- ,ret = 0
- ,l = hull.length
- ;
-
- if ( l < 3 ){
- // it must be a point or a line
- // area = 0
- scratch.done();
- return 0;
- }
-
- prev.clone( hull[ l - 1 ] );
-
- for ( var i = 0; i < l; ++i ){
-
- next.clone( hull[ i ] );
-
- ret += prev.cross( next );
-
- prev.swap( next );
- }
-
- scratch.done();
- return ret / 2;
-};
-
-/**
- * Physics.geometry.getPolygonCentroid( hull ) -> Physics.vector
- * - hull (Array): Array of ([[Vectorish]]) vertices
- * + (Physics.vector): The centroid
- *
- * Get the coordinates of the centroid.
- **/
-Physics.geometry.getPolygonCentroid = function getPolygonCentroid( hull ){
-
- var scratch = Physics.scratchpad()
- ,prev = scratch.vector()
- ,next = scratch.vector()
- ,ret = new Physics.vector()
- ,tmp
- ,l = hull.length
- ;
-
- if ( l < 2 ){
- // it must be a point
- scratch.done();
- return new Physics.vector( hull[0] );
- }
-
- if ( l === 2 ){
- // it's a line
- // get the midpoint
- scratch.done();
- return new Physics.vector((hull[ 1 ].x + hull[ 0 ].x)/2, (hull[ 1 ].y + hull[ 0 ].y)/2 );
- }
-
- prev.clone( hull[ l - 1 ] );
-
- for ( var i = 0; i < l; ++i ){
-
- next.clone( hull[ i ] );
-
- tmp = prev.cross( next );
- prev.vadd( next ).mult( tmp );
- ret.vadd( prev );
-
- prev.swap( next );
- }
-
- tmp = 1 / (6 * Physics.geometry.getPolygonArea( hull ));
-
- scratch.done();
- return ret.mult( tmp );
-};
-
-/**
- * Physics.geometry.nearestPointOnLine( pt, linePt1, linePt2 ) -> Physics.vector
- * - pt (Vectorish): The point
- * - linePt1 (Vectorish): The first endpoint of the line
- * - linePt2 (Vectorish): The second endpoint of the line
- * + (Vector): The closest point
- *
- * Get the closest point on a discrete line to specified point.
- **/
-Physics.geometry.nearestPointOnLine = function nearestPointOnLine( pt, linePt1, linePt2 ){
-
- var scratch = Physics.scratchpad()
- ,p = scratch.vector().clone( pt )
- ,A = scratch.vector().clone( linePt1 ).vsub( p )
- ,L = scratch.vector().clone( linePt2 ).vsub( p ).vsub( A )
- ,lambdaB
- ,lambdaA
- ;
-
- if ( L.equals(Physics.vector.zero) ){
- // oh.. it's a zero vector. So A and B are both the closest.
- // just use one of them
- scratch.done();
- return new Physics.vector( linePt1 );
- }
-
- lambdaB = - L.dot( A ) / L.normSq();
- lambdaA = 1 - lambdaB;
-
- if ( lambdaA <= 0 ){
- // woops.. that means the closest simplex point
- // isn't on the line it's point B itself
- scratch.done();
- return new Physics.vector( linePt2 );
- } else if ( lambdaB <= 0 ){
- // vice versa
- scratch.done();
- return new Physics.vector( linePt1 );
- }
-
- // guess we'd better do the math now...
- p = new Physics.vector( linePt2 ).mult( lambdaB ).vadd( A.clone( linePt1 ).mult( lambdaA ) );
- scratch.done();
- return p;
-};
-
-
-// ---
-// inside: src/core/integrator.js
-
-(function(){
-
- var defaults = {
-
- // drag applied during integration
- // 0 means vacuum
- // 0.9 means molasses
- drag: 0
- };
-
- /** related to: Physics.util.decorator
- * Physics.integrator( name[, options] ) -> Integrator
- * - name (String): The name of the integrator to create
- * - options (Object): The configuration for that integrator ( depends on integrator ).
- Available options and defaults:
-
- ```javascript
- {
- // drag applied during integration
- // 0 means vacuum
- // 0.9 means molasses
- drag: 0
- }
- ```
- *
- * Factory function for creating Integrators.
- *
- * Visit [the PhysicsJS wiki on Integrators](https://github.com/wellcaffeinated/PhysicsJS/wiki/Integrators)
- * for usage documentation.
- **/
- Physics.integrator = Decorator('integrator', {
-
- /** belongs to: Physics.integrator
- * class Integrator
- *
- * The base class for integrators created by [[Physics.integrator]] factory function.
- **/
-
- /** internal
- * Integrator#init( options )
- * - options (Object): The configuration options passed by the factory
- *
- * Initialization. Internal use.
- **/
- init: function( options ){
-
- /** related to: Physics.util.options
- * Integrator#options( options ) -> Object
- * - options (Object): The options to set as an object
- * + (Object): The options
- *
- * Set options on this instance.
- *
- * Access options directly from the options object.
- *
- * Example:
- *
- * ```javascript
- * this.options.someOption;
- * ```
- *
- **/
- this.options = Physics.util.options( defaults );
- this.options( options );
- },
-
- /**
- * Integrator#setWorld( world ) -> this
- * - world (Object): The world (or null)
- *
- * Set which world to apply to.
- *
- * Usually this is called internally. Shouldn't be a need to call this yourself usually.
- **/
- setWorld: function( world ){
-
- if ( this.disconnect && this._world ){
- this.disconnect( this._world );
- }
-
- this._world = world;
-
- if ( this.connect && world ){
- this.connect( world );
- }
-
- return this;
- },
-
- /**
- * Integrator#integrate( bodies, dt ) -> this
- * - bodies (Array): List of bodies to integrate
- * - dt (Number): Timestep size
- *
- * Integrate bodies by timestep.
- *
- * Will emit `integrate:velocities` and `integrate:positions`
- * events on the world.
- **/
- integrate: function( bodies, dt ){
-
- var world = this._world;
-
- this.integrateVelocities( bodies, dt );
-
- if ( world ){
- world.emit('integrate:velocities', {
- bodies: bodies,
- dt: dt
- });
- }
-
- this.integratePositions( bodies, dt );
-
- if ( world ){
- world.emit('integrate:positions', {
- bodies: bodies,
- dt: dt
- });
- }
-
- return this;
- },
-
- /**
- * Integrator#connect( world )
- * - world (Physics.world): The world to connect to
- *
- * Connect to a world.
- *
- * Extend this when creating integrators if you need to specify pubsub management.
- * Automatically called when added to world by the [[Integrator#setWorld]] method.
- **/
- connect: null,
-
- /**
- * Integrator#disconnect( world )
- * - world (Physics.world): The world to disconnect from
- *
- * Disconnect from a world.
- *
- * Extend this when creating integrators if you need to specify pubsub management.
- * Automatically called when added to world by the [[Integrator#setWorld]] method.
- **/
- disconnect: null,
-
- /**
- * Integrator#integrateVelocities( bodies, dt )
- * - bodies (Array): List of bodies to integrate
- * - dt (Number): Timestep size
- *
- * Just integrate the velocities.
- *
- * Should be overridden when creating integrators.
- **/
- integrateVelocities: function( bodies, dt ){
-
- throw 'The integrator.integrateVelocities() method must be overriden';
- },
-
- /**
- * Integrator#integratePositions( bodies, dt )
- * - bodies (Array): List of bodies to integrate
- * - dt (Number): Timestep size
- *
- * Just integrate the positions.
- *
- * Called after [[Integrator#integrateVelocities]].
- *
- * Should be overridden when creating integrators.
- **/
- integratePositions: function( bodies, dt ){
-
- throw 'The integrator.integratePositions() method must be overriden';
- }
- });
-
-}());
-
-
-// ---
-// inside: src/core/renderer.js
-
-(function(){
-
- var defaults = {
- // draw meta data (fps, steps, etc)
- meta: false,
- // refresh rate of meta info
- metaRefresh: 200,
-
- // width of viewport
- width: 600,
- // height of viewport
- height: 600,
- // automatically resize the renderer
- autoResize: true
- };
-
- /** related to: Physics.util.decorator
- * Physics.renderer( name[, options] ) -> Renderer
- * - name (String): The name of the renderer to create
- * - options (Object): The configuration for that renderer ( depends on renderer ).
- Available options and defaults:
-
- ```javascript
- {
- // draw meta data (fps, steps, etc)
- meta: false,
- // refresh rate of meta info
- metaRefresh: 200,
-
- // width of viewport
- width: 600,
- // height of viewport
- height: 600
- // automatically resize the renderer
- autoResize: true
- }
- ```
- *
- * Factory function for creating Renderers.
- *
- * Visit [the PhysicsJS wiki on Renderers](https://github.com/wellcaffeinated/PhysicsJS/wiki/Renderers)
- * for usage documentation.
- **/
- Physics.renderer = Decorator('renderer', {
-
- /** belongs to: Physics.renderer
- * class Renderer
- *
- * The base class for renderers created by [[Physics.renderer]] factory function.
- **/
-
- /** internal
- * Renderer#init( options )
- * - options (Object): The configuration options passed by the factory
- *
- * Initialization. Internal use.
- **/
- init: function( options ){
-
- var self = this
- ,el = typeof options.el === 'string' ? document.getElementById(options.el) : options.el
- ;
-
- this.options = Physics.util.options(defaults);
- this.options( options );
-
- this.el = el ? el : document.body;
- this.container = el && el.parentNode ? el.parentNode : document.body;
- this.drawMeta = Physics.util.throttle( Physics.util.bind(this.drawMeta, this), this.options.metaRefresh );
-
- window.addEventListener('resize', Physics.util.throttle(function(){
- if ( self.options.autoResize ){
- self.resize();
- }
- }), 100);
- },
-
- /**
- * Renderer#resize( [width, height] ) -> this
- * - width (Number): The width in px
- * - height (Number): The height in px
- *
- * Set the dimensions of the renderer.
- *
- * If no dimensions are specified it will auto resize.
- **/
- resize: function( width, height ){
-
- if ( width === undefined && height === undefined ){
- width = this.container.offsetWidth;
- height = this.container.offsetHeight;
- }
-
- this.width = width || 0;
- this.height = height || 0;
- // should be implemented in renderers
- },
-
- /**
- * Renderer#setWorld( world ) -> this
- * - world (Object): The world (or null)
- *
- * Set which world to apply to.
- *
- * Usually this is called internally. Shouldn't be a need to call this yourself usually.
- **/
- setWorld: function( world ){
-
- if ( this.disconnect && this._world ){
- this.disconnect( this._world );
- }
-
- this._world = world;
-
- if ( this.connect && world ){
- this.connect( world );
- }
-
- return this;
- },
-
- /**
- * Renderer#render( bodies, meta ) -> this
- * - bodies (Array): Array of bodies in the world (by reference!)
- * - meta (Object): meta information
- *
- * Render the world bodies and meta. Called by world.render()
- **/
- render: function( bodies, meta ){
-
- var body
- ,view
- ,pos
- ;
-
- if (this.beforeRender){
-
- this.beforeRender();
- }
-
- this._world.emit('beforeRender', {
- renderer: this,
- bodies: bodies,
- meta: meta
- });
-
- if (this.options.meta){
- this.drawMeta( meta );
- }
-
- this._interpolateTime = meta.interpolateTime;
-
- for ( var i = 0, l = bodies.length; i < l; ++i ){
-
- body = bodies[ i ];
- view = body.view || ( body.view = this.createView(body.geometry, body.styles) );
-
- if ( !body.hidden ){
- this.drawBody( body, view );
- }
- }
-
- return this;
- },
-
- /**
- * Renderer#createView( geometry, styles ) -> Mixed
- * - geometry (Geometry): geometry The geometry
- * - styles (Object|String): The styles configuration
- * + (Mixed): Whatever the renderer needs to render the body.
- *
- * Create a view for the specified geometry.
- *
- * The view is used to render the body. It is a cached version
- * of the body that gets moved and rotated according to the simulation.
- *
- * The styles are used to modify the appearance of the view.
- * They depend on the renderer.
- *
- * Override this when creating renderers.
- **/
- createView: function( geometry, styles ){
-
- // example:
- // var el = document.createElement('div');
- // el.style.height = geometry.height + 'px';
- // el.style.width = geometry.width + 'px';
- // return el;
- throw 'You must override the renderer.createView() method.';
- },
-
- /**
- * Renderer#drawMeta( meta )
- * - meta (Object): The meta data
- *
- * Draw the meta data.
- *
- * The meta data will look like this:
- *
- * ```javascript
- * meta = {
- * fps: 60, // the frames per second
- * ipf: 4 // the number of iterations per frame
- * };
- * ```
- *
- * Override this when creating renderers.
- **/
- drawMeta: function( meta ){
-
- // example:
- // this.els.fps.innerHTML = meta.fps.toFixed(2);
- // this.els.steps.innerHTML = meta.steps;
- throw 'You must override the renderer.drawMeta() method.';
- },
-
- /**
- * Renderer#drawBody( body, view )
- * - body (Object): The body to draw
- * - view (Object): The view for the body
- *
- * Draw specified body using specified view.
- *
- * Override this when creating renderers.
- **/
- drawBody: function( body, view ){
-
- // example (pseudocode):
- // view.angle = body.state.angle
- // view.position = body.state.position
- throw 'You must override the renderer.drawBody() method.';
- }
-
-
- });
-
-}());
-
-
-// ---
-// inside: src/core/world.js
-
-/** related to: Physics
- * class Physics.world
- *
- * The world class and factory function.
- *
- * Use [[Physics]] to create worlds.
- **/
-(function(){
-
- var execCallbacks = function execCallbacks( fns, scope, args ){
-
- var fn
- ,ret
- ,cb = function(){
- return execCallbacks( fns, scope, args );
- }
- ;
-
- while ( fn = fns.shift() ){
-
- ret = fn.apply(scope, args);
-
- if (ret && ret.then){
- return ret.then( cb );
- }
- }
- };
-
- var defaults = {
-
- // default timestep
- timestep: 6,
- // maximum number of iterations per step
- maxIPF: 4,
- webworker: false, // NOT YET IMPLEMENTED
-
- // default integrator
- integrator: 'verlet',
-
- // is sleeping disabled?
- sleepDisabled: false,
- // speed at which bodies wake up
- sleepSpeedLimit: 0.05,
- // variance in position below which bodies fall asleep
- sleepVarianceLimit: 0.02,
- // time (ms) before sleepy bodies fall asleep
- sleepTimeLimit: 500
- };
-
- // begin world definitions
-
- /** alias of: Physics
- * new Physics.world([options, fn(world, Physics)])
- * - options (Object): configuration options (see description)
- * - fn (Function|Array): Callback function or array of callbacks called with this === world
- * - world (Physics.world): The current world created
- * - Physics (Physics): The Physics namespace
- *
- * World Constructor.
- *
- * Use [[Physics]] to create worlds.
- *
- * Configuration options and defaults:
- *
- * ```javascript
- * {
- * // default timestep
- * timestep: 6,
- * // maximum number of iterations per step
- * maxIPF: 4,
- *
- * // default integrator
- * integrator: 'verlet',
- *
- * // is sleeping disabled?
- * sleepDisabled: false,
- * // speed at which bodies wake up
- * sleepSpeedLimit: 0.1,
- * // variance in position below which bodies fall asleep
- * sleepVarianceLimit: 2,
- * // time (ms) before sleepy bodies fall asleep
- * sleepTimeLimit: 500
- * }
- * ```
- *
- * If called with an array of functions, and any functions
- * return a [promise-like object](http://promises-aplus.github.io/promises-spec/),
- * each remaining callback will be called only when that promise is resolved.
- *
- * Example:
- *
- * ```javascript
- * // hypothetical resources need to be loaded...
- * Physics( cfg, [
- * function( world ){
- * var dfd = $.Deferred()
- * ,images = []
- * ,toLoad = myImages.length
- * ,callback = function(){
- * toLoad--;
- * // wait for all images to be loaded
- * if ( toLoad <= 0 ){
- * dfd.resolve();
- * }
- * }
- * ;
- *
- * // load images
- * $.each(myImages, function( src ){
- * var img = new Image();
- * img.onload = callback;
- * img.src = src;
- * });
- *
- * return dfd.promise();
- * },
- * function( world ){
- * // won't be executed until images are loaded
- * // initialize world... etc...
- * }
- * ]);
- * ```
- **/
- var World = function World( cfg, fn ){
-
- // allow creation of world without "new"
- if (!(this instanceof World)){
- return new World( cfg, fn );
- }
-
- this.init( cfg, fn );
- };
-
- // extend pubsub
- World.prototype = Physics.util.extend({}, Physics.util.pubsub.prototype, {
-
- /** internal, see: new Physics.world
- * Physics.world#init( [options, fn(world, Physics)] )
- * - options (Object): configuration options (see constructor)
- * - fn (Function|Array): Callback function or array of callbacks called with this === world
- *
- * Initialization
- **/
- init: function( cfg, fn ){
-
- var self = this;
-
- if ( Physics.util.isFunction( cfg ) || Physics.util.isArray( cfg ) ){
- fn = cfg;
- cfg = {};
- }
-
- this._meta = {
- // statistics (fps, etc)
- fps: 0,
- ipf: 0
- };
- this._bodies = [];
- this._behaviors = [];
- this._integrator = null;
- this._renderer = null;
- this._paused = false;
- this._warp = 1;
- this._time = 0;
-
- // set options
- this.options = Physics.util.options( defaults );
- this.options.onChange(function( opts ){
-
- // set timestep
- self.timestep( opts.timestep );
- });
- this.options( cfg );
-
- // add integrator
- this.add(Physics.integrator( this.options.integrator ));
-
- // apply the callback function
- if ( Physics.util.isFunction( fn ) ){
-
- execCallbacks([ fn ], this, [this, Physics] );
-
- } else if ( Physics.util.isArray( fn ) ){
-
- execCallbacks(fn, this, [this, Physics] );
- }
- },
-
- /**
- * Physics.world#options( cfg ) -> Object
- * - options (Object): configuration options (see constructor)
- * + (Object): Options container
- *
- * Set config options. Also access options by `.options.