Skip to content

Commit

Permalink
now using a verlet integrator by default
Browse files Browse the repository at this point in the history
the euler integrator can still be selected in the ParticleSystem
constructor
  • Loading branch information
samizdatco committed May 26, 2012
1 parent 279231d commit 7be64db
Showing 4 changed files with 69 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/dev.js
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
// <script src="js/src/tween/easing.js"></script>
// <script src="js/src/tween/tween.js"></script>
// <script src="js/src/physics/atoms.js"></script>
// <script src="js/src/physics/barnes-hut.js"></script>
// <script src="js/src/physics/physics.js"></script>
// <script src="js/src/physics/system.js"></script>
// <script src="js/src/dev.js"></script>
8 changes: 4 additions & 4 deletions src/kernel.js
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
var chrome_local_file = window.location.protocol == "file:" &&
navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
var USE_WORKER = (window.Worker !== undefined && !chrome_local_file)

var _physics = null
var _tween = null
var _fpsWindow = [] // for keeping track of the actual frame rate
@@ -36,7 +36,7 @@
var params = pSystem.parameters()

if(USE_WORKER){
trace('using web workers')
trace('arbor.js/web-workers',params)
_screenInterval = setInterval(that.screenUpdate, params.timeout)

_physics = new Worker(arbor_path()+'physics/worker.js')
@@ -46,8 +46,8 @@
physics:objmerge(params,
{timeout:Math.ceil(params.timeout)}) })
}else{
trace("couldn't use web workers, be careful...")
_physics = Physics(params.dt, params.stiffness, params.repulsion, params.friction, that.system._updateGeometry)
trace('arbor.js/single-threaded',params)
_physics = Physics(params.dt, params.stiffness, params.repulsion, params.friction, that.system._updateGeometry, params.integrator)
that.start()
}

81 changes: 54 additions & 27 deletions src/physics/physics.js
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
// the particle system itself. either run inline or in a worker (see worker.js)
//

