physics.js 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153
  1. /**
  2. * Physics
  3. * A requirified port of Traer Physics from Processing to JavaScript.
  4. * Copyright (C) 2012 jonobr1
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. 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<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  20. var _ = require('./common')
  21. , Vector = require('./vector')
  22. ;
  23. function Attraction(a, b, k, d) {
  24. this.a = a;
  25. this.b = b;
  26. this.constant = k;
  27. this.on = true;
  28. this.distanceMin = d;
  29. this.distanceMinSquared = d * d;
  30. }
  31. _.extend(Attraction.prototype, {
  32. update: function() {
  33. var a = this.a, b = this.b;
  34. if (!this.on || (a.fixed && b.fixed)) {
  35. return;
  36. }
  37. var a2bx = a.position.x - b.position.x;
  38. var a2by = a.position.y - b.position.y;
  39. var a2b = new Vector().sub(a.position, b.position);
  40. var a2bdistanceSquared = Math.max(a2b.lengthSquared(), this.distanceMinSquared);
  41. var force = (this.constant * a.mass * b.mass) / a2bdistanceSquared;
  42. var length = Math.sqrt(a2bdistanceSquared);
  43. if (force === 0 || length === 0) {
  44. a2b.clear();
  45. } else {
  46. a2b.divideScalar(length).multiplyScalar(force);
  47. }
  48. if (!a.fixed) {
  49. a.force.subSelf(a2b);
  50. }
  51. if (!b.fixed) {
  52. b.force.addSelf(a2b);
  53. }
  54. return this;
  55. },
  56. /**
  57. * Returns a boolean describing whether the spring is resting or not.
  58. * Convenient for knowing whether or not the spring needs another update
  59. * tick.
  60. *
  61. * TODO: Test
  62. */
  63. resting: function() {
  64. var a = this.a;
  65. var b = this.b;
  66. var l = this.distanceMin;
  67. return !this.on || (a.fixed && b.fixed)
  68. || (a.fixed && b.position.distanceTo(a.position) <= l && b.resting())
  69. || (b.fixed && a.position.distanceTo(b.position) <= l && a.resting());
  70. }
  71. });
  72. module.exports = Attraction;
  73. },{"./common":8,"./vector":12}],2:[function(require,module,exports){
  74. var _ = require('./common')
  75. , Vector = require('./vector')
  76. ;
  77. /**
  78. * Runge Kutta Integrator
  79. * http://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods
  80. *
  81. * @class
  82. */
  83. function Integrator(s) {
  84. this.s = s;
  85. this.originalPositions = [];
  86. this.originalVelocities = [];
  87. this.k1Forces = [];
  88. this.k1Velocities = [];
  89. this.k2Forces = [];
  90. this.k2Velocities = [];
  91. this.k3Forces = [];
  92. this.k3Velocities = [];
  93. this.k4Forces = [];
  94. this.k4Velocities = [];
  95. }
  96. _.extend(Integrator.prototype, {
  97. allocateParticles: function() {
  98. while (this.s.particles.length > this.originalPositions.length) {
  99. this.originalPositions.push(new Vector());
  100. this.originalVelocities.push(new Vector());
  101. this.k1Forces.push(new Vector());
  102. this.k1Velocities.push(new Vector());
  103. this.k2Forces.push(new Vector());
  104. this.k2Velocities.push(new Vector());
  105. this.k3Forces.push(new Vector());
  106. this.k3Velocities.push(new Vector());
  107. this.k4Forces.push(new Vector());
  108. this.k4Velocities.push(new Vector());
  109. }
  110. return this;
  111. },
  112. step: function(dt) {
  113. var s = this.s;
  114. var p, x, y;
  115. this.allocateParticles();
  116. _.each(s.particles, function(p, i) {
  117. if (!p.fixed) {
  118. this.originalPositions[i].copy(p.position);
  119. this.originalVelocities[i].copy(p.velocity);
  120. }
  121. p.force.clear();
  122. }, this);
  123. // K1
  124. s.applyForces();
  125. _.each(s.particles, function(p, i) {
  126. if (!p.fixed) {
  127. this.k1Forces[i].copy(p.force);
  128. this.k1Velocities[i].copy(p.velocity);
  129. }
  130. p.force.clear();
  131. }, this);
  132. // K2
  133. _.each(s.particles, function(p, i) {
  134. if (!p.fixed) {
  135. var op = this.originalPositions[i];
  136. var k1v = this.k1Velocities[i];
  137. x = op.x + k1v.x * 0.5 * dt;
  138. y = op.y + k1v.y * 0.5 * dt;
  139. p.position.set(x, y);
  140. var ov = this.originalVelocities[i];
  141. var k1f = this.k1Forces[i];
  142. x = ov.x + k1f.x * 0.5 * dt / p.mass;
  143. y = ov.y + k1f.y * 0.5 * dt / p.mass;
  144. p.velocity.set(x, y);
  145. }
  146. }, this);
  147. s.applyForces();
  148. _.each(s.particles, function(p, i) {
  149. if (!p.fixed) {
  150. this.k2Forces[i].copy(p.force);
  151. this.k2Velocities[i].copy(p.velocity);
  152. }
  153. p.force.clear();
  154. }, this);
  155. // K3
  156. _.each(s.particles, function(p, i) {
  157. if (!p.fixed) {
  158. var op = this.originalPositions[i];
  159. var k2v = this.k2Velocities[i];
  160. p.position.set(op.x + k2v.x * 0.5 * dt, op.y + k2v.y * 0.5 * dt);
  161. var ov = this.originalVelocities[i];
  162. var k2f = this.k2Forces[i];
  163. p.velocity.set(ov.x + k2f.x * 0.5 * dt / p.mass, ov.y + k2f.y * 0.5 * dt / p.mass);
  164. }
  165. }, this);
  166. s.applyForces();
  167. _.each(s.particles, function(p, i) {
  168. if (!p.fixed) {
  169. this.k3Forces[i].copy(p.force);
  170. this.k3Velocities[i].copy(p.velocity);
  171. }
  172. p.force.clear();
  173. }, this);
  174. // K4
  175. _.each(s.particles, function(p, i) {
  176. if (!p.fixed) {
  177. var op = this.originalPositions[i];
  178. var k3v = this.k3Velocities[i];
  179. p.position.set(op.x + k3v.x * dt, op.y + k3v.y * dt)
  180. var ov = this.originalVelocities[i];
  181. var k3f = this.k3Forces[i];
  182. p.velocity.set(ov.x + k3f.x * dt / p.mass, ov.y + k3f.y * dt / p.mass);
  183. }
  184. }, this);
  185. s.applyForces();
  186. _.each(s.particles, function(p, i) {
  187. if (!p.fixed) {
  188. this.k4Forces[i].copy(p.force);
  189. this.k4Velocities[i].copy(p.velocity);
  190. }
  191. }, this);
  192. // TOTAL
  193. _.each(s.particles, function(p, i) {
  194. p.age += dt;
  195. if (!p.fixed) {
  196. var op = this.originalPositions[i];
  197. var k1v = this.k1Velocities[i];
  198. var k2v = this.k2Velocities[i];
  199. var k3v = this.k3Velocities[i];
  200. var k4v = this.k4Velocities[i];
  201. var x = op.x + dt / 6.0 * (k1v.x + 2.0 * k2v.x + 2.0 * k3v.x + k4v.x);
  202. var y = op.y + dt / 6.0 * (k1v.y + 2.0 * k2v.y + 2.0 * k3v.y + k4v.y);
  203. p.position.set(x, y);
  204. var ov = this.originalVelocities[i];
  205. var k1f = this.k1Forces[i];
  206. var k2f = this.k2Forces[i];
  207. var k3f = this.k3Forces[i];
  208. var k4f = this.k4Forces[i];
  209. x = ov.x + dt / (6.0 * p.mass) * (k1f.x + 2.0 * k2f.x + 2.0 * k3f.x + k4f.x);
  210. y = ov.y + dt / (6.0 * p.mass) * (k1f.y + 2.0 * k2f.y + 2.0 * k3f.y + k4f.y);
  211. p.velocity.set(x, y);
  212. }
  213. }, this);
  214. return this;
  215. }
  216. });
  217. module.exports = Integrator;
  218. },{"./common":8,"./vector":12}],3:[function(require,module,exports){
  219. var _ = require('./common')
  220. , Vector = require('./vector')
  221. ;
  222. function Particle(mass) {
  223. this.position = new Vector();
  224. this.velocity = new Vector();
  225. this.force = new Vector();
  226. this.mass = mass;
  227. this.fixed = false;
  228. this.age = 0;
  229. this.dead = false;
  230. }
  231. _.extend(Particle.prototype, {
  232. /**
  233. * Get the distance between two particles.
  234. */
  235. distanceTo: function(p) {
  236. return this.position.distanceTo(p.position);
  237. },
  238. /**
  239. * Make the particle fixed in 2D space.
  240. */
  241. makeFixed: function() {
  242. this.fixed = true;
  243. this.velocity.clear();
  244. return this;
  245. },
  246. /**
  247. * Reset a particle.
  248. */
  249. reset: function() {
  250. this.age = 0;
  251. this.dead = false;
  252. this.position.clear();
  253. this.velocity.clear();
  254. this.force.clear();
  255. this.mass = 1.0;
  256. return this;
  257. },
  258. /**
  259. * Returns a boolean describing whether the particle is in movement.
  260. */
  261. resting: function() {
  262. return this.fixed || this.velocity.isZero() && this.force.isZero();
  263. }
  264. });
  265. module.exports = Particle;
  266. },{"./common":8,"./vector":12}],4:[function(require,module,exports){
  267. var _ = require('./common')
  268. , Vector = require('./Vector')
  269. , Particle = require('./Particle')
  270. , Spring = require('./Spring')
  271. , Attraction = require('./Attraction')
  272. , Integrator = require('./Integrator')
  273. ;
  274. /**
  275. * traer.js
  276. * A particle-based physics engine ported from Jeff Traer's Processing
  277. * library to JavaScript. This version is intended for use with the
  278. * HTML5 canvas element. It is dependent on Three.js' Vector2 class,
  279. * but can be overridden with any Vector2 class with the methods included.
  280. *
  281. * @author Jeffrey Traer Bernstein <jeff TA traer TOD cc> (original Java library)
  282. * @author Adam Saponara <saponara TA gmail TOD com> (JavaScript port)
  283. * @author Jono Brandel <http://jonobr1.com/> (requirified/optimization port)
  284. * @author David Schoonover <http://less.ly> (Node/CommonJS/Browserify port)
  285. *
  286. * @version 0.3
  287. * @date March 25, 2012
  288. */
  289. /**
  290. * The whole kit and kaboodle.
  291. *
  292. * @class
  293. */
  294. function ParticleSystem() {
  295. this.__equilibriumCriteria = { particles: true, springs: true, attractions: true };
  296. this.__equilibrium = false; // are we at equilibrium?
  297. this.__optimized = false;
  298. this.particles = [];
  299. this.springs = [];
  300. this.attractions = [];
  301. this.forces = [];
  302. this.integrator = new Integrator(this);
  303. this.hasDeadParticles = false;
  304. var args = arguments.length;
  305. if (args === 1) {
  306. this.gravity = new Vector(0, arguments[0]);
  307. this.drag = ParticleSystem.DEFAULT_DRAG;
  308. } else if (args === 2) {
  309. this.gravity = new Vector(0, arguments[0]);
  310. this.drag = arguments[1];
  311. } else if (args === 3) {
  312. this.gravity = new Vector(arguments[0], arguments[1]);
  313. this.drag = arguments[3];
  314. } else {
  315. this.gravity = new Vector(0, ParticleSystem.DEFAULT_GRAVITY);
  316. this.drag = ParticleSystem.DEFAULT_DRAG;
  317. }
  318. }
  319. _.extend(ParticleSystem, {
  320. DEFAULT_GRAVITY: 0,
  321. DEFAULT_DRAG: 0.001,
  322. Attraction: Attraction,
  323. Integrator: Integrator,
  324. Particle: Particle,
  325. Spring: Spring,
  326. Vector: Vector
  327. });
  328. _.extend(ParticleSystem.prototype, {
  329. /**
  330. * Set whether to optimize the simulation. This enables the check of whether
  331. * particles are moving.
  332. */
  333. optimize: function(b) {
  334. this.__optimized = !!b;
  335. return this;
  336. },
  337. /**
  338. * Set the gravity of the ParticleSystem.
  339. */
  340. setGravity: function(x, y) {
  341. this.gravity.set(x, y);
  342. return this;
  343. },
  344. /**
  345. * Sets the criteria for equilibrium
  346. */
  347. setEquilibriumCriteria: function(particles, springs, attractions) {
  348. this.__equilibriumCriteria.particles = !!particles;
  349. this.__equilibriumCriteria.springs = !!springs;
  350. this.__equilibriumCriteria.attractions = !!attractions;
  351. },
  352. /**
  353. * Update the integrator
  354. */
  355. tick: function() {
  356. this.integrator.step(arguments.length === 0 ? 1 : arguments[0]);
  357. if (this.__optimized) {
  358. this.__equilibrium = !this.needsUpdate();
  359. }
  360. return this;
  361. },
  362. /**
  363. * Checks all springs and attractions to see if the contained particles are
  364. * inert / resting and returns a boolean.
  365. */
  366. needsUpdate: function() {
  367. var i = 0;
  368. if(this.__equilibriumCriteria.particles) {
  369. for (i = 0, l = this.particles.length; i < l; i++) {
  370. if (!this.particles[i].resting()) {
  371. return true;
  372. }
  373. }
  374. }
  375. if(this.__equilibriumCriteria.springs) {
  376. for (i = 0, l = this.springs.length; i < l; i++) {
  377. if (!this.springs[i].resting()) {
  378. return true;
  379. }
  380. }
  381. }
  382. if(this.__equilibriumCriteria.attractions) {
  383. for (i = 0, l = this.attractions.length; i < l; i++) {
  384. if (!this.attractions[i].resting()) {
  385. return true;
  386. }
  387. }
  388. }
  389. return false;
  390. },
  391. /**
  392. * Add a particle to the ParticleSystem.
  393. */
  394. addParticle: function(p) {
  395. this.particles.push(p);
  396. return this;
  397. },
  398. /**
  399. * Add a spring to the ParticleSystem.
  400. */
  401. addSpring: function(s) {
  402. this.springs.push(s);
  403. return this;
  404. },
  405. /**
  406. * Add an attraction to the ParticleSystem.
  407. */
  408. addAttraction: function(a) {
  409. this.attractions.push(a);
  410. return this;
  411. },
  412. /**
  413. * Makes and then adds Particle to ParticleSystem.
  414. */
  415. makeParticle: function(m, x, y) {
  416. var mass = _.isNumber(m) ? m : 1.0;
  417. var x = x || 0;
  418. var y = y || 0;
  419. var p = new Particle(mass);
  420. p.position.set(x, y);
  421. this.addParticle(p);
  422. return p;
  423. },
  424. /**
  425. * Makes and then adds Spring to ParticleSystem.
  426. */
  427. makeSpring: function(a, b, k, d, l) {
  428. var s = new Spring(a, b, k, d, l);
  429. this.addSpring(s);
  430. return s;
  431. },
  432. /**
  433. * Makes and then adds Attraction to ParticleSystem.
  434. */
  435. makeAttraction: function(a, b, k, d) {
  436. var a = new Attraction(a, b, k, d);
  437. this.addAttraction(a);
  438. return a;
  439. },
  440. /**
  441. * Wipe the ParticleSystem clean.
  442. */
  443. clear: function() {
  444. this.particles.length = 0;
  445. this.springs.length = 0;
  446. this.attractions.length = 0;
  447. },
  448. /**
  449. * Calculate and apply forces.
  450. */
  451. applyForces: function() {
  452. if (!this.gravity.isZero()) {
  453. _.each(this.particles, function(p) {
  454. p.force.addSelf(this.gravity);
  455. }, this);
  456. }
  457. var t = new Vector();
  458. _.each(this.particles, function(p) {
  459. t.set(p.velocity.x * -1 * this.drag, p.velocity.y * -1 * this.drag);
  460. p.force.addSelf(t);
  461. }, this);
  462. _.each(this.springs, function(s) {
  463. s.update();
  464. });
  465. _.each(this.attractions, function(a) {
  466. a.update();
  467. });
  468. _.each(this.forces, function(f) {
  469. f.update();
  470. });
  471. return this;
  472. },
  473. /**
  474. * Clear all particles in the system.
  475. */
  476. clearForces: function() {
  477. _.each(this.particles, function(p) {
  478. p.clear();
  479. });
  480. return this;
  481. }
  482. });
  483. module.exports = ParticleSystem;
  484. },{"./Attraction":1,"./Integrator":2,"./Particle":3,"./Spring":6,"./Vector":7,"./common":8}],5:[function(require,module,exports){
  485. var _ = require('./common')
  486. , raf = require('./requestAnimationFrame')
  487. , ParticleSystem = require('./ParticleSystem')
  488. ;
  489. var updates = [];
  490. /**
  491. * Extended singleton instance of ParticleSystem with convenience methods for
  492. * Request Animation Frame.
  493. * @class
  494. */
  495. function Physics() {
  496. var _this = this;
  497. this.playing = false;
  498. ParticleSystem.apply(this, arguments);
  499. this.animations = [];
  500. this.equilibriumCallbacks = [];
  501. update.call(this);
  502. }
  503. _.extend(Physics, ParticleSystem, {
  504. superclass: ParticleSystem
  505. });
  506. _.extend(Physics.prototype, ParticleSystem.prototype, {
  507. /**
  508. * Play the animation loop. Doesn't affect whether in equilibrium or not.
  509. */
  510. play: function() {
  511. if (this.playing) {
  512. return this;
  513. }
  514. this.playing = true;
  515. this.__equilibrium = false;
  516. update.call(this);
  517. return this;
  518. },
  519. /**
  520. * Pause the animation loop. Doesn't affect whether in equilibrium or not.
  521. */
  522. pause: function() {
  523. this.playing = false;
  524. return this;
  525. },
  526. /**
  527. * Toggle between playing and pausing the simulation.
  528. */
  529. toggle: function() {
  530. if (this.playing) {
  531. this.pause();
  532. } else {
  533. this.play();
  534. }
  535. return this;
  536. },
  537. onUpdate: function(func) {
  538. if (_.indexOf(this.animations, func) >= 0 || !_.isFunction(func)) {
  539. return this;
  540. }
  541. this.animations.push(func);
  542. return this;
  543. },
  544. onEquilibrium: function(func) {
  545. if (_.indexOf(this.equilibriumCallbacks, func) >= 0 || !_.isFunction(func)) {
  546. return this;
  547. }
  548. this.equilibriumCallbacks.push(func);
  549. return this;
  550. },
  551. /**
  552. * Call update after values in the system have changed and this will fire
  553. * it's own Request Animation Frame to update until things have settled
  554. * to equilibrium — at which point the system will stop updating.
  555. */
  556. update: function() {
  557. if (!this.__equilibrium) {
  558. return this;
  559. }
  560. this.__equilibrium = false;
  561. if (this.playing) {
  562. update.call(this);
  563. }
  564. return this;
  565. }
  566. });
  567. function update() {
  568. var _this = this;
  569. this.tick();
  570. _.each(this.animations, function(a) {
  571. a();
  572. });
  573. if ((this.__optimized && !this.__equilibrium || !this.__optimized) && this.playing) {
  574. raf(function() {
  575. update.call(_this);
  576. });
  577. }
  578. if (this.__optimized && this.__equilibrium){
  579. _.each(this.equilibriumCallbacks, function(a) {
  580. a();
  581. });
  582. }
  583. }
  584. module.exports = Physics;
  585. },{"./ParticleSystem":4,"./common":8,"./requestAnimationFrame":11}],6:[function(require,module,exports){
  586. var _ = require('./common')
  587. , Vector = require('./vector')
  588. ;
  589. function Spring(a, b, k, d, l) {
  590. this.constant = k;
  591. this.damping = d;
  592. this.length = l;
  593. this.a = a;
  594. this.b = b;
  595. this.on = true;
  596. }
  597. _.extend(Spring.prototype, {
  598. /**
  599. * Returns the distance between particle a and particle b
  600. * in 2D space.
  601. */
  602. currentLength: function() {
  603. return this.a.position.distanceTo(this.b.position);
  604. },
  605. /**
  606. * Update spring logic.
  607. */
  608. update: function() {
  609. var a = this.a;
  610. var b = this.b;
  611. if (!(this.on && (!a.fixed || !b.fixed))) return this;
  612. var a2b = new Vector().sub(a.position, b.position);
  613. var d = a2b.length();
  614. if (d === 0) {
  615. a2b.clear();
  616. } else {
  617. a2b.divideScalar(d); // Essentially normalize
  618. }
  619. var fspring = -1 * (d - this.length) * this.constant;
  620. var va2b = new Vector().sub(a.velocity, b.velocity);
  621. var fdamping = -1 * this.damping * va2b.dot(a2b);
  622. var fr = fspring + fdamping;
  623. a2b.multiplyScalar(fr);
  624. if (!a.fixed) {
  625. a.force.addSelf(a2b);
  626. }
  627. if (!b.fixed) {
  628. b.force.subSelf(a2b);
  629. }
  630. return this;
  631. },
  632. /**
  633. * Returns a boolean describing whether the spring is resting or not.
  634. * Convenient for knowing whether or not the spring needs another update
  635. * tick.
  636. */
  637. resting: function() {
  638. var a = this.a;
  639. var b = this.b;
  640. var l = this.length;
  641. return !this.on || (a.fixed && b.fixed)
  642. || (a.fixed && (l === 0 ? b.position.equals(a.position) : b.position.distanceTo(a.position) <= l) && b.resting())
  643. || (b.fixed && (l === 0 ? a.position.equals(b.position) : a.position.distanceTo(b.position) <= l) && a.resting());
  644. }
  645. });
  646. module.exports = Spring;
  647. },{"./common":8,"./vector":12}],7:[function(require,module,exports){
  648. /**
  649. * @author mr.doob / http://mrdoob.com/
  650. * @author philogb / http://blog.thejit.org/
  651. * @author egraether / http://egraether.com/
  652. * @author zz85 / http://www.lab4games.net/zz85/blog
  653. * @author jonobr1 / http://jonobr1.com/
  654. */
  655. var _ = require('./common');
  656. /**
  657. * A two dimensional vector.
  658. */
  659. function Vector(x, y) {
  660. this.x = x || 0;
  661. this.y = y || 0;
  662. }
  663. _.extend(Vector.prototype, {
  664. set: function(x, y) {
  665. this.x = x;
  666. this.y = y;
  667. return this;
  668. },
  669. copy: function(v) {
  670. this.x = v.x;
  671. this.y = v.y;
  672. return this;
  673. },
  674. clear: function() {
  675. this.x = 0;
  676. this.y = 0;
  677. return this;
  678. },
  679. clone: function() {
  680. return new Vector(this.x, this.y);
  681. },
  682. add: function(v1, v2) {
  683. this.x = v1.x + v2.x;
  684. this.y = v1.y + v2.y;
  685. return this;
  686. },
  687. addSelf: function(v) {
  688. this.x += v.x;
  689. this.y += v.y;
  690. return this;
  691. },
  692. sub: function(v1, v2) {
  693. this.x = v1.x - v2.x;
  694. this.y = v1.y - v2.y;
  695. return this;
  696. },
  697. subSelf: function(v) {
  698. this.x -= v.x;
  699. this.y -= v.y;
  700. return this;
  701. },
  702. multiplySelf: function(v) {
  703. this.x *= v.x;
  704. this.y *= v.y;
  705. return this;
  706. },
  707. multiplyScalar: function(s) {
  708. this.x *= s;
  709. this.y *= s;
  710. return this;
  711. },
  712. multiplyScalarXY: function(sx,sy) {
  713. this.x *= sx;
  714. this.y *= sy;
  715. return this;
  716. },
  717. divideScalar: function(s) {
  718. if (s) {
  719. this.x /= s;
  720. this.y /= s;
  721. } else {
  722. this.set(0, 0);
  723. }
  724. return this;
  725. },
  726. negate: function() {
  727. return this.multiplyScalar(-1);
  728. },
  729. dot: function(v) {
  730. return this.x * v.x + this.y * v.y;
  731. },
  732. lengthSquared: function() {
  733. return this.x * this.x + this.y * this.y;
  734. },
  735. length: function() {
  736. return Math.sqrt(this.lengthSquared());
  737. },
  738. normalize: function() {
  739. return this.divideScalar(this.length());
  740. },
  741. distanceTo: function(v) {
  742. return Math.sqrt(this.distanceToSquared(v));
  743. },
  744. distanceToSquared: function(v) {
  745. var dx = this.x - v.x, dy = this.y - v.y;
  746. return dx * dx + dy * dy;
  747. },
  748. setLength: function(l) {
  749. return this.normalize().multiplyScalar(l);
  750. },
  751. equals: function(v) {
  752. return (this.distanceTo(v) < 0.0001 /* almost same position */);
  753. },
  754. lerp: function(v, t) {
  755. var x = (v.x - this.x) * t + this.x;
  756. var y = (v.y - this.y) * t + this.y;
  757. return this.set(x, y);
  758. },
  759. isZero: function() {
  760. return (this.length() < 0.0001 /* almost zero */ );
  761. }
  762. });
  763. module.exports = Vector;
  764. },{"./common":8}],8:[function(require,module,exports){
  765. /**
  766. * Pulled only what's needed from:
  767. *
  768. * Underscore.js 1.3.3
  769. * (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
  770. * http://documentcloud.github.com/underscore
  771. */
  772. var breaker = {};
  773. var ArrayProto = Array.prototype;
  774. var ObjProto = Object.prototype;
  775. var hasOwnProperty = ObjProto.hasOwnProperty;
  776. var slice = ArrayProto.slice;
  777. var nativeForEach = ArrayProto.forEach;
  778. var nativeIndexOf = ArrayProto.indexOf;
  779. var toString = ObjProto.toString;
  780. var has = function(obj, key) {
  781. return hasOwnProperty.call(obj, key);
  782. };
  783. var each = function(obj, iterator, context) {
  784. if (obj == null) return;
  785. if (nativeForEach && obj.forEach === nativeForEach) {
  786. obj.forEach(iterator, context);
  787. } else if (obj.length === +obj.length) {
  788. for (var i = 0, l = obj.length; i < l; i++) {
  789. if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
  790. }
  791. } else {
  792. for (var key in obj) {
  793. if (_.has(obj, key)) {
  794. if (iterator.call(context, obj[key], key, obj) === breaker) return;
  795. }
  796. }
  797. }
  798. };
  799. var identity = function(value) {
  800. return value;
  801. };
  802. var sortedIndex = function(array, obj, iterator) {
  803. iterator || (iterator = identity);
  804. var low = 0, high = array.length;
  805. while (low < high) {
  806. var mid = (low + high) >> 1;
  807. iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
  808. }
  809. return low;
  810. };
  811. module.exports = {
  812. has: has,
  813. each: each,
  814. extend: function(obj) {
  815. each(slice.call(arguments, 1), function(source) {
  816. for (var prop in source) {
  817. obj[prop] = source[prop];
  818. }
  819. });
  820. return obj;
  821. },
  822. indexOf: function(array, item, isSorted) {
  823. if (array == null) return -1;
  824. var i, l;
  825. if (isSorted) {
  826. i = sortedIndex(array, item);
  827. return array[i] === item ? i : -1;
  828. }
  829. if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
  830. for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
  831. return -1;
  832. },
  833. sortedIndex: sortedIndex,
  834. identity: identity,
  835. isNumber: function(obj) {
  836. return toString.call(obj) == '[object Number]';
  837. },
  838. isFunction: function(obj) {
  839. return toString.call(obj) == '[object Function]' || typeof obj == 'function';
  840. },
  841. isUndefined: function(obj) {
  842. return obj === void 0;
  843. },
  844. isNull: function(obj) {
  845. return obj === null;
  846. }
  847. };
  848. },{}],"H99CHA":[function(require,module,exports){
  849. var root = (function(){ return this; })()
  850. , previousShortcut = root.Physics
  851. ;
  852. module.exports = root.Physics = require('./Physics');
  853. },{"./Physics":5}],"physics":[function(require,module,exports){
  854. module.exports=require('H99CHA');
  855. },{}],11:[function(require,module,exports){
  856. /*
  857. * Requirified version of Paul Irish's request animation frame.
  858. * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
  859. */
  860. module.exports =
  861. window.requestAnimationFrame ||
  862. window.webkitRequestAnimationFrame ||
  863. window.mozRequestAnimationFrame ||
  864. window.oRequestAnimationFrame ||
  865. window.msRequestAnimationFrame ||
  866. function (callback) {
  867. window.setTimeout(callback, 1000 / 60);
  868. };
  869. },{}],12:[function(require,module,exports){
  870. module.exports=require(7)
  871. },{"./common":8}]},{},["H99CHA"])