From 6255e3285ad89c565087a0d1ac9c8e65d57fc17c Mon Sep 17 00:00:00 2001 From: Bachir Soussi Chiadmi Date: Mon, 18 Dec 2017 19:03:20 +0100 Subject: [PATCH] corpus ajax loaded and displayed as physics map --- .../edlp_corpus/assets/dist/bower/physics.js | 1153 ++ .../assets/dist/bower/physicsjs-full.js | 11963 ---------------- .../assets/dist/scripts/corpus.min.js | 141 +- .../assets/dist/styles/corpus.min.css | 7 + .../edlp_corpus/assets/scripts/corpus.js | 141 +- .../edlp_corpus/assets/styles/corpus.scss | 7 + .../all/modules/figli/edlp_corpus/bower.json | 2 +- .../edlp_corpus/edlp_corpus.libraries.yml | 3 +- .../figli/edlp_corpus/edlp_corpus.module | 8 +- .../figli/edlp_corpus/edlp_corpus.routing.yml | 4 +- .../all/modules/figli/edlp_corpus/gulpfile.js | 5 + .../src/Controller/CorpusController.php | 63 +- sites/all/themes/custom/edlptheme/.gitignore | 1 + .../edlptheme/assets/dist/styles/app.min.css | 3 +- .../custom/edlptheme/assets/styles/app.scss | 1 + 15 files changed, 1520 insertions(+), 11982 deletions(-) create mode 100644 sites/all/modules/figli/edlp_corpus/assets/dist/bower/physics.js delete mode 100644 sites/all/modules/figli/edlp_corpus/assets/dist/bower/physicsjs-full.js 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.