var Physics = function(dt, stiffness, repulsion, friction, updateFn){
var Physics = function(dt, stiffness, repulsion, friction, updateFn, integrator){
var bhTree = BarnesHutTree() // for computing particle repulsion
var active = {particles:{}, springs:{}}
var free = {particles:{}}
@@ -17,6 +17,7 @@
var SPEED_LIMIT = 1000 // the max particle velocity per tick

var that = {
integrator:['verlet','euler'].indexOf(integrator)>=0 ? integrator : 'verlet',
stiffness:(stiffness!==undefined) ? stiffness : 1000,
repulsion:(repulsion!==undefined)? repulsion : 600,
friction:(friction!==undefined)? friction : .3,
@@ -29,14 +30,14 @@
},

modifyPhysics:function(param){
$.each(['stiffness','repulsion','friction','gravity','dt','precision'], function(i, p){
$.each(['stiffness','repulsion','friction','gravity','dt','precision', 'integrator'], function(i, p){
if (param[p]!==undefined){
if (p=='precision'){
that.theta = 1-param[p]
return
}
that[p] = param[p]

if (p=='stiffness'){
var stiff=param[p]
$.each(active.springs, function(id, spring){
@@ -129,10 +130,20 @@
return _epoch
},


tick:function(){
that.tendParticles()
that.eulerIntegrator(that.dt)
if (that.integrator=='euler'){
that.updateForces()
that.updateVelocity(that.dt)
that.updatePosition(that.dt)
}else{
// default to verlet
that.updateForces();
that.cacheForces(); // snapshot f(t)
that.updatePosition(that.dt); // update position to x(t + 1)
that.updateForces(); // calculate f(t+1)
that.updateVelocity(that.dt); // update using f(t) and f(t+1)
}
that.tock()
},

@@ -168,19 +179,24 @@
},


// Physics stuff
eulerIntegrator:function(dt){
// Physics stuff
updateForces:function() {
if (that.repulsion>0){
if (that.theta>0) that.applyBarnesHutRepulsion()
else that.applyBruteForceRepulsion()
}
if (that.stiffness>0) that.applySprings()
that.applyCenterDrift()
if (that.gravity) that.applyCenterGravity()
that.updateVelocity(dt)
that.updatePosition(dt)
},


cacheForces:function() {
// keep a snapshot of the current forces for the verlet integrator
$.each(active.particles, function(id, point) {
point._F = point.f;
});
},

applyBruteForceRepulsion:function(){
$.each(active.particles, function(id1, point1){
$.each(active.particles, function(id2, point2){
@@ -266,39 +282,51 @@

updateVelocity:function(timestep){
// translate forces to a new velocity for this particle
var sum=0, max=0, n = 0;
$.each(active.particles, function(id, point) {
if (point.fixed){
point.v = new Point(0,0)
point.f = new Point(0,0)
return
}

var was = point.v.magnitude()
point.v = point.v.add(point.f.multiply(timestep)).multiply(1-that.friction);
if (that.integrator=='euler'){
point.v = point.v.add(point.f.multiply(timestep)).multiply(1-that.friction);
}else{
point.v = point.v.add(point.f.add(point._F).multiply(timestep*0.5)).multiply(1-that.friction);
}
point.f.x = point.f.y = 0

var speed = point.v.magnitude()
if (speed>SPEED_LIMIT) point.v = point.v.divide(speed*speed)

var speed = point.v.magnitude();
var e = speed*speed
sum += e
max = Math.max(e,max)
n++
});
_energy = {sum:sum, max:max, mean:sum/n, n:n}

},

updatePosition:function(timestep){
// translate velocity to a position delta
var sum=0, max=0, n = 0;
var bottomright = null
var topleft = null

var topleft = null
$.each(active.particles, function(i, point) {

// move the node to its new position
point.p = point.p.add(point.v.multiply(timestep));
if (that.integrator=='euler'){
point.p = point.p.add(point.v.multiply(timestep));
}else{
//this should follow the equation
//x(t+1) = x(t) + v(t) * timestep + 1/2 * timestep^2 * a(t)
var accelPart = point.f.multiply(0.5 * timestep * timestep);
point.p = point.p.add(point.v.multiply(timestep)).add(accelPart);
}

// keep stats to report in systemEnergy
var speed = point.v.magnitude();
var e = speed*speed
sum += e
max = Math.max(e,max)
n++

if (!bottomright){
bottomright = new Point(point.p.x, point.p.y)
topleft = new Point(point.p.x, point.p.y)
@@ -309,11 +337,10 @@
if (pt.x===null || pt.y===null) return
if (pt.x > bottomright.x) bottomright.x = pt.x;
if (pt.y > bottomright.y) bottomright.y = pt.y;
if (pt.x < topleft.x) topleft.x = pt.x;
if (pt.y < topleft.y) topleft.y = pt.y;
if (pt.x < topleft.x) topleft.x = pt.x;
if (pt.y < topleft.y) topleft.y = pt.y;
});

_energy = {sum:sum, max:max, mean:sum/n, n:n}
_bounds = {topleft:topleft||new Point(-1,-1), bottomright:bottomright||new Point(1,1)}
},

@@ -333,4 +360,4 @@
var y = center_pt.y
var d = r*2
return new Point(x-r+Math.random()*d, y-r+Math.random()*d)
}
}
16 changes: 10 additions & 6 deletions src/physics/system.js
Original file line number Diff line number Diff line change
@@ -4,8 +4,8 @@
// the main controller object for creating/modifying graphs
//

var ParticleSystem = function(repulsion, stiffness, friction, centerGravity, targetFps, dt, precision){
// also callable with ({stiffness:, repulsion:, friction:, timestep:, fps:, dt:, gravity:})
var ParticleSystem = function(repulsion, stiffness, friction, centerGravity, targetFps, dt, precision, integrator){
// also callable with ({integrator:, stiffness:, repulsion:, friction:, timestep:, fps:, dt:, gravity:})

var _changes=[]
var _notification=null
@@ -17,26 +17,30 @@
var _bounds = null
var _boundsTarget = null

if (typeof stiffness=='object'){
var _p = stiffness
if (typeof repulsion=='object'){
var _p = repulsion
friction = _p.friction
repulsion = _p.repulsion
targetFps = _p.fps
dt = _p.dt
stiffness = _p.stiffness
centerGravity = _p.gravity
precision = _p.precision
integrator = _p.integrator
}

// param validation and defaults
if (integrator!='verlet' && integrator!='euler') integrator='verlet'
friction = isNaN(friction) ? .5 : friction
repulsion = isNaN(repulsion) ? 1000 : repulsion
targetFps = isNaN(targetFps) ? 55 : targetFps
stiffness = isNaN(stiffness) ? 600 : stiffness
dt = isNaN(dt) ? 0.02 : dt
precision = isNaN(precision) ? .6 : precision
centerGravity = (centerGravity===true)

var _systemTimeout = (targetFps!==undefined) ? 1000/targetFps : 1000/50
var _parameters = {repulsion:repulsion, stiffness:stiffness, friction:friction, dt:dt, gravity:centerGravity, precision:precision, timeout:_systemTimeout}
var _parameters = {integrator:integrator, repulsion:repulsion, stiffness:stiffness, friction:friction, dt:dt, gravity:centerGravity, precision:precision, timeout:_systemTimeout}
var _energy

var state = {
@@ -68,10 +72,10 @@
else that.parameters({timeout:1000/(newFPS||50)})
},


start:function(){
state.kernel.start()
},

stop:function(){
state.kernel.stop()
},

0 comments on commit 7be64db

Please sign in to comment.