We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hi, I'm want to use a simple particles code to visualize migration of refugees and asylum seekers. The code should run on processing.js as a web canvas.
Each source country is an emitter, and each destination country should be a concentration point.
right now I'm trying to make the particles move to a destination point, but I'm unsure why they don't (they just overshoot). Problem is probably in "update()" or in "Particle()"
// All Examples Written by Casey Reas and Ben Fry
// unless otherwise stated.
ParticleSystem ps;
ParticleSystem ps2;
int n = 0;
int emmitMultiplyer = 5;
float locationX = 250;
float locationY = 450;
void setup() {
size(800,600);
//frameRate(30);
//colorMode(RGB,255,255,255,255);
ps = new ParticleSystem(1,new Vector3D(width/2,height/2,0));
ps2 = new ParticleSystem(1,new Vector3D(100,200,0));
smooth();
}
void draw() {
background(0);
ellipse(locationX,locationY,5,5);
ps.run();
ps2.run();
for (int i = 0; i<emmitMultiplyer; i++)
{
ps.addParticle();
ps2.addParticle();
n++;
//println(n);
}
fill(255);
text("Frame rate: " + int(frameRate), 10, 20);
}
// A simple Particle class
class Particle {
Vector3D loc;
Vector3D vel;
Vector3D acc;
float r;
float timer;
// Another constructor (the one we are using here)
Particle(Vector3D l) {
//acc = new Vector3D(0,0.0005,0); // particle acceleration
vel = new Vector3D(random(-0.1,0.1),random(-0.02,0),0);
loc = l.copy();
acc = new Vector3D((locationX-loc.x)*0.000001, (locationY-loc.y)*0.000001,0);
r = 1.5; // particle radius
timer = 10000.0; // particles lifespan
// * emmitMultiplyer = number of living
}
void run() {
update();
render();
}
// Method to update location
void update() {
vel.add(acc);
loc.add(vel);
timer -= 1.0;
}
// Method to display
void render() {
ellipseMode(CENTER);
noStroke();
fill(255,timer);
ellipse(loc.x,loc.y,r,r);
}
// Is the particle still useful?
boolean dead() {
if (timer <= 0.0) {
return true;
} else {
return false;
}
}
}
// A class to describe a group of Particles
// An ArrayList is used to manage the list of Particles
class ParticleSystem {
ArrayList particles; // An arraylist for all the particles
Vector3D origin; // An origin point for where particles are birthed
ParticleSystem(int num, Vector3D v) {
particles = new ArrayList(); // Initialize the arraylist
origin = v.copy(); // Store the origin point
for (int i = 0; i < num; i++) {
particles.add(new Particle(origin)); // Add "num" amount of particles to the arraylist
}
}
void run() {
// Cycle through the ArrayList backwards b/c we are deleting
for (int i = particles.size()-1; i >= 0; i--) {
Particle p = (Particle) particles.get(i);
p.run();
if (p.dead()) {
n--;
particles.remove(i);
}
}
}
void addParticle() {
particles.add(new Particle(origin));
}
void addParticle(Particle p) {
particles.add(p);
}
// A method to test if the particle system still has particles
boolean dead() {
if (particles.isEmpty()) {
return true;
} else {
return false;
}
}
}
// Simple Vector3D Class
public class Vector3D {
public float x;
public float y;
public float z;
Vector3D(float x_, float y_, float z_) {
x = x_; y = y_; z = z_;
}
Vector3D(float x_, float y_) {
x = x_; y = y_; z = 0f;
}
Vector3D() {
x = 0f; y = 0f; z = 0f;
}
void setX(float x_) {
x = x_;
}
void setY(float y_) {
y = y_;
}
void setZ(float z_) {
z = z_;
}
void setXY(float x_, float y_) {
x = x_;
y = y_;
}
void setXYZ(float x_, float y_, float z_) {
x = x_;
y = y_;
z = z_;
}
void setXYZ(Vector3D v) {
x = v.x;
y = v.y;
z = v.z;
}
public float magnitude() {
return (float) Math.sqrt(x*x + y*y + z*z);
}
public Vector3D copy() {
return new Vector3D(x,y,z);
}
public Vector3D copy(Vector3D v) {
return new Vector3D(v.x, v.y,v.z);
}
public void add(Vector3D v) {
x += v.x;
y += v.y;
z += v.z;
}
public void sub(Vector3D v) {
x -= v.x;
y -= v.y;
z -= v.z;
}
public void mult(float n) {
x *= n;
y *= n;
z *= n;
}
public void div(float n) {
x /= n;
y /= n;
z /= n;
}
public void normalize() {
float m = magnitude();
if (m > 0) {
div(m);
}
}
public void limit(float max) {
if (magnitude() > max) {
normalize();
mult(max);
}
}
public float heading2D() {
float angle = (float) Math.atan2(-y, x);
return -1*angle;
}
public Vector3D add(Vector3D v1, Vector3D v2) {
Vector3D v = new Vector3D(v1.x + v2.x,v1.y + v2.y, v1.z + v2.z);
return v;
}
public Vector3D sub(Vector3D v1, Vector3D v2) {
Vector3D v = new Vector3D(v1.x - v2.x,v1.y - v2.y,v1.z - v2.z);
return v;
}
public Vector3D div(Vector3D v1, float n) {
Vector3D v = new Vector3D(v1.x/n,v1.y/n,v1.z/n);
return v;
}
public Vector3D mult(Vector3D v1, float n) {
Vector3D v = new Vector3D(v1.x*n,v1.y*n,v1.z*n);
return v;
}
public float distance (Vector3D v1, Vector3D v2) {
float dx = v1.x - v2.x;
float dy = v1.y - v2.y;
float dz = v1.z - v2.z;
return (float) Math.sqrt(dx*dx + dy*dy + dz*dz);
}
}
Answers
here based on bezierPoint (similar to lerp() by the way)
https://www.processing.org/reference/bezierPoint_.html
Chrisir
Thank you so much! I'll try to wrap my head around what you did :)
is "t" the progress that is bade on the bezier?
Yes, that's right.
It would be neat if you had a world map and adress the countries on that map.
The the points would emit from a area (the country) and go to an area (instead of a single point).
I'm thinking about it as one possible representation. although data visualization wise I would lose the ability to display other information on the x and y axes.
yeah, maybe
If you are using xy for geo coordinates then you can use the size or color (or shape) of a particle to convey extra dimensions of information.
@jeremydouglass true, but I might want to use color and size of emmiter for different information like country geographical size, selection indicator, migrant status etc.
It's still in early stages so I'll see where it goes :) right now just trying to get the basic particle movement thing going
YOu can simply use lerp() for movement but it would just give you a straight line
I'm running into another issue that I'm at loss how to solve:
I'm slowly assigning the dataset to create particle systems. right now i just want it to create an emitter for every country.
for some reason PSystems[] creates a nullPointerException on the draw() function, while it's a working array in setup()
Line 82/83 should be your guiding star
Don’t define a new list in line 73/78
@Chrisir I'm trying to create an array of ParticleSystems, eventually to have different sources, destinations and amounts based on a CSV.
That's why I'm using lines 73 / 78 that way.
Remove this ParticleSystem[]
From line 73
Otherwise you declare the array anew locally, overshadowing the global array/ variable
OH amazing thank you @Chrisir
;-)