fieldkit
Version:
Basic building blocks for computational design projects. Written in CoffeeScript for browser and server environments.
314 lines (253 loc) • 7.84 kB
JavaScript
// Generated by CoffeeScript 1.6.3
(function() {
var Behaviour, Constraint, Emitter, Particle, Physics, Space, Spring, particleModule, util, _ref,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
util = require('../util');
particleModule = require('./particle');
Particle = particleModule.Particle;
/*
A Particle Physics Simulation
*/
Physics = (function() {
function Physics() {
this.particles = [];
this.springs = [];
this.behaviours = [];
this.constraints = [];
this.emitter = null;
this.space = null;
this.constraintIterations = 1;
this.springIterations = 1;
this.space = new Space();
this.emitter = new Emitter(this);
this.clear();
}
Physics.prototype.clear = function() {
this.particles = [];
this.behaviours = [];
return this.constraints = [];
};
Physics.prototype.add = function() {
var arg, state;
if (arguments.length === 0) {
return;
}
arg = arguments[0];
if (arg instanceof Particle) {
this.addParticle(arg);
} else if (arg instanceof Behaviour) {
console.log("adding behaviour " + arg);
if (arguments.length > 1) {
state = arguments[1];
}
this.addBehaviour(arg, state);
} else if (arg instanceof Spring) {
console.log("adding spring " + arg);
this.addSpring(arg);
} else {
"Cannot add " + arg;
}
return arg;
};
Physics.prototype.addParticle = function(particle) {
this.particles.push(particle);
return particle;
};
Physics.prototype.addSpring = function(spring) {
this.springs.push(spring);
return spring;
};
Physics.prototype.addBehaviour = function(effector, state) {
var list;
if (state == null) {
state = particleModule.State.ALIVE;
}
list = effector instanceof Constraint ? this.constraints : this.behaviours;
if (!list[state]) {
list[state] = [];
}
return list[state].push(effector);
};
Physics.prototype.update = function() {
var dead, i, j, particle, particles, spring, stateDead, _i, _j, _k, _l, _len, _len1, _ref, _ref1, _ref2;
this.emitter.update();
this.space.update(this);
particles = this.particles;
this.applyEffectors(this.behaviours, particles);
for (j = _i = 0, _ref = this.constraintIterations; 0 <= _ref ? _i <= _ref : _i >= _ref; j = 0 <= _ref ? ++_i : --_i) {
this.applyEffectors(this.constraints, particles);
for (i = _j = 0, _ref1 = this.springIterations; 0 <= _ref1 ? _j <= _ref1 : _j >= _ref1; i = 0 <= _ref1 ? ++_j : --_j) {
_ref2 = this.springs;
for (_k = 0, _len = _ref2.length; _k < _len; _k++) {
spring = _ref2[_k];
spring.update();
}
}
}
dead = [];
stateDead = particleModule.State.DEAD;
for (_l = 0, _len1 = particles.length; _l < _len1; _l++) {
particle = particles[_l];
particle.update();
if (particle.state === stateDead) {
dead.push(particle);
}
void 0;
}
i = dead.length;
while (i--) {
particle = dead[i];
util.removeElement(particle, particles);
void 0;
}
return void 0;
};
Physics.prototype.applyEffectors = function(effectors, particles) {
var effector, particle, state, stateEffectors, _i, _j, _len, _len1;
state = effectors.length;
while (state--) {
stateEffectors = effectors[state];
for (_i = 0, _len = stateEffectors.length; _i < _len; _i++) {
effector = stateEffectors[_i];
effector.prepare(this);
for (_j = 0, _len1 = particles.length; _j < _len1; _j++) {
particle = particles[_j];
if (particle.state === state && !particle.isLocked) {
effector.apply(particle);
}
void 0;
}
void 0;
}
void 0;
}
return void 0;
};
Physics.prototype.size = function() {
return this.particles.length;
};
return Physics;
})();
/*
Spatial Search
Simple brute force spatial searches.
Subclasses may override this to organise particles so they can be found quicker later
*/
Space = (function() {
var physics;
physics = null;
function Space() {}
Space.prototype.update = function(physics_) {
return physics = physics_;
};
Space.prototype.search = function(center, radius) {
var particle, radiusSq, result, _i, _len, _ref;
result = [];
radiusSq = radius * radius;
_ref = physics.particles;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
particle = _ref[_i];
if (center.distanceSquared(particle.position) < radiusSq) {
result.push(particle);
}
}
return result;
};
return Space;
})();
/*
Particle Emitter
*/
Emitter = (function() {
var id, timer;
timer = -1;
id = 0;
function Emitter(physics) {
this.physics = physics;
this.rate = 1;
this.interval = 1;
this.max = 100;
this.type = particleModule.Particle3;
}
Emitter.prototype.update = function() {
var i, p;
if (timer === -1 || timer >= this.interval) {
timer = 0;
i = 0;
while (i < this.rate && this.physics.size() < this.max) {
p = this.create();
this.init(p);
i++;
}
}
return timer++;
};
Emitter.prototype.create = function() {
var p;
p = new this.type(id++);
this.physics.addParticle(p);
return p;
};
Emitter.prototype.init = function(particle) {};
return Emitter;
})();
/*
Base class for all physical forces, behaviours & constraints
*/
Behaviour = (function() {
function Behaviour() {}
Behaviour.prototype.prepare = function() {};
Behaviour.prototype.apply = function(particle) {};
return Behaviour;
})();
Constraint = (function(_super) {
__extends(Constraint, _super);
function Constraint() {
_ref = Constraint.__super__.constructor.apply(this, arguments);
return _ref;
}
Constraint.prototype.prepare = function() {};
Constraint.prototype.apply = function(particle) {};
return Constraint;
})(Behaviour);
/*
Verlet Spring
*/
Spring = (function() {
function Spring(a, b, strength) {
this.a = a;
this.b = b;
this.strength = strength != null ? strength : 0.5;
this.restLength = this.a.position.distance(this.b.position);
}
Spring.prototype.update = function() {
var delta, dist, normDistStrength;
delta = this.b.position.sub_(this.a.position);
dist = delta.length() + Number.MIN_VALUE;
normDistStrength = (dist - this.restLength) / dist * this.strength;
if (normDistStrength === 0) {
return;
}
delta.scale(normDistStrength);
if (!this.a.isLocked) {
this.a.position.add(delta);
}
if (!this.b.isLocked) {
return this.b.position.sub(delta);
}
};
Spring.prototype.toString = function() {
return "Spring(" + a + ", " + b + ")";
};
return Spring;
})();
module.exports = {
Physics: Physics,
Emitter: Emitter,
Space: Space,
Behaviour: Behaviour,
Constraint: Constraint,
Spring: Spring
};
}).call(this);