day3 (german!) libs

This commit is contained in:
gauthiier
2015-03-04 09:41:41 +01:00
parent 6b37eb529e
commit e772172cbc
133 changed files with 18241 additions and 0 deletions
@@ -0,0 +1,71 @@
import mathematik.*;
import processing.opengl.*;
import mathematik.*;
import teilchen.Particle;
import teilchen.Physics;
/**
* this sketch show how to create a particle system with a single particle in it.
*/
Physics mPhysics;
Particle mParticle;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system. */
mPhysics = new Physics();
/*
* a physic-based particle system consists of a few components.
*
* 1 particles.
* there are different kinds of particles. for now we use a simple particle.
*
* 2 forces.
* there are all kinds of forces. one of the most obvious force is the gravitational force,
* but there all kinds of different forces like attractors and springs. forces usually
* affect all particles in the system.
*
* 3 behaviors
* a behavior is special kind of force. it is something like an internal force or a motor
* that only affects a single particle. a typical force is for example the 'seek force'
* which constantly pulls a particle into a certain direction.
*
* 4 integrators.
* integrators are used to integrate acceleration and velocity to calculate the new position.
* the most well-known is the 'euler' integrator, but there are also optimized versions like 'runge-kutta'
* or 'Midpoint' or even slightly different concepts like 'verlet'.
*
*/
/* create a particle. note that the particle is automatically added to particle system */
mParticle = mPhysics.makeParticle();
}
void draw() {
/* update the particle system to the next step. usually the time step is the duration of the las frame */
final float mDeltaTime = 1.0 / frameRate;
mPhysics.step(mDeltaTime);
/* draw particle */
background(255);
stroke(0, 127);
fill(0, 32);
ellipse(mParticle.position().x, mParticle.position().y, 12, 12);
/* reset particle s position and velocity */
if (mousePressed) {
mParticle.position().set(mouseX, mouseY);
mParticle.velocity().set(mouseX - pmouseX, mouseY - pmouseY);
mParticle.velocity().scale(10);
}
}
@@ -0,0 +1,54 @@
import processing.opengl.*;
import mathematik.*;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.Gravity;
/**
* this sketch show how to create a particle system with a single particle in it.
*/
Physics mPhysics;
Particle mParticle;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a gravitational force */
Gravity mGravity = new Gravity();
/* the direction of the gravity is defined by the 'force' vector */
mGravity.force().set(0, 30, 0);
/* forces, like gravity or any other force, can be added to the system. they will be automatically applied to all particles */
mPhysics.add(mGravity);
/* create a particle and add it to the system */
mParticle = mPhysics.makeParticle();
}
void draw() {
/* update the particle system. this applies the gravity to the particle */
final float mDeltaTime = 1.0 / frameRate;
mPhysics.step(mDeltaTime);
/* draw particle */
background(255);
stroke(0, 127);
fill(0, 32);
ellipse(mParticle.position().x, mParticle.position().y, 12, 12);
/* reset particle s position and velocity */
if (mousePressed) {
mParticle.position().set(mouseX, mouseY);
mParticle.velocity().set(mouseX - pmouseX, mouseY - pmouseY);
mParticle.velocity().scale(10);
}
}
@@ -0,0 +1,58 @@
import processing.opengl.*;
import mathematik.*;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.Gravity;
/**
* this sketch shows how to create and handle multiple particles and remove individual particles.
*/
Physics mPhysics;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a gravitational force and add it to the particle system */
Gravity myGravity = new Gravity(0, 30, 0);
mPhysics.add(myGravity);
}
void draw() {
if (mousePressed) {
/* create and add a particle to the system */
Particle mParticle = mPhysics.makeParticle();
/* set particle to mouse position with random velocity */
mParticle.position().set(mouseX, mouseY);
mParticle.velocity().set(random(-20, 20), random(-50));
}
/* update the particle system */
final float mDeltaTime = 1.0 / frameRate;
mPhysics.step(mDeltaTime);
/* remove particles right before they hit the edge of the screen */
for (int i = 0; i < mPhysics.particles().size(); i++) {
Particle mParticle = mPhysics.particles(i);
if (mParticle.position().y > height * 0.9f) {
mPhysics.particles().remove(i);
}
}
/* draw all the particles in the system */
background(255);
stroke(0, 127);
fill(0, 32);
for (int i = 0; i < mPhysics.particles().size(); i++) {
Particle mParticle = mPhysics.particles(i);
ellipse(mParticle.position().x, mParticle.position().y, 10, 10);
}
}
@@ -0,0 +1,88 @@
import processing.opengl.*;
import mathematik.*;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.Teleporter;
import teilchen.force.Attractor;
import teilchen.force.ViscousDrag;
/**
* this sketch shows how to create and use attractors.
*/
Physics mPhysics;
Attractor mAttractor;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a viscous force that slows down all motion */
ViscousDrag myDrag = new ViscousDrag();
myDrag.coefficient = 0.75f;
mPhysics.add(myDrag);
/* teleport particles from one edge of the screen to the other */
Teleporter mTeleporter = new Teleporter();
mTeleporter.min().set(0, 0);
mTeleporter.max().set(width, height);
mPhysics.add(mTeleporter);
/* create some particles */
for (int i = 0; i < 100; i++) {
Particle myParticle = mPhysics.makeParticle();
myParticle.position().set(random(width), random(height));
}
/* create an attractor */
mAttractor = new Attractor();
mAttractor.radius(100);
mAttractor.strength(150);
mPhysics.add(mAttractor);
}
void mousePressed() {
/* flip the direction of the attractors strength. */
float myInvertedStrength = -1 * mAttractor.strength();
/* a negative strength turns the attractor into a repulsor */
mAttractor.strength(myInvertedStrength);
}
void draw() {
/* set attractor to mouse position */
mAttractor.position().set(mouseX, mouseY);
/* update the particle system */
final float mDeltaTime = 1.0 / frameRate;
mPhysics.step(mDeltaTime);
/* draw */
background(255);
/* draw all the particles in particle system */
fill(245);
stroke(164);
for (int i = 0; i < mPhysics.particles().size(); i++) {
Particle myParticle = mPhysics.particles(i);
ellipse(myParticle.position().x, myParticle.position().y, 12, 12);
}
/* draw attractor. green if it is attracting and red if it is repelling */
noStroke();
if (mAttractor.strength() < 0) {
fill(255, 0, 0, 50);
}
else {
fill(0, 255, 0, 50);
}
ellipse(mAttractor.position().x, mAttractor.position().y,
mAttractor.radius(), mAttractor.radius());
}
@@ -0,0 +1,102 @@
import processing.opengl.*;
import mathematik.*;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.ShortLivedParticle;
import teilchen.force.Gravity;
import teilchen.force.PlaneDeflector;
import teilchen.force.ViscousDrag;
/**
* this sketch shows
* 1 how to create and use plane deflectors
* 2 how to use 'ShortLivedParticle'
*/
Physics mPhysics;
PlaneDeflector mDeflector;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a deflector and add it to the particle system.
* the that defines the deflection area is defined by an
* origin and a normal. this also means that the plane s size
* is infinite.
* note that there is also a triangle delfector that is constraint
* by three points.
*/
mDeflector = new PlaneDeflector();
/* set plane origin into the center of the screen */
mDeflector.plane().origin.set(width / 2, height / 2, 0);
mDeflector.plane().normal.set(0, -1, 0);
/* the coefficient of restitution defines how hard particles bounce of the deflector */
mDeflector.coefficientofrestitution(0.7f);
mPhysics.add(mDeflector);
/* create gravitiy */
Gravity myGravity = new Gravity();
myGravity.force().y = 50;
mPhysics.add(myGravity);
/* create drag */
ViscousDrag myViscousDrag = new ViscousDrag();
myViscousDrag.coefficient = 0.1f;
mPhysics.add(myViscousDrag);
}
void draw() {
/* rotate deflector plane */
if (mousePressed) {
final float myAngle = 2 * PI * (float)mouseX / width - PI;
mDeflector.plane().normal.set(sin(myAngle), -cos(myAngle), 0);
}
/* create a special particle */
ShortLivedParticle myNewParticle = new ShortLivedParticle();
myNewParticle.position().set(mouseX, mouseY);
myNewParticle.velocity().set(0, random(100) + 50);
/* this particle is removed after a specific interval */
myNewParticle.setMaxAge(4);
/* add particle manually to the particle system */
mPhysics.add(myNewParticle);
/* update physics */
final float mDeltaTime = 1.0 / frameRate;
mPhysics.step(mDeltaTime);
/* draw all the particles in the particle system */
background(255);
for (int i = 0; i < mPhysics.particles().size(); i++) {
Particle myParticle = mPhysics.particles(i);
/* this special particle can tell you how much time it has to live.
* we map this information to its transparency.
*/
float myRatio = 1 - ((ShortLivedParticle)myParticle).ageRatio();
stroke(0, 64 * myRatio);
fill(0, 32 * myRatio);
ellipse(myParticle.position().x, myParticle.position().y, 12, 12);
}
/* draw deflector */
stroke(0, 127);
line(mDeflector.plane().origin.x - mDeflector.plane().normal.y * -width,
mDeflector.plane().origin.y + mDeflector.plane().normal.x * -width,
mDeflector.plane().origin.x - mDeflector.plane().normal.y * width,
mDeflector.plane().origin.y + mDeflector.plane().normal.x * width);
stroke(255, 0, 0, 127);
line(mDeflector.plane().origin.x,
mDeflector.plane().origin.y,
mDeflector.plane().origin.x + mDeflector.plane().normal.x * 20,
mDeflector.plane().origin.y + mDeflector.plane().normal.y * 20);
}
@@ -0,0 +1,68 @@
import processing.opengl.*;
import mathematik.*;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
/**
* this sketch shows
* 1 how to create a viscous drag to slow motion eventually down.
* 2 how to create a spring that connects two particles.
*/
Physics mPhysics;
Spring mSpring;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a viscous force that slows down all motion; 0 means no slowing down. */
ViscousDrag myDrag = new ViscousDrag(0.25f);
mPhysics.add(myDrag);
/* create two particles that we can connect with a spring */
Particle myA = mPhysics.makeParticle();
myA.position().set(width / 2 - 50, height / 2);
Particle myB = mPhysics.makeParticle();
myB.position().set(width / 2 + 50, height / 2);
/* create a spring force that connects two particles.
* note that there is more than one way to create a spring.
* in our case the restlength of the spring is defined by the
* particles current position.
*/
mSpring = mPhysics.makeSpring(myA, myB);
}
void draw() {
/* set first particle to mouse position */
if (mousePressed) {
mSpring.a().position().set(mouseX, mouseY);
}
/* update the particle system */
final float mDeltaTime = 1.0 / frameRate;
mPhysics.step(mDeltaTime);
/* draw particles and connecting line */
background(255);
noFill();
stroke(255, 0, 127, 64);
line(mSpring.a().position().x, mSpring.a().position().y,
mSpring.b().position().x, mSpring.b().position().y);
fill(245);
stroke(164);
ellipse(mSpring.a().position().x, mSpring.a().position().y, 12, 12);
ellipse(mSpring.b().position().x, mSpring.b().position().y, 12, 12);
}
@@ -0,0 +1,70 @@
import processing.opengl.*;
import mathematik.*;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.Spring;
/**
* this sketch shows
* 1 how to create a viscous drag to slow motion eventually down.
* 2 how to create a spring that connects two particles.
*/
Physics mPhysics;
Particle mRoot;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a particle to which we will connect springs */
mRoot = mPhysics.makeParticle(width / 2, height / 2, 0.0);
/* we give the root particle a higher mass so it doesn t move as easily */
mRoot.mass(30);
}
void draw() {
/* create a particle at mouse position and connect it to the root particle through a spring */
if (mousePressed) {
Particle mParticle = mPhysics.makeParticle(mouseX, mouseY, 0);
Spring mSpring = mPhysics.makeSpring(mRoot, mParticle);
/* restlength defines the desired length of the spring. in this case it is the distance between the two particles. */
float mRestlength = mSpring.restlength();
/* we modify the restlength to add a bit of energy into the system */
mSpring.restlength(mRestlength * 1.5f);
}
/* update the particle system */
final float mDeltaTime = 1.0 / frameRate;
mPhysics.step(mDeltaTime);
/* draw particles and connecting line */
background(255);
/* draw springs */
noFill();
stroke(255, 0, 127, 64);
for (int i = 0; i < mPhysics.forces().size(); i++) {
if (mPhysics.forces().get(i) instanceof Spring) {
Spring mSSpring = (Spring)mPhysics.forces().get(i);
line(mSSpring.a().position().x, mSSpring.a().position().y,
mSSpring.b().position().x, mSSpring.b().position().y);
}
}
/* draw particles */
fill(245);
stroke(164);
for (int i = 0; i < mPhysics.particles().size(); i++) {
ellipse(mPhysics.particles().get(i).position().x,
mPhysics.particles().get(i).position().y,
12, 12);
}
}
@@ -0,0 +1,83 @@
import processing.opengl.*;
import mathematik.*;
import teilchen.Physics;
import teilchen.force.Gravity;
import teilchen.force.ViscousDrag;
import teilchen.util.DrawLib;
import teilchen.Particle;
import teilchen.constraint.Box;
import teilchen.integration.RungeKutta;
import teilchen.util.StableSpringQuad;
Physics mPhysics;
Particle mRoot;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(60);
mPhysics = new Physics();
/* we use 'runge kutta' as it is more stable for this application */
mPhysics.setInegratorRef(new RungeKutta());
Gravity myGravity = new Gravity();
myGravity.force().y = 98.1f;
mPhysics.add(myGravity);
/* add drag to smooth the spring interaction */
mPhysics.add(new ViscousDrag(0.2f));
/* add a container */
Box myBox = new Box();
myBox.min().set(0, 0, 0);
myBox.max().set(width, height, 0);
mPhysics.add(myBox);
/* create root */
Particle a = mPhysics.makeParticle(0, 0);
Particle b = mPhysics.makeParticle(100, 0);
Particle c = mPhysics.makeParticle(100, 100);
Particle d = mPhysics.makeParticle(0, 100);
new StableSpringQuad(mPhysics, d, c, mPhysics.makeParticle(100, 200), mPhysics.makeParticle(0, 200));
/* create stable quad from springs */
/* first the edge-springs ... */
final float mySpringConstant = 100;
final float mySpringDamping = 5;
mPhysics.makeSpring(a, b, mySpringConstant, mySpringDamping);
mPhysics.makeSpring(b, c, mySpringConstant, mySpringDamping);
mPhysics.makeSpring(c, d, mySpringConstant, mySpringDamping);
mPhysics.makeSpring(d, a, mySpringConstant, mySpringDamping).restlength();
/* ... then the diagonal-springs */
mPhysics.makeSpring(a, c, mySpringConstant, mySpringDamping);
mPhysics.makeSpring(b, d, mySpringConstant, mySpringDamping).restlength();
/* define 'a' as root particle for mouse interaction */
mRoot = a;
mRoot.fixed(true);
}
void draw() {
/* handle particles */
if (mousePressed) {
mRoot.fixed(true);
mRoot.position().set(mouseX, mouseY);
}
else {
mRoot.fixed(false);
}
mPhysics.step(1f / frameRate);
/* draw */
background(255);
DrawLib.drawSprings(g, mPhysics, color(255, 0, 127, 64));
DrawLib.drawParticles(g, mPhysics, 12, color(164), color(245));
}
@@ -0,0 +1,71 @@
import processing.opengl.*;
import mathematik.*;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.Stick;
import teilchen.force.Gravity;
import teilchen.integration.Verlet;
Physics mPhysics;
Particle[] mParticles;
void setup() {
size(640, 480, OPENGL);
frameRate(60);
smooth();
mPhysics = new Physics();
/* increase the number of iterations for contraints in each step. this can greatly relaxes tensions in the system. */
mPhysics.contraint_iterations_per_steps = 5;
/* add gravity for extra fun */
mPhysics.add(new Gravity());
/* we chose verlet integration as it integrates much more nicely with sticks ( and constraints in general ) */
Verlet myVerlet = new Verlet();
myVerlet.damping(0.99f);
mPhysics.setInegratorRef(myVerlet);
/* setup sticks to form a whip */
mParticles = new Particle[16];
float mSegmentLength = 20.0;
/* create root */
for (int x = 0; x < mParticles.length; x++) {
mParticles[x] = mPhysics.makeParticle(x * mSegmentLength, 0, 0, 0.1f);
if (x > 0) {
Stick myStick = new Stick(mParticles[x - 1],
mParticles[x],
mSegmentLength);
/* damp the stick to release tensions from the system */
myStick.damping(0.99f);
mPhysics.add(myStick);
}
}
/* fix root particle so it can stick to the mouse later */
mParticles[0].fixed(true);
}
void draw() {
/* stick root particle to mouse */
mParticles[0].position().set(mouseX, mouseY);
/* update */
mPhysics.step(1.0 / frameRate);
/* draw sticks with descending stroke weight */
background(255);
stroke(0, 192);
for (int x = 1; x < mParticles.length; x++) {
Particle p1 = mParticles[x - 1];
Particle p2 = mParticles[x];
final float mStrokeWeight = 4.0 * (1.0 - (float)x / mParticles.length);
strokeWeight(mStrokeWeight);
line(p1.position().x, p1.position().y, p1.position().z,
p2.position().x, p2.position().y, p2.position().z);
}
}
@@ -0,0 +1,113 @@
import processing.opengl.*;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.IConstraint;
import teilchen.constraint.Stick;
import teilchen.force.Attractor;
import teilchen.force.Gravity;
import teilchen.integration.Verlet;
Physics mPhysics;
Particle[][] mParticles;
final int GRID_WIDTH = 32;
final int GRID_HEIGHT = 16;
Attractor mAttractor;
void setup() {
size(640, 480, OPENGL);
frameRate(60);
mPhysics = new Physics();
mPhysics.contraint_iterations_per_steps = 5;
Verlet myVerlet = new Verlet();
myVerlet.damping(0.9f);
mPhysics.setInegratorRef(myVerlet);
mPhysics.add(new Gravity(new Vector3f(0, 1000f, 0)));
mAttractor = new Attractor();
mAttractor.strength(-15000);
mAttractor.radius(300);
mPhysics.add(mAttractor);
mParticles = new Particle[GRID_WIDTH][GRID_HEIGHT];
/* setup cloth */
float mGridStepX = ((float)width / GRID_WIDTH);
float mGridStepY = (((float)height * 0.5f) / GRID_HEIGHT);
for (int y = 0; y < GRID_HEIGHT; y++) {
for (int x = 0; x < GRID_WIDTH; x++) {
mParticles[x][y] = mPhysics.makeParticle();
mParticles[x][y].position().set((x + 0.5f) * mGridStepX,
y * mGridStepY,
random(0, 1));
mParticles[x][y].old_position().set(mParticles[x][y].position());
mParticles[x][y].mass(0.1f);
final float DAMPING = 0.9f;
if (y > 0) {
Stick myStick = new Stick(mParticles[x][y - 1],
mParticles[x][y],
mGridStepY);
myStick.damping(DAMPING);
mPhysics.add(myStick);
}
if (x > 0) {
Stick myStick = new Stick(mParticles[x - 1][y],
mParticles[x][y],
mGridStepX);
myStick.damping(DAMPING);
mPhysics.add(myStick);
}
if (x > 0 && y > 0) {
Stick myStick1 = new Stick(mParticles[x - 1][y - 1],
mParticles[x][y],
new Vector3f(mGridStepX, mGridStepY).length());
mPhysics.add(myStick1);
Stick myStick2 = new Stick(mParticles[x][y - 1],
mParticles[x - 1][y],
new Vector3f(mGridStepX, mGridStepY).length());
mPhysics.add(myStick2);
}
}
}
/* fix first row */
for (int x = 0; x < mParticles.length; x++) {
mParticles[x][0].fixed(true);
}
}
void draw() {
/* update */
mAttractor.position().set(mouseX, mouseY, 50);
mPhysics.step(1.0 / frameRate);
background(255);
/* draw sticks */
stroke(0, 127);
for (int i = 0; i < mPhysics.constraints().size(); i++) {
IConstraint mConstraint = mPhysics.constraints().get(i);
if (mConstraint instanceof Stick) {
final Stick myStick = (Stick)mConstraint;
line(myStick.a().position().x,
myStick.a().position().y,
myStick.a().position().z,
myStick.b().position().x,
myStick.b().position().y,
myStick.b().position().z);
}
}
}
@@ -0,0 +1,73 @@
import mathematik.*;
import teilchen.BehaviorParticle;
import teilchen.Physics;
import teilchen.behavior.Arrival;
/**
* this sketch shows how to assign an 'arrival' behavior to a particle.
*/
Physics mPhysics;
BehaviorParticle mParticle;
Arrival mArrival;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(120);
colorMode(RGB, 1.0f);
noFill();
/* physics */
mPhysics = new Physics();
/* create particles */
mParticle = mPhysics.makeParticle(BehaviorParticle.class);
mParticle.maximumInnerForce(100);
/* create arrival behavior */
mArrival = new Arrival();
mArrival.breakforce(mParticle.maximumInnerForce() * 0.25f);
mArrival.breakradius(mParticle.maximumInnerForce() * 0.25f);
mParticle.behaviors().add(mArrival);
}
void draw() {
/* set the arrival position to the mouse position */
mArrival.position().set(mouseX, mouseY);
/* update particle system */
mPhysics.step(1.0f / frameRate);
/* draw behavior particle */
background(1);
stroke(0, 0.5f);
if (mArrival.arriving()) {
/* color particle red while it is arriving */
stroke(1, 0, 0, 0.5f);
}
if (mArrival.arrived()) {
/* color particle green when it has arrived */
stroke(0, 1, 0, 0.5f);
}
line(mParticle.position().x,
mParticle.position().y,
mParticle.position().x + mParticle.velocity().x,
mParticle.position().y + mParticle.velocity().y);
fill(1);
ellipse(mParticle.position().x, mParticle.position().y, 12, 12);
/* draw arrival */
stroke(0, 0.25f);
noFill();
ellipse(mArrival.position().x,
mArrival.position().y,
mArrival.breakradius() * 2,
mArrival.breakradius() * 2);
}
@@ -0,0 +1,69 @@
import processing.opengl.*;
import mathematik.*;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.Spring;
import teilchen.util.Overlap;
/**
* this sketch is exactly like Lesson06_Springs, except that it also shows how to remove overlaps.
*/
Physics mPhysics;
Particle mRoot;
static final float PARTICLE_RADIUS = 6;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
mPhysics = new Physics();
mRoot = mPhysics.makeParticle(width / 2, height / 2, 0.0);
mRoot.mass(30);
}
void draw() {
if (mousePressed) {
Particle mParticle = mPhysics.makeParticle(mouseX, mouseY, 0);
Spring mSpring = mPhysics.makeSpring(mRoot, mParticle);
float mRestlength = mSpring.restlength();
mSpring.restlength(mRestlength * 1.5f);
/* we define a radius for the particle so the particle has dimensions */
mParticle.radius(PARTICLE_RADIUS);
}
/* move overlapping particles away from each other */
Overlap.resolveOverlap(mPhysics.particles());
/* update the particle system */
final float mDeltaTime = 1.0 / frameRate;
mPhysics.step(mDeltaTime);
/* draw particles and connecting line */
background(255);
/* draw springs */
noFill();
stroke(255, 0, 127, 64);
for (int i = 0; i < mPhysics.forces().size(); i++) {
if (mPhysics.forces().get(i) instanceof Spring) {
Spring mSSpring = (Spring)mPhysics.forces().get(i);
line(mSSpring.a().position().x, mSSpring.a().position().y,
mSSpring.b().position().x, mSSpring.b().position().y);
}
}
/* draw particles */
fill(245);
stroke(164);
for (int i = 0; i < mPhysics.particles().size(); i++) {
ellipse(mPhysics.particles().get(i).position().x,
mPhysics.particles().get(i).position().y,
PARTICLE_RADIUS * 2, PARTICLE_RADIUS * 2);
}
}
@@ -0,0 +1,91 @@
import processing.opengl.*;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.Box;
import teilchen.force.Gravity;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
import teilchen.util.CollisionManager;
static final float PARTICLE_SIZE = 12;
CollisionManager mCollision;
Physics mPhysics;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
noFill();
ellipseMode(CENTER);
mCollision = new CollisionManager();
mCollision.distancemode(CollisionManager.DISTANCE_MODE_FIXED);
mCollision.minimumDistance(50);
mPhysics = new Physics();
mPhysics.add(new ViscousDrag(0.85f));
mPhysics.add(new Gravity());
Box myBox = new Box();
myBox.min().set(50, 50, 0);
myBox.max().set(width - 50, height - 50, 0);
myBox.coefficientofrestitution(0.7f);
myBox.reflect(true);
mPhysics.add(myBox);
/* create a first particle */
final Particle myParticle = mPhysics.makeParticle(new Vector3f(mouseX, mouseY, 0), 10);
mCollision.collision().add(myParticle);
}
void draw() {
/* create particles */
if (mousePressed) {
final Particle myParticle = mPhysics.makeParticle(new Vector3f(mouseX, mouseY, 0), 10);
mCollision.collision().add(myParticle);
}
/* collision handler */
final float mDeltaTime = 1.0 / frameRate;
mCollision.createCollisionResolvers();
mCollision.loop(mDeltaTime);
mPhysics.step(mDeltaTime);
/* draw */
background(255);
drawThings();
mCollision.removeCollisionResolver();
}
void drawThings() {
/* collision springs */
noFill();
stroke(255, 0, 127, 64);
for (int i = 0; i < mCollision.collision().forces().size(); ++i) {
if (mCollision.collision().forces().get(i) instanceof Spring) {
Spring mySpring = (Spring)mCollision.collision_forces().get(i);
line(mySpring.a().position().x, mySpring.a().position().y, mySpring.a().position().z,
mySpring.b().position().x, mySpring.b().position().y, mySpring.b().position().z);
}
}
/* particles */
fill(245);
stroke(164);
for (int i = 0; i < mPhysics.particles().size(); ++i) {
Particle myParticle = mPhysics.particles().get(i);
pushMatrix();
translate(myParticle.position().x, myParticle.position().y, myParticle.position().z);
ellipse(0, 0,
PARTICLE_SIZE,
PARTICLE_SIZE);
popMatrix();
}
}
@@ -0,0 +1,131 @@
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.ShortLivedParticle;
import teilchen.constraint.Box;
import teilchen.force.Attractor;
import teilchen.force.Gravity;
import teilchen.force.ViscousDrag;
import teilchen.util.ParticleTrail;
import java.util.Vector;
Physics mPhysics;
Vector<ParticleTrail> mTrails;
Attractor mAttractor;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(60);
/* create a particle system */
mPhysics = new Physics();
/* create a gravitational force */
Gravity myGravity = new Gravity();
mPhysics.add(myGravity);
myGravity.force().y = 20;
/* create drag */
ViscousDrag myViscousDrag = new ViscousDrag();
myViscousDrag.coefficient = 0.1f;
mPhysics.add(myViscousDrag);
final float mBorder = 40;
Box mBox = new Box(new Vector3f(mBorder, mBorder, mBorder), new Vector3f(width - mBorder, height - mBorder, 100 - mBorder));
mBox.reflect(true);
mPhysics.add(mBox);
/* create an attractor */
mAttractor = new Attractor();
mAttractor.radius(200);
mAttractor.strength(-300);
mPhysics.add(mAttractor);
/* create trails and particles */
mTrails = new Vector<ParticleTrail>();
for (int i = 0; i < 500; i++) {
Particle mParticle = mPhysics.makeParticle();
mParticle.mass(2.0f);
ParticleTrail myParticleTrail = new ParticleTrail(mPhysics, mParticle, 0.2f, random(0.5f, 1));
myParticleTrail.mass(0.5f);
mTrails.add(myParticleTrail);
}
resetParticles(width / 2, height / 2);
}
void resetParticles(float x, float y) {
for (ParticleTrail myTrails : mTrails) {
myTrails.particle().position().set(x + random(-10, 10), y + random(-10, 10), 0);
myTrails.particle().velocity().set(random(-10, 10), random(-10, 10), random(-10, 10));
myTrails.fragments().clear();
}
}
void draw() {
/* set attractor to mouse position */
mAttractor.position().set(mouseX, mouseY);
for (ParticleTrail myTrails : mTrails) {
myTrails.loop(1f / frameRate);
}
mPhysics.step(1f / frameRate);
background(255);
for (ParticleTrail myTrail : mTrails) {
drawTrail(myTrail);
}
}
void drawTrail(ParticleTrail theTrail) {
final Vector<Particle> mFragments = theTrail.fragments();
final Particle mParticle = theTrail.particle();
/* draw head */
if (mFragments.size() > 1) {
fill(255, 0, 127);
noStroke();
pushMatrix();
translate(mParticle.position().x,
mParticle.position().y,
mParticle.position().z);
sphereDetail(4);
sphere(3);
popMatrix();
}
/* draw trail */
for (int i = 0; i < mFragments.size() - 1; i++) {
if (mFragments.get(i) instanceof ShortLivedParticle) {
final float mRatio = 1.0f - ((ShortLivedParticle)mFragments.get(i)).ageRatio();
stroke(127, mRatio * 255);
strokeWeight(mRatio * 3);
}
int j = (i + 1) % mFragments.size();
line(mFragments.get(i).position().x,
mFragments.get(i).position().y,
mFragments.get(i).position().z,
mFragments.get(j).position().x,
mFragments.get(j).position().y,
mFragments.get(j).position().z);
}
if (!mFragments.isEmpty()) {
line(mFragments.lastElement().position().x,
mFragments.lastElement().position().y,
mFragments.lastElement().position().z,
mParticle.position().x,
mParticle.position().y,
mParticle.position().z);
}
}
void mousePressed() {
resetParticles(mouseX, mouseY);
}
@@ -0,0 +1,146 @@
import mathematik.*;
import teilchen.test.cubicle.*;
import teilchen.integration.*;
import verhalten.*;
import teilchen.*;
import verhalten.view.*;
import teilchen.test.particle.behavior.*;
import teilchen.behavior.*;
import teilchen.demo.*;
import teilchen.test.particle.springs.*;
import teilchen.gestalt.test.*;
import teilchen.cubicle.*;
import verhalten.test.*;
import teilchen.force.flowfield.*;
import teilchen.test.particle.*;
import teilchen.gestalt.util.*;
import teilchen.constraint.*;
import teilchen.force.vectorfield.*;
import teilchen.force.*;
import teilchen.util.*;
import mathematik.*;
import teilchen.Physics;
import teilchen.force.Attractor;
import teilchen.force.Gravity;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
import teilchen.integration.RungeKutta;
import teilchen.util.Overlap;
import teilchen.util.StickMan;
/**
* this demo shows some advanced use of particles, springs and attractors to create stickmen.
*/
Physics mPhysics;
Attractor mAttractor;
Gravity mGravity;
ViscousDrag mViscousDrag;
StickMan[] mMyStickMan;
void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(60);
noFill();
mPhysics = new Physics();
mPhysics.setInegratorRef(new RungeKutta());
mGravity = new Gravity();
mGravity.force().y = 20;
mPhysics.add(mGravity);
mViscousDrag = new ViscousDrag();
mViscousDrag.coefficient = 0.85f;
mPhysics.add(mViscousDrag);
mAttractor = new Attractor();
mAttractor.radius(500);
mAttractor.strength(0);
mAttractor.position().set(width / 2, height / 2);
mPhysics.add(mAttractor);
mMyStickMan = new StickMan[20];
for (int i = 0; i < mMyStickMan.length; i++) {
mMyStickMan[i] = new StickMan(mPhysics, random(0, width), random(0.3f, 0.6f));
}
}
void draw() {
mPhysics.step(1f / 60f);
Overlap.resolveOverlap(mPhysics.particles());
/* constraint particles */
for (int i = 0; i < mPhysics.particles().size(); i++) {
if (mPhysics.particles(i).position().y > height - 10) {
mPhysics.particles(i).position().y = height - 10;
}
if (mPhysics.particles(i).position().x > width) {
mPhysics.particles(i).position().x = width;
}
if (mPhysics.particles(i).position().x < 0) {
mPhysics.particles(i).position().x = 0;
}
}
/* handle particles */
if (mousePressed) {
mAttractor.position().set(mouseX, mouseY);
if (mouseButton == RIGHT) {
mAttractor.strength(-500);
mAttractor.radius(500);
}
else {
mAttractor.strength(500);
mAttractor.radius(100);
}
}
else {
mAttractor.strength(0);
}
if (keyPressed) {
mGravity.force().y = -10;
}
else {
mGravity.force().y = 20;
}
/* draw */
background(255);
/* draw springs */
stroke(0, 20);
for (int i = 0; i < mPhysics.forces().size(); i++) {
if (mPhysics.forces(i) instanceof Spring) {
Spring mySpring = (Spring)mPhysics.forces(i);
line(mySpring.a().position().x,
mySpring.a().position().y,
mySpring.b().position().x,
mySpring.b().position().y);
}
}
/* draw particles */
for (int i = 0; i < mPhysics.particles().size(); i++) {
ellipse(mPhysics.particles(i).position().x,
mPhysics.particles(i).position().y, 5, 5);
}
/* draw man */
for (int i = 0; i < mMyStickMan.length; i++) {
mMyStickMan[i].draw(g);
}
}
@@ -0,0 +1,184 @@
import mathematik.*;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.AngleConstraintStick;
import teilchen.constraint.Stick;
import teilchen.force.AngleConstraintSpring;
import teilchen.force.Gravity;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
import teilchen.integration.RungeKutta;
Physics mPhysics;
Particle mParticleA;
Particle mParticleB;
Particle mParticleC;
Particle mParticleD;
AngleConstraintSpring mAngleConstraintABC;
AngleConstraintStick mAngleConstraintBCD;
void setup() {
size(640, 480);
frameRate(30);
smooth();
mPhysics = new Physics();
mPhysics.setInegratorRef(new RungeKutta());
ViscousDrag myViscousDrag = new ViscousDrag();
myViscousDrag.coefficient = 1f;
mPhysics.add(myViscousDrag);
Gravity myGravity = new Gravity();
myGravity.force().y = 50;
mPhysics.add(myGravity);
/* particles */
mParticleA = mPhysics.makeParticle();
mParticleB = mPhysics.makeParticle();
mParticleC = mPhysics.makeParticle();
mParticleD = mPhysics.makeParticle();
mParticleA.position().set(width / 2 + 50, height / 3);
mParticleB.position().set(width / 2, height - height / 1.75f);
mParticleC.position().set(width / 2, height - height / 4);
mParticleD.position().set(width / 2, height - height / 8);
mParticleA.radius(7);
mParticleB.radius(3);
mParticleC.radius(10);
mParticleD.radius(2);
mParticleB.fixed(true);
/* springs */
Spring mSpringAB = new Spring(mParticleA, mParticleB);
mSpringAB.strength(250);
mSpringAB.damping(10);
mPhysics.add(mSpringAB);
Spring mSpringBC = new Spring(mParticleB, mParticleC);
mSpringBC.strength(250);
mSpringBC.damping(10);
mPhysics.add(mSpringBC);
Stick mSpringCD = new Stick(mParticleC, mParticleD);
mSpringCD.damping(1);
mPhysics.add(mSpringCD);
/* angle constraint */
mAngleConstraintABC = new AngleConstraintSpring(mParticleA, mParticleB, mParticleC);
mAngleConstraintABC.min_angle(PI * 0.5f);
mAngleConstraintABC.damping(1);
mAngleConstraintABC.strength(200);
mPhysics.add(mAngleConstraintABC);
mAngleConstraintBCD = new AngleConstraintStick(mParticleB, mParticleC, mParticleD);
mAngleConstraintBCD.min_angle(PI * 0.8f);
mAngleConstraintBCD.damping(0.5f);
mPhysics.add(mAngleConstraintBCD);
}
void draw() {
/* attach particle to mouse */
if (mousePressed) {
mParticleA.position().set(mouseX, mouseY);
}
/* apply constraints */
mAngleConstraintABC.pre_step();
mAngleConstraintBCD.pre_step();
draw_physics();
mPhysics.step(1f / frameRate);
/* remove contraints */
mAngleConstraintABC.post_step();
mAngleConstraintBCD.post_step();
}
void draw_physics() {
background(255);
drawSprings();
drawSticks();
drawParticles();
}
void drawSprings() {
for (int i = 0; i < mPhysics.forces().size(); i++) {
if (mPhysics.forces(i) instanceof Spring) {
final Spring mSpring = (Spring)mPhysics.forces(i);
if (mSpring instanceof AngleConstraintSpring) {
strokeWeight(1);
if (mSpring.active()) {
stroke(255, 0, 0, 64);
}
else {
stroke(255, 0, 0, 16);
}
}
else {
strokeWeight(3);
stroke(0, 128);
}
line(mSpring.a(), mSpring.b());
}
}
strokeWeight(1);
}
void drawSticks() {
for (int i = 0; i < mPhysics.constraints().size(); i++) {
if (mPhysics.constraints(i) instanceof Stick) {
final Stick mStick = (Stick)mPhysics.constraints(i);
if (mStick instanceof AngleConstraintStick) {
strokeWeight(1);
if (mStick.active()) {
stroke(0, 127, 255, 64);
}
else {
stroke(0, 127, 255, 16);
}
}
else {
strokeWeight(3);
stroke(0, 128);
}
line(mStick.a(), mStick.b());
}
}
strokeWeight(1);
}
void drawParticles() {
stroke(0);
fill(92);
drawParticle(mParticleA);
fill(127);
drawParticle(mParticleB);
fill(192);
drawParticle(mParticleC);
fill(64);
drawParticle(mParticleD);
}
void drawParticle(Particle p) {
ellipse(p.position().x,
p.position().y,
p.radius() * 2, p.radius() * 2);
}
void line(Particle p1, Particle p2) {
line(p1.position().x, p1.position().y,
p2.position().x, p2.position().y);
}
@@ -0,0 +1,145 @@
import mathematik.*;
import processing.opengl.*;
import teilchen.BehaviorParticle;
import teilchen.Physics;
import teilchen.behavior.Arrival;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
import teilchen.util.CollisionManager;
/**
* this demo shows how to add behaviors to particles. in this example the
* arrival behavior.
*/
Physics mPhysics;
ArrayList<Duckling> mDucklings;
CollisionManager mCollision;
void setup() {
size(640, 480, OPENGL);
frameRate(60);
smooth();
colorMode(RGB, 1.0f);
/* physics */
mPhysics = new Physics();
ViscousDrag myViscousDrag = new ViscousDrag();
myViscousDrag.coefficient = 0.25f;
mPhysics.add(myViscousDrag);
mCollision = new CollisionManager();
mCollision.minimumDistance(25);
/* ducklings */
mDucklings = new ArrayList<Duckling>();
for (int i = 0; i < 13; i++) {
final Duckling mDuckling = new Duckling();
if (!mDucklings.isEmpty()) {
mDuckling.arrival.setPositionRef(mDucklings.get(mDucklings.size()-1).particle.position());
}
mCollision.collision().add(mDuckling.particle);
mDucklings.add(mDuckling);
}
}
void draw() {
final float mDeltaTime = 1.0f / frameRate;
background(1);
/* update particles */
mCollision.createCollisionResolvers();
mCollision.loop(mDeltaTime);
mPhysics.step(mDeltaTime);
drawCollisionSprings();
mCollision.removeCollisionResolver();
mDucklings.get(0).arrival.oversteer(!mousePressed);
mDucklings.get(0).arrival.position().set(mouseX, mouseY);
/* draw */
for (int i=0; i < mDucklings.size(); i++) {
Duckling mDuckling = mDucklings.get(i);
drawParticle(mDuckling);
}
/* draw arrival */
stroke(0, 0.25f);
noFill();
ellipse(mDucklings.get(0).arrival.position().x,
mDucklings.get(0).arrival.position().y,
20, 20);
}
void drawParticle(Duckling pDuckling) {
final BehaviorParticle mParticle = pDuckling.particle;
final Arrival mArrival = pDuckling.arrival;
/* draw particle */
stroke(0, 0.5f);
noFill();
if (mArrival.arriving()) {
stroke(1, 0, 0, 0.5f);
}
if (mArrival.arrived()) {
stroke(0, 1, 0, 0.5f);
}
ellipse(mParticle.position().x, mParticle.position().y,
mParticle.radius() * 2, mParticle.radius() * 2);
/* - */
pushMatrix();
translate(mParticle.position().x,
mParticle.position().y);
/* draw velocity */
stroke(1, 0, 0, 0.5f);
line(0, 0, mParticle.velocity().x, mParticle.velocity().y);
/* draw break force */
stroke(0, 0.5f, 1, 0.5f);
line(0, 0, mArrival.force().x, mArrival.force().y);
/* - */
popMatrix();
}
void drawCollisionSprings() {
stroke(0, 1, 0, 0.25f);
for (int i = 0; i < mCollision.collision().forces().size(); ++i) {
if (mCollision.collision().forces().get(i) instanceof Spring) {
Spring mySpring = (Spring) mCollision.collision_forces().get(i);
line(mySpring.a().position().x, mySpring.a().position().y, mySpring.a().position().z,
mySpring.b().position().x, mySpring.b().position().y, mySpring.b().position().z);
}
}
}
class Duckling {
BehaviorParticle particle;
Arrival arrival;
Duckling() {
/* create particles */
particle = mPhysics.makeParticle(BehaviorParticle.class);
particle.position().set(random(width), random(height));
particle.maximumInnerForce(random(50, 150));
particle.radius(random(6, 10));
arrival = new Arrival();
arrival.breakforce(random(12, 28));
arrival.breakradius(random(45, 55));
particle.behaviors().add(arrival);
}
}
Binary file not shown.
+142
View File
@@ -0,0 +1,142 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen;
import java.io.Serializable;
import mathematik.Vector3f;
public class BasicParticle
implements Particle, Serializable {
private boolean mFixed;
private float mAge;
private float mMass;
private Vector3f mPosition;
private final Vector3f mOldPosition;
private final Vector3f mVelocity;
private final Vector3f mForce;
private boolean mTagged;
private boolean mStill;
private float mRadius;
private static final long serialVersionUID = 3737917975116369338L;
public BasicParticle() {
mPosition = new Vector3f();
mOldPosition = new Vector3f();
mVelocity = new Vector3f();
mForce = new Vector3f();
mMass = 1;
mFixed = false;
mAge = 0;
mTagged = false;
mStill = false;
mRadius = 0;
}
public boolean fixed() {
return mFixed;
}
public void fixed(boolean theFixed) {
mFixed = theFixed;
}
public float age() {
return mAge;
}
public void age(float theAge) {
mAge = theAge;
}
public float mass() {
return mMass;
}
public void mass(float theMass) {
mMass = theMass;
}
public Vector3f position() {
return mPosition;
}
public Vector3f old_position() {
return mOldPosition;
}
public void setPositionRef(Vector3f thePosition) {
mPosition = thePosition;
}
public Vector3f velocity() {
return mVelocity;
}
public Vector3f force() {
return mForce;
}
public boolean dead() {
return false;
}
public void accumulateInnerForce(final float theDeltaTime) {
}
public boolean tagged() {
return mTagged;
}
public void tag(boolean theTag) {
mTagged = theTag;
}
public boolean still() {
return mStill;
}
public void still(boolean theStill) {
mStill = theStill;
}
public float radius() {
return mRadius;
}
public void radius(float theRadius) {
mRadius = theRadius;
}
}
+72
View File
@@ -0,0 +1,72 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen;
import java.util.Vector;
import teilchen.behavior.IBehavior;
public class BehaviorParticle
extends BasicParticle
implements IBehaviorParticle {
private final Vector<IBehavior> mBehaviors;
private float mMaximumInnerForce;
private static final long serialVersionUID = 2735849326244271321L;
public BehaviorParticle() {
mBehaviors = new Vector<IBehavior>();
mMaximumInnerForce = 50;
}
public void accumulateInnerForce(final float theDeltaTime) {
for (final IBehavior mBehavior : mBehaviors) {
if (mBehavior != null) {
mBehavior.update(theDeltaTime, this);
force().add(mBehavior.force());
}
}
/* clamp to maximum force */
if (maximumInnerForce() > 0) {
final float mForceLength = force().length();
if (mForceLength > maximumInnerForce()) {
force().scale(maximumInnerForce() / mForceLength);
}
}
}
public float maximumInnerForce() {
return mMaximumInnerForce;
}
public void maximumInnerForce(float theForce) {
mMaximumInnerForce = theForce;
}
public Vector<IBehavior> behaviors() {
return mBehaviors;
}
}
+33
View File
@@ -0,0 +1,33 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen;
public abstract class ConditionalParticle
extends BasicParticle {
public boolean dead() {
return !condition();
}
public abstract boolean condition();
}
+36
View File
@@ -0,0 +1,36 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen;
import java.util.Vector;
public interface IBehaviorParticle
extends Particle {
float maximumInnerForce();
void maximumInnerForce(float theForce);
Vector<teilchen.behavior.IBehavior> behaviors();
}
+30
View File
@@ -0,0 +1,30 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen;
public interface IConnection {
Particle a();
Particle b();
}
+70
View File
@@ -0,0 +1,70 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen;
import mathematik.Vector3f;
import teilchen.util.SpatialEntity;
public interface Particle
extends SpatialEntity {
boolean fixed();
void fixed(boolean theFixed);
float age();
void age(float theAge);
float mass();
void mass(float theMass);
Vector3f position();
Vector3f old_position();
void setPositionRef(Vector3f thePosition);
Vector3f velocity();
Vector3f force();
boolean dead();
boolean tagged();
void tag(boolean theTag);
void accumulateInnerForce(final float theDeltaTime);
float radius();
void radius(float theRadius);
boolean still();
void still(boolean theStill);
}
+374
View File
@@ -0,0 +1,374 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen;
import mathematik.Vector3f;
import teilchen.constraint.IConstraint;
import teilchen.force.IForce;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
import teilchen.integration.IIntegrator;
import teilchen.integration.Midpoint;
import teilchen.integration.Verlet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;
import teilchen.integration.RungeKutta;
public class Physics {
private final Vector<Particle> mParticles;
private final Vector<IForce> mForces;
private final Vector<IConstraint> mConstraints;
private IIntegrator mIntegrator;
private static final float EPSILON = 0.001f;
public boolean HINT_OPTIMIZE_STILL = true;
public boolean HINT_REMOVE_DEAD = true;
public boolean HINT_RECOVER_NAN = true;
public int contraint_iterations_per_steps = 1;
public static boolean HINT_UPDATE_OLD_POSITION = true;
public Physics() {
mParticles = new Vector<Particle>();
mForces = new Vector<IForce>();
mConstraints = new Vector<IConstraint>();
mIntegrator = new Midpoint();
}
/* particles */
public void add(Particle theParticle) {
mParticles.add(theParticle);
}
public void add(Collection<? extends Particle> theParticles) {
mParticles.addAll(theParticles);
}
public void remove(Particle theParticle) {
mParticles.remove(theParticle);
}
public void remove(Collection<? extends Particle> theParticles) {
mParticles.removeAll(theParticles);
}
public Vector<Particle> particles() {
return mParticles;
}
public Particle particles(final int theIndex) {
return mParticles.get(theIndex);
}
public BasicParticle makeParticle() {
BasicParticle myParticle = new BasicParticle();
mParticles.add(myParticle);
return myParticle;
}
public BasicParticle makeParticle(final Vector3f thePosition) {
BasicParticle myParticle = makeParticle();
myParticle.setPositionRef(thePosition);
myParticle.old_position().set(myParticle.position());
return myParticle;
}
public BasicParticle makeParticle(final float x, final float y) {
BasicParticle myParticle = makeParticle();
myParticle.position().set(x, y);
myParticle.old_position().set(myParticle.position());
return myParticle;
}
public BasicParticle makeParticle(final float x, final float y, final float z) {
BasicParticle myParticle = makeParticle();
myParticle.position().set(x, y, z);
myParticle.old_position().set(myParticle.position());
return myParticle;
}
public BasicParticle makeParticle(final float x, final float y, final float z, final float pMass) {
BasicParticle myParticle = makeParticle();
myParticle.position().set(x, y, z);
myParticle.mass(pMass);
myParticle.old_position().set(myParticle.position());
return myParticle;
}
public BasicParticle makeParticle(final Vector3f thePosition, final float pMass) {
BasicParticle myParticle = makeParticle();
myParticle.setPositionRef(thePosition);
myParticle.old_position().set(myParticle.position());
myParticle.mass(pMass);
return myParticle;
}
public <T extends Particle> T makeParticle(Class<T> theParticleClass) {
T myParticle;
try {
myParticle = theParticleClass.newInstance();
mParticles.add(myParticle);
} catch (Exception ex) {
System.err.println(ex);
myParticle = null;
}
return myParticle;
}
public void removeTags() {
for (final Particle myParticle : mParticles) {
myParticle.tag(false);
}
}
/* forces */
public void add(IForce theForce) {
if (theForce instanceof ViscousDrag && mIntegrator instanceof Verlet) {
System.err.println(
"### WARNING / 'viscous drag' might have no effect with 'verlet' integration. use 'Verlet.damping(float theDamping)' instead.");
}
mForces.add(theForce);
}
public void addForces(final Vector<? extends IForce> theForces) {
mForces.addAll(theForces);
}
public void remove(IForce theForce) {
mForces.remove(theForce);
}
public Vector<IForce> forces() {
return mForces;
}
public IForce forces(final int theIndex) {
return mForces.get(theIndex);
}
public void applyForces(final float theDeltaTime) {
/* accumulate inner forces */
synchronized (mParticles) {
final Iterator<Particle> iter = mParticles.iterator();
while (iter.hasNext()) {
final Particle myParticle = iter.next();
if (!myParticle.fixed()) {
/* accumulate inner forces */
myParticle.accumulateInnerForce(theDeltaTime);
}
}
}
/* add new forces to each particle */
synchronized (mForces) {
Iterator<IForce> iter = mForces.iterator();
while (iter.hasNext()) {
final IForce mForce = iter.next();
if (mForce.active()) {
mForce.apply(theDeltaTime, this);
}
}
}
}
public <T extends IForce> T makeForce(Class<T> theForceClass) {
T myForce;
try {
myForce = theForceClass.newInstance();
mForces.add(myForce);
} catch (Exception ex) {
System.err.println(ex);
myForce = null;
}
return myForce;
}
public Spring makeSpring(final Particle theA, final Particle theB) {
Spring mySpring = new Spring(theA, theB);
mForces.add(mySpring);
return mySpring;
}
public Spring makeSpring(final Particle theA,
final Particle theB,
final float theRestLength) {
Spring mySpring = new Spring(theA, theB, theRestLength);
mForces.add(mySpring);
return mySpring;
}
public Spring makeSpring(final Particle theA,
final Particle theB,
final float theSpringConstant,
final float theSpringDamping) {
Spring mySpring = new Spring(theA, theB, theSpringConstant, theSpringDamping);
mForces.add(mySpring);
return mySpring;
}
public Spring makeSpring(final Particle theA,
final Particle theB,
final float theSpringConstant,
final float theSpringDamping,
final float theRestLength) {
Spring mySpring = new Spring(theA, theB, theSpringConstant, theSpringDamping, theRestLength);
mForces.add(mySpring);
return mySpring;
}
/* constraints */
public void add(final IConstraint theConstraint) {
mConstraints.add(theConstraint);
}
public void addConstraints(final Vector<? extends IConstraint> theConstraints) {
mConstraints.addAll(theConstraints);
}
public void remove(final IConstraint theConstraint) {
mConstraints.remove(theConstraint);
}
public Vector<IConstraint> constraints() {
return mConstraints;
}
public IConstraint constraints(final int theIndex) {
return mConstraints.get(theIndex);
}
/* integration */
public void setInegratorRef(IIntegrator theIntegrator) {
mIntegrator = theIntegrator;
}
public IIntegrator getIntegrator() {
return mIntegrator;
}
public void loop(final float theDeltaTime, final int theIterations) {
for (int i = 0; i < theIterations; i++) {
step(theDeltaTime / (float) theIterations);
}
}
public void step(final float theDeltaTime) {
prepareParticles(theDeltaTime);
handleForces();
integrate(theDeltaTime);
handleParticles(theDeltaTime);
handleContraints();
}
protected synchronized void integrate(float theDeltaTime) {
mIntegrator.step(theDeltaTime, this);
}
protected synchronized void handleForces() {
synchronized (mForces) {
final Iterator<IForce> iter = mForces.iterator();
while (iter.hasNext()) {
final IForce myForce = iter.next();
if (myForce.dead()) {
iter.remove();
}
}
}
}
protected synchronized void handleContraints() {
synchronized (mConstraints) {
for (int i = 0; i < contraint_iterations_per_steps; i++) {
final Iterator<IConstraint> iter = mConstraints.iterator();
while (iter.hasNext()) {
final IConstraint myContraint = iter.next();
myContraint.apply(this);
}
}
}
}
protected synchronized void handleParticles(float theDeltaTime) {
synchronized (mParticles) {
final Iterator<Particle> iter = mParticles.iterator();
while (iter.hasNext()) {
final Particle myParticle = iter.next();
/* clear force */
myParticle.force().set(0, 0, 0);
/* age particle */
myParticle.age(myParticle.age() + theDeltaTime);
/* remove dead */
if (HINT_REMOVE_DEAD) {
if (myParticle.dead()) {
iter.remove();
}
}
/* recover NAN */
if (HINT_RECOVER_NAN) {
if (myParticle.position().isNaN()) {
if (myParticle.old_position().isNaN()) {
myParticle.position().set(0, 0, 0);
} else {
myParticle.position().set(myParticle.old_position());
}
}
if (myParticle.velocity().isNaN()) {
myParticle.velocity().set(0, 0, 0);
}
}
/* still */
if (HINT_OPTIMIZE_STILL) {
final float mySpeed = myParticle.velocity().lengthSquared();
myParticle.still(mySpeed > -EPSILON && mySpeed < EPSILON);
}
}
}
}
protected synchronized void prepareParticles(float theDeltaTime) {
synchronized (mParticles) {
final Iterator<Particle> iter = mParticles.iterator();
while (iter.hasNext()) {
final Particle myParticle = iter.next();
if (HINT_UPDATE_OLD_POSITION) {
myParticle.old_position().set(myParticle.position());
}
}
}
}
}
+49
View File
@@ -0,0 +1,49 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen;
public class ShortLivedParticle
extends BasicParticle {
private float _myMaxAge;
public ShortLivedParticle(float theMaxAge) {
_myMaxAge = theMaxAge;
}
public ShortLivedParticle() {
this(1);
}
public void setMaxAge(float theMaxAge) {
_myMaxAge = theMaxAge;
}
public float ageRatio() {
return Math.min(age() / _myMaxAge, 1);
}
public boolean dead() {
return age() >= _myMaxAge;
}
}
+48
View File
@@ -0,0 +1,48 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen;
import mathematik.Vector3i;
public class VectorfieldParticle
extends BasicParticle {
private Vector3i _myLastUnit;
public VectorfieldParticle() {
super();
_myLastUnit = new Vector3i();
}
public void setLastUnit(Vector3i theUnit) {
_myLastUnit = theUnit;
}
public Vector3i getLastUnit() {
return _myLastUnit;
}
public void accumulateInnerForce(final float theDeltaTime) {
}
}
+107
View File
@@ -0,0 +1,107 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
import teilchen.behavior.Util.ProximityStructure;
import java.io.Serializable;
import java.util.Vector;
public class Alignment
implements IBehavior,
Serializable {
private static final long serialVersionUID = -4953599448151741585L;
private float mProximity;
private float mWeight;
private final Vector3f mForce;
private Vector<IBehaviorParticle> mNeighbors;
public Alignment() {
mProximity = 100.0f;
mWeight = 1.0f;
mForce = new Vector3f();
}
public void update(float theDeltaTime, IBehaviorParticle pParent) {
mForce.set(0, 0, 0);
if (mNeighbors != null) {
Vector<ProximityStructure> mCloseNeighbors = ProximityStructure.findProximityEntities(pParent, mNeighbors, mProximity);
findCommonVelocity(mCloseNeighbors, mForce);
mForce.scale(weight());
}
}
private static void findCommonVelocity(Vector<ProximityStructure> mCloseNeighbors, final Vector3f pForce) {
/* find away vector */
pForce.set(0, 0, 0);
if (!mCloseNeighbors.isEmpty()) {
/**
* @todo the vectors could be weighted according to distance: 1.0 -
* distance ( for example )
*/
for (ProximityStructure p : mCloseNeighbors) {
pForce.add(p.particle.velocity());
}
pForce.scale(1.0f / mCloseNeighbors.size());
pForce.normalize();
if (pForce.isNaN()) {
pForce.set(0, 0, 0);
}
}
}
public <E extends IBehaviorParticle> void neighbors(final Vector<E> pNeighbors) {
/**
* @todo well is this OK?
*/
mNeighbors = (Vector<IBehaviorParticle>) pNeighbors;
}
public Vector3f force() {
return mForce;
}
public float weight() {
return mWeight;
}
public void weight(float pWeight) {
mWeight = pWeight;
}
public float proximity() {
return mProximity;
}
public void proximity(float thePrivacyRadius) {
mProximity = thePrivacyRadius;
}
}
+159
View File
@@ -0,0 +1,159 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
public class Arrival
implements IBehavior, Verhalten {
static final long serialVersionUID = 6897889750581191781L;
private Vector3f mSeekPosition;
private final Vector3f mForce;
private float mWeight;
private float mBreakRadius;
private float mBreakForce;
private boolean mIsArriving;
private boolean mHasArrived;
private boolean mOverSteer;
public Arrival() {
mBreakRadius = 50.0f;
mBreakForce = 50.0f;
mForce = new Vector3f();
mSeekPosition = new Vector3f();
mWeight = 1;
mIsArriving = false;
mHasArrived = false;
mOverSteer = true;
}
public boolean arriving() {
return mIsArriving;
}
public boolean arrived() {
return mHasArrived;
}
public boolean oversteer() {
return mOverSteer;
}
public void oversteer(boolean pOverSteer) {
mOverSteer = pOverSteer;
}
public Vector3f position() {
return mSeekPosition;
}
public void setPositionRef(final Vector3f pPoint) {
mSeekPosition = pPoint;
}
public void breakforce(float pBreakForce) {
mBreakForce = pBreakForce;
}
public float breakforce() {
return mBreakForce;
}
public void breakradius(float pOutterRadius) {
mBreakRadius = pOutterRadius;
}
public float breakradius() {
return mBreakRadius;
}
public void update(float theDeltaTime, IBehaviorParticle pParent) {
mForce.sub(mSeekPosition, pParent.position());
final float myDistanceToArrivalPoint = mForce.length();
/* get direction */
if (myDistanceToArrivalPoint < mBreakRadius) {
mIsArriving = true;
final float mSpeed = pParent.velocity().length();
final float MIN_ACCEPTABLE_SPEED = 10.0f;
if (mSpeed < MIN_ACCEPTABLE_SPEED) {
/* sleep */
mForce.set(0, 0, 0);
mHasArrived = true;
} else {
/* break */
final boolean USE_WEIGHTED_BREAK_FORCE = true;
if (USE_WEIGHTED_BREAK_FORCE) {
final float mRatio = myDistanceToArrivalPoint / mBreakRadius;
final Vector3f mBreakForceVector = new Vector3f(pParent.velocity());
mBreakForceVector.scale(-mBreakForce);
mBreakForceVector.scale(1.0f - mRatio);
final Vector3f mSteerForce = new Vector3f(mForce);
mSteerForce.scale(pParent.maximumInnerForce() / myDistanceToArrivalPoint);
mSteerForce.scale(mRatio);
mForce.add(mBreakForceVector, mSteerForce);
} else {
mForce.set(pParent.velocity().x * -mBreakForce,
pParent.velocity().y * -mBreakForce,
pParent.velocity().z * -mBreakForce);
}
mHasArrived = false;
}
} else {
/* outside of the outter radius continue 'seeking' */
mForce.scale(pParent.maximumInnerForce() / myDistanceToArrivalPoint);
if (mOverSteer) {
mForce.sub(mForce, pParent.velocity());
}
mIsArriving = false;
mHasArrived = false;
}
mForce.scale(weight());
}
public Vector3f force() {
return mForce;
}
public float weight() {
return mWeight;
}
public void weight(float pWeight) {
mWeight = pWeight;
}
}
+111
View File
@@ -0,0 +1,111 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
import teilchen.behavior.Util.ProximityStructure;
import java.io.Serializable;
import java.util.Vector;
public class Cohesion
implements IBehavior,
Serializable {
private static final long serialVersionUID = -4953599448151741585L;
private float mProximity;
private float mWeight;
private final Vector3f mForce;
private Vector<IBehaviorParticle> mNeighbors;
public Cohesion() {
mProximity = 100.0f;
mWeight = 1.0f;
mForce = new Vector3f();
}
public void update(float theDeltaTime, IBehaviorParticle pParent) {
mForce.set(0, 0, 0);
if (mNeighbors != null) {
Vector<ProximityStructure> mCloseNeighbors = ProximityStructure.findProximityEntities(pParent, mNeighbors, mProximity);
findTowardsVector(mCloseNeighbors, mForce);
mForce.scale(weight());
}
}
private static void findTowardsVector(Vector<ProximityStructure> mCloseNeighbors, final Vector3f pForce) {
/* find away vector */
if (!mCloseNeighbors.isEmpty()) {
pForce.set(0, 0, 0);
/**
* @todo the vectors could be weighted according to distance: 1.0 -
* distance ( for example )
*/
for (ProximityStructure p : mCloseNeighbors) {
final Vector3f mTowardsVector = mathematik.Util.scale(p.distanceVec, -1.0f);
pForce.add(mTowardsVector);
}
pForce.scale(1.0f / mCloseNeighbors.size());
pForce.normalize();
if (pForce.isNaN()) {
pForce.set(0, 0, 0);
}
} else {
pForce.set(0, 0, 0);
}
}
public <E extends IBehaviorParticle> void neighbors(final Vector<E> pNeighbors) {
/**
* @todo well is this OK?
*/
mNeighbors = (Vector<IBehaviorParticle>) pNeighbors;
}
public Vector3f force() {
return mForce;
}
public float weight() {
return mWeight;
}
public void weight(float pWeight) {
mWeight = pWeight;
}
public float proximity() {
return mProximity;
}
public void proximity(float thePrivacyRadius) {
mProximity = thePrivacyRadius;
}
}
+77
View File
@@ -0,0 +1,77 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
public class Flee
implements IBehavior, Verhalten {
static final long serialVersionUID = -6530887943347815188L;
private Vector3f mFleePosition;
private Vector3f mForce;
private float mWeight = 1;
public Flee() {
mFleePosition = new Vector3f();
mForce = new Vector3f();
}
public Vector3f position() {
return mFleePosition;
}
public void setPositionRef(final Vector3f thePoint) {
mFleePosition = thePoint;
}
public void update(float theDeltaTime, IBehaviorParticle theParent) {
mForce.sub(theParent.position(), mFleePosition);
final float myDistanceToPoint = mForce.length();
if (myDistanceToPoint > SMALLEST_ACCEPTABLE_DISTANCE) {
mForce.scale(theParent.maximumInnerForce() / myDistanceToPoint);
mForce.sub(mForce, theParent.velocity());
mForce.scale(weight());
} else {
mForce.set(0, 0, 0);
}
}
public Vector3f force() {
return mForce;
}
public float weight() {
return mWeight;
}
public void weight(float theWeight) {
mWeight = theWeight;
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import java.io.Serializable;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
public interface IBehavior
extends Serializable {
void update(float theDeltaTime, final IBehaviorParticle pParent);
Vector3f force();
float weight();
void weight(float theWeight);
}
+127
View File
@@ -0,0 +1,127 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
public class Motor
implements IBehavior,
Verhalten {
static final long serialVersionUID = -3781170603537691466L;
private Vector3f mDirection;
private float mStrength;
private final Vector3f mForce;
private float mWeight;
private boolean mAutoNormalizeDirection;
private boolean mActive;
private boolean mAutoUpdateDirection;
public final Vector3f AUTO_RECOVER_DIRECTION;
public Motor() {
mDirection = new Vector3f(1, 0, 0);
mForce = new Vector3f();
mActive = true;
mStrength = 1;
mWeight = 1;
mAutoUpdateDirection = false;
mAutoNormalizeDirection = true;
AUTO_RECOVER_DIRECTION = new Vector3f();
AUTO_RECOVER_DIRECTION.randomize();
AUTO_RECOVER_DIRECTION.z = 0;
}
public boolean active() {
return mActive;
}
public void active(boolean pActive) {
mActive = pActive;
}
public float strength() {
return mStrength;
}
public void strength(final float theStrength) {
mStrength = theStrength;
}
public Vector3f direction() {
return mDirection;
}
public void setDirectionRef(final Vector3f theDirection) {
mDirection = theDirection;
}
public void auto_update_direction(boolean pAutoUpdateDirection) {
mAutoUpdateDirection = pAutoUpdateDirection;
}
public void auto_normalize_direction(boolean pAutoNormalizeDirection) {
mAutoNormalizeDirection = pAutoNormalizeDirection;
}
public void update(float theDeltaTime, IBehaviorParticle pParent) {
if (mActive) {
if (mAutoUpdateDirection) {
if (pParent.velocity().length() > 0.0f) {
mDirection.set(pParent.velocity());
} else {
mDirection.set(AUTO_RECOVER_DIRECTION);
}
}
if (mAutoNormalizeDirection) {
mDirection.normalize();
}
mForce.scale(mStrength, mDirection);
mForce.scale(mWeight, mForce);
} else {
mForce.set(0, 0, 0);
}
}
public Vector3f force() {
return mForce;
}
public float weight() {
return mWeight;
}
public void weight(float theWeight) {
mWeight = theWeight;
}
}
+96
View File
@@ -0,0 +1,96 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
public class Seek
implements IBehavior, Verhalten {
static final long serialVersionUID = -3781170603537691477L;
private Vector3f mSeekPosition;
private Vector3f mForce;
private float mWeight = 1;
private float mDistanceToPoint;
private boolean mOverSteer;
public Seek() {
mSeekPosition = new Vector3f();
mForce = new Vector3f();
mOverSteer = false;
}
public boolean oversteer() {
return mOverSteer;
}
public void oversteer(boolean pOverSteer) {
mOverSteer = pOverSteer;
}
public Vector3f position() {
return mSeekPosition;
}
public void setPositionRef(final Vector3f thePoint) {
mSeekPosition = thePoint;
}
public float distancetopoint() {
return mDistanceToPoint;
}
public void update(float theDeltaTime, IBehaviorParticle theParent) {
mForce.sub(mSeekPosition, theParent.position());
mDistanceToPoint = mForce.length();
if (mDistanceToPoint > SMALLEST_ACCEPTABLE_DISTANCE) {
mForce.scale(theParent.maximumInnerForce() / mDistanceToPoint);
if (mOverSteer) {
mForce.sub(mForce, theParent.velocity());
}
mForce.scale(weight());
} else {
mForce.set(0, 0, 0);
}
}
public Vector3f force() {
return mForce;
}
public float weight() {
return mWeight;
}
public void weight(float theWeight) {
mWeight = theWeight;
}
}
+110
View File
@@ -0,0 +1,110 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
import teilchen.behavior.Util.ProximityStructure;
import java.io.Serializable;
import java.util.Vector;
public class Separation
implements IBehavior,
Serializable {
private static final long serialVersionUID = -4953599448151741585L;
private float mProximity;
private float mWeight;
private final Vector3f mForce;
private Vector<IBehaviorParticle> mNeighbors;
public Separation() {
mProximity = 100.0f;
mWeight = 1.0f;
mForce = new Vector3f();
}
public void update(float theDeltaTime, IBehaviorParticle pParent) {
mForce.set(0, 0, 0);
if (mNeighbors != null) {
Vector<ProximityStructure> mCloseNeighbors = ProximityStructure.findProximityEntities(pParent, mNeighbors, mProximity);
findAwayVector(mCloseNeighbors, mForce);
mForce.scale(weight());
}
}
private static void findAwayVector(Vector<ProximityStructure> mCloseNeighbors, final Vector3f pForce) {
/* find away vector */
if (!mCloseNeighbors.isEmpty()) {
pForce.set(0, 0, 0);
/**
* @todo the vectors could be weighted according to distance: 1.0 -
* distance ( for example )
*/
for (ProximityStructure p : mCloseNeighbors) {
pForce.add(p.distanceVec);
}
pForce.scale(1.0f / mCloseNeighbors.size());
pForce.normalize();
if (pForce.isNaN()) {
pForce.set(0, 0, 0);
}
} else {
pForce.set(0, 0, 0);
}
}
public <E extends IBehaviorParticle> void neighbors(final Vector<E> pNeighbors) {
/**
* @todo well is this OK?
*/
mNeighbors = (Vector<IBehaviorParticle>) pNeighbors;
}
public Vector3f force() {
return mForce;
}
public float weight() {
return mWeight;
}
public void weight(float pWeight) {
mWeight = pWeight;
}
public float proximity() {
return mProximity;
}
public void proximity(float thePrivacyRadius) {
mProximity = thePrivacyRadius;
}
}
+91
View File
@@ -0,0 +1,91 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
public class Steering implements IBehavior,
Verhalten {
private final Vector3f mForce;
private final Vector3f mUPVector;
private float mWeight;
private float mSteering = 0.0f;
private boolean mActive = true;
public Steering() {
mForce = new Vector3f();
mUPVector = new Vector3f(0, 0, -1);
mWeight = 1;
}
public void update(float theDeltaTime, IBehaviorParticle pParent) {
if (mActive) {
/* 2D warning -- ignoring z-axis for now */
Vector3f mDirection = new Vector3f(pParent.velocity());
if (mDirection.lengthSquared() > 0) {
mDirection.normalize();
mDirection = mathematik.Util.cross(mDirection, mUPVector);
mDirection.scale(mSteering);
mForce.set(mDirection);
} else {
mForce.set(0, 0, 0);
}
} else {
mForce.set(0, 0, 0);
}
}
public float steering_strength() {
return mSteering;
}
public void steering_strength(float pSteering) {
mSteering = pSteering;
}
public Vector3f force() {
return mForce;
}
public Vector3f upvector() {
return mUPVector;
}
public float weight() {
return mWeight;
}
public void weight(float pWeight) {
mWeight = pWeight;
}
public void active(boolean pActive) {
mActive = pActive;
}
}
+66
View File
@@ -0,0 +1,66 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
import teilchen.Particle;
import java.util.Vector;
public class Util {
public static class ProximityStructure {
public final Particle particle;
public final Vector3f distanceVec;
public final float distance;
public ProximityStructure(Particle pP, Vector3f pDistanceVec, float pDistance) {
particle = pP;
distanceVec = pDistanceVec;
distance = pDistance;
}
public static Vector<ProximityStructure> findProximityEntities(IBehaviorParticle pParentEntity,
Vector<IBehaviorParticle> pNeighborsEntity,
float pProximity) {
/* find neighbors in proximity */
Vector<ProximityStructure> mCloseNeighbors = new Vector<ProximityStructure>();
for (IBehaviorParticle p : pNeighborsEntity) {
if (!p.equals(pParentEntity)) { /* exclude self */
final Vector3f mDistanceVec = mathematik.Util.sub(pParentEntity.position(), p.position());
final float mDistance = mDistanceVec.length();
if (mDistance <= pProximity) {
mCloseNeighbors.add(new ProximityStructure(p, mDistanceVec, mDistance));
}
}
}
return mCloseNeighbors;
}
}
}
+33
View File
@@ -0,0 +1,33 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import java.io.Serializable;
public interface Verhalten
extends Serializable {
float SMALLEST_ACCEPTABLE_DISTANCE = 0.01f;
}
+122
View File
@@ -0,0 +1,122 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.behavior;
import mathematik.Random;
import mathematik.Vector3f;
import teilchen.IBehaviorParticle;
public class Wander
implements IBehavior {
static final long serialVersionUID = 4957162698340669663L;
private Vector3f mForce;
private float mSteeringStrength;
private float mSteeringOffset;
private float mCurrentSteeringStrength;
private Vector3f mUpVector;
private float mWeight;
private final Random mRandom;
private boolean mActive;
public Wander() {
mRandom = new Random();
mForce = new Vector3f();
mSteeringStrength = 10f;
mSteeringOffset = 5f;
mUpVector = new Vector3f(0, 0, 1);
mWeight = 1;
mActive = true;
}
public boolean active() {
return mActive;
}
public void active(boolean pActive) {
mActive = pActive;
}
public Vector3f force() {
return mForce;
}
public float weight() {
return mWeight;
}
public void weight(float theWeight) {
mWeight = theWeight;
}
public void update(float pDeltaTime, IBehaviorParticle pParent) {
if (mActive && pParent.velocity().length() > 0) {
mCurrentSteeringStrength += mRandom.getFloat(-0.5f, 0.5f) * mSteeringOffset;
mCurrentSteeringStrength = Math.max(Math.min(mCurrentSteeringStrength, mSteeringStrength), -mSteeringStrength);
final Vector3f mWanderTarget = mathematik.Util.cross(mUpVector, pParent.velocity());
mWanderTarget.normalize();
mWanderTarget.scale(mCurrentSteeringStrength);
if (mWanderTarget.isNaN()) {
mForce.set(0, 0, 0);
} else {
mForce.scale(mWeight, mWanderTarget);
}
} else {
mForce.set(0, 0, 0);
}
}
public Vector3f upvector() {
return mUpVector;
}
public float steeringstrength() {
return mSteeringStrength;
}
public void steeringstrength(final float theSteeringStrength) {
mSteeringStrength = theSteeringStrength;
}
public float steeringoffset() {
return mSteeringOffset;
}
public void steeringoffset(final float theSteeringOffset) {
mSteeringOffset = theSteeringOffset;
}
}
@@ -0,0 +1,79 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.constraint;
import mathematik.Vector3f;
import teilchen.Particle;
public class AngleConstraintStick
extends Stick {
private final Particle mParticleA;
private final Particle mParticleB;
private final Particle mParticleC;
private float mMinAngle;
/**
*
* particles are connected like this: A -- B -- C
*
* @param pParticleA
* @param pParticleB
* @param pParticleC
*/
public AngleConstraintStick(Particle pParticleA, Particle pParticleB, Particle pParticleC) {
super(pParticleA, pParticleC);
mParticleA = pParticleA;
mParticleB = pParticleB;
mParticleC = pParticleC;
mMinAngle = Float.MAX_VALUE;
}
public void min_angle(float pAngle) {
mMinAngle = pAngle;
}
public void pre_step() {
Vector3f ab = mathematik.Util.sub(mParticleA.position(), mParticleB.position());
Vector3f cb = mathematik.Util.sub(mParticleC.position(), mParticleB.position());
final float mCurrentAngle = ab.angle(cb);
if (mCurrentAngle < mMinAngle) {
final float b = ab.length();
final float c = cb.length();
// a = sqrt ( b*b + c*c - 2bc*cosA )
final float mDistance = (float) Math.sqrt(b * b + c * c - 2 * b * c * (float) Math.cos(mMinAngle));
restlength(mDistance);
active(true);
}
}
public void post_step() {
active(false);
}
}
+221
View File
@@ -0,0 +1,221 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.constraint;
import mathematik.Util;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
/**
* @todo it probably pays of two check if we deal with a 2D or 3D constraint. it
* s just checking components once and then saving a lot of time.
*/
public class Angular
implements IConstraint {
protected boolean mActive = true;
private final Particle _myA;
private final Particle _myB;
private final Particle _myC;
private final Vector3f _myTempA = new Vector3f();
private final Vector3f _myTempB = new Vector3f();
private float _myMinimumAngle;
private float _myMaximumAngle;
private final Vector3f _myTempNormal;
public boolean OK;
private static final double EPSILON = 0.001;
private static final double _myStrength = 1;
public Angular(Particle theA, Particle theB, Particle theC,
float theMinimumAngle, float theMaximumAngle) {
_myA = theA;
_myB = theB;
_myC = theC;
_myTempNormal = new Vector3f();
range(theMinimumAngle, theMaximumAngle);
}
public Angular(Particle theA, Particle theB, Particle theC) {
this(theA,
theB,
theC,
0, 0);
}
public void range(float theMinimumAngle, float theMaximumAngle) {
_myMinimumAngle = theMinimumAngle;
_myMaximumAngle = theMaximumAngle;
sortAngles();
}
public float minimumAngle() {
return _myMinimumAngle;
}
public float maximumAngle() {
return _myMaximumAngle;
}
private void sortAngles() {
final float myMaximumAngle = _myMaximumAngle;
final float myMinimumAngle = _myMinimumAngle;
_myMaximumAngle = Math.max(myMaximumAngle, myMinimumAngle);
_myMinimumAngle = Math.min(myMaximumAngle, myMinimumAngle);
}
public void apply(Physics theParticleSystem) {
if (!mActive) {
return;
}
/**
* @todo test for special case: a and c are in the same place.
*/
_myTempA.sub(_myB.position(), _myA.position());
_myTempB.sub(_myB.position(), _myC.position());
_myTempA.normalize();
_myTempB.normalize();
/**
* @todo check for special cases! like angle being 0 etc.
*/
/**
* @todo check if the range exceeds PI.
*/
if (_myMinimumAngle < Math.PI && _myMaximumAngle > Math.PI) {
System.out.println("### WARNING split range and check twice.");
}
float myCosinusAngle = _myTempA.dot(_myTempB);
if (myCosinusAngle > 1) {
System.out.println("### WARNING myCosinusAngle > 1: " + myCosinusAngle);
myCosinusAngle = 1;
}
final float myTempCosMaximumAngle = (float) Math.cos(_myMaximumAngle);
final float myTempCosMinimumAngle = (float) Math.cos(_myMinimumAngle);
final float myCosMaximumAngle = Math.max(myTempCosMinimumAngle, myTempCosMaximumAngle);
final float myCosMinimumAngle = Math.min(myTempCosMinimumAngle, myTempCosMaximumAngle);
calculateNormal(_myTempA, _myTempB);
final boolean myLeftSide = checkForHemisphere(_myTempA, _myTempB);
double myCurrentAngle = 0;
/**
* @todo until i the split is implemented agular constraints only work
* for one side.
*/
OK = myLeftSide;
if (myLeftSide) {
if (myCosinusAngle < myCosMinimumAngle || myCosinusAngle > myCosMaximumAngle) {
myCurrentAngle = Math.acos(myCosinusAngle);
OK = false;
} else {
OK = true;
}
} else {
myCurrentAngle = 2 * Math.PI - Math.acos(myCosinusAngle);
}
if (!OK) {
final double myTheta;
if (myCurrentAngle > _myMaximumAngle) {
myTheta = _myMaximumAngle - myCurrentAngle;
} else if (myCosinusAngle < _myMinimumAngle) {
myTheta = -1 * (myCurrentAngle - _myMinimumAngle);
} else {
System.out.println("### WARNING puzzled.");
myTheta = 0;
}
correctAngle(myTheta);
}
}
private void calculateNormal(Vector3f myVectorA, Vector3f myVectorB) {
_myTempNormal.cross(myVectorA, myVectorB);
_myTempNormal.normalize();
if (_myTempNormal.isNaN()) {
_myTempNormal.set(0, 0, 1);
System.out.println("### WARNING can t find normal.");
}
}
private void correctAngle(double theTheta) {
if (theTheta < -EPSILON || theTheta > EPSILON) {
Vector3f myOtherPointOnAxis = Util.add(_myB.position(), _myTempNormal);
Vector3f myRotatedPointA = Util.rotatePoint(_myA.position(), theTheta * -0.5 * _myStrength,
_myB.position(),
myOtherPointOnAxis);
_myA.position().set(myRotatedPointA);
Vector3f myRotatedPointB = Util.rotatePoint(_myC.position(), theTheta * 0.5 * _myStrength,
_myB.position(),
myOtherPointOnAxis);
_myC.position().set(myRotatedPointB);
System.out.println("correct " + Math.toDegrees(theTheta) + " / " + _myTempNormal);
}
}
private boolean checkForHemisphere(Vector3f myVectorA, Vector3f myVectorB) {
/* special case thus easy to find the direction */
if (myVectorA.z == 0 && myVectorB.z == 0) {
return _myTempNormal.z > 0;
} else {
/**
* @todo do it the hard way and create a matrix from the two vectors
* and transform the cross vector into local space
*/
System.out.println("### WARNING calculate for 3D plane / not implemented.");
return true;
}
}
public boolean active() {
return mActive;
}
public void active(boolean theActiveState) {
mActive = theActiveState;
}
}
+179
View File
@@ -0,0 +1,179 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.constraint;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.integration.Verlet;
public class Box
implements IConstraint {
protected boolean mActive = true;
private final Vector3f _myMin;
private final Vector3f _myMax;
private boolean _myReflectFlag;
private float _myCoefficientOfRestitution;
private boolean _myTeleport;
public Box(final Vector3f theMin, final Vector3f theMax) {
_myMin = theMin;
_myMax = theMax;
_myReflectFlag = true;
_myCoefficientOfRestitution = 1.0f;
_myTeleport = false;
}
public Box() {
this(new Vector3f(), new Vector3f());
}
public void telelport(boolean theTeleportState) {
_myTeleport = theTeleportState;
}
public void reflect(boolean theReflectState) {
_myReflectFlag = theReflectState;
}
public Vector3f min() {
return _myMin;
}
public Vector3f max() {
return _myMax;
}
private static final Vector3f[] _myNormals;
static {
_myNormals = new Vector3f[6];
_myNormals[0] = new Vector3f(-1, 0, 0);
_myNormals[1] = new Vector3f(0, -1, 0);
_myNormals[2] = new Vector3f(0, 0, -1);
_myNormals[3] = new Vector3f(1, 0, 0);
_myNormals[4] = new Vector3f(0, 1, 0);
_myNormals[5] = new Vector3f(0, 0, 1);
}
public void coefficientofrestitution(float theCoefficientOfRestitution) {
_myCoefficientOfRestitution = theCoefficientOfRestitution;
}
public float coefficientofrestitution() {
return _myCoefficientOfRestitution;
}
public void apply(final Physics theParticleSystem) {
if (!mActive) {
return;
}
for (final Particle myParticle : theParticleSystem.particles()) {
if (_myTeleport) {
if (myParticle.position().x > _myMax.x) {
myParticle.position().x = _myMin.x;
}
if (myParticle.position().y > _myMax.y) {
myParticle.position().y = _myMin.y;
}
if (myParticle.position().z > _myMax.z) {
myParticle.position().z = _myMin.z;
}
if (myParticle.position().x < _myMin.x) {
myParticle.position().x = _myMax.x;
}
if (myParticle.position().y < _myMin.y) {
myParticle.position().y = _myMax.y;
}
if (myParticle.position().z < _myMin.z) {
myParticle.position().z = _myMax.z;
}
} else {
/**
* @todo to do this properly we would need to add the normals
* and normalize them. maybe later.
*/
int myTag = -1;
final Vector3f myPosition = new Vector3f(myParticle.position());
if (myParticle.position().x > _myMax.x) {
myParticle.position().x = _myMax.x;
myTag = 0;
}
if (myParticle.position().y > _myMax.y) {
myParticle.position().y = _myMax.y;
myTag = 1;
}
if (myParticle.position().z > _myMax.z) {
myParticle.position().z = _myMax.z;
myTag = 2;
}
if (myParticle.position().x < _myMin.x) {
myParticle.position().x = _myMin.x;
myTag = 3;
}
if (myParticle.position().y < _myMin.y) {
myParticle.position().y = _myMin.y;
myTag = 4;
}
if (myParticle.position().z < _myMin.z) {
myParticle.position().z = _myMin.z;
myTag = 5;
}
if (myTag >= 0) {
if (_myReflectFlag) {
if (theParticleSystem.getIntegrator() instanceof Verlet) {
final Vector3f myDiff = mathematik.Util.sub(myPosition, myParticle.position());
teilchen.util.Util.reflect(myDiff, _myNormals[myTag], _myCoefficientOfRestitution);
// System.out.println("### reflect " + _myNormals[myTag]);
// System.out.println("myDiff " + myDiff);
myParticle.old_position().sub(myDiff);
} else {
teilchen.util.Util.reflectVelocity(myParticle,
_myNormals[myTag],
_myCoefficientOfRestitution);
}
} else {
myParticle.velocity().set(0, 0, 0);
}
}
}
}
}
public boolean active() {
return mActive;
}
public void active(boolean theActiveState) {
mActive = theActiveState;
}
}
@@ -0,0 +1,35 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.constraint;
import teilchen.Physics;
public interface IConstraint {
void apply(final Physics theParticleSystem);
boolean active();
void active(boolean theActiveState);
}
+221
View File
@@ -0,0 +1,221 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.constraint;
import java.util.Vector;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.integration.Verlet;
public class ReflectBox
implements IConstraint {
protected boolean mActive = true;
private final Vector3f _myMin;
private final Vector3f _myMax;
private float _myCoefficientOfRestitution;
private float _myEpsilon;
public boolean NEGATIVE_X = true;
public boolean NEGATIVE_Y = true;
public boolean NEGATIVE_Z = true;
public boolean POSITIV_X = true;
public boolean POSITIV_Y = true;
public boolean POSITIV_Z = true;
public ReflectBox(final Vector3f theMin, final Vector3f theMax) {
_myMin = theMin;
_myMax = theMax;
_myCoefficientOfRestitution = 1.0f;
_myEpsilon = 0.001f;
}
public ReflectBox() {
this(new Vector3f(), new Vector3f());
}
public void epsilon(final float theEpsilon) {
_myEpsilon = theEpsilon;
}
public Vector3f min() {
return _myMin;
}
public Vector3f max() {
return _myMax;
}
private static final Vector3f[] _myNormals;
static {
_myNormals = new Vector3f[6];
_myNormals[0] = new Vector3f(-1, 0, 0);
_myNormals[1] = new Vector3f(0, -1, 0);
_myNormals[2] = new Vector3f(0, 0, -1);
_myNormals[3] = new Vector3f(1, 0, 0);
_myNormals[4] = new Vector3f(0, 1, 0);
_myNormals[5] = new Vector3f(0, 0, 1);
}
public void coefficientofrestitution(float theCoefficientOfRestitution) {
_myCoefficientOfRestitution = theCoefficientOfRestitution;
}
public float coefficientofrestitution() {
return _myCoefficientOfRestitution;
}
public void apply(final Physics theParticleSystem) {
if (!(theParticleSystem.getIntegrator() instanceof Verlet)) {
System.out.println("### WARNING @ " + getClass().getSimpleName() + " / only works with verlet integrator.");
}
apply(theParticleSystem.particles());
}
public void apply(final Vector<Particle> theParticles) {
apply(theParticles, null);
}
public void apply(final Vector<Particle> theParticles, final Vector<Particle> theCollisionParticles) {
if (!mActive) {
return;
}
for (final Particle myParticle : theParticles) {
final Vector3f myPositionBeforeCollision = new Vector3f(myParticle.position());
final Vector3f p = myParticle.position();
final Vector3f p_old = myParticle.old_position();
final float r = myParticle.radius();
/**
* @todo we should weight the deflection normal
*/
if (p.x + r > _myMax.x
|| p.y + r > _myMax.y
|| p.z + r > _myMax.z
|| p.x - r < _myMin.x
|| p.y - r < _myMin.y
|| p.z - r < _myMin.z) {
int myNumberOfCollisions = 0;
final Vector3f myDeflectionNormal = new Vector3f();
if (POSITIV_X) {
if (p.x + r > _myMax.x) {
final float myBorderDiff = _myMax.x - p_old.x - r;
p.x = p_old.x + myBorderDiff;
myDeflectionNormal.add(_myNormals[0]);
myNumberOfCollisions++;
}
}
if (POSITIV_Y) {
if (p.y + r > _myMax.y) {
final float myBorderDiff = _myMax.y - p_old.y - r;
p.y = p_old.y + myBorderDiff;
myDeflectionNormal.add(_myNormals[1]);
myNumberOfCollisions++;
}
}
if (POSITIV_Z) {
if (p.z + r > _myMax.z) {
final float myBorderDiff = _myMax.z - p_old.z - r;
p.z = p_old.z + myBorderDiff;
myDeflectionNormal.add(_myNormals[2]);
myNumberOfCollisions++;
}
}
if (NEGATIVE_X) {
if (p.x - r < _myMin.x) {
final float myBorderDiff = _myMin.x - p_old.x + r;
p.x = p_old.x + myBorderDiff;
myDeflectionNormal.add(_myNormals[3]);
myNumberOfCollisions++;
}
}
if (NEGATIVE_Y) {
if (p.y - r < _myMin.y) {
final float myBorderDiff = _myMin.y - p_old.y + r;
p.y = p_old.y + myBorderDiff;
myDeflectionNormal.add(_myNormals[4]);
myNumberOfCollisions++;
}
}
if (NEGATIVE_Z) {
if (p.z - r < _myMin.z) {
final float myBorderDiff = _myMin.z - p_old.z + r;
p.z = p_old.z + myBorderDiff;
myDeflectionNormal.add(_myNormals[5]);
myNumberOfCollisions++;
}
}
if (myNumberOfCollisions > 0) {
/* remember collided particles */
if (theCollisionParticles != null) {
theCollisionParticles.add(myParticle);
}
/* room for optimization / we don t need to reflect twice. */
final float mySpeed = myPositionBeforeCollision.distanceSquared(myParticle.old_position());
if (mySpeed > _myEpsilon) {
final Vector3f myDiffAfterCollision = mathematik.Util.sub(myPositionBeforeCollision,
myParticle.position());
final Vector3f myDiffBeforeCollision = mathematik.Util.sub(myParticle.old_position(),
myParticle.position());
myDeflectionNormal.scale(1.0f / (float) myNumberOfCollisions);
teilchen.util.Util.reflect(myDiffAfterCollision, myDeflectionNormal,
_myCoefficientOfRestitution);
teilchen.util.Util.reflect(myDiffBeforeCollision, myDeflectionNormal, 1);
if (!myParticle.old_position().isNaN() && !myParticle.position().isNaN()) {
myParticle.old_position().add(myParticle.position(), myDiffBeforeCollision);
myParticle.position().add(myDiffAfterCollision);
}
}
}
}
}
}
public boolean active() {
return mActive;
}
public void active(boolean theActiveState) {
mActive = theActiveState;
}
}
+158
View File
@@ -0,0 +1,158 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.constraint;
import mathematik.Vector3f;
import teilchen.IConnection;
import teilchen.Particle;
import teilchen.Physics;
public class Stick
implements IConstraint,
IConnection {
protected final Particle mA;
protected final Particle mB;
protected float mRestLength;
protected final Vector3f mTempDistanceVector;
protected final Vector3f mTempVector;
protected boolean mOneWay;
protected float mDamping;
protected boolean mActive = true;
protected static final float EPSILON = 0.0001f;
public Stick(Particle theA, Particle theB) {
this(theA,
theB,
theA.position().distance(theB.position()));
}
public Stick(final Particle theA,
final Particle theB,
final float theRestLength) {
mRestLength = theRestLength;
mA = theA;
mB = theB;
mTempDistanceVector = new Vector3f();
mTempVector = new Vector3f();
mOneWay = false;
mDamping = 1f;
}
public void setRestLengthByPosition() {
mRestLength = mA.position().distance(mB.position());
}
public float damping() {
return mDamping;
}
public void damping(float theDamping) {
mDamping = theDamping;
}
public float restlength() {
return mRestLength;
}
public void restlength(float theRestLength) {
mRestLength = theRestLength;
}
public final Particle a() {
return mA;
}
public final Particle b() {
return mB;
}
public void setOneWay(boolean theOneWayState) {
mOneWay = theOneWayState;
}
public void apply(Physics theParticleSystem) {
if (!mActive) {
return;
}
if (mA.fixed() && mB.fixed()) {
return;
}
mTempDistanceVector.sub(mA.position(), mB.position());
final float myDistanceSquared = mTempDistanceVector.lengthSquared();
if (myDistanceSquared > 0) {
final float myDistance = (float) Math.sqrt(myDistanceSquared);
final float myDifference = mRestLength - myDistance;
if (myDifference > EPSILON || myDifference < -EPSILON) {
if (!mOneWay) {
final float myDifferenceScale = mDamping * 0.5f * myDifference / myDistance;
mTempVector.scale(myDifferenceScale, mTempDistanceVector);
if (mA.fixed()) {
mB.position().sub(mTempVector);
mB.position().sub(mTempVector);
} else if (mB.fixed()) {
mA.position().add(mTempVector);
mA.position().add(mTempVector);
} else {
mA.position().add(mTempVector);
mB.position().sub(mTempVector);
}
} else {
final float myDifferenceScale = myDifference / myDistance;
mTempVector.scale(myDifferenceScale, mTempDistanceVector);
mB.position().sub(mTempVector);
}
}
} else {
if (mA.fixed()) {
mB.position().set(mA.position());
mB.position().x += mRestLength;
} else if (mB.fixed()) {
mA.position().set(mB.position());
mA.position().x += mRestLength;
} else {
mB.position().set(mA.position());
mA.position().x -= mRestLength / 2;
mB.position().x += mRestLength / 2;
}
}
}
public boolean active() {
return mActive;
}
public void active(boolean theActiveState) {
mActive = theActiveState;
}
}
+90
View File
@@ -0,0 +1,90 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.constraint;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
public class Teleporter
implements IConstraint {
protected boolean mActive = true;
private final Vector3f mMin;
private final Vector3f mMax;
public Teleporter() {
this(new Vector3f(), new Vector3f());
}
public Teleporter(final Vector3f pMin, final Vector3f pMax) {
mMin = new Vector3f(pMin);
mMax = new Vector3f(pMax);
}
public Vector3f max() {
return mMax;
}
public Vector3f min() {
return mMin;
}
public void apply(Physics theParticleSystem) {
if (!mActive) {
return;
}
for (final Particle mParticle : theParticleSystem.particles()) {
if (mParticle.position().x > mMax.x) {
mParticle.position().x -= Math.abs(mMax.x - mMin.x);
}
if (mParticle.position().y > mMax.y) {
mParticle.position().y -= Math.abs(mMax.y - mMin.y);
}
if (mParticle.position().z > mMax.z) {
mParticle.position().z -= Math.abs(mMax.z - mMin.z);
}
if (mParticle.position().x < mMin.x) {
mParticle.position().x += Math.abs(mMax.x - mMin.x);
}
if (mParticle.position().y < mMin.y) {
mParticle.position().y += Math.abs(mMax.y - mMin.y);
}
if (mParticle.position().z < mMin.z) {
mParticle.position().z += Math.abs(mMax.z - mMin.z);
}
}
}
public boolean active() {
return mActive;
}
public void active(boolean theActiveState) {
mActive = theActiveState;
}
}
+67
View File
@@ -0,0 +1,67 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.cubicle;
import java.util.Vector;
import mathematik.Vector3i;
/*
* container class for ICubicleEntity representing one cube in the world.
*/
public class CubicleAtom {
private Vector<ICubicleEntity> mContainer;
private final Vector3i mPosition;
public CubicleAtom(int x, int y, int z) {
mContainer = new Vector<ICubicleEntity>();
mPosition = new Vector3i(x, y, z);
}
public Vector3i position() {
return mPosition;
}
public void add(ICubicleEntity theEntity) {
mContainer.add(theEntity);
}
public boolean remove(ICubicleEntity theEntity) {
return mContainer.remove(theEntity);
}
public void clear() {
mContainer.clear();
}
public int size() {
return mContainer.size();
}
public Vector<ICubicleEntity> data() {
return mContainer;
}
}
+61
View File
@@ -0,0 +1,61 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.cubicle;
import mathematik.Vector3f;
import mathematik.Vector3i;
public class CubicleEntity
implements ICubicleEntity {
private Vector3i _myCubiclePosition;
private final Vector3f _myPosition;
public CubicleEntity() {
_myCubiclePosition = new Vector3i();
_myPosition = new Vector3f();
}
public Vector3i cubicle() {
return _myCubiclePosition;
}
public Vector3f position() {
return _myPosition;
}
public boolean leaving(int theX, int theY, int theZ) {
if (theX == cubicle().x
&& theY == cubicle().y
&& theZ == cubicle().z) {
return false;
}
return true;
}
public boolean isActive() {
return true;
}
}
@@ -0,0 +1,63 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.cubicle;
import mathematik.Vector3f;
import mathematik.Vector3i;
import teilchen.BasicParticle;
public class CubicleParticle
extends BasicParticle implements ICubicleEntity {
private final Vector3i _myCubiclePosition;
private final Vector3f _myPosition;
public CubicleParticle() {
_myCubiclePosition = new Vector3i();
_myPosition = new Vector3f();
}
public Vector3i cubicle() {
return _myCubiclePosition;
}
public Vector3f position() {
return _myPosition;
}
public boolean leaving(int theX, int theY, int theZ) {
if (theX == cubicle().x
&& theY == cubicle().y
&& theZ == cubicle().z) {
return false;
}
return true;
}
public boolean isActive() {
return !fixed();
}
}
+302
View File
@@ -0,0 +1,302 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.cubicle;
import mathematik.TransformMatrix4f;
import mathematik.Vector3f;
import mathematik.Vector3i;
import java.util.Iterator;
import java.util.Vector;
/*
* cubicle world handles entities and queries about a cubicles state.
*/
public class CubicleWorld {
public static final int OFF_WORLD = -1;
private CubicleAtom[][][] mWorld;
private CubicleAtom mOffWorld;
private TransformMatrix4f mTransform;
private Vector3f mScale;
private Vector<ICubicleEntity> mEntites;
public CubicleWorld(Vector3i theNumberOfAtoms) {
this(theNumberOfAtoms.x, theNumberOfAtoms.y, theNumberOfAtoms.z);
}
public CubicleWorld(int theNumberOfXAtoms,
int theNumberOfYAtoms,
int theNumberOfZAtoms) {
initializeAtoms(theNumberOfXAtoms, theNumberOfYAtoms, theNumberOfZAtoms);
mTransform = new TransformMatrix4f(TransformMatrix4f.IDENTITY);
mScale = new Vector3f(1, 1, 1);
mEntites = new Vector<ICubicleEntity>();
}
private void initializeAtoms(int theNumberOfXAtoms,
int theNumberOfYAtoms,
int theNumberOfZAtoms) {
mWorld = new CubicleAtom[theNumberOfXAtoms][theNumberOfYAtoms][theNumberOfZAtoms];
for (int x = 0; x < mWorld.length; x++) {
for (int y = 0; y < mWorld[x].length; y++) {
for (int z = 0; z < mWorld[x][y].length; z++) {
mWorld[x][y][z] = new CubicleAtom(x, y, z);
}
}
}
mOffWorld = new CubicleAtom(OFF_WORLD, OFF_WORLD, OFF_WORLD);
}
public void update() {
Iterator<ICubicleEntity> myIterator = mEntites.iterator();
while (myIterator.hasNext()) {
handleEntity(myIterator.next());
}
}
public void add(ICubicleEntity theEntity) {
mEntites.add(theEntity);
theEntity.cubicle().set(OFF_WORLD, OFF_WORLD, OFF_WORLD);
mOffWorld.add(theEntity);
}
public boolean remove(ICubicleEntity theEntity) {
return removeFromCubicle(theEntity) && mEntites.remove(theEntity);
}
public void handleEntity(ICubicleEntity theEntity) {
if (theEntity.isActive()) {
/* transform entity position into cubicle world space */
final Vector3i myIndex = worldposition2index(theEntity.position());
/* handle entites position in cubicle grid */
if (checkBounds(myIndex.x, myIndex.y, myIndex.z)) {
if (theEntity.leaving(myIndex.x, myIndex.y, myIndex.z)) {
/* remove from previous cubicles */
if (!removeFromCubicle(theEntity)) {
System.err.println("### ERROR @ CubicleWorld / removing entity / inworld");
}
/* add to current cubicle */
mWorld[myIndex.x][myIndex.y][myIndex.z].add(theEntity);
/* store cubicle */
theEntity.cubicle().set(myIndex.x, myIndex.y, myIndex.z);
}
} else {
if (theEntity.leaving(OFF_WORLD, OFF_WORLD, OFF_WORLD)) {
/* remove from cubicles */
if (!removeFromCubicle(theEntity)) {
System.err.println("### ERROR @ CubicleWorld / removing entity / offworld");
}
/* add to off world */
mOffWorld.add(theEntity);
/* store cubicle */
theEntity.cubicle().set(OFF_WORLD, OFF_WORLD, OFF_WORLD);
}
}
}
}
public Vector<ICubicleEntity> getLocalEntities(Vector3f thePosition) {
final Vector3i myIndex = worldposition2index(thePosition);
if (checkBounds(myIndex.x, myIndex.y, myIndex.z)) {
final CubicleAtom myCubicleAtom = getAtom(myIndex.x, myIndex.y, myIndex.z);
return myCubicleAtom.data();
}
return null;
}
public Vector<ICubicleEntity> getLocalEntities(ICubicleEntity theEntity) {
final Vector3i myIndex = theEntity.cubicle();
return getAtom(myIndex.x, myIndex.y, myIndex.z).data();
}
public Vector<ICubicleEntity> getLocalEntities(Vector3f thePosition, int pExtraRadius) {
return getLocalEntities(thePosition, pExtraRadius, pExtraRadius, pExtraRadius);
}
public Vector<ICubicleEntity> getLocalEntities(Vector3f thePosition,
int theXRadius,
int theYRadius,
int theZRadius) {
final Vector3i myIndex = worldposition2index(thePosition);
if (checkBounds(myIndex.x, myIndex.y, myIndex.z)) {
final Vector<CubicleAtom> mAtoms = getAtoms(myIndex.x,
myIndex.y,
myIndex.z,
theXRadius,
theYRadius,
theZRadius);
final Vector<ICubicleEntity> mEntities = new Vector<ICubicleEntity>();
for (CubicleAtom a : mAtoms) {
mEntities.addAll(a.data());
}
return mEntities.isEmpty() ? null : mEntities;
} else {
return null;
}
}
public Vector<ICubicleEntity> getLocalEntities(ICubicleEntity theEntity,
int theXRadius,
int theYRadius,
int theZRadius) {
final Vector3i myIndex = theEntity.cubicle();
final Vector<CubicleAtom> mAtoms = getAtoms(myIndex.x,
myIndex.y,
myIndex.z,
theXRadius,
theYRadius,
theZRadius);
final Vector<ICubicleEntity> mEntities = new Vector<ICubicleEntity>();
for (CubicleAtom a : mAtoms) {
mEntities.addAll(a.data());
}
return mEntities.isEmpty() ? null : mEntities;
}
public Vector<ICubicleEntity> entities() {
return mEntites;
}
public Vector3i worldposition2index(Vector3f thePosition) {
/* get position */
final Vector3f myPosition = new Vector3f(thePosition);
/* translation */
myPosition.sub(mTransform.translation);
/* rotation */
mTransform.rotation.transform(myPosition);
/* scale */
myPosition.divide(mScale);
/* round off */
final Vector3i myIndex = new Vector3i((int) Math.floor(myPosition.x),
(int) Math.floor(myPosition.y),
(int) Math.floor(myPosition.z));
return myIndex;
}
private boolean removeFromCubicle(ICubicleEntity theEntity) {
if (theEntity.cubicle().x == OFF_WORLD
&& theEntity.cubicle().y == OFF_WORLD
&& theEntity.cubicle().z == OFF_WORLD) {
/* was stored in the offworld cubicle */
return mOffWorld.remove(theEntity);
} else {
if (checkBounds(theEntity.cubicle().x, theEntity.cubicle().y, theEntity.cubicle().z)) {
/* was stored in a cubicle */
return mWorld[theEntity.cubicle().x][theEntity.cubicle().y][theEntity.cubicle().z].remove(theEntity);
} else {
/* values were invalid */
System.out.println("### WARNING @ CubicleWorld / couldn t remove entity");
return false;
}
}
}
private boolean checkBounds(int theX,
int theY,
int theZ) {
if (theX < mWorld.length && theX >= 0) {
if (theY < mWorld[theX].length && theY >= 0) {
if (theZ < mWorld[theX][theY].length && theZ >= 0) {
return true;
}
}
}
return false;
}
public CubicleAtom getAtom(int theX,
int theY,
int theZ) {
if (checkBounds(theX, theY, theZ)) {
return mWorld[theX][theY][theZ];
} else {
return mOffWorld;
}
}
public Vector<CubicleAtom> getAtoms(int theX,
int theY,
int theZ,
int theXRadius,
int theYRadius,
int theZRadius) {
Vector<CubicleAtom> myAtoms = new Vector<CubicleAtom>();
for (int z = -theZRadius; z < theZRadius + 1; ++z) {
for (int y = -theYRadius; y < theYRadius + 1; ++y) {
for (int x = -theXRadius; x < theXRadius + 1; ++x) {
int myX = theX + x;
int myY = theY + y;
int myZ = theZ + z;
if (checkBounds(myX, myY, myZ) && mWorld[myX][myY][myZ].size() > 0) {
myAtoms.add(mWorld[myX][myY][myZ]);
}
}
}
}
return myAtoms;
}
public Vector3f cellscale() {
return mScale;
}
public TransformMatrix4f transform() {
return mTransform;
}
public CubicleAtom[][][] getDataRef() {
return mWorld;
}
public Vector<ICubicleEntity> getEntities() {
return mEntites;
}
public CubicleAtom getOffWorldAtom() {
return mOffWorld;
}
public void removeAll() {
final Iterator<ICubicleEntity> iter = mEntites.iterator();
while (iter.hasNext()) {
final ICubicleEntity c = iter.next();
removeFromCubicle(c);
iter.remove();
}
}
}
@@ -0,0 +1,60 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.cubicle;
import mathematik.Vector3f;
import mathematik.Vector3i;
public interface ICubicleEntity {
/**
* get reference to the cubicle id
*
* @return Vector3i
*/
Vector3i cubicle();
/**
* get reference to position vector
*
* @return Vector3f
*/
Vector3f position();
/**
* returns true if the new position don t match the previously stored
* position
*
* @return boolean
*/
boolean leaving(int theX, int theY, int theZ);
/**
* entities can be temporarily removed from the process of being updated by
* the world.
*
* @return
*/
boolean isActive();
}
@@ -0,0 +1,98 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import processing.core.PApplet;
import teilchen.Particle;
import teilchen.Physics;
/**
* this sketch show how to create a particle system with a single particle in
* it.
*/
public class Lesson00_Particle
extends PApplet {
private Physics mPhysics;
private Particle mParticle;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system. */
mPhysics = new Physics();
/*
* a physic-based particle system consists of a few components.
*
* 1 particles.
* there are different kinds of particles. for now we use a simple particle.
*
* 2 forces.
* there are all kinds of forces. one of the most obvious force is the gravitational force,
* but there all kinds of different forces like attractors and springs. forces usually
* affect all particles in the system.
*
* 3 behaviors
* a behavior is special kind of force. it is something like an internal force or a motor
* that only affects a single particle. a typical force is for example the 'seek force'
* which constantly pulls a particle into a certain direction.
*
* 4 integrators.
* integrators are used to integrate acceleration and velocity to calculate the new position.
* the most well-known is the 'euler' integrator, but there are also optimized versions like 'runge-kutta'
* or 'Midpoint' or even slightly different concepts like 'verlet'.
*
*/
/* create a particle. note that the particle is automatically added to particle system */
mParticle = mPhysics.makeParticle();
}
public void draw() {
/* update the particle system to the next step. usually the time step is the duration of the las frame */
final float mDeltaTime = 1.0f / frameRate;
mPhysics.step(mDeltaTime);
/* draw particle */
background(255);
stroke(0, 127);
fill(0, 32);
ellipse(mParticle.position().x, mParticle.position().y, 12, 12);
/* reset particle s position and velocity */
if (mousePressed) {
mParticle.position().set(mouseX, mouseY);
mParticle.velocity().set(mouseX - pmouseX, mouseY - pmouseY);
mParticle.velocity().scale(10);
}
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson00_Particle.class.getName()});
}
}
+83
View File
@@ -0,0 +1,83 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.Gravity;
import processing.core.PApplet;
/**
* this sketch show how to create a particle system with a single particle in
* it.
*/
public class Lesson01_Gravity
extends PApplet {
private Physics mPhysics;
private Particle mParticle;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a gravitational force */
Gravity mGravity = new Gravity();
/* the direction of the gravity is defined by the 'force' vector */
mGravity.force().set(0, 30, 0);
/* forces, like gravity or any other force, can be added to the system. they will be automatically applied to all particles */
mPhysics.add(mGravity);
/* create a particle and add it to the system */
mParticle = mPhysics.makeParticle();
}
public void draw() {
/* update the particle system. this applies the gravity to the particle */
final float mDeltaTime = 1.0f / frameRate;
mPhysics.step(mDeltaTime);
/* draw particle */
background(255);
stroke(0, 127);
fill(0, 32);
ellipse(mParticle.position().x, mParticle.position().y, 12, 12);
/* reset particle s position and velocity */
if (mousePressed) {
mParticle.position().set(mouseX, mouseY);
mParticle.velocity().set(mouseX - pmouseX, mouseY - pmouseY);
mParticle.velocity().scale(10);
}
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson01_Gravity.class.getName()});
}
}
@@ -0,0 +1,87 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.Gravity;
import processing.core.PApplet;
/**
* this sketch shows how to create and handle multiple particles and remove
* individual particles.
*/
public class Lesson02_Particles
extends PApplet {
private Physics mPhysics;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a gravitational force and add it to the particle system */
Gravity myGravity = new Gravity(0, 30, 0);
mPhysics.add(myGravity);
}
public void draw() {
if (mousePressed) {
/* create and add a particle to the system */
Particle mParticle = mPhysics.makeParticle();
/* set particle to mouse position with random velocity */
mParticle.position().set(mouseX, mouseY);
mParticle.velocity().set(random(-20, 20), random(-50));
}
/* update the particle system */
final float mDeltaTime = 1.0f / frameRate;
mPhysics.step(mDeltaTime);
/* remove particles right before they hit the edge of the screen */
for (int i = 0; i < mPhysics.particles().size(); i++) {
Particle mParticle = mPhysics.particles(i);
if (mParticle.position().y > height * 0.9f) {
mPhysics.particles().remove(i);
}
}
/* draw all the particles in the system */
background(255);
stroke(0, 127);
fill(0, 32);
for (int i = 0; i < mPhysics.particles().size(); i++) {
Particle mParticle = mPhysics.particles(i);
ellipse(mParticle.position().x, mParticle.position().y, 10, 10);
}
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson02_Particles.class.getName()});
}
}
@@ -0,0 +1,116 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import processing.core.PApplet;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.Teleporter;
import teilchen.force.Attractor;
import teilchen.force.ViscousDrag;
/**
* this sketch shows how to create and use attractors.
*/
public class Lesson03_Attractors
extends PApplet {
private Physics mPhysics;
private Attractor mAttractor;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a viscous force that slows down all motion */
ViscousDrag myDrag = new ViscousDrag();
myDrag.coefficient = 0.75f;
mPhysics.add(myDrag);
/* teleport particles from one edge of the screen to the other */
Teleporter mTeleporter = new Teleporter();
mTeleporter.min().set(0, 0);
mTeleporter.max().set(width, height);
mPhysics.add(mTeleporter);
/* create some particles */
for (int i = 0; i < 100; i++) {
Particle myParticle = mPhysics.makeParticle();
myParticle.position().set(random(width), random(height));
}
mPhysics.particles().firstElement().fixed(true);
/* create an attractor */
mAttractor = new Attractor();
mAttractor.radius(100);
mAttractor.strength(150);
mPhysics.add(mAttractor);
}
public void mousePressed() {
/* flip the direction of the attractors strength. */
float myInvertedStrength = -1 * mAttractor.strength();
/* a negative strength turns the attractor into a repulsor */
mAttractor.strength(myInvertedStrength);
}
public void draw() {
/* set attractor to mouse position */
mAttractor.position().set(mouseX, mouseY);
/* update the particle system */
final float mDeltaTime = 1.0f / frameRate;
mPhysics.step(mDeltaTime);
/* draw */
background(255);
/* draw all the particles in particle system */
fill(245);
stroke(164);
for (int i = 0; i < mPhysics.particles().size(); i++) {
Particle myParticle = mPhysics.particles(i);
ellipse(myParticle.position().x, myParticle.position().y, 12, 12);
}
/* draw attractor. green if it is attracting and red if it is repelling */
noStroke();
if (mAttractor.strength() < 0) {
fill(255, 0, 0, 50);
} else {
fill(0, 255, 0, 50);
}
ellipse(mAttractor.position().x, mAttractor.position().y,
mAttractor.radius(), mAttractor.radius());
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson03_Attractors.class.getName()});
}
}
@@ -0,0 +1,129 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import processing.core.PApplet;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.ShortLivedParticle;
import teilchen.force.Gravity;
import teilchen.force.PlaneDeflector;
import teilchen.force.ViscousDrag;
/**
* this sketch shows 1 how to create and use plane deflectors 2 how to use
* 'ShortLivedParticle'
*/
public class Lesson04_Deflectors
extends PApplet {
private Physics mPhysics;
private PlaneDeflector mDeflector;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a deflector and add it to the particle system.
* the that defines the deflection area is defined by an
* origin and a normal. this also means that the plane s size
* is infinite.
* note that there is also a triangle delfector that is constraint
* by three points.
*/
mDeflector = new PlaneDeflector();
/* set plane origin into the center of the screen */
mDeflector.plane().origin.set(width / 2, height / 2, 0);
mDeflector.plane().normal.set(0, -1, 0);
/* the coefficient of restitution defines how hard particles bounce of the deflector */
mDeflector.coefficientofrestitution(0.7f);
mPhysics.add(mDeflector);
/* create gravitiy */
Gravity myGravity = new Gravity();
myGravity.force().y = 50;
mPhysics.add(myGravity);
/* create drag */
ViscousDrag myViscousDrag = new ViscousDrag();
myViscousDrag.coefficient = 0.1f;
mPhysics.add(myViscousDrag);
}
public void draw() {
/* rotate deflector plane */
if (mousePressed) {
final float myAngle = 2 * PI * (float) mouseX / width - PI;
mDeflector.plane().normal.set(sin(myAngle), -cos(myAngle), 0);
}
/* create a special particle */
ShortLivedParticle myNewParticle = new ShortLivedParticle();
myNewParticle.position().set(mouseX, mouseY);
myNewParticle.velocity().set(0, random(100) + 50);
/* this particle is removed after a specific interval */
myNewParticle.setMaxAge(4);
/* add particle manually to the particle system */
mPhysics.add(myNewParticle);
/* update physics */
final float mDeltaTime = 1.0f / frameRate;
mPhysics.step(mDeltaTime);
/* draw all the particles in the particle system */
background(255);
for (int i = 0; i < mPhysics.particles().size(); i++) {
Particle myParticle = mPhysics.particles(i);
/* this special particle can tell you how much time it has to live.
* we map this information to its transparency.
*/
float myRatio = 1 - ((ShortLivedParticle) myParticle).ageRatio();
stroke(0, 64 * myRatio);
fill(0, 32 * myRatio);
ellipse(myParticle.position().x, myParticle.position().y, 12, 12);
}
/* draw deflector */
stroke(0, 127);
line(mDeflector.plane().origin.x - mDeflector.plane().normal.y * -width,
mDeflector.plane().origin.y + mDeflector.plane().normal.x * -width,
mDeflector.plane().origin.x - mDeflector.plane().normal.y * width,
mDeflector.plane().origin.y + mDeflector.plane().normal.x * width);
stroke(255, 0, 0, 127);
line(mDeflector.plane().origin.x,
mDeflector.plane().origin.y,
mDeflector.plane().origin.x + mDeflector.plane().normal.x * 20,
mDeflector.plane().origin.y + mDeflector.plane().normal.y * 20);
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson04_Deflectors.class.getName()});
}
}
+95
View File
@@ -0,0 +1,95 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import processing.core.PApplet;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
/**
* this sketch shows 1 how to create a viscous drag to slow motion eventually
* down. 2 how to create a spring that connects two particles.
*/
public class Lesson05_Spring
extends PApplet {
private Physics mPhysics;
private Spring mSpring;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a viscous force that slows down all motion; 0 means no slowing down. */
ViscousDrag myDrag = new ViscousDrag(0.25f);
mPhysics.add(myDrag);
/* create two particles that we can connect with a spring */
Particle myA = mPhysics.makeParticle();
myA.position().set(width / 2 - 50, height / 2);
Particle myB = mPhysics.makeParticle();
myB.position().set(width / 2 + 50, height / 2);
/* create a spring force that connects two particles.
* note that there is more than one way to create a spring.
* in our case the restlength of the spring is defined by the
* particles current position.
*/
mSpring = mPhysics.makeSpring(myA, myB);
}
public void draw() {
/* set first particle to mouse position */
if (mousePressed) {
mSpring.a().position().set(mouseX, mouseY);
}
/* update the particle system */
final float mDeltaTime = 1.0f / frameRate;
mPhysics.step(mDeltaTime);
/* draw particles and connecting line */
background(255);
noFill();
stroke(255, 0, 127, 64);
line(mSpring.a().position().x, mSpring.a().position().y,
mSpring.b().position().x, mSpring.b().position().y);
fill(245);
stroke(164);
ellipse(mSpring.a().position().x, mSpring.a().position().y, 12, 12);
ellipse(mSpring.b().position().x, mSpring.b().position().y, 12, 12);
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson05_Spring.class.getName()});
}
}
+97
View File
@@ -0,0 +1,97 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.Spring;
import processing.core.PApplet;
/**
* this sketch shows 1 how to create a viscous drag to slow motion eventually
* down. 2 how to create a spring that connects two particles.
*/
public class Lesson06_Springs
extends PApplet {
private Physics mPhysics;
private Particle mRoot;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
/* create a particle system */
mPhysics = new Physics();
/* create a particle to which we will connect springs */
mRoot = mPhysics.makeParticle(width / 2, height / 2, 0.0f);
/* we give the root particle a higher mass so it doesn t move as easily */
mRoot.mass(30);
}
public void draw() {
/* create a particle at mouse position and connect it to the root particle through a spring */
if (mousePressed) {
Particle mParticle = mPhysics.makeParticle(mouseX, mouseY, 0);
Spring mSpring = mPhysics.makeSpring(mRoot, mParticle);
/* restlength defines the desired length of the spring. in this case it is the distance between the two particles. */
float mRestlength = mSpring.restlength();
/* we modify the restlength to add a bit of energy into the system */
mSpring.restlength(mRestlength * 1.5f);
}
/* update the particle system */
final float mDeltaTime = 1.0f / frameRate;
mPhysics.step(mDeltaTime);
/* draw particles and connecting line */
background(255);
/* draw springs */
noFill();
stroke(255, 0, 127, 64);
for (int i = 0; i < mPhysics.forces().size(); i++) {
if (mPhysics.forces().get(i) instanceof Spring) {
Spring mSSpring = (Spring) mPhysics.forces().get(i);
line(mSSpring.a().position().x, mSSpring.a().position().y,
mSSpring.b().position().x, mSSpring.b().position().y);
}
}
/* draw particles */
fill(245);
stroke(164);
for (int i = 0; i < mPhysics.particles().size(); i++) {
ellipse(mPhysics.particles().get(i).position().x,
mPhysics.particles().get(i).position().y,
12, 12);
}
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson06_Springs.class.getName()});
}
}
@@ -0,0 +1,111 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import teilchen.Physics;
import teilchen.force.Gravity;
import teilchen.force.ViscousDrag;
import teilchen.util.DrawLib;
import processing.core.PApplet;
import teilchen.Particle;
import teilchen.constraint.Box;
import teilchen.integration.RungeKutta;
import teilchen.util.StableSpringQuad;
public class Lesson07_StableQuads
extends PApplet {
private Physics mPhysics;
private Particle mRoot;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(60);
mPhysics = new Physics();
/* we use 'runge kutta' as it is more stable for this application */
mPhysics.setInegratorRef(new RungeKutta());
Gravity myGravity = new Gravity();
myGravity.force().y = 98.1f;
mPhysics.add(myGravity);
/* add drag to smooth the spring interaction */
mPhysics.add(new ViscousDrag(0.2f));
/* add a container */
Box myBox = new Box();
myBox.min().set(0, 0, 0);
myBox.max().set(width, height, 0);
mPhysics.add(myBox);
/* create root */
Particle a = mPhysics.makeParticle(0, 0);
Particle b = mPhysics.makeParticle(100, 0);
Particle c = mPhysics.makeParticle(100, 100);
Particle d = mPhysics.makeParticle(0, 100);
new StableSpringQuad(mPhysics, d, c, mPhysics.makeParticle(100, 200), mPhysics.makeParticle(0, 200));
/* create stable quad from springs */
/* first the edge-springs ... */
final float mySpringConstant = 100;
final float mySpringDamping = 5;
mPhysics.makeSpring(a, b, mySpringConstant, mySpringDamping);
mPhysics.makeSpring(b, c, mySpringConstant, mySpringDamping);
mPhysics.makeSpring(c, d, mySpringConstant, mySpringDamping);
mPhysics.makeSpring(d, a, mySpringConstant, mySpringDamping).restlength();
/* ... then the diagonal-springs */
mPhysics.makeSpring(a, c, mySpringConstant, mySpringDamping);
mPhysics.makeSpring(b, d, mySpringConstant, mySpringDamping).restlength();
/* define 'a' as root particle for mouse interaction */
mRoot = a;
mRoot.fixed(true);
}
public void draw() {
/* handle particles */
if (mousePressed) {
mRoot.fixed(true);
mRoot.position().set(mouseX, mouseY);
} else {
mRoot.fixed(false);
}
mPhysics.step(1f / frameRate);
/* draw */
background(255);
DrawLib.drawSprings(g, mPhysics, color(255, 0, 127, 64));
DrawLib.drawParticles(g, mPhysics, 12, color(164), color(245));
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson07_StableQuads.class.getName()});
}
}
+100
View File
@@ -0,0 +1,100 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.Stick;
import teilchen.force.Gravity;
import teilchen.integration.Verlet;
import processing.core.PApplet;
public class Lesson08_Sticks
extends PApplet {
private Physics mPhysics;
private Particle[] mParticles;
public void setup() {
size(640, 480, OPENGL);
frameRate(60);
smooth();
mPhysics = new Physics();
/* increase the number of iterations for contraints in each step. this can greatly relaxes tensions in the system. */
mPhysics.contraint_iterations_per_steps = 5;
/* add gravity for extra fun */
mPhysics.add(new Gravity());
/* we chose verlet integration as it integrates much more nicely with sticks ( and constraints in general ) */
Verlet myVerlet = new Verlet();
myVerlet.damping(0.99f);
mPhysics.setInegratorRef(myVerlet);
/* setup sticks to form a whip */
mParticles = new Particle[16];
float mSegmentLength = 20.0f;
/* create root */
for (int x = 0; x < mParticles.length; x++) {
mParticles[x] = mPhysics.makeParticle(x * mSegmentLength, 0, 0, 0.1f);
if (x > 0) {
Stick myStick = new Stick(mParticles[x - 1],
mParticles[x],
mSegmentLength);
/* damp the stick to release tensions from the system */
myStick.damping(0.99f);
mPhysics.add(myStick);
}
}
/* fix root particle so it can stick to the mouse later */
mParticles[0].fixed(true);
}
public void draw() {
/* stick root particle to mouse */
mParticles[0].position().set(mouseX, mouseY);
/* update */
mPhysics.step(1.0f / frameRate);
/* draw sticks with descending stroke weight */
background(255);
stroke(0, 192);
for (int x = 1; x < mParticles.length; x++) {
Particle p1 = mParticles[x - 1];
Particle p2 = mParticles[x];
final float mStrokeWeight = 4.0f * (1.0f - (float) x / mParticles.length);
strokeWeight(mStrokeWeight);
line(p1.position().x, p1.position().y, p1.position().z,
p2.position().x, p2.position().y, p2.position().z);
}
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson08_Sticks.class.getName()});
}
}
+141
View File
@@ -0,0 +1,141 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import mathematik.Vector3f;
import processing.core.PApplet;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.IConstraint;
import teilchen.constraint.Stick;
import teilchen.force.Attractor;
import teilchen.force.Gravity;
import teilchen.integration.Verlet;
public class Lesson09_Cloth
extends PApplet {
private Physics mPhysics;
private Particle[][] mParticles;
private final int GRID_WIDTH = 32;
private final int GRID_HEIGHT = 16;
private Attractor mAttractor;
public void setup() {
size(640, 480, OPENGL);
frameRate(60);
mPhysics = new Physics();
mPhysics.contraint_iterations_per_steps = 5;
Verlet myVerlet = new Verlet();
myVerlet.damping(0.9f);
mPhysics.setInegratorRef(myVerlet);
mPhysics.add(new Gravity(new Vector3f(0, 1000f, 0)));
mAttractor = new Attractor();
mAttractor.strength(-15000);
mAttractor.radius(300);
mPhysics.add(mAttractor);
mParticles = new Particle[GRID_WIDTH][GRID_HEIGHT];
/* setup cloth */
float mGridStepX = ((float) width / GRID_WIDTH);
float mGridStepY = (((float) height * 0.5f) / GRID_HEIGHT);
for (int y = 0; y < GRID_HEIGHT; y++) {
for (int x = 0; x < GRID_WIDTH; x++) {
mParticles[x][y] = mPhysics.makeParticle();
mParticles[x][y].position().set((x + 0.5f) * mGridStepX,
y * mGridStepY,
random(0, 1));
mParticles[x][y].old_position().set(mParticles[x][y].position());
mParticles[x][y].mass(0.1f);
final float DAMPING = 0.9f;
if (y > 0) {
Stick myStick = new Stick(mParticles[x][y - 1],
mParticles[x][y],
mGridStepY);
myStick.damping(DAMPING);
mPhysics.add(myStick);
}
if (x > 0) {
Stick myStick = new Stick(mParticles[x - 1][y],
mParticles[x][y],
mGridStepX);
myStick.damping(DAMPING);
mPhysics.add(myStick);
}
if (x > 0 && y > 0) {
Stick myStick1 = new Stick(mParticles[x - 1][y - 1],
mParticles[x][y],
new Vector3f(mGridStepX, mGridStepY).length());
mPhysics.add(myStick1);
Stick myStick2 = new Stick(mParticles[x][y - 1],
mParticles[x - 1][y],
new Vector3f(mGridStepX, mGridStepY).length());
mPhysics.add(myStick2);
}
}
}
/* fix first row */
for (int x = 0; x < mParticles.length; x++) {
mParticles[x][0].fixed(true);
}
}
public void draw() {
/* update */
mAttractor.position().set(mouseX, mouseY, 50);
mPhysics.step(1.0f / frameRate);
background(255);
/* draw sticks */
stroke(0, 127);
for (final IConstraint myIConstraint : mPhysics.constraints()) {
if (myIConstraint instanceof Stick) {
final Stick myStick = (Stick) myIConstraint;
line(myStick.a().position().x,
myStick.a().position().y,
myStick.a().position().z,
myStick.b().position().x,
myStick.b().position().y,
myStick.b().position().z);
}
}
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson09_Cloth.class.getName()});
}
}
@@ -0,0 +1,96 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import processing.core.PApplet;
import teilchen.BehaviorParticle;
import teilchen.Physics;
import teilchen.behavior.Motor;
import teilchen.behavior.Wander;
import teilchen.force.ViscousDrag;
import static processing.core.PConstants.OPENGL;
import static processing.core.PConstants.RGB;
/**
* this sketch shows how to assign an 'wander' behavior to a particle.
*/
public class Lesson10_WanderBehavior
extends PApplet {
private Physics mPhysics;
private BehaviorParticle mParticle;
private Wander mWander;
private Motor mMotor;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(120);
/* physics */
mPhysics = new Physics();
mPhysics.add(new ViscousDrag());
/* create particles */
mParticle = mPhysics.makeParticle(BehaviorParticle.class);
mParticle.position().set(width / 2, height / 2);
mParticle.maximumInnerForce(100);
mParticle.radius(10);
/* create behavior */
mWander = new Wander();
mParticle.behaviors().add(mWander);
/* a motor is required to push the particle forward - wander manipulats the direction the particle is pushed in */
mMotor = new Motor();
mMotor.auto_update_direction(true); /* the direction the motor pushes into is each step automatically set to the velocity */
mMotor.strength(25);
mParticle.behaviors().add(mMotor);
}
public void draw() {
/* update particle system */
mPhysics.step(1.0f / frameRate);
/* draw behavior particle */
background(255);
fill(1);
stroke(0, 127);
line(mParticle.position().x,
mParticle.position().y,
mParticle.position().x + mParticle.velocity().x,
mParticle.position().y + mParticle.velocity().y);
ellipse(mParticle.position().x, mParticle.position().y,
mParticle.radius() * 2, mParticle.radius() * 2);
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson10_WanderBehavior.class.getName()});
}
}
@@ -0,0 +1,103 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import processing.core.PApplet;
import teilchen.BehaviorParticle;
import teilchen.Physics;
import teilchen.behavior.Arrival;
/**
* this sketch shows how to assign an 'arrival' behavior to a particle.
*/
public class Lesson11_ArrivalBehavior
extends PApplet {
private Physics mPhysics;
private BehaviorParticle mParticle;
private Arrival mArrival;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(120);
colorMode(RGB, 1.0f);
noFill();
/* physics */
mPhysics = new Physics();
/* create particles */
mParticle = mPhysics.makeParticle(BehaviorParticle.class);
mParticle.maximumInnerForce(100);
/* create behavior */
mArrival = new Arrival();
mArrival.breakforce(mParticle.maximumInnerForce() * 0.25f);
mArrival.breakradius(mParticle.maximumInnerForce() * 0.25f);
mParticle.behaviors().add(mArrival);
}
public void draw() {
/* set the arrival position to the mouse position */
mArrival.position().set(mouseX, mouseY);
/* update particle system */
mPhysics.step(1.0f / frameRate);
/* draw behavior particle */
background(1);
stroke(0, 0.5f);
if (mArrival.arriving()) {
/* color particle red while it is arriving */
stroke(1, 0, 0, 0.5f);
}
if (mArrival.arrived()) {
/* color particle green when it has arrived */
stroke(0, 1, 0, 0.5f);
}
line(mParticle.position().x,
mParticle.position().y,
mParticle.position().x + mParticle.velocity().x,
mParticle.position().y + mParticle.velocity().y);
fill(1);
ellipse(mParticle.position().x, mParticle.position().y, 12, 12);
/* draw arrival */
stroke(0, 0.25f);
noFill();
ellipse(mArrival.position().x,
mArrival.position().y,
mArrival.breakradius() * 2,
mArrival.breakradius() * 2);
}
public static void main(String[] args) {
PApplet.main(new String[]{Lesson11_ArrivalBehavior.class.getName()});
}
}
+118
View File
@@ -0,0 +1,118 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import mathematik.Vector3f;
import processing.core.PApplet;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.Gravity;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
import teilchen.util.Overlap;
import teilchen.util.Packing;
/**
* this sketch is exactly like Lesson06_Springs, except that it also shows how
* to resolveOverlap overlaps.
*/
public class LessonX01_Overlap
extends PApplet {
private Physics mPhysics;
private Particle mRoot;
private static final float PARTICLE_RADIUS = 13;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
mPhysics = new Physics();
/* create drag */
mPhysics.add(new ViscousDrag());
mPhysics.add(new Gravity(new Vector3f(0, 100f, 0)));
mRoot = mPhysics.makeParticle(width / 2, height / 2, 0.0f);
mRoot.mass(30);
mRoot.fixed(true);
mRoot.radius(PARTICLE_RADIUS);
}
public void draw() {
if (mousePressed) {
Particle mParticle = mPhysics.makeParticle(mouseX, mouseY, 0);
mPhysics.makeSpring(mRoot, mParticle);
/*
* we define a radius for the particle so the particle has
* dimensions
*/
mParticle.radius(random(PARTICLE_RADIUS / 2) + PARTICLE_RADIUS);
}
/* move overlapping particles away from each other */
for (int i = 0; i < 10; i++) {
mRoot.position().set(width / 2, height / 2, 0.0f); // a bit of a 'hack'
Overlap.resolveOverlap(mPhysics.particles());
}
/* update the particle system */
final float mDeltaTime = 1.0f / frameRate;
mPhysics.step(mDeltaTime);
/* draw particles and connecting line */
background(255);
/* draw springs */
noFill();
stroke(255, 0, 127, 64);
for (int i = 0; i < mPhysics.forces().size(); i++) {
if (mPhysics.forces().get(i) instanceof Spring) {
Spring mSSpring = (Spring) mPhysics.forces().get(i);
line(mSSpring.a().position().x, mSSpring.a().position().y,
mSSpring.b().position().x, mSSpring.b().position().y);
}
}
/* draw particles */
fill(255, 127);
stroke(164);
for (int i = 0; i < mPhysics.particles().size(); i++) {
ellipse(mPhysics.particles().get(i).position().x,
mPhysics.particles().get(i).position().y,
mPhysics.particles().get(i).radius() * 2,
mPhysics.particles().get(i).radius() * 2);
}
}
public static void main(String[] args) {
PApplet.main(new String[]{LessonX01_Overlap.class.getName()});
}
}
@@ -0,0 +1,121 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import mathematik.Vector3f;
import processing.core.PApplet;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.Box;
import teilchen.force.Gravity;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
import teilchen.util.CollisionManager;
public class LessonX02_Collisions
extends PApplet {
private static final float PARTICLE_SIZE = 12;
private CollisionManager mCollision;
private Physics mPhysics;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(30);
noFill();
ellipseMode(CENTER);
mCollision = new CollisionManager();
mCollision.distancemode(CollisionManager.DISTANCE_MODE_FIXED);
mCollision.minimumDistance(50);
mPhysics = new Physics();
mPhysics.add(new ViscousDrag(0.85f));
mPhysics.add(new Gravity());
Box myBox = new Box();
myBox.min().set(50, 50, 0);
myBox.max().set(width - 50, height - 50, 0);
myBox.coefficientofrestitution(0.7f);
myBox.reflect(true);
mPhysics.add(myBox);
/* create a first particle */
final Particle myParticle = mPhysics.makeParticle(new Vector3f(mouseX, mouseY, 0), 10);
mCollision.collision().add(myParticle);
}
public void draw() {
/* create particles */
if (mousePressed) {
final Particle myParticle = mPhysics.makeParticle(new Vector3f(mouseX, mouseY, 0), 10);
mCollision.collision().add(myParticle);
}
/* collision handler */
final float mDeltaTime = 1.0f / frameRate;
mCollision.createCollisionResolvers();
mCollision.loop(mDeltaTime);
mPhysics.step(mDeltaTime);
/* draw */
background(255);
drawThings();
mCollision.removeCollisionResolver();
}
private void drawThings() {
/* collision springs */
noFill();
stroke(255, 0, 127, 64);
for (int i = 0; i < mCollision.collision().forces().size(); ++i) {
if (mCollision.collision().forces().get(i) instanceof Spring) {
Spring mySpring = (Spring) mCollision.collision_forces().get(i);
line(mySpring.a().position().x, mySpring.a().position().y, mySpring.a().position().z,
mySpring.b().position().x, mySpring.b().position().y, mySpring.b().position().z);
}
}
/* particles */
fill(245);
stroke(164);
for (int i = 0; i < mPhysics.particles().size(); ++i) {
Particle myParticle = mPhysics.particles().get(i);
pushMatrix();
translate(myParticle.position().x, myParticle.position().y, myParticle.position().z);
ellipse(0, 0,
PARTICLE_SIZE,
PARTICLE_SIZE);
popMatrix();
}
}
public static void main(String[] args) {
PApplet.main(new String[]{LessonX02_Collisions.class.getName()});
}
}
@@ -0,0 +1,167 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import mathematik.Vector3f;
import processing.core.PApplet;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.ShortLivedParticle;
import teilchen.constraint.Box;
import teilchen.force.Attractor;
import teilchen.force.Gravity;
import teilchen.force.ViscousDrag;
import teilchen.util.ParticleTrail;
import java.util.Vector;
public class LessonX03_ParticlesLeavingTrails
extends PApplet {
private Physics mPhysics;
private Vector<ParticleTrail> mTrails;
private Attractor mAttractor;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(60);
/* create a particle system */
mPhysics = new Physics();
/* create a gravitational force */
Gravity myGravity = new Gravity();
mPhysics.add(myGravity);
myGravity.force().y = 20;
/* create drag */
ViscousDrag myViscousDrag = new ViscousDrag();
myViscousDrag.coefficient = 0.1f;
mPhysics.add(myViscousDrag);
final float mBorder = 40;
Box mBox = new Box(new Vector3f(mBorder, mBorder, mBorder), new Vector3f(width - mBorder, height - mBorder, 100 - mBorder));
mBox.reflect(true);
mPhysics.add(mBox);
/* create an attractor */
mAttractor = new Attractor();
mAttractor.radius(200);
mAttractor.strength(-300);
mPhysics.add(mAttractor);
/* create trails and particles */
mTrails = new Vector<ParticleTrail>();
for (int i = 0; i < 500; i++) {
Particle mParticle = mPhysics.makeParticle();
mParticle.mass(2.0f);
ParticleTrail myParticleTrail = new ParticleTrail(mPhysics,
mParticle,
0.2f,
random(0.5f, 1));
myParticleTrail.mass(0.5f);
mTrails.add(myParticleTrail);
}
resetParticles(width / 2, height / 2);
}
private void resetParticles(float x, float y) {
for (ParticleTrail myTrails : mTrails) {
myTrails.particle().position().set(x + random(-10, 10), y + random(-10, 10), 0);
myTrails.particle().velocity().set(random(-10, 10), random(-10, 10), random(-10, 10));
myTrails.fragments().clear();
}
}
public void draw() {
/* set attractor to mouse position */
mAttractor.position().set(mouseX, mouseY);
for (ParticleTrail myTrails : mTrails) {
myTrails.loop(1f / frameRate);
}
mPhysics.step(1f / frameRate);
background(255);
for (ParticleTrail myTrail : mTrails) {
drawTrail(myTrail);
}
}
private void drawTrail(ParticleTrail theTrail) {
final Vector<Particle> mFragments = theTrail.fragments();
final Particle mParticle = theTrail.particle();
/* draw head */
if (mFragments.size() > 1) {
fill(255, 0, 127);
noStroke();
pushMatrix();
translate(mParticle.position().x,
mParticle.position().y,
mParticle.position().z);
sphereDetail(4);
sphere(3);
popMatrix();
}
/* draw trail */
for (int i = 0; i < mFragments.size() - 1; i++) {
if (mFragments.get(i) instanceof ShortLivedParticle) {
final float mRatio = 1.0f - ((ShortLivedParticle) mFragments.get(i)).ageRatio();
stroke(127, mRatio * 255);
strokeWeight(mRatio * 3);
}
int j = (i + 1) % mFragments.size();
line(mFragments.get(i).position().x,
mFragments.get(i).position().y,
mFragments.get(i).position().z,
mFragments.get(j).position().x,
mFragments.get(j).position().y,
mFragments.get(j).position().z);
}
if (!mFragments.isEmpty()) {
line(mFragments.lastElement().position().x,
mFragments.lastElement().position().y,
mFragments.lastElement().position().z,
mParticle.position().x,
mParticle.position().y,
mParticle.position().z);
}
}
public void mousePressed() {
resetParticles(mouseX, mouseY);
}
public static void main(String[] args) {
PApplet.main(new String[]{LessonX03_ParticlesLeavingTrails.class.getName()});
}
}
@@ -0,0 +1,150 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import processing.core.PApplet;
import teilchen.Physics;
import teilchen.force.Attractor;
import teilchen.force.Gravity;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
import teilchen.integration.RungeKutta;
import teilchen.util.Overlap;
import teilchen.util.StickMan;
/**
* this demo shows some advanced use of particles, springs and attractors to
* create stickmen.
*/
public class LessonX04_StickMan
extends PApplet {
private Physics mPhysics;
private Attractor mAttractor;
private Gravity mGravity;
private ViscousDrag mViscousDrag;
private StickMan[] mMyStickMan;
public void setup() {
size(640, 480, OPENGL);
smooth();
frameRate(60);
noFill();
mPhysics = new Physics();
mPhysics.setInegratorRef(new RungeKutta());
mGravity = new Gravity();
mGravity.force().y = 20;
mPhysics.add(mGravity);
mViscousDrag = new ViscousDrag();
mViscousDrag.coefficient = 0.85f;
mPhysics.add(mViscousDrag);
mAttractor = new Attractor();
mAttractor.radius(500);
mAttractor.strength(0);
mAttractor.position().set(width / 2, height / 2);
mPhysics.add(mAttractor);
mMyStickMan = new StickMan[20];
for (int i = 0; i < mMyStickMan.length; i++) {
mMyStickMan[i] = new StickMan(mPhysics, random(0, width), random(0.3f, 0.6f));
}
}
public void draw() {
mPhysics.step(1f / 60f);
Overlap.resolveOverlap(mPhysics.particles());
/* constraint particles */
for (int i = 0; i < mPhysics.particles().size(); i++) {
if (mPhysics.particles(i).position().y > height - 10) {
mPhysics.particles(i).position().y = height - 10;
}
if (mPhysics.particles(i).position().x > width) {
mPhysics.particles(i).position().x = width;
}
if (mPhysics.particles(i).position().x < 0) {
mPhysics.particles(i).position().x = 0;
}
}
/* handle particles */
if (mousePressed) {
mAttractor.position().set(mouseX, mouseY);
if (mouseButton == RIGHT) {
mAttractor.strength(-500);
mAttractor.radius(500);
} else {
mAttractor.strength(500);
mAttractor.radius(100);
}
} else {
mAttractor.strength(0);
}
if (keyPressed) {
mGravity.force().y = -10;
} else {
mGravity.force().y = 20;
}
/* draw */
background(255);
/* draw springs */
stroke(0, 20);
for (int i = 0; i < mPhysics.forces().size(); i++) {
if (mPhysics.forces(i) instanceof Spring) {
Spring mySpring = (Spring) mPhysics.forces(i);
line(mySpring.a().position().x,
mySpring.a().position().y,
mySpring.b().position().x,
mySpring.b().position().y);
}
}
/* draw particles */
for (int i = 0; i < mPhysics.particles().size(); i++) {
ellipse(mPhysics.particles(i).position().x,
mPhysics.particles(i).position().y, 5, 5);
}
/* draw man */
for (int i = 0; i < mMyStickMan.length; i++) {
mMyStickMan[i].draw(g);
}
}
public static void main(String[] args) {
PApplet.main(new String[]{LessonX04_StickMan.class.getName()});
}
}
@@ -0,0 +1,210 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import processing.core.PApplet;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.AngleConstraintStick;
import teilchen.constraint.Stick;
import teilchen.force.AngleConstraintSpring;
import teilchen.force.Gravity;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
import teilchen.integration.RungeKutta;
public class LessonX05_AngleConstraints
extends PApplet {
private Physics mPhysics;
private Particle mParticleA;
private Particle mParticleB;
private Particle mParticleC;
private Particle mParticleD;
private AngleConstraintSpring mAngleConstraintABC;
private AngleConstraintStick mAngleConstraintBCD;
public void setup() {
size(640, 480);
frameRate(30);
smooth();
mPhysics = new Physics();
mPhysics.setInegratorRef(new RungeKutta());
ViscousDrag myViscousDrag = new ViscousDrag();
myViscousDrag.coefficient = 1f;
mPhysics.add(myViscousDrag);
Gravity myGravity = new Gravity();
myGravity.force().y = 50;
mPhysics.add(myGravity);
/* particles */
mParticleA = mPhysics.makeParticle();
mParticleB = mPhysics.makeParticle();
mParticleC = mPhysics.makeParticle();
mParticleD = mPhysics.makeParticle();
mParticleA.position().set(width / 2 + 50, height / 3);
mParticleB.position().set(width / 2, height - height / 1.75f);
mParticleC.position().set(width / 2, height - height / 4);
mParticleD.position().set(width / 2, height - height / 8);
mParticleA.radius(7);
mParticleB.radius(3);
mParticleC.radius(10);
mParticleD.radius(2);
mParticleB.fixed(true);
/* springs */
Spring mSpringAB = new Spring(mParticleA, mParticleB);
mSpringAB.strength(250);
mSpringAB.damping(10);
mPhysics.add(mSpringAB);
Spring mSpringBC = new Spring(mParticleB, mParticleC);
mSpringBC.strength(250);
mSpringBC.damping(10);
mPhysics.add(mSpringBC);
Stick mSpringCD = new Stick(mParticleC, mParticleD);
mSpringCD.damping(1);
mPhysics.add(mSpringCD);
/* angle constraint */
mAngleConstraintABC = new AngleConstraintSpring(mParticleA, mParticleB, mParticleC);
mAngleConstraintABC.min_angle(PI * 0.5f);
mAngleConstraintABC.damping(1);
mAngleConstraintABC.strength(200);
mPhysics.add(mAngleConstraintABC);
mAngleConstraintBCD = new AngleConstraintStick(mParticleB, mParticleC, mParticleD);
mAngleConstraintBCD.min_angle(PI * 0.8f);
mAngleConstraintBCD.damping(0.5f);
mPhysics.add(mAngleConstraintBCD);
}
public void draw() {
/* attach particle to mouse */
if (mousePressed) {
mParticleA.position().set(mouseX, mouseY);
}
/* apply constraints */
mAngleConstraintABC.pre_step();
mAngleConstraintBCD.pre_step();
draw_physics();
mPhysics.step(1f / frameRate);
/* remove contraints */
mAngleConstraintABC.post_step();
mAngleConstraintBCD.post_step();
}
private void draw_physics() {
background(255);
drawSprings();
drawSticks();
drawParticles();
}
private void drawSprings() {
for (int i = 0; i < mPhysics.forces().size(); i++) {
if (mPhysics.forces(i) instanceof Spring) {
final Spring mSpring = (Spring) mPhysics.forces(i);
if (mSpring instanceof AngleConstraintSpring) {
strokeWeight(1);
if (mSpring.active()) {
stroke(255, 0, 0, 64);
} else {
stroke(255, 0, 0, 16);
}
} else {
strokeWeight(3);
stroke(0, 128);
}
line(mSpring.a(), mSpring.b());
}
}
strokeWeight(1);
}
private void drawSticks() {
for (int i = 0; i < mPhysics.constraints().size(); i++) {
if (mPhysics.constraints(i) instanceof Stick) {
final Stick mStick = (Stick) mPhysics.constraints(i);
if (mStick instanceof AngleConstraintStick) {
strokeWeight(1);
if (mStick.active()) {
stroke(0, 127, 255, 64);
} else {
stroke(0, 127, 255, 16);
}
} else {
strokeWeight(3);
stroke(0, 128);
}
line(mStick.a(), mStick.b());
}
}
strokeWeight(1);
}
private void drawParticles() {
stroke(0);
fill(92);
drawParticle(mParticleA);
fill(127);
drawParticle(mParticleB);
fill(192);
drawParticle(mParticleC);
fill(64);
drawParticle(mParticleD);
}
private void drawParticle(Particle p) {
ellipse(p.position().x,
p.position().y,
p.radius() * 2, p.radius() * 2);
}
private void line(Particle p1, Particle p2) {
line(p1.position().x, p1.position().y,
p2.position().x, p2.position().y);
}
public static void main(String[] args) {
PApplet.main(new String[]{LessonX05_AngleConstraints.class.getName()});
}
}
@@ -0,0 +1,173 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import processing.core.PApplet;
import teilchen.BehaviorParticle;
import teilchen.Physics;
import teilchen.behavior.Arrival;
import teilchen.force.Spring;
import teilchen.force.ViscousDrag;
import teilchen.util.CollisionManager;
import java.util.Vector;
/**
* this demo shows how to add behaviors to particles. in this example the
* arrival behavior.
*/
public class LessonX06_Ducklings
extends PApplet {
private Physics mPhysics;
private Vector<Duckling> mDucklings;
private CollisionManager mCollision;
public void setup() {
size(640, 480, OPENGL);
frameRate(60);
smooth();
colorMode(RGB, 1.0f);
/* physics */
mPhysics = new Physics();
ViscousDrag myViscousDrag = new ViscousDrag();
myViscousDrag.coefficient = 0.25f;
mPhysics.add(myViscousDrag);
mCollision = new CollisionManager();
mCollision.minimumDistance(25);
/* ducklings */
mDucklings = new Vector<Duckling>();
for (int i = 0; i < 13; i++) {
final Duckling mDuckling = new Duckling();
if (!mDucklings.isEmpty()) {
mDuckling.arrival.setPositionRef(mDucklings.lastElement().particle.position());
}
mCollision.collision().add(mDuckling.particle);
mDucklings.add(mDuckling);
}
}
public void draw() {
final float mDeltaTime = 1.0f / frameRate;
background(1);
/* update particles */
mCollision.createCollisionResolvers();
mCollision.loop(mDeltaTime);
mPhysics.step(mDeltaTime);
drawCollisionSprings();
mCollision.removeCollisionResolver();
mDucklings.firstElement().arrival.oversteer(!mousePressed);
mDucklings.firstElement().arrival.position().set(mouseX, mouseY);
/* draw */
for (Duckling mDuckling : mDucklings) {
drawParticle(mDuckling);
}
/* draw arrival */
stroke(0, 0.25f);
noFill();
ellipse(mDucklings.firstElement().arrival.position().x,
mDucklings.firstElement().arrival.position().y,
20, 20);
}
private void drawParticle(Duckling pDuckling) {
final BehaviorParticle mParticle = pDuckling.particle;
final Arrival mArrival = pDuckling.arrival;
/* draw particle */
stroke(0, 0.5f);
noFill();
if (mArrival.arriving()) {
stroke(1, 0, 0, 0.5f);
}
if (mArrival.arrived()) {
stroke(0, 1, 0, 0.5f);
}
ellipse(mParticle.position().x, mParticle.position().y,
mParticle.radius() * 2, mParticle.radius() * 2);
/* - */
pushMatrix();
translate(mParticle.position().x,
mParticle.position().y);
/* draw velocity */
stroke(1, 0, 0, 0.5f);
line(0, 0, mParticle.velocity().x, mParticle.velocity().y);
/* draw break force */
stroke(0, 0.5f, 1, 0.5f);
line(0, 0, mArrival.force().x, mArrival.force().y);
/* - */
popMatrix();
}
private void drawCollisionSprings() {
stroke(0, 1, 0, 0.25f);
for (int i = 0; i < mCollision.collision().forces().size(); ++i) {
if (mCollision.collision().forces().get(i) instanceof Spring) {
Spring mySpring = (Spring) mCollision.collision_forces().get(i);
line(mySpring.a().position().x, mySpring.a().position().y, mySpring.a().position().z,
mySpring.b().position().x, mySpring.b().position().y, mySpring.b().position().z);
}
}
}
class Duckling {
BehaviorParticle particle;
Arrival arrival;
Duckling() {
/* create particles */
particle = mPhysics.makeParticle(BehaviorParticle.class);
particle.position().set(random(width), random(height));
particle.maximumInnerForce(random(50, 150));
particle.radius(random(6, 10));
arrival = new Arrival();
arrival.breakforce(random(12, 28));
arrival.breakradius(random(45, 55));
particle.behaviors().add(arrival);
}
}
public static void main(String[] args) {
PApplet.main(new String[]{LessonX06_Ducklings.class.getName()});
}
}
@@ -0,0 +1,192 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import mathematik.Vector3f;
import mathematik.Vector3i;
import processing.core.PApplet;
import teilchen.cubicle.CubicleWorld;
import teilchen.cubicle.ICubicleEntity;
import teilchen.util.CubicleWorldView;
import teilchen.util.DrawLib;
import java.util.Vector;
public class LessonX07_CubicleWorld
extends PApplet {
private final int WORLD_NUMBER_OF_CUBICLES = 15;
private final float WORLD_CUBICLE_SCALE = 20;
private final float WORLD_SCALE = WORLD_NUMBER_OF_CUBICLES * WORLD_CUBICLE_SCALE;
private boolean showCubicles = true;
private float mRotationZ = 0.1f;
private Vector3f mPosition = new Vector3f();
private CubicleWorld mCubicleWorld;
private CubicleWorldView mCubicleWorldView;
public void setup() {
size(640, 480, OPENGL);
textFont(createFont("Courier", 11));
hint(DISABLE_DEPTH_SORT);
hint(DISABLE_DEPTH_TEST);
/* setup world */
mCubicleWorld = new CubicleWorld(WORLD_NUMBER_OF_CUBICLES, WORLD_NUMBER_OF_CUBICLES, WORLD_NUMBER_OF_CUBICLES);
mCubicleWorld.cellscale().set(WORLD_CUBICLE_SCALE, WORLD_CUBICLE_SCALE, WORLD_CUBICLE_SCALE);
mCubicleWorld.transform().translation.set(-WORLD_SCALE / 2, -WORLD_SCALE / 2, -WORLD_SCALE / 2);
mCubicleWorldView = new CubicleWorldView(mCubicleWorld);
mCubicleWorldView.color_empty = color(0, 1);
mCubicleWorldView.color_full = color(0, 4);
mCubicleWorld.add(new MCubicleEntity());
}
public void draw() {
/* handle entities */
if (frameRate > 30) {
addRandomEntities(2);
}
mCubicleWorld.update();
Vector<ICubicleEntity> mEntities = mCubicleWorld.getLocalEntities(mPosition, 1);
/* draw things */
background(255);
pushMatrix();
translate(width / 2, height / 2, 0);
/* rotate */
if (mousePressed) {
mRotationZ += (mouseX * 0.01f - mRotationZ) * 0.05f;
} else {
mPosition.x = mouseX - width / 2;
mPosition.y = mouseY - height / 2;
}
rotateX(THIRD_PI);
rotateZ(mRotationZ);
/* draw cubicle world */
if (showCubicles) {
stroke(0, 127);
noFill();
mCubicleWorldView.draw(g);
}
/* draw entities */
int mNumberOfPointsSelected = 0;
stroke(0, 127, 255, 127);
noFill();
if (mEntities != null) {
mNumberOfPointsSelected = mEntities.size();
for (ICubicleEntity mEntity : mEntities) {
MCubicleEntity m = (MCubicleEntity) mEntity;
stroke(m.color);
DrawLib.cross3(g, mEntity.position(), 5.0f);
}
}
/* draw crosshair */
stroke(255, 0, 0, 63);
noFill();
beginShape(LINES);
vertex(mPosition.x, -WORLD_SCALE / 2, 0);
vertex(mPosition.x, WORLD_SCALE / 2, 0);
vertex(-WORLD_SCALE / 2, mPosition.y, 0);
vertex(WORLD_SCALE / 2, mPosition.y, 0);
endShape();
/* draw selection sphere */
stroke(255, 0, 0, 63);
noFill();
translate(mPosition.x, mPosition.y, 0);
box(WORLD_CUBICLE_SCALE);
popMatrix();
fill(0);
noStroke();
text("POINTS : " + mCubicleWorld.entities().size(), 10, 12);
text("SELECTED : " + mNumberOfPointsSelected, 10, 24);
text("FPS : " + frameRate, 10, 36);
}
private void addRandomEntities(int pNumberParticles) {
for (int i = 0; i < pNumberParticles; i++) {
MCubicleEntity mEntity = new MCubicleEntity();
mEntity.position().x = random(-WORLD_SCALE / 2, WORLD_SCALE / 2);
mEntity.position().y = random(-WORLD_SCALE / 2, WORLD_SCALE / 2);
mEntity.position().z = random(-WORLD_SCALE / 2, WORLD_SCALE / 2);
mCubicleWorld.add(mEntity);
}
}
class MCubicleEntity
implements ICubicleEntity {
int color = color(0, 127, random(0, 255), 127);
private Vector3i mCubiclePosition;
private final Vector3f mPosition;
public MCubicleEntity() {
mCubiclePosition = new Vector3i();
mPosition = new Vector3f();
}
public Vector3i cubicle() {
return mCubiclePosition;
}
public Vector3f position() {
return mPosition;
}
public boolean leaving(int theX, int theY, int theZ) {
if (theX == cubicle().x
&& theY == cubicle().y
&& theZ == cubicle().z) {
return false;
}
return true;
}
public boolean isActive() {
return true;
}
}
public static void main(String[] args) {
PApplet.main(new String[]{LessonX07_CubicleWorld.class.getName()});
}
}
+174
View File
@@ -0,0 +1,174 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.demo;
import mathematik.Vector3f;
import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PMatrix3D;
import teilchen.BehaviorParticle;
import teilchen.Physics;
import teilchen.behavior.Alignment;
import teilchen.behavior.Cohesion;
import teilchen.behavior.Motor;
import teilchen.behavior.Separation;
import teilchen.behavior.Wander;
import teilchen.constraint.Teleporter;
import teilchen.force.ViscousDrag;
import teilchen.util.Util;
import java.util.Vector;
public class LessonX08_Schwarm
extends PApplet {
private Physics mPhysics;
private Vector<SwarmEntity> mSwarmEntities;
public void setup() {
size(640, 480, OPENGL);
frameRate(60);
smooth();
rectMode(CENTER);
hint(DISABLE_DEPTH_TEST);
/* physics */
mPhysics = new Physics();
Teleporter mTeleporter = new Teleporter();
mTeleporter.min().set(0, 0, height / -2);
mTeleporter.max().set(width, height, height / 2);
mPhysics.add(mTeleporter);
ViscousDrag myViscousDrag = new ViscousDrag();
mPhysics.add(myViscousDrag);
/* setup entities */
mSwarmEntities = new Vector<SwarmEntity>();
for (int i = 0; i < 60; i++) {
SwarmEntity mSwarmEntity = new SwarmEntity();
mSwarmEntity.position().set(random(mTeleporter.min().x, mTeleporter.max().x),
random(mTeleporter.min().y, mTeleporter.max().y),
random(mTeleporter.min().z, mTeleporter.max().z));
mSwarmEntities.add(mSwarmEntity);
mPhysics.add(mSwarmEntity);
}
}
public void draw() {
final float mDeltaTime = 1.0f / frameRate;
/* physics */
mPhysics.step(mDeltaTime);
/* entities */
for (SwarmEntity s : mSwarmEntities) {
s.update(mDeltaTime);
}
/* draw */
background(255);
for (SwarmEntity s : mSwarmEntities) {
s.draw(g);
}
}
private class SwarmEntity
extends BehaviorParticle {
private Separation separation;
private Alignment alignment;
private Cohesion cohesion;
private Wander wander;
private Motor motor;
public SwarmEntity() {
maximumInnerForce(random(100.0f, 1000.0f));
radius(10f);
separation = new Separation();
separation.proximity(20);
separation.weight(50.0f);
behaviors().add(separation);
alignment = new Alignment();
alignment.proximity(30);
alignment.weight(30.0f);
behaviors().add(alignment);
cohesion = new Cohesion();
cohesion.proximity(100);
cohesion.weight(5.0f);
behaviors().add(cohesion);
wander = new Wander();
behaviors().add(wander);
motor = new Motor();
motor.auto_update_direction(true);
motor.strength(20.0f);
behaviors().add(motor);
}
public void update(float theDeltaTime) {
separation.neighbors(mSwarmEntities);
alignment.neighbors(mSwarmEntities);
cohesion.neighbors(mSwarmEntities);
}
private void draw(PGraphics g) {
pushMatrix();
translate(position().x, position().y, position().z);
pushMatrix();
PMatrix3D p = new PMatrix3D();
Util.pointAt(p, position(), new Vector3f(0, 1, 0), mathematik.Util.add(position(), velocity()));
applyMatrix(p);
noStroke();
fill(0);
scale(1, 0.25f, 3);
box(6);
popMatrix();
/* velocity */
stroke(0, 31);
line(0, 0, 0, velocity().x, velocity().y, velocity().z);
popMatrix();
}
}
public static void main(String[] args) {
PApplet.main(new String[]{LessonX08_Schwarm.class.getName()});
}
}
@@ -0,0 +1,101 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force;
import mathematik.Vector3f;
import teilchen.Particle;
public class AngleConstraintSpring
extends Spring {
private final Particle mParticleA;
private final Particle mParticleB;
private final Particle mParticleC;
private float mMinAngle;
/**
*
* particles are connected like this: A -- B -- C
*
* @param pParticleA
* @param pParticleB
* @param pParticleC
*/
public AngleConstraintSpring(Particle pParticleA, Particle pParticleB, Particle pParticleC) {
super(pParticleA, pParticleC);
mParticleA = pParticleA;
mParticleB = pParticleB;
mParticleC = pParticleC;
mMinAngle = Float.MAX_VALUE;
}
public void min_angle(float pAngle) {
mMinAngle = pAngle;
}
public void pre_step() {
Vector3f ab = mathematik.Util.sub(mParticleA.position(), mParticleB.position());
Vector3f cb = mathematik.Util.sub(mParticleC.position(), mParticleB.position());
final float mCurrentAngle = ab.angle(cb);
if (mCurrentAngle < mMinAngle) {
final int TINY_FACTOR_MODELL = 0;
final int TRIG_MODELL = 1;
final int MAX_DISTANCE_MODELL = 2;
final int mModell = TRIG_MODELL;
switch (mModell) {
case TINY_FACTOR_MODELL: {
final float TINY_FACTOR = 1.1f;
final float mDistance = mParticleA.position().distance(mParticleC.position()) * TINY_FACTOR;
restlength(mDistance);
}
break;
case TRIG_MODELL: {
// a = sqrt ( b*b + c*c - 2bc*cosA )
final float b = ab.length();
final float c = cb.length();
final float mDistance = (float) Math.sqrt(b * b + c * c - 2 * b * c * (float) Math.cos(mMinAngle));
restlength(mDistance);
}
break;
case MAX_DISTANCE_MODELL: {
final float mDistance = mParticleA.position().distance(mParticleB.position()) + mParticleC.position().distance(mParticleB.position());
restlength(mDistance);
}
break;
}
active(true);
}
}
public void post_step() {
active(false);
}
}
+114
View File
@@ -0,0 +1,114 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
public class Attractor
implements IForce {
protected Vector3f _myPosition;
protected float _myStrength;
protected float _myRadius;
protected final Vector3f myTemp = new Vector3f();
private boolean _myActive;
public Attractor() {
_myPosition = new Vector3f();
_myRadius = 100;
_myStrength = 1;
_myActive = true;
}
public Vector3f position() {
return _myPosition;
}
public void setPositionRef(Vector3f thePosition) {
_myPosition = thePosition;
}
public float strength() {
return _myStrength;
}
public void strength(float theStrength) {
_myStrength = theStrength;
}
public float radius() {
return _myRadius;
}
public void radius(float theRadius) {
_myRadius = theRadius;
}
public void apply(float theDeltaTime, Physics theParticleSystem) {
if (_myStrength != 0) {
for (final Particle myParticle : theParticleSystem.particles()) {
/* each particle */
if (!myParticle.fixed()) {
myTemp.sub(_myPosition, myParticle.position());
final float myDistance = fastInverseSqrt(1 / myTemp.lengthSquared());
if (myDistance < _myRadius) {
float myFallOff = 1f - myDistance / _myRadius;
final float myForce = myFallOff * myFallOff * _myStrength;
myTemp.scale(myForce / myDistance);
if (!myParticle.fixed()) {
myParticle.force().add(myTemp);
}
}
}
}
}
}
protected static float fastInverseSqrt(float v) {
final float half = 0.5f * v;
int i = Float.floatToIntBits(v);
i = 0x5f375a86 - (i >> 1);
v = Float.intBitsToFloat(i);
return v * (1.5f - half * v * v);
}
public boolean dead() {
return false;
}
public boolean active() {
return _myActive;
}
public void active(boolean theActiveState) {
_myActive = theActiveState;
}
}
@@ -0,0 +1,63 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
public class DirectedAttractor
extends Attractor {
private final Vector3f myVectorA = new Vector3f();
private final Vector3f myVectorB = new Vector3f();
public DirectedAttractor() {
super();
}
public void apply(float theDeltaTime, Physics theParticleSystem) {
for (final Particle myParticle : theParticleSystem.particles()) {
/* each particle */
if (!myParticle.fixed()) {
myTemp.sub(_myPosition, myParticle.position());
final float myDistance = fastInverseSqrt(1 / myTemp.lengthSquared());
if (myDistance < _myRadius) {
myVectorA.scale(1 / myDistance, myTemp);
myVectorB.normalize(myParticle.velocity());
float myAngle = myVectorA.dot(myVectorB);
float myFallOff = 1f - myDistance / _myRadius;
final float myForce = myAngle * myFallOff * myFallOff * _myStrength;
myTemp.scale(myForce / myDistance);
myParticle.force().add(myTemp);
}
}
}
}
}
+74
View File
@@ -0,0 +1,74 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
public class Gravity
implements IForce {
private boolean _myActive;
private Vector3f _myForce;
public Gravity(final Vector3f theForce) {
_myActive = true;
_myForce = theForce;
}
public Gravity() {
this(new Vector3f(0, 9.81f, 0));
}
public Gravity(float theX, float theY, float theZ) {
this(new Vector3f(theX, theY, theZ));
}
public Vector3f force() {
return _myForce;
}
public void apply(final float theDeltaTime, final Physics theParticleSystem) {
for (final Particle myParticle : theParticleSystem.particles()) {
if (!myParticle.fixed()) {
myParticle.force().add(_myForce);
}
}
}
public boolean dead() {
return false;
}
public boolean active() {
return _myActive;
}
public void active(boolean theActiveState) {
_myActive = theActiveState;
}
}
+37
View File
@@ -0,0 +1,37 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force;
import teilchen.Physics;
public interface IForce {
void apply(final float theDeltaTime, final Physics theParticleSystem);
boolean dead();
boolean active();
void active(boolean theActiveState);
}
+114
View File
@@ -0,0 +1,114 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force;
import teilchen.Particle;
import teilchen.Physics;
public class MuscleSpring
extends Spring {
private float mAmplitude = 1;
private float mOffset = 0;
private float mFrequency = 1;
private float mInitialRestLength;
private float mCurrentTime;
private boolean mAutomaticContraction = true;
public MuscleSpring(Particle theA, Particle theB) {
super(theA, theB);
mInitialRestLength = mRestLength;
}
public MuscleSpring(final Particle theA,
final Particle theB,
final float theSpringConstant,
final float theSpringDamping,
final float theRestLength) {
super(theA,
theB,
theSpringConstant,
theSpringDamping,
theRestLength);
mInitialRestLength = mRestLength;
}
public void setRestLengthByPosition() {
mInitialRestLength = mA.position().distance(mB.position());
}
public float restlength() {
return mInitialRestLength;
}
public void restlength(float theRestLength) {
mInitialRestLength = theRestLength;
}
public void frequency(final float theFrequency) {
mFrequency = theFrequency;
}
public float frequency() {
return mFrequency;
}
public void amplitude(final float theAmplitude) {
mAmplitude = theAmplitude;
}
public float amplitude() {
return mAmplitude;
}
/**
* set the offset of the contraction in radians.
*
* @param theOffset float
*/
public void offset(final float theOffset) {
mOffset = theOffset;
}
public float offset() {
return mOffset;
}
public void apply(final float theDeltaTime, final Physics theParticleSystem) {
if (mAutomaticContraction) {
mCurrentTime += theDeltaTime;
final float myOffset = (float) Math.sin(mCurrentTime * mFrequency + mOffset) * mAmplitude;
mRestLength = mInitialRestLength + myOffset;
}
super.apply(theDeltaTime, theParticleSystem);
}
}
+160
View File
@@ -0,0 +1,160 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force;
import mathematik.Plane3f;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
public class PlaneDeflector
implements IForce {
private final Plane3f mPlane;
private float mCoefficientOfRestitution;
private final Vector3f _myTempDiff;
private final Vector3f mTempReflectionVector;
private final Vector3f mTempNormalComponent;
private final Vector3f mTempTangentComponent;
private boolean _myActive;
public PlaneDeflector() {
mPlane = new Plane3f();
mPlane.normal = new Vector3f(0, 1, 0);
mCoefficientOfRestitution = 1.0f;
_myTempDiff = new Vector3f();
mTempReflectionVector = new Vector3f();
mTempNormalComponent = new Vector3f();
mTempTangentComponent = new Vector3f();
_myActive = true;
}
public void apply(final float theDeltaTime, final Physics theParticleSystem) {
for (final Particle myParticle : theParticleSystem.particles()) {
if (!myParticle.fixed()) {
/* test if particle passed plane */
if (testParticlePosition(myParticle, mPlane) < 0) {
/* find intersection with plane */
Vector3f myResult = new Vector3f();
/**
* using the normal of the plane instead of the velocity of
* the particle. though less correct it seems to be more
* stable.
*/
final float myIntersectionResult = intersectLinePlane(myParticle.position(),
mPlane.normal,
mPlane,
myResult);
/* remove particle from collision */
if (myIntersectionResult != Float.NEGATIVE_INFINITY
&& !myResult.isNaN()) {
myParticle.position().set(myResult);
}
/* change direction */
seperateComponents(myParticle, mPlane);
myParticle.velocity().set(mTempReflectionVector);
}
}
}
}
public Plane3f plane() {
return mPlane;
}
public void coefficientofrestitution(float theCoefficientOfRestitution) {
mCoefficientOfRestitution = theCoefficientOfRestitution;
}
public float coefficientofrestitution() {
return mCoefficientOfRestitution;
}
private final float testParticlePosition(Particle theParticle, Plane3f thePlane) {
_myTempDiff.sub(theParticle.position(), thePlane.origin);
_myTempDiff.normalize();
final float myAngle = _myTempDiff.dot(thePlane.normal);
return myAngle;
}
private final void seperateComponents(Particle theParticle, Plane3f thePlane) {
/* normal */
mTempNormalComponent.set(thePlane.normal);
mTempNormalComponent.scale(thePlane.normal.dot(theParticle.velocity()));
/* tangent */
mTempTangentComponent.sub(theParticle.velocity(), mTempNormalComponent);
/* negate normal */
mTempNormalComponent.scale(-mCoefficientOfRestitution);
/* set reflection vector */
mTempReflectionVector.add(mTempTangentComponent, mTempNormalComponent);
}
private final float intersectLinePlane(final Vector3f theRayOrigin,
final Vector3f theRayDirection,
final Plane3f thePlane,
final Vector3f theIntersectionPoint) {
float myT;
final float myDenominator = thePlane.normal.dot(theRayDirection);
if (myDenominator == 0) {
System.err.println("### ERROR @ Intersection / NEGATIVE_INFINITY");
return Float.NEGATIVE_INFINITY;
}
final float numer = thePlane.normal.dot(theRayOrigin);
final float D = -thePlane.origin.dot(thePlane.normal);
myT = -((numer + D) / myDenominator);
if (theIntersectionPoint != null) {
theIntersectionPoint.set(theRayDirection);
theIntersectionPoint.scale((float) myT);
theIntersectionPoint.add(theRayOrigin);
}
return myT;
}
public boolean dead() {
return false;
}
public boolean active() {
return _myActive;
}
public void active(boolean theActiveState) {
_myActive = theActiveState;
}
}
+211
View File
@@ -0,0 +1,211 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force;
import teilchen.IConnection;
import teilchen.Particle;
import teilchen.Physics;
public class Spring
implements IForce,
IConnection {
protected float mSpringConstant;
protected float mSpringDamping;
protected float mRestLength;
protected Particle mA;
protected Particle mB;
protected boolean mOneWay;
protected boolean mActive;
public Spring(Particle theA, Particle theB) {
this(theA,
theB,
2.0f, 0.1f,
theA.position().distance(theB.position()));
}
public Spring(Particle theA, Particle theB, float theRestLength) {
this(theA,
theB,
2.0f, 0.1f,
theRestLength);
}
public Spring(Particle theA,
Particle theB,
final float theSpringConstant,
final float theSpringDamping) {
this(theA,
theB,
theSpringConstant,
theSpringDamping,
theA.position().distance(theB.position()));
}
public Spring(final Particle theA,
final Particle theB,
final float theSpringConstant,
final float theSpringDamping,
final float theRestLength) {
mSpringConstant = theSpringConstant;
mSpringDamping = theSpringDamping;
mRestLength = theRestLength;
mA = theA;
mB = theB;
mOneWay = false;
mActive = true;
}
public void setRestLengthByPosition() {
mRestLength = mA.position().distance(mB.position());
}
public float restlength() {
return mRestLength;
}
public void restlength(float theRestLength) {
mRestLength = theRestLength;
}
public final Particle a() {
return mA;
}
public final Particle b() {
return mB;
}
public final Particle a(Particle theA) {
return mA = theA;
}
public final Particle b(Particle theB) {
return mB = theB;
}
public final float currentLength() {
return mA.position().distance(mB.position());
}
/**
* spring constant.
*
* @return float
*/
public final float strength() {
return mSpringConstant;
}
/**
* spring constant.
*
* @param theSpringConstant float
*/
public final void strength(float theSpringConstant) {
mSpringConstant = theSpringConstant;
}
public final float damping() {
return mSpringDamping;
}
public final void damping(float theSpringDamping) {
mSpringDamping = theSpringDamping;
}
public void setOneWay(boolean theOneWayState) {
mOneWay = theOneWayState;
}
public void apply(final float theDeltaTime, final Physics theParticleSystem) {
// if (!mA.fixed() || !mB.fixed()) {
float a2bX = mA.position().x - mB.position().x;
float a2bY = mA.position().y - mB.position().y;
float a2bZ = mA.position().z - mB.position().z;
final float myInversDistance = fastInverseSqrt(a2bX * a2bX + a2bY * a2bY + a2bZ * a2bZ);
final float myDistance = 1.0F / myInversDistance;
if (myDistance == 0.0F) {
a2bX = 0.0F;
a2bY = 0.0F;
a2bZ = 0.0F;
} else {
a2bX *= myInversDistance;
a2bY *= myInversDistance;
a2bZ *= myInversDistance;
}
final float mSpringForce = -(myDistance - mRestLength) * mSpringConstant;
final float Va2bX = mA.velocity().x - mB.velocity().x;
final float Va2bY = mA.velocity().y - mB.velocity().y;
final float Va2bZ = mA.velocity().z - mB.velocity().z;
final float mDampingForce = -mSpringDamping * (a2bX * Va2bX + a2bY * Va2bY + a2bZ * Va2bZ);
final float r = mSpringForce + mDampingForce;
a2bX *= r;
a2bY *= r;
a2bZ *= r;
if (mOneWay) {
if (!mB.fixed()) {
mB.force().add(-2 * a2bX, -2 * a2bY, -2 * a2bZ);
}
} else {
if (!mA.fixed()) {
mA.force().add(a2bX, a2bY, a2bZ);
}
if (!mB.fixed()) {
mB.force().add(-a2bX, -a2bY, -a2bZ);
}
}
// }
}
protected static float fastInverseSqrt(float v) {
final float half = 0.5f * v;
int i = Float.floatToIntBits(v);
i = 0x5f375a86 - (i >> 1);
v = Float.intBitsToFloat(i);
return v * (1.5f - half * v * v);
}
public boolean dead() {
return mA.dead() || mB.dead();
}
public boolean active() {
return mActive;
}
public void active(boolean theActiveState) {
mActive = theActiveState;
}
}
+82
View File
@@ -0,0 +1,82 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force;
import teilchen.Particle;
import teilchen.Physics;
public class TearableSpring
extends Spring {
private boolean _myTornApart = false;
private float _myTearDistance = -1;
public TearableSpring(Particle theA, Particle theB) {
super(theA,
theB,
2.0f, 0.1f,
theA.position().distance(theB.position()));
}
public TearableSpring(final Particle theA,
final Particle theB,
final float theSpringConstant,
final float theSpringDamping,
final float theRestLength,
final float theTearDistance) {
super(theA,
theB,
theSpringConstant,
theSpringDamping,
theRestLength);
_myTearDistance = theTearDistance;
}
public final float teardistance() {
return _myTearDistance;
}
public final void teardistance(float theTearDistance) {
_myTearDistance = theTearDistance;
}
public void apply(final float theDeltaTime, final Physics theParticleSystem) {
/* check if spring will tear */
if (_myTearDistance > 0) {
final float myActualDistance = a().position().distance(b().position());
if (myActualDistance > restlength() + _myTearDistance) {
_myTornApart = true;
}
}
/* apply force if spring is ok */
if (!_myTornApart) {
super.apply(theDeltaTime, theParticleSystem);
}
}
public boolean dead() {
return _myTornApart || super.dead();
}
}
@@ -0,0 +1,230 @@
package teilchen.force;
import mathematik.Intersection;
import mathematik.Intersection.IntersectionResult;
import mathematik.Vector3f;
import mathematik.WorldAxisAlignedBoundingBox;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.IConstraint;
public class TriangleDeflector
implements IConstraint {
private final Vector3f a;
private final Vector3f b;
private final Vector3f c;
private final Vector3f mNormal;
private float mCoefficientOfRestitution;
private final Vector3f mTempReflectionVector;
private final Vector3f mTempNormalComponent;
private final Vector3f mTempTangentComponent;
private final IntersectionResult mIntersectionResult;
private final Vector3f mTempPointOfIntersection = new Vector3f();
private final WorldAxisAlignedBoundingBox mWorldAxisAlignedBoundingBox;
private final Vector3f[] mVectorCollection;
public boolean AUTO_UPDATE = true;
private boolean mGotHit = false;
private boolean mActive;
public TriangleDeflector() {
a = new Vector3f();
b = new Vector3f();
c = new Vector3f();
/* hmmm. */
mVectorCollection = new Vector3f[3];
mVectorCollection[0] = a;
mVectorCollection[1] = b;
mVectorCollection[2] = c;
mNormal = new Vector3f();
mCoefficientOfRestitution = 1.0f;
mTempReflectionVector = new Vector3f();
mTempNormalComponent = new Vector3f();
mTempTangentComponent = new Vector3f();
mIntersectionResult = new IntersectionResult();
mWorldAxisAlignedBoundingBox = new WorldAxisAlignedBoundingBox();
mActive = true;
}
public Vector3f a() {
return a;
}
public Vector3f b() {
return b;
}
public Vector3f c() {
return c;
}
public WorldAxisAlignedBoundingBox boundingbox() {
return mWorldAxisAlignedBoundingBox;
}
public void updateProperties() {
mVectorCollection[0] = a;
mVectorCollection[1] = b;
mVectorCollection[2] = c;
mathematik.Util.calculateNormal(a, b, c, mNormal);
mathematik.Util.updateBoundingBox(mWorldAxisAlignedBoundingBox, mVectorCollection);
}
private float mPreviousT = -1.0f;
public void apply(Physics pParticleSystem) {
// public void apply(final float pDeltaTime, final Physics pParticleSystem) {
/* update triangle properties -- maybe this is better not done automatically */
if (AUTO_UPDATE) {
updateProperties();
}
mGotHit = false;
for (final Particle myParticle : pParticleSystem.particles()) {
if (!myParticle.fixed()) {
final boolean IGNORE_BOUNDING_BOX = true;
/* adjust boundingbox width to particle velocity to avoid particle shooting through the boundingbox */
final Vector3f myTempBoundingBoxScale = new Vector3f(mWorldAxisAlignedBoundingBox.scale);
if (!IGNORE_BOUNDING_BOX) {
if (myParticle.velocity().x > mWorldAxisAlignedBoundingBox.scale.x) {
mWorldAxisAlignedBoundingBox.scale.x = myParticle.velocity().x;
}
if (myParticle.velocity().y > mWorldAxisAlignedBoundingBox.scale.y) {
mWorldAxisAlignedBoundingBox.scale.y = myParticle.velocity().y;
}
if (myParticle.velocity().z > mWorldAxisAlignedBoundingBox.scale.z) {
mWorldAxisAlignedBoundingBox.scale.z = myParticle.velocity().z;
}
}
/* only test if in bounding box */
if (IGNORE_BOUNDING_BOX || mathematik.Util.contains(myParticle.position(), mWorldAxisAlignedBoundingBox)) {
final Vector3f mRay;
final int RAY_FROM_VELOCITY = 0;
final int RAY_FROM_NORMAL = 1;
final int RAY_FROM_OLD_POSITION = 2;
final int CREATE_RAY_FROM = RAY_FROM_OLD_POSITION;
switch (CREATE_RAY_FROM) {
case RAY_FROM_VELOCITY:
mRay = myParticle.velocity();
break;
case RAY_FROM_NORMAL:
mRay = mathematik.Util.scale(mNormal, -myParticle.velocity().length());
break;
case RAY_FROM_OLD_POSITION:
mRay = mathematik.Util.sub(myParticle.position(), myParticle.old_position());
break;
default:
mRay = new Vector3f(1, 0, 0);
break;
}
if (mRay.isNaN()) {
break;
}
if (mRay.lengthSquared() == 0) {
break;
}
final boolean mSuccess = Intersection.intersectRayTriangle(myParticle.position(),
mRay,
a, b, c,
mIntersectionResult,
true);
/* is particle past plane. */
if (mSuccess && mIntersectionResult.t <= 0 && mPreviousT > 0) {
mTempPointOfIntersection.set(mRay);
mTempPointOfIntersection.scale(mIntersectionResult.t);
mTempPointOfIntersection.add(myParticle.position());
myParticle.position().set(mTempPointOfIntersection);
/* reflect velocity i.e. change direction */
seperateComponents(myParticle, mNormal);
myParticle.velocity().set(mTempReflectionVector);
mGotHit = true;
myParticle.tag(true);
markParticle(myParticle);
// mPreviousT = 0.0f; /* ??? */
}
if (mSuccess) {
mPreviousT = mIntersectionResult.t;
} else {
mPreviousT = 0.0f;
}
}
/* reset boundingbox scale */
if (!IGNORE_BOUNDING_BOX) {
mWorldAxisAlignedBoundingBox.scale.set(myTempBoundingBoxScale);
}
}
}
}
protected void markParticle(Particle pParticle) {
}
public boolean hit() {
return mGotHit;
}
public void coefficientofrestitution(float pCoefficientOfRestitution) {
mCoefficientOfRestitution = pCoefficientOfRestitution;
}
public float coefficientofrestitution() {
return mCoefficientOfRestitution;
}
private void seperateComponents(Particle pParticle, Vector3f pNormal) {
/* normal */
mTempNormalComponent.set(pNormal);
mTempNormalComponent.scale(pNormal.dot(pParticle.velocity()));
/* tangent */
mTempTangentComponent.sub(pParticle.velocity(), mTempNormalComponent);
/* negate normal */
mTempNormalComponent.scale(-mCoefficientOfRestitution);
/* set reflection vector */
mTempReflectionVector.add(mTempTangentComponent, mTempNormalComponent);
}
public Vector3f normal() {
return mNormal;
}
public boolean dead() {
return false;
}
public boolean active() {
return mActive;
}
public void active(boolean pActiveState) {
mActive = pActiveState;
}
}
@@ -0,0 +1,40 @@
package teilchen.force;
public class TriangleDeflectorIndexed
extends TriangleDeflector {
private final int a_index;
private final int b_index;
private final int c_index;
private final float[] _myVertices;
public TriangleDeflectorIndexed(float[] theVertices, int theA, int theB, int theC) {
super();
_myVertices = theVertices;
a_index = theA;
b_index = theB;
c_index = theC;
updateProperties();
}
public void updateProperties() {
updateVertices();
super.updateProperties();
}
private void updateVertices() {
a().set(_myVertices[a_index + 0],
_myVertices[a_index + 1],
_myVertices[a_index + 2]);
b().set(_myVertices[b_index + 0],
_myVertices[b_index + 1],
_myVertices[b_index + 2]);
c().set(_myVertices[c_index + 0],
_myVertices[c_index + 1],
_myVertices[c_index + 2]);
}
}
+72
View File
@@ -0,0 +1,72 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.integration.Verlet;
public class ViscousDrag
implements IForce {
public float coefficient;
private boolean _myActive;
public ViscousDrag(float theCoefficient) {
coefficient = theCoefficient;
_myActive = true;
}
public ViscousDrag() {
this(1.0f);
}
public final void apply(final float theDeltaTime, final Physics theParticleSystem) {
if (theParticleSystem.getIntegrator() instanceof Verlet) {
return;
}
if (coefficient != 0) {
for (final Particle myParticle : theParticleSystem.particles()) {
if (!myParticle.fixed()) {
myParticle.force().add(myParticle.velocity().x * -coefficient,
myParticle.velocity().y * -coefficient,
myParticle.velocity().z * -coefficient);
}
}
}
}
public boolean dead() {
return false;
}
public boolean active() {
return _myActive;
}
public void active(boolean theActiveState) {
_myActive = theActiveState;
}
}
@@ -0,0 +1,503 @@
package teilchen.force.flowfield;
import java.util.Vector;
import mathematik.TransformMatrix4f;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.force.IForce;
/*
* todo:
* make density switchable
* clean redundancies
*/
public class FlowField implements IForce {
public int n = 100; // The size of the calculation grid
private int _myGridSize = n + 2; // Extra grid space for boundary
private int _myPixelSize = 10; // The size of each grid square on the screen
// I unravelled the 1D arrays from Jos Stam's paper back to 2D arrays, as we don't have compile time macros in Java...
private float[][] u = new float[_myGridSize][_myGridSize];
private float[][] v = new float[_myGridSize][_myGridSize];
private float[][] uPrev = new float[_myGridSize][_myGridSize];
private float[][] vPrev = new float[_myGridSize][_myGridSize];
private float[][] dens = new float[_myGridSize][_myGridSize];
private float[][] densPrev = new float[_myGridSize][_myGridSize];
private float viscosity = 0.0001f; // Viscosity of fluid
public float deltatime = 0.2f; // Rate of change
private float diff = 0.0001f; // Degree of diffusion of density over time
private int densityBrushSize = n / 10; // Size of the density area applied with the mouse
public int velocityBrushSize = n / 20; // Ditto velocity
private int lineSpacing = n / n; // Spacing between velocity and normal lines
public boolean showHair = true;
public boolean showVelocity = true;
public boolean calculateDensity = true;
public boolean calculateVelocity = true;
private Vector3f _myScale;
private TransformMatrix4f _myTransform;
private Vector<FlowFieldForce> _myForces;
public float forceScale = 1;
public FlowField() {
n = 100;
init();
}
public FlowField(int theResolutionX, int theResolutionY, Vector3f theScale) {
n = theResolutionX;
init();
_myScale.set(theScale);
}
private void init() {
_myScale = new Vector3f();
_myTransform = new TransformMatrix4f();
_myForces = new Vector<FlowFieldForce>();
_myGridSize = n + 2;
u = new float[_myGridSize][_myGridSize];
v = new float[_myGridSize][_myGridSize];
uPrev = new float[_myGridSize][_myGridSize];
vPrev = new float[_myGridSize][_myGridSize];
dens = new float[_myGridSize][_myGridSize];
densPrev = new float[_myGridSize][_myGridSize];
}
public void reset() {
initVelocity();
initDensity();
}
public void addForce(FlowFieldForce theForce) {
_myForces.add(theForce);
}
private void updateForces() {
for (FlowFieldForce myForce : _myForces) {
myForce.applyForce(this);
}
}
public Vector<FlowFieldForce> forces() {
return _myForces;
}
public void setForce() {
initField(densPrev);
initField(uPrev);
initField(vPrev);
}
public float[][] u() {
return u;
}
public float[][] v() {
return v;
}
//float[][] field, int x, int y, float s, float r
public void setForceArea(float[][] field, int x, int y, float s, float r) {
for (int i = (int) (clamp(x - r, 1, n)); i <= (int) (clamp(x + r, 1, n)); i++) {
int dx = x - i;
for (int j = (int) (clamp(y - r, 1, n)); j <= (int) (clamp(y + r, 1, n)); j++) {
int dy = y - j;
float f = 1 - ((float) Math.sqrt(dx * dx + dy * dy) / r);
field[i][j] += clamp(f, 0, 1) * s;
}
}
}
public void setForce(float theX, float theY, Vector3f theStrength, float theRadius) {
int x = (int) (theX / _myScale.x * n);
int y = (int) (theY / _myScale.y * n);
for (int i = (int) (clamp(x - theRadius, 1, n)); i <= (int) (clamp(x + theRadius, 1, n)); i++) {
int dx = x - i;
for (int j = (int) (clamp(y - theRadius, 1, n)); j <= (int) (clamp(y + theRadius, 1, n)); j++) {
int dy = y - j;
float f = 1 - ((float) Math.sqrt(dx * dx + dy * dy) / theRadius);
u[i][j] += clamp(f, 0, 1) * theStrength.x;
v[i][j] += clamp(f, 0, 1) * theStrength.y;
}
}
}
//public void calculateVelocity(float[][] u, float[][] v, float[][] u0, float[][] v0, float visc, float dt
public void calculateVelocity() {
addSource(u, uPrev, deltatime);
addSource(v, vPrev, deltatime);
float[][] tmp;
tmp = u;
u = uPrev;
uPrev = tmp;
tmp = v;
v = vPrev;
vPrev = tmp;
diffuse(1, u, uPrev, viscosity, deltatime);
diffuse(2, v, vPrev, viscosity, deltatime);
project(u, v, uPrev, vPrev);
tmp = u;
u = uPrev;
uPrev = tmp;
tmp = v;
v = vPrev;
vPrev = tmp;
advect(1, u, uPrev, uPrev, vPrev, deltatime);
advect(2, v, vPrev, uPrev, vPrev, deltatime);
project(u, v, uPrev, vPrev);
}
// public void calculateDensity(float[][] x, float[][] x0, float[][] u, float[][] v, float diff, float dt) {
public void calculateDensity() {
float[][] tmp;
addSource(dens, densPrev, deltatime);
tmp = dens;
dens = densPrev;
densPrev = tmp;
diffuse(0, dens, densPrev, diff, deltatime);
tmp = dens;
dens = densPrev;
densPrev = tmp;
advect(0, dens, densPrev, u, v, deltatime);
}
public void loop(final float theDeltaTime) {
updateForces();
setForce();
deltatime = theDeltaTime;
if (calculateVelocity) {
calculateVelocity();
}
if (calculateDensity) {
calculateDensity();
}
}
// public void draw(GLContext theRenderContext) {
// GL gl = ( theRenderContext).gl;
// float vu;
// float vv;
//
// gl.glPushMatrix();
// JoglUtil.applyTransform(gl,
// _myTransformMode,
// transform,
// rotation,
// scale);
//
// material.begin(theRenderContext);
//
// for (int y = 1; y <= n; y++) {
// for (int x = 1; x <= n; x++) {
// if (showHair) {
// if ((x % lineSpacing) == 0 && (y % lineSpacing) == 0) {
//
// float myRatioX = x / (float) n;
// float myRatioY = y / (float) n;
// vu = u[x][y];
// vv = v[x][y];
// Vector2f myDirection = new Vector2f(vu, vv);
// float VIEW_VECTOR_LENGTH = myDirection.length();
// float myAlpha = material.color.a * VIEW_VECTOR_LENGTH;
// gl.glLineWidth(10);
//
// float myTargetLength = VIEW_VECTOR_LENGTH;
//
// gl.glBegin(GL.GL_LINES);
// gl.glColor4f(material.color.r, material.color.g, material.color.b, 0);
// gl.glVertex3f(myRatioX,
// myRatioY,
// 0);
//
// myTargetLength = VIEW_VECTOR_LENGTH * 0.05f;
// gl.glColor4f(material.color.r, material.color.g, material.color.b, myAlpha);
// gl.glVertex3f(myRatioX + vu * myTargetLength,
// myRatioY + vv * myTargetLength,
// 0);
// gl.glEnd();
//
// gl.glBegin(GL.GL_LINES);
// gl.glColor4f(material.color.r, material.color.g, material.color.b, myAlpha);
// gl.glVertex3f(myRatioX + vu * myTargetLength,
// myRatioY + vv * myTargetLength,
// 0);
//
// myTargetLength = VIEW_VECTOR_LENGTH * 0.6f;
// gl.glColor4f(material.color.r, material.color.g, material.color.b, 0);
// gl.glVertex3f(myRatioX + vu * myTargetLength,
// myRatioY + vv * myTargetLength,
// 0);
// gl.glEnd();
// }
// }
// if (showVelocity) {
// if ((x % lineSpacing) == 0 && (y % lineSpacing) == 0) {
//
// float myRatioX = x / (float) n;
// float myRatioY = y / (float) n;
// vu = u[x][y];
// vv = v[x][y];
// Vector2f myDirection = new Vector2f(vu, vv);
// myDirection.normalize();
// myDirection.scale(3);
//
// gl.glBegin(GL.GL_LINES);
// gl.glVertex3f(myRatioX,
// myRatioY,
// 0);
// gl.glVertex3f(myRatioX + vu,
// myRatioY + vv,
// 0);
// gl.glEnd();
// }
// }
// }
// }
// gl.glPopMatrix();
// material.end(theRenderContext);
// }
public Vector3f scale() {
return _myScale;
}
public TransformMatrix4f transform() {
return _myTransform;
}
public Vector3f position() {
return _myTransform.translation;
}
private float clamp(float f, float minf, float maxf) {
return Math.max(Math.min(f, maxf), minf);
}
private void initField(float[][] f) {
for (int i = 0; i < _myGridSize; i++) {
for (int j = 0; j < _myGridSize; j++) {
f[i][j] = 0.0f;
}
}
}
private void initVelocity() {
initField(u);
initField(v);
initField(uPrev);
initField(vPrev);
}
private void initDensity() {
initField(dens);
initField(densPrev);
}
public Vector3f getForce(Vector3f thePosition) {
Vector3f myDeltaPos = new Vector3f(thePosition);
myDeltaPos.sub(position());
float myRatioX = myDeltaPos.x / _myScale.x;
float myRatioY = myDeltaPos.y / _myScale.y;
if (myRatioX >= 0 && myRatioX <= 1 && myRatioY >= 0 && myRatioY <= 1) {
int myIndexX = (int) (myRatioX * (u.length - 1));
int myIndexY = (int) (myRatioY * (v.length - 1));
if (u[myIndexX] == null || v[myIndexY] == null) {
System.out.println(myIndexX + " " + myIndexY);
}
Vector3f myForce = new Vector3f(u()[myIndexX][myIndexY], v()[myIndexX][myIndexY], 0);
return myForce;
}
return new Vector3f();
}
private void addSource(float[][] x, float[][] s, float dt) {
for (int i = 0; i < _myGridSize; i++) {
for (int j = 0; j < _myGridSize; j++) {
x[i][j] += s[i][j] * dt;
}
}
}
private void setBnd(int b, float[][] x) {
// for (int i = 1; i <= n; i++) {
// if (b == 1) {
// x[0][i] = -x[1][i];
// } else {
// x[0][i] = x[1][i];
// }
// if (b == 1) {
// x[n + 1][i] = -x[n][i];
// } else {
// x[n + 1][i] = x[n][i];
// }
// if (b == 2) {
// x[i][0] = -x[i][1];
// } else {
// x[i][0] = x[i][1];
// }
// if (b == 2) {
// x[i][n + 1] = -x[i][n];
// } else {
// x[i][n + 1] = x[i][n];
// }
//
// }
// x[0][0] = 0.5f * (x[1][0] + x[0][1]);
// x[0][n + 1] = 0.5f * (x[1][n + 1] + x[0][n]);
// x[n + 1][0] = 0.5f * (x[n][0] + x[n + 1][1]);
// x[n + 1][n + 1] = 0.5f * (x[n][n + 1] + x[n + 1][n]);
}
private void diffuse(int b, float[][] x, float[][] x0, float diff, float dt) {
int i, j, k;
float a = dt * diff * n * n;
/* todo: why is it '20' */
// for (k = 0; k < 20; k++) {
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
x[i][j] = (x0[i][j] + a * (x[i - 1][j] + x[i + 1][j] + x[i][j - 1] + x[i][j + 1])) / (1 + 4 * a);
}
}
setBnd(b, x);
// }
}
private void project(float[][] u, float[][] v, float[][] p, float[][] div) {
int i;
int j;
int k;
float h;
h = 1.0f / n;
/* todo check loop */
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
div[i][j] = -0.5f * h * (u[i + 1][j] - u[i - 1][j] + v[i][j + 1] - v[i][j - 1]);
p[i][j] = 0;
}
}
setBnd(0, div);
setBnd(0, p);
/* todo: why is it '20' */
for (k = 0; k < 20; k++) {
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
p[i][j] = (div[i][j] + p[i - 1][j] + p[i + 1][j] + p[i][j - 1] + p[i][j + 1]) / 4;
}
}
setBnd(0, p);
}
/* todo check loop */
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
u[i][j] -= 0.5f * (p[i + 1][j] - p[i - 1][j]) / h;
v[i][j] -= 0.5f * (p[i][j + 1] - p[i][j - 1]) / h;
}
}
setBnd(1, u);
setBnd(2, v);
}
private void advect(int b, float[][] d, float[][] d0, float[][] u, float[][] v, float dt) {
int i;
int j;
int i0;
int j0;
int i1;
int j1;
float x;
float y;
float s0;
float t0;
float s1;
float t1;
float dt0;
dt0 = dt * n;
/* todo check loop */
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
x = i - dt0 * u[i][j];
y = j - dt0 * v[i][j];
x = Math.max(0.5f, x);
x = Math.min(n + 0.5f, x);
i0 = (int) Math.floor(x);
i1 = i0 + 1;
y = Math.max(0.5f, y);
y = Math.min(n + 0.5f, y);
j0 = (int) Math.floor(y);
j1 = j0 + 1;
s1 = x - i0;
s0 = 1 - s1;
t1 = y - j0;
t0 = 1 - t1;
d[i][j] = s0 * (t0 * d0[i0][j0] + t1 * d0[i0][j1])
+ s1 * (t0 * d0[i1][j0] + t1 * d0[i1][j1]);
}
}
setBnd(b, d);
}
public void apply(float theDeltaTime, Physics theParticleSystem) {
for (Particle myParticle : theParticleSystem.particles()) {
if (!myParticle.fixed()) {
Vector3f myForce = getForce(myParticle.position());
myForce.scale(forceScale);
myParticle.force().add(myForce);
}
}
}
public boolean dead() {
return false;
}
public boolean active() {
return true;
}
public void active(boolean theActiveState) {
}
}
@@ -0,0 +1,37 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force.flowfield;
import mathematik.Vector3f;
public abstract class FlowFieldForce {
public Vector3f strength = new Vector3f();
public float range;
public Vector3f position = new Vector3f();
public abstract void applyForce(FlowField theField);
}
@@ -0,0 +1,46 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force.flowfield;
import mathematik.Vector3f;
public class FlowFieldForceMOUSE extends FlowFieldForce {
private Vector3f _myOldPosition;
public FlowFieldForceMOUSE() {
_myOldPosition = new Vector3f();
}
public void setPosition(Vector3f thePosition) {
position.set(thePosition);
strength.set(thePosition);
strength.sub(_myOldPosition);
_myOldPosition.set(position);
}
public void applyForce(FlowField theField) {
theField.setForce(position.x, position.y, strength, range);
}
}
@@ -0,0 +1,212 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force.vectorfield;
import mathematik.Vector3f;
import mathematik.Vector3i;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.VectorfieldParticle;
import teilchen.force.IForce;
public class VectorField
implements IForce {
private VectorFieldUnit[][][] _myField;
public float strength;
private Vector3f _myPosition;
private Vector3f _myScale;
private boolean _myActive;
public VectorField(VectorFieldGenerator theGenerator) {
/* init fields */
strength = 1;
_myPosition = new Vector3f();
_myScale = new Vector3f(1f, 1f, 1f);
_myField = theGenerator.data();
_myActive = true;
}
public VectorFieldUnit[][][] data() {
return _myField;
}
public Vector3f getPosition() {
return _myPosition;
}
public void setPosition(final Vector3f thePosition) {
_myPosition.set(thePosition);
for (int x = 0; x < _myField.length; x++) {
for (int y = 0; y < _myField[x].length; y++) {
for (int z = 0; z < _myField[x][y].length; z++) {
Vector3f myPosition = new Vector3f(x
* (_myScale.x / (float) _myField.length),
y * (_myScale.y / (float) _myField[x].length),
z * (_myScale.z / (float) _myField[x][y].length));
_myField[x][y][z].getPosition().set(myPosition);
_myField[x][y][z].getPosition().add(thePosition);
}
}
}
}
public final Vector3f getScale() {
return _myScale;
}
public void setScale(final Vector3f theScale) {
_myScale.set(theScale);
for (int x = 0; x < _myField.length; x++) {
for (int y = 0; y < _myField[x].length; y++) {
for (int z = 0; z < _myField[x][y].length; z++) {
Vector3f myUnitScale = new Vector3f(_myScale.x
/ (float) _myField.length,
_myScale.y / (float) _myField[x].length,
_myScale.z / (float) _myField[x][y].length);
_myField[x][y][z].setScale(myUnitScale);
Vector3f myPosition = new Vector3f(x
* (_myScale.x / (float) _myField.length),
y * (_myScale.y / (float) _myField[x].length),
z * (_myScale.z / (float) _myField[x][y].length));
myPosition.add(_myPosition);
_myField[x][y][z].setPosition(myPosition);
}
}
}
}
// public void setScale(final Vector3f theScale) {
// _myScale.set(theScale);
// for (int x = 0; x < _myField.length; x++) {
// for (int y = 0; y < _myField[x].length; y++) {
// for (int z = 0; z < _myField[x][y].length; z++) {
// Vector3f myUnitScale = new Vector3f(_myScale.x,
// _myScale.y,
// _myScale.z);
// _myField[x][y][z].setScale(myUnitScale);
// Vector3f myPosition = new Vector3f(x *
// (_myScale.x),
// y * (_myScale.y),
// z * (_myScale.z));
// myPosition.add(_myPosition);
// _myField[x][y][z].setPosition(myPosition);
// }
// }
// }
//}
/* IForce */
private Vector3f force(float theDeltaTime, VectorfieldParticle theParticle) {
if (isInBoundingBox(theParticle)) {
Vector3i myUnit = checkIfIsInside(theParticle, 1);
if (myUnit != null) {
Vector3f myAcceleration = new Vector3f(_myField[myUnit.x][
myUnit.y][
myUnit.z].
getAcceleration());
myAcceleration.scale(strength);
theParticle.setLastUnit(myUnit);
return myAcceleration;
}
for (int x = 0; x < _myField.length; x++) {
for (int y = 0; y < _myField[x].length; y++) {
for (int z = 0; z < _myField[x][y].length; z++) {
if (_myField[x][y][z].isInside(theParticle.position())) {
Vector3f myAcceleration = new Vector3f(_myField[x][
y][z].
getAcceleration());
myAcceleration.scale(strength);
theParticle.setLastUnit(new Vector3i(x, y, z));
return myAcceleration;
}
}
}
}
}
return new Vector3f();
}
private boolean isInBoundingBox(VectorfieldParticle theParticle) {
if (theParticle.position().x >= _myPosition.x
&& theParticle.position().x <= _myPosition.x + _myScale.x
&& theParticle.position().y >= _myPosition.y
&& theParticle.position().y <= _myPosition.y + _myScale.y
&& theParticle.position().z >= _myPosition.z
&& theParticle.position().z <= _myPosition.z + _myScale.z) {
return true;
}
return false;
}
private Vector3i checkIfIsInside(VectorfieldParticle theParticle,
int theRadius) {
Vector3i myUnit = new Vector3i(theParticle.getLastUnit());
for (int x = myUnit.x - theRadius; x < myUnit.x + theRadius; x++) {
for (int y = myUnit.y - theRadius; y < myUnit.y + theRadius; y++) {
for (int z = myUnit.z - theRadius; z < myUnit.z + theRadius; z++) {
if (x >= 0 && x < _myField.length
&& y >= 0 && y < _myField[x].length
&& z >= 0 && z < _myField[x][y].length) {
if (_myField[x][y][z].isInside(theParticle.position())) {
return new Vector3i(x, y, z);
}
}
}
}
}
return null;
}
public void apply(final float theDeltaTime,
final Physics theParticleSystem) {
/**
* @todo clean up force method
*/
for (final Particle myParticle : theParticleSystem.particles()) {
if (!myParticle.fixed()) {
if (myParticle instanceof VectorfieldParticle) {
myParticle.force().add(force(theDeltaTime,
(VectorfieldParticle) myParticle));
}
}
}
}
public boolean dead() {
return false;
}
public boolean active() {
return _myActive;
}
public void active(boolean theActiveState) {
_myActive = theActiveState;
}
}
@@ -0,0 +1,28 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force.vectorfield;
public interface VectorFieldGenerator {
VectorFieldUnit[][][] data();
}
@@ -0,0 +1,87 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force.vectorfield;
import mathematik.Vector3f;
public class VectorFieldGeneratorAVERAGEUNITS
implements VectorFieldGenerator {
private VectorFieldUnit[][][] _myField;
public VectorFieldGeneratorAVERAGEUNITS(int theSizeX,
int theSizeY,
int theSizeZ,
Vector3f[] theCoordinats,
Vector3f[] theAccelerations) {
/* populate field */
_myField = new VectorFieldUnit[theSizeX][theSizeY][theSizeZ];
for (int x = 0; x < theSizeX; x++) {
for (int y = 0; y < theSizeY; y++) {
for (int z = 0; z < theSizeZ; z++) {
Vector3f myPosition = new Vector3f(x
* (1f / (float) theSizeX),
y * (1f / (float) theSizeY),
z * (1f / (float) theSizeZ));
Vector3f myScale = new Vector3f(1f
/ (float) theSizeX,
1f / (float) theSizeY,
1f / (float) theSizeZ);
Vector3f myAcceleration = new Vector3f(1f, 1f, 1f);
VectorFieldUnit myUnit = new VectorFieldUnit(myPosition,
myScale,
myAcceleration);
_myField[x][y][z] = myUnit;
}
}
}
float myMaxDistance = (float) Math.sqrt(2);
for (int x = 0; x < theSizeX; x++) {
for (int y = 0; y < theSizeY; y++) {
for (int z = 0; z < theSizeZ; z++) {
Vector3f myAcceleration = new Vector3f();
VectorFieldUnit myUnit = _myField[x][y][z];
for (int i = 0; i < theCoordinats.length; i++) {
Vector3f myDistance = new Vector3f();
VectorFieldUnit myOtherUnit = _myField[ (int) theCoordinats[i].x][ (int) theCoordinats[i].y][ (int) theCoordinats[i].z];
myDistance.set(myOtherUnit.getPosition());
myDistance.sub(myUnit.getPosition());
float myRatio = myMaxDistance - myDistance.length();
Vector3f myTempAcceleration = new Vector3f();
myTempAcceleration.set(theAccelerations[i]);
myTempAcceleration.scale(myRatio);
myAcceleration.add(myTempAcceleration);
}
myAcceleration.scale(1f / myMaxDistance);
myUnit.setAcceleration(myAcceleration);
}
}
}
}
public VectorFieldUnit[][][] data() {
return _myField;
}
}
@@ -0,0 +1,65 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force.vectorfield;
import mathematik.Vector3f;
public class VectorFieldGeneratorRANDOM
implements VectorFieldGenerator {
private VectorFieldUnit[][][] _myField;
public VectorFieldGeneratorRANDOM(int theSizeX,
int theSizeY,
int theSizeZ) {
_myField = new VectorFieldUnit[theSizeX][theSizeY][theSizeZ];
for (int x = 0; x < theSizeX; x++) {
for (int y = 0; y < theSizeY; y++) {
for (int z = 0; z < theSizeZ; z++) {
Vector3f myPosition = new Vector3f(x
* (1f / (float) theSizeX),
y * (1f / (float) theSizeY),
z * (1f / (float) theSizeZ));
Vector3f myScale = new Vector3f(1f
/ (float) theSizeX,
1f / (float) theSizeY,
1f / (float) theSizeZ);
Vector3f myAcceleration = new Vector3f((float) Math.
random() - 0.5f,
(float) Math.random() - 0.5f,
(float) Math.random() - 0.5f);
myAcceleration.normalize();
VectorFieldUnit myUnit = new VectorFieldUnit(myPosition,
myScale,
myAcceleration);
_myField[x][y][z] = myUnit;
}
}
}
}
public VectorFieldUnit[][][] data() {
return _myField;
}
}
@@ -0,0 +1,80 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.force.vectorfield;
import mathematik.Vector3f;
public class VectorFieldUnit {
private Vector3f _myPosition;
private Vector3f _myScale;
private Vector3f _myAcceleration;
public VectorFieldUnit(final Vector3f thePosition,
final Vector3f theScale,
final Vector3f theAcceleration) {
_myPosition = new Vector3f(thePosition);
_myScale = new Vector3f(theScale);
_myAcceleration = new Vector3f(theAcceleration);
}
public void setAcceleration(final Vector3f theAcceleration) {
_myAcceleration.set(theAcceleration);
}
public Vector3f getAcceleration() {
return _myAcceleration;
}
public Vector3f getPosition() {
return _myPosition;
}
public void setPosition(final Vector3f thePosition) {
_myPosition.set(thePosition);
}
public Vector3f getScale() {
return _myScale;
}
public void setScale(final Vector3f theScale) {
_myScale.set(theScale);
}
public boolean isInside(final Vector3f thePosition) {
if (thePosition.x >= _myPosition.x
&& thePosition.x < _myPosition.x + _myScale.x
&& thePosition.y >= _myPosition.y
&& thePosition.y < _myPosition.y + _myScale.y
&& thePosition.z >= _myPosition.z
&& thePosition.z < _myPosition.z + _myScale.z) {
return true;
} else {
return false;
}
}
}
@@ -0,0 +1,39 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.integration;
public final class Derivate3f {
public float px;
public float py;
public float pz;
public float vx;
public float vy;
public float vz;
}
+103
View File
@@ -0,0 +1,103 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.integration;
import java.util.Iterator;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
public class Euler
implements IIntegrator {
private final Vector3f mTemp1;
private final Vector3f mTemp2;
public Euler() {
mTemp1 = new Vector3f();
mTemp2 = new Vector3f();
}
public void step(final float theDeltaTime, final Physics theParticleSystem) {
theParticleSystem.applyForces(theDeltaTime);
synchronized (theParticleSystem.particles()) {
final Iterator<Particle> myIterator = theParticleSystem.particles().iterator();
while (myIterator.hasNext()) {
final Particle myParticle = myIterator.next();
if (!myParticle.fixed()) {
integrate(theDeltaTime, myParticle);
}
}
}
}
private void integrate(final float theDeltaTime, final Particle theParticle) {
mTemp1.set(theParticle.force());
mTemp1.scale(theDeltaTime / theParticle.mass());
mTemp2.set(theParticle.velocity());
mTemp2.scale(theDeltaTime);
theParticle.velocity().add(mTemp1);
theParticle.position().add(mTemp2);
}
}
/* this version scales better with the other integrators but is definitly slower */
//import java.util.Vector;
//
//import particles.IParticle;
//import particles.ParticleSystem;
//
//
//public class Euler
// implements IIntegrator {
//
// private final Vector<Derivate3f> myK1 = new Vector<Derivate3f> ();
//
// public void step(final float theDeltaTime, final ParticleSystem theParticleSystem) {
//
// Util.checkContainerSize(theParticleSystem.particles().size(), myK1, Derivate3f.class);
//
// theParticleSystem.applyForces(theDeltaTime);
// Util.calculateDerivatives(theParticleSystem.particles(), myK1);
// for (int i = 0; i < theParticleSystem.particles().size(); i++) {
// Particle myParticle = theParticleSystem.particles().get(i);
// if (!myParticle.fixed()) {
// myParticle.position().x += myK1.get(i).px * theDeltaTime;
// myParticle.position().y += myK1.get(i).py * theDeltaTime;
// myParticle.position().z += myK1.get(i).pz * theDeltaTime;
// myParticle.velocity().x += myK1.get(i).vx * theDeltaTime;
// myParticle.velocity().y += myK1.get(i).vy * theDeltaTime;
// myParticle.velocity().z += myK1.get(i).vz * theDeltaTime;
// }
// }
// }
//}
@@ -0,0 +1,110 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.integration;
import teilchen.Physics;
public interface IIntegrator {
void step(final float theDeltaTime, final Physics theParticleSystem);
}
/**
* from paul bourke http://astronomy.swin.edu.au/~pbourke/modelling/solver/
*/
/*
// A 1st order 1D DE solver.
// Assumes the function is not time dependent.
// Parameters
// h - step size
// y0 - last value
// method - algorithm to use [0,5]
// fcn - evaluate the derivative of the field
double Solver1D(double h, double y0, int method, double ( * fcn) (double)) {
double ynew;
double k1, k2, k3, k4, k5, k6;
switch (method) {
case 0: // Euler method
k1 = h * ( * fcn) (y0);
ynew = y0 + k1;
break;
case 1: // Modified Euler
k1 = h * ( * fcn) (y0);
k2 = h * ( * fcn) (y0 + k1);
ynew = y0 + (k1 + k2) / 2;
break;
case 2: // Heuns method
k1 = h * ( * fcn) (y0);
k2 = h * ( * fcn) (y0 + 2 * k1 / 3);
ynew = y0 + k1 / 4 + 3 * k2 / 4;
break;
case 3: // Midpoint
k1 = h * ( * fcn) (y0);
k2 = h * ( * fcn) (y0 + k1 / 2);
ynew = y0 + k2;
break;
case 4: // 4'th order Runge-kutta
k1 = h * ( * fcn) (y0);
k2 = h * ( * fcn) (y0 + k1 / 2);
k3 = h * ( * fcn) (y0 + k2 / 2);
k4 = h * ( * fcn) (y0 + k3);
ynew = y0 + k1 / 6 + k2 / 3 + k3 / 3 + k4 / 6;
break;
case 5: // England 4'th order, six stage
k1 = h * ( * fcn) (y0);
k2 = h * ( * fcn) (y0 + k1 / 2);
k3 = h * ( * fcn) (y0 + (k1 + k2) / 4);
k4 = h * ( * fcn) (y0 - k2 + 2 * k3);
k5 = h * ( * fcn) (y0 + (7 * k1 + 10 * k2 + k4) / 27);
k6 = h * ( * fcn) (y0 + (28 * k1 - 125 * k2 + 546 * k3 + 54 * k4 - 378 * k5) / 625);
ynew = y0 + k1 / 6 + 4 * k3 / 6 + k4 / 6;
break;
}
return (ynew);
}
*/
/* example C program */
/*
int main(int argc, char * * argv) {
double t;
double dt = 0.1; // Step size
double T = 100; // Simulation duration
double y = 1; // Initial value
for (t = 0; t < T; t += dt) {
printf("%g %g\n", t, y);
y = Solver1D(dt, y, MIDPOINT, (double ( * ) (double)) EvalFcn);
}
}
// Sample derivative function
double EvalFcn(double x) {
return ( -0.05 * x);
}
*/
+70
View File
@@ -0,0 +1,70 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.integration;
import java.util.Vector;
import teilchen.Particle;
import teilchen.Physics;
public class Midpoint
implements IIntegrator {
private final Vector<Derivate3f> mK1 = new Vector<Derivate3f>();
public void step(final float theDeltaTime, final Physics theParticleSystem) {
Util.checkContainerSize(theParticleSystem.particles().size(), mK1, Derivate3f.class);
/* one */
theParticleSystem.applyForces(theDeltaTime);
Util.calculateDerivatives(theParticleSystem.particles(), mK1);
for (int i = 0; i < theParticleSystem.particles().size(); i++) {
Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
myParticle.position().x += mK1.get(i).px * theDeltaTime / 2;
myParticle.position().y += mK1.get(i).py * theDeltaTime / 2;
myParticle.position().z += mK1.get(i).pz * theDeltaTime / 2;
myParticle.position().x += mK1.get(i).vx * theDeltaTime / 2;
myParticle.position().y += mK1.get(i).vy * theDeltaTime / 2;
myParticle.position().z += mK1.get(i).vz * theDeltaTime / 2;
}
}
/* two */
theParticleSystem.applyForces(theDeltaTime);
Util.calculateDerivatives(theParticleSystem.particles(), mK1);
for (int i = 0; i < theParticleSystem.particles().size(); i++) {
Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
myParticle.position().x += mK1.get(i).px * theDeltaTime;
myParticle.position().y += mK1.get(i).py * theDeltaTime;
myParticle.position().z += mK1.get(i).pz * theDeltaTime;
myParticle.velocity().x += mK1.get(i).vx * theDeltaTime;
myParticle.velocity().y += mK1.get(i).vy * theDeltaTime;
myParticle.velocity().z += mK1.get(i).vz * theDeltaTime;
}
}
}
}
+238
View File
@@ -0,0 +1,238 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.integration;
import java.util.Vector;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
public class RungeKutta
implements IIntegrator {
private final Vector<Vector3f> mOriginalPositions;
private final Vector<Vector3f> mOriginalVelocities;
private final Vector<Vector3f> mK1Forces;
private final Vector<Vector3f> mK1Velocities;
private final Vector<Vector3f> mK2Forces;
private final Vector<Vector3f> mK2Velocities;
private final Vector<Vector3f> mK3Forces;
private final Vector<Vector3f> mK3Velocities;
private final Vector<Vector3f> mK4Forces;
private final Vector<Vector3f> mK4Velocities;
public RungeKutta() {
mOriginalPositions = new Vector<Vector3f>();
mOriginalVelocities = new Vector<Vector3f>();
mK1Forces = new Vector<Vector3f>();
mK1Velocities = new Vector<Vector3f>();
mK2Forces = new Vector<Vector3f>();
mK2Velocities = new Vector<Vector3f>();
mK3Forces = new Vector<Vector3f>();
mK3Velocities = new Vector<Vector3f>();
mK4Forces = new Vector<Vector3f>();
mK4Velocities = new Vector<Vector3f>();
}
public void step(final float theDeltaTime,
final Physics theParticleSystem) {
final int mySize = theParticleSystem.particles().size();
Util.checkContainerSize(mySize, mOriginalPositions, Vector3f.class);
Util.checkContainerSize(mySize, mOriginalVelocities, Vector3f.class);
Util.checkContainerSize(mySize, mK1Forces, Vector3f.class);
Util.checkContainerSize(mySize, mK1Velocities, Vector3f.class);
Util.checkContainerSize(mySize, mK2Forces, Vector3f.class);
Util.checkContainerSize(mySize, mK2Velocities, Vector3f.class);
Util.checkContainerSize(mySize, mK3Forces, Vector3f.class);
Util.checkContainerSize(mySize, mK3Velocities, Vector3f.class);
Util.checkContainerSize(mySize, mK4Forces, Vector3f.class);
Util.checkContainerSize(mySize, mK4Velocities, Vector3f.class);
/* save original position and velocities */
for (int i = 0; i < theParticleSystem.particles().size(); ++i) {
final Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
mOriginalPositions.get(i).set(myParticle.position());
mOriginalVelocities.get(i).set(myParticle.velocity());
}
}
/* get all the k1 values */
theParticleSystem.applyForces(theDeltaTime);
/* save the intermediate forces */
for (int i = 0; i < theParticleSystem.particles().size(); ++i) {
final Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
mK1Forces.get(i).set(myParticle.force());
mK1Velocities.get(i).set(myParticle.velocity());
}
}
/* get k2 values */
for (int i = 0; i < theParticleSystem.particles().size(); ++i) {
final Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
final Vector3f originalPosition = mOriginalPositions.get(i);
final Vector3f k1Velocity = mK1Velocities.get(i);
myParticle.position().x = originalPosition.x + k1Velocity.x * 0.5f * theDeltaTime;
myParticle.position().y = originalPosition.y + k1Velocity.y * 0.5f * theDeltaTime;
myParticle.position().z = originalPosition.z + k1Velocity.z * 0.5f * theDeltaTime;
final Vector3f originalVelocity = mOriginalVelocities.get(i);
final Vector3f k1Force = mK1Forces.get(i);
myParticle.velocity().x = originalVelocity.x + k1Force.x * 0.5f * theDeltaTime / myParticle.mass();
myParticle.velocity().y = originalVelocity.y + k1Force.y * 0.5f * theDeltaTime / myParticle.mass();
myParticle.velocity().z = originalVelocity.z + k1Force.z * 0.5f * theDeltaTime / myParticle.mass();
}
}
theParticleSystem.applyForces(theDeltaTime);
/* save the intermediate forces */
for (int i = 0; i < theParticleSystem.particles().size(); ++i) {
final Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
mK2Forces.get(i).set(myParticle.force());
mK2Velocities.get(i).set(myParticle.velocity());
}
}
/* get k3 values */
for (int i = 0; i < theParticleSystem.particles().size(); ++i) {
final Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
final Vector3f originalPosition = mOriginalPositions.get(i);
final Vector3f k2Velocity = mK2Velocities.get(i);
myParticle.position().x = originalPosition.x + k2Velocity.x * 0.5f * theDeltaTime;
myParticle.position().y = originalPosition.y + k2Velocity.y * 0.5f * theDeltaTime;
myParticle.position().z = originalPosition.z + k2Velocity.z * 0.5f * theDeltaTime;
final Vector3f originalVelocity = mOriginalVelocities.get(i);
final Vector3f k2Force = mK2Forces.get(i);
myParticle.velocity().x = originalVelocity.x + k2Force.x * 0.5f * theDeltaTime / myParticle.mass();
myParticle.velocity().y = originalVelocity.y + k2Force.y * 0.5f * theDeltaTime / myParticle.mass();
myParticle.velocity().z = originalVelocity.z + k2Force.z * 0.5f * theDeltaTime / myParticle.mass();
}
}
theParticleSystem.applyForces(theDeltaTime);
/* save the intermediate forces */
for (int i = 0; i < theParticleSystem.particles().size(); ++i) {
final Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
(mK3Forces.get(i)).set(myParticle.force());
(mK3Velocities.get(i)).set(myParticle.velocity());
}
}
/* get k4 values */
for (int i = 0; i < theParticleSystem.particles().size(); ++i) {
final Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
final Vector3f originalPosition = mOriginalPositions.get(i);
final Vector3f k3Velocity = mK3Velocities.get(i);
myParticle.position().x = originalPosition.x + k3Velocity.x * theDeltaTime;
myParticle.position().y = originalPosition.y + k3Velocity.y * theDeltaTime;
myParticle.position().z = originalPosition.z + k3Velocity.z * theDeltaTime;
final Vector3f originalVelocity = mOriginalVelocities.get(i);
final Vector3f k3Force = mK3Forces.get(i);
myParticle.velocity().x = originalVelocity.x + k3Force.x * theDeltaTime / myParticle.mass();
myParticle.velocity().y = originalVelocity.y + k3Force.y * theDeltaTime / myParticle.mass();
myParticle.velocity().z = originalVelocity.z + k3Force.z * theDeltaTime / myParticle.mass();
}
}
theParticleSystem.applyForces(theDeltaTime);
/* save the intermediate forces */
for (int i = 0; i < theParticleSystem.particles().size(); ++i) {
final Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
mK4Forces.get(i).set(myParticle.force());
mK4Velocities.get(i).set(myParticle.velocity());
}
}
/* put them all together and what do you get? */
for (int i = 0; i < theParticleSystem.particles().size(); ++i) {
final Particle myParticle = theParticleSystem.particles().get(i);
if (!myParticle.fixed()) {
/* update position */
final Vector3f originalPosition = mOriginalPositions.get(i);
final Vector3f k1Velocity = mK1Velocities.get(i);
final Vector3f k2Velocity = mK2Velocities.get(i);
final Vector3f k3Velocity = mK3Velocities.get(i);
final Vector3f k4Velocity = mK4Velocities.get(i);
myParticle.position().x = originalPosition.x
+ theDeltaTime / 6.0f
* (k1Velocity.x + 2.0f * k2Velocity.x + 2.0f * k3Velocity.x + k4Velocity.x);
myParticle.position().y = originalPosition.y
+ theDeltaTime / 6.0f
* (k1Velocity.y + 2.0f * k2Velocity.y + 2.0f * k3Velocity.y + k4Velocity.y);
myParticle.position().z = originalPosition.z
+ theDeltaTime / 6.0f
* (k1Velocity.z + 2.0f * k2Velocity.z + 2.0f * k3Velocity.z + k4Velocity.z);
/* update velocity */
final Vector3f originalVelocity = mOriginalVelocities.get(i);
final Vector3f k1Force = mK1Forces.get(i);
final Vector3f k2Force = mK2Forces.get(i);
final Vector3f k3Force = mK3Forces.get(i);
final Vector3f k4Force = mK4Forces.get(i);
myParticle.velocity().x = originalVelocity.x
+ theDeltaTime / (6.0f * myParticle.mass())
* (k1Force.x + 2.0f * k2Force.x + 2.0f * k3Force.x + k4Force.x);
myParticle.velocity().y = originalVelocity.y
+ theDeltaTime / (6.0f * myParticle.mass())
* (k1Force.y + 2.0f * k2Force.y + 2.0f * k3Force.y + k4Force.y);
myParticle.velocity().z = originalVelocity.z
+ theDeltaTime / (6.0f * myParticle.mass())
* (k1Force.z + 2.0f * k2Force.z + 2.0f * k3Force.z + k4Force.z);
}
}
}
}
+62
View File
@@ -0,0 +1,62 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.integration;
import java.util.List;
import teilchen.Particle;
public final class Util {
public static final <T> void checkContainerSize(final int theSize,
final List<T> theContainer,
Class<T> theClass) {
final int myDiff = theSize - theContainer.size();
if (myDiff > 0) {
for (int i = 0; i < myDiff; i++) {
try {
theContainer.add(theClass.newInstance());
} catch (Exception ex) {
System.err.println(ex);
}
}
} else if (myDiff < 0) {
for (int i = 0; i < myDiff; i++) {
theContainer.remove(myDiff + theSize);
}
}
}
public static final void calculateDerivatives(final List<Particle> theParticles,
final List<Derivate3f> theDerivates) {
for (int i = 0; i < theParticles.size(); i++) {
theDerivates.get(i).px = theParticles.get(i).velocity().x;
theDerivates.get(i).py = theParticles.get(i).velocity().y;
theDerivates.get(i).pz = theParticles.get(i).velocity().z;
theDerivates.get(i).vx = theParticles.get(i).force().x / theParticles.get(i).mass();
theDerivates.get(i).vy = theParticles.get(i).force().y / theParticles.get(i).mass();
theDerivates.get(i).vz = theParticles.get(i).force().z / theParticles.get(i).mass();
}
}
}
+115
View File
@@ -0,0 +1,115 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.integration;
import java.util.Iterator;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
public class Verlet
implements IIntegrator {
private final Vector3f temp1;
private final Vector3f temp2;
private float _myDamping;
public Verlet() {
this(1.0f);
}
public Verlet(final float theDamping) {
_myDamping = theDamping;
temp1 = new Vector3f();
temp2 = new Vector3f();
}
public float damping() {
return _myDamping;
}
public void damping(float theDamping) {
_myDamping = theDamping;
}
public void step(final float theDeltaTime, final Physics theParticleSystem) {
theParticleSystem.applyForces(theDeltaTime);
synchronized (theParticleSystem.particles()) {
final Iterator<Particle> myIterator = theParticleSystem.particles().iterator();
while (myIterator.hasNext()) {
final Particle myParticle = myIterator.next();
if (!myParticle.fixed()) {
integrate(theDeltaTime, myParticle);
}
}
}
}
private final void integrate(float theDeltaTime, Particle theParticle) {
final Vector3f myOldPosition = new Vector3f(theParticle.position());
/*
Physics simulation using Verlet integration
sgreen@nvidia.com 6/2002
based on Thomas Jakobsen's "Advanced Character Physics":
http://www.ioi.dk/Homepages/tj/publications/gdc2001.htm
basic idea:
x' = x + v*dt
v' = v + a*dt
x' = x + (v + a*dt) * dt
= x + v*dt + a*dt^2
v ~= (x - ox) / dt
x' = x + (x - ox) + a*dt^2
*/
/* v ~= (x - ox) / dt */
theParticle.velocity().sub(theParticle.position(), theParticle.old_position());
theParticle.velocity().scale(1.0f / theDeltaTime);
/* x' = x + (x - ox) + a*dt^2 */
temp1.set(theParticle.force());
temp1.scale(1.0f / theParticle.mass());
temp1.scale(theDeltaTime * theDeltaTime);
temp2.sub(theParticle.position(), theParticle.old_position());
temp2.scale(_myDamping);
theParticle.position().add(temp1);
theParticle.position().add(temp2);
/* --- */
theParticle.old_position().set(myOldPosition);
}
}
+425
View File
@@ -0,0 +1,425 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.util;
import java.util.Vector;
import mathematik.Random;
import mathematik.Vector3f;
import teilchen.Particle;
import teilchen.Physics;
import teilchen.constraint.Stick;
import teilchen.cubicle.CubicleParticle;
import teilchen.cubicle.CubicleWorld;
import teilchen.cubicle.ICubicleEntity;
import teilchen.force.IForce;
import teilchen.force.Spring;
/**
* this manager uses it s own particle system. we could make it more integrated
* by using a shared physic world. this would of course make everthing more
* slower.
*/
public class CollisionManager {
public boolean HINT_IGNORE_STILL_OR_FIXED = false;
private float mCollisionSpringConstant;
private float mCollisionSpringDamping;
private final Physics mCollisionPhysics;
private float mMinimumDistance;
private Vector3f mResolveSamePosition;
public enum ResolverType {
// COLLISION_STICK, COLLISION_SPRING,
SPRING, STICK
}
private final Random mRandom;
private ResolverType mResolverType;
private float mCollisionResolverIntervalCounter = 1;
private float mCollisionResolverInterval = 0;
private int mDistanceMode = DISTANCE_MODE_FIXED;
public static final int DISTANCE_MODE_RADIUS = 0;
public static final int DISTANCE_MODE_FIXED = 1;
public CollisionManager() {
this(new Physics());
}
public CollisionManager(final Physics thePhysics) {
mCollisionPhysics = thePhysics;
mResolveSamePosition = new Vector3f(1, 1, 1);
mCollisionSpringConstant = 20.0f;
mCollisionSpringDamping = 1.0f;
mMinimumDistance = 20;
mResolverType = ResolverType.SPRING;
mRandom = new Random();
}
public void distancemode(int theDistanceMode) {
mDistanceMode = theDistanceMode;
}
public void setResolverType(ResolverType theResolverType) {
mResolverType = theResolverType;
}
public Vector3f resolveSamePosition() {
return mResolveSamePosition;
}
public void springDamping(float theSpringDamping) {
mCollisionSpringDamping = theSpringDamping;
}
public float springDamping() {
return mCollisionSpringDamping;
}
public void springConstant(float theSpringConstant) {
mCollisionSpringConstant = theSpringConstant;
}
public float springConstant() {
return mCollisionSpringConstant;
}
public void minimumDistance(float theMinimumDistance) {
mMinimumDistance = theMinimumDistance;
}
public float minimumDistance() {
return mMinimumDistance;
}
public Physics collision() {
return mCollisionPhysics;
}
public Vector<IForce> collision_forces() {
return mCollisionPhysics.forces();
}
public void loop(float theDeltaTime) {
// /* collision resolver */
// if (mCollisionResolverIntervalCounter > mCollisionResolverInterval) {
// mCollisionResolverIntervalCounter = 0;
//// createCollisionResolvers();
// } else {
// mCollisionResolverIntervalCounter += theDeltaTime;
// }
/* physics */
mCollisionPhysics.step(theDeltaTime);
// /* remove collision resolver */
// removeCollisionResolver();
}
public void autoloop(float theDeltaTime) {
/* collision resolver */
if (mCollisionResolverIntervalCounter > mCollisionResolverInterval) {
mCollisionResolverIntervalCounter = 0;
// mCollisionResolverIntervalCounter -= mCollisionResolverInterval;
// mCollisionResolverIntervalCounter %= mCollisionResolverInterval;
createCollisionResolvers();
} else {
mCollisionResolverIntervalCounter += theDeltaTime;
}
/* physics */
mCollisionPhysics.step(theDeltaTime);
/* remove collision resolver */
removeCollisionResolver();
}
public void removeCollisionResolver() {
mCollisionPhysics.forces().clear();
mCollisionPhysics.constraints().clear();
}
public void createCollisionResolvers() {
for (int i = 0; i < mCollisionPhysics.particles().size(); i++) {
createCollisionResolver(mCollisionPhysics.particles().get(i), i);
}
}
private void createCollisionResolver(final Particle theParticle, final int theStart) {
if (HINT_IGNORE_STILL_OR_FIXED) {
if (theParticle.fixed() || theParticle.still()) {
return;
}
}
for (int j = theStart; j < mCollisionPhysics.particles().size(); j++) {
Particle myOtherParticle = mCollisionPhysics.particles().get(j);
if (theParticle != myOtherParticle) { // && !myOtherParticle.fixed()) {
final float myDistance = theParticle.position().distance(myOtherParticle.position());
final float myMinimumDistance = getMinimumDistance(theParticle, myOtherParticle);
if (myDistance < myMinimumDistance) {
if (theParticle.fixed() && myOtherParticle.fixed()) {
// continue;
}
/**
* because of the way we handle the collision resolver
* creation there is no need to check for multiple spring
* connections.
* checkSpringConnectionExistence(mCollisionPhysics.getForces(),
* myParticle, myOtherParticle);
*/
if (mResolverType == ResolverType.SPRING) {
Spring mySpring = new Spring(theParticle,
myOtherParticle,
mCollisionSpringConstant,
mCollisionSpringDamping,
myMinimumDistance);
mCollisionPhysics.add(mySpring);
} else if (mResolverType == ResolverType.STICK) {
Stick mySpring = new Stick(theParticle,
myOtherParticle,
myMinimumDistance);
mCollisionPhysics.add(mySpring);
}
/* hack to prevent particles from being in the same place */
if (myDistance < mathematik.Mathematik.EPSILON && myDistance > -mathematik.Mathematik.EPSILON) {
myOtherParticle.position().x += mRandom.getFloat(mResolveSamePosition.x * -0.5f,
mResolveSamePosition.x * 0.5f);
myOtherParticle.position().y += mRandom.getFloat(mResolveSamePosition.y * -0.5f,
mResolveSamePosition.y * 0.5f);
myOtherParticle.position().z += mRandom.getFloat(mResolveSamePosition.z * -0.5f,
mResolveSamePosition.z * 0.5f);
}
}
}
}
}
public void createCollisionResolvers(final CubicleWorld theWorld) {
for (int i = 0; i < mCollisionPhysics.particles().size(); i++) {
final Particle myParticle = mCollisionPhysics.particles().get(i);
if (myParticle instanceof CubicleParticle) {
createCollisionResolver(theWorld, (CubicleParticle) myParticle);
}
}
}
private void createCollisionResolver(final CubicleWorld theWorld, final CubicleParticle theParticle) {
if (HINT_IGNORE_STILL_OR_FIXED) {
if (theParticle.fixed() || theParticle.still()) {
return;
}
}
final Vector<ICubicleEntity> myNeigbors = theWorld.getLocalEntities(theParticle);
if (myNeigbors.size() > 1) {
for (int j = 0; j < myNeigbors.size(); j++) {
final ICubicleEntity myEntity = myNeigbors.get(j);
if (myEntity instanceof Particle) {
final Particle myOtherParticle = (Particle) myEntity;
if (theParticle != myOtherParticle) {
final float myDistance = theParticle.position().distance(myOtherParticle.position());
final float myMinimumDistance = getMinimumDistance(theParticle, myOtherParticle);
if (myDistance < myMinimumDistance) {
if (theParticle.fixed() && myOtherParticle.fixed()) {
continue;
}
/**
* because of the way we handle the collision
* resolver creation there is no need to check for
* multiple spring connections.
* checkSpringConnectionExistence(mCollisionPhysics.getForces(),
* myParticle, myOtherParticle);
*/
if (mResolverType == ResolverType.SPRING) {
Spring mySpring = new Spring(theParticle,
myOtherParticle,
mCollisionSpringConstant,
mCollisionSpringDamping,
myMinimumDistance);
mCollisionPhysics.add(mySpring);
} else if (mResolverType == ResolverType.STICK) {
Stick mySpring = new Stick(theParticle,
myOtherParticle,
myMinimumDistance);
mCollisionPhysics.add(mySpring);
}
/* hack to prevent particles from being in the same place */
if (myDistance < mathematik.Mathematik.EPSILON
&& myDistance > -mathematik.Mathematik.EPSILON) {
myOtherParticle.position().x += mRandom.getFloat(mResolveSamePosition.x * -0.5f,
mResolveSamePosition.x * 0.5f);
myOtherParticle.position().y += mRandom.getFloat(mResolveSamePosition.y * -0.5f,
mResolveSamePosition.y * 0.5f);
myOtherParticle.position().z += mRandom.getFloat(mResolveSamePosition.z * -0.5f,
mResolveSamePosition.z * 0.5f);
}
}
}
}
}
}
}
private float getMinimumDistance(Particle theParticle, Particle myOtherParticle) {
final float myMinimumDistance;
if (mDistanceMode == DISTANCE_MODE_RADIUS) {
myMinimumDistance = theParticle.radius() + myOtherParticle.radius();
} else {
myMinimumDistance = mMinimumDistance;
}
return myMinimumDistance;
}
public static class CollisionSpring
extends Spring {
public CollisionSpring(Particle theA, Particle theB) {
super(theA,
theB,
2.0f, 0.1f,
theA.position().distance(theB.position()));
}
public CollisionSpring(Particle theA,
Particle theB,
final float theSpringConstant,
final float theSpringDamping) {
super(theA,
theB,
theSpringConstant,
theSpringDamping,
theA.position().distance(theB.position()));
}
public CollisionSpring(final Particle theA,
final Particle theB,
final float theSpringConstant,
final float theSpringDamping,
final float theRestLength) {
super(theA,
theB,
theSpringConstant,
theSpringDamping,
theRestLength);
}
public void apply(final float theDeltaTime, final Physics theParticleSystem) {
if (!mA.fixed() || !mB.fixed()) {
float a2bX = mA.position().x - mB.position().x;
float a2bY = mA.position().y - mB.position().y;
float a2bZ = mA.position().z - mB.position().z;
final float myInversDistance = fastInverseSqrt(a2bX * a2bX + a2bY * a2bY + a2bZ * a2bZ);
final float myDistance = 1.0F / myInversDistance;
if (myDistance < mRestLength) {
if (myDistance == 0.0F) {
a2bX = 0.0F;
a2bY = 0.0F;
a2bZ = 0.0F;
} else {
a2bX *= myInversDistance;
a2bY *= myInversDistance;
a2bZ *= myInversDistance;
}
final float mSpringForce = -(myDistance - mRestLength) * mSpringConstant;
final float Va2bX = mA.velocity().x - mB.velocity().x;
final float Va2bY = mA.velocity().y - mB.velocity().y;
final float Va2bZ = mA.velocity().z - mB.velocity().z;
final float mDampingForce = -mSpringDamping * (a2bX * Va2bX + a2bY * Va2bY + a2bZ * Va2bZ);
final float r = mSpringForce + mDampingForce;
a2bX *= r;
a2bY *= r;
a2bZ *= r;
if (!mA.fixed()) {
mA.force().add(a2bX, a2bY, a2bZ);
}
if (!mB.fixed()) {
mB.force().add(-a2bX, -a2bY, -a2bZ);
}
}
}
}
}
public static class CollisionStick
extends Stick {
public CollisionStick(Particle theA, Particle theB) {
super(theA, theB);
}
public CollisionStick(final Particle theA,
final Particle theB,
final float theRestLength) {
super(theA, theB, theRestLength);
}
public void apply(Physics theParticleSystem) {
if (!mA.fixed() || !mB.fixed()) {
mTempDistanceVector.sub(mA.position(), mB.position());
final float myDistanceSquared = mTempDistanceVector.lengthSquared();
if (myDistanceSquared > 0) {
if (myDistanceSquared < mRestLength * mRestLength) {
final float myDistance = (float) Math.sqrt(myDistanceSquared);
final float myDifference = mRestLength - myDistance;
if (myDifference > EPSILON || myDifference < -EPSILON) {
if (!mOneWay) {
final float myDifferenceScale = 0.5f * myDifference / myDistance;
mTempVector.scale(myDifferenceScale, mTempDistanceVector);
mA.position().add(mTempVector);
mB.position().sub(mTempVector);
} else {
final float myDifferenceScale = myDifference / myDistance;
mTempVector.scale(myDifferenceScale, mTempDistanceVector);
mB.position().sub(mTempVector);
}
}
}
} else {
mB.position().set(mA.position());
mB.position().x += mRestLength;
}
}
}
}
}
+86
View File
@@ -0,0 +1,86 @@
/*
* Teilchen
*
* Copyright (C) 2013
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* {@link http://www.gnu.org/licenses/lgpl.html}
*
*/
package teilchen.util;
import mathematik.TransformMatrix4f;
import mathematik.Vector3f;
import processing.core.PGraphics;
import teilchen.cubicle.CubicleAtom;
import teilchen.cubicle.CubicleWorld;
public class CubicleWorldView {
private final CubicleWorld mCubicleWorld;
public int color_full = -1;
public int color_empty = -8421505;
public CubicleWorldView(CubicleWorld theWorld) {
mCubicleWorld = theWorld;
}
public void draw(PGraphics theParent) {
/* collect data */
final CubicleAtom[][][] myData = mCubicleWorld.getDataRef();
final TransformMatrix4f myTransform = mCubicleWorld.transform();
final Vector3f myScale = mCubicleWorld.cellscale();
/* draw world */
theParent.pushMatrix();
/* rotation */
float[] f = myTransform.toArray();
theParent.translate(f[12], f[13], f[14]);
theParent.applyMatrix(f[0], f[1], f[2], f[3],
f[4], f[5], f[6], f[7],
f[8], f[9], f[10], f[11],
0, 0, 0, f[15]);
/* scale */
theParent.scale(myScale.x, myScale.y, myScale.z);
for (int x = 0; x < myData.length; x++) {
for (int y = 0; y < myData[x].length; y++) {
for (int z = 0; z < myData[x][y].length; z++) {
CubicleAtom myCubicle = myData[x][y][z];
theParent.pushMatrix();
theParent.translate(x, y, z);
theParent.translate(mCubicleWorld.cellscale().x / 2 / myScale.x,
mCubicleWorld.cellscale().y / 2 / myScale.y,
mCubicleWorld.cellscale().z / 2 / myScale.z);
if (myCubicle.size() > 0) {
theParent.stroke(color_full);
} else {
theParent.stroke(color_empty);
}
theParent.box(1);
theParent.popMatrix();
}
}
}
theParent.popMatrix();
}
}

Some files were not shown because too many files have changed in this diff Show More