# Drawing array of curves from PVector

Hi friends! I am trying to draw an array of curves from PVector coordinates.
Basically it is similar to Particle system tutorial, just instead of points, I need to get curves.

I try to use begin shape (in class Particle), storing x,y coordinates in arraylists, but I am getting an error while iterating over the ArrayList (NullPointException).

Heeeeeeeeeeeeeeeeeeeelp :[

``````ArrayList<ParticleSystem> systems;

void setup() {
size(640, 360);
systems = new ArrayList<ParticleSystem>();
}

void draw() {
background(0);
for (ParticleSystem ps : systems) {
ps.run();
}
if (systems.isEmpty()) {
fill(255,255,0);
}
}

void mousePressed() {
}

// A simple Particle class

class Particle {
PVector position;
//ArrayList<PVector> position;
PVector velocity;
float vector_scale;
float lifespan;

FloatList xx;
FloatList yy;
ArrayList<FloatList> old_x;
ArrayList<FloatList> old_y;

Particle(PVector l) {
float vector_scale = 0.05;//ector scaling factor, we want small steps

FloatList xx = new FloatList();
FloatList yy = new FloatList();
ArrayList<FloatList> old_x = new ArrayList<FloatList>();
ArrayList<FloatList> old_y = new ArrayList<FloatList>();

// v is vector from the field
float n = 3 * map(noise(l.x/155,l.y/155),0,1,-1,1); // 100, 300 or 1000
velocity = new PVector(cos(n),sin(n));

l.x += vector_scale * velocity.x;
l.y += vector_scale * velocity.y;

//velocity = new PVector(random(-1, 1), random(-2, 0)); //moving vector
position = l.copy();

lifespan = 100.0;
}

void run() {
update();
display();
}

// Method to update position
void update() {

lifespan -= 1.0;
}

// Method to display
void display() {
strokeWeight(2);
stroke(255, lifespan);

beginShape();

for (int i = xx.size()-1; i <= 0; i--) {
curveVertex(xx.get(i), yy.get(i));
}
endShape();
// populate the x and y lists
xx.append(position.x);
yy.append(position.y);

}

// Is the particle still useful?
return (lifespan < 0.0);
}
}

// An ArrayList is used to manage the list of Particles

class ParticleSystem {

ArrayList<Particle> particles;    // An arraylist for all the particles
PVector origin;                   // An origin point for where particles are birthed

ParticleSystem(int num, PVector v) {
particles = new ArrayList<Particle>();   // Initialize the arraylist
origin = v.copy();

// Store the origin point
for (int i = 0; i < num; i++) {

}
}

void run() {
// Cycle through the ArrayList backwards, because we are deleting while iterating
for (int i = particles.size()-1; i >= 0; i--) {
Particle p = particles.get(i);
p.run();

//println(XXorigin.get(i));
stroke(255,0,0);
strokeWeight(8);
strokeJoin(ROUND);
//point(XXorigin.get(i), YYorigin.get(i));
//line(XXorigin.get(0), YYorigin.get(0), XXorigin.get(i), YYorigin.get(i));
particles.remove(i);
}
}
}

Particle p;
// Add either a Particle or CrazyParticle to the system
p = new Particle(origin);

}

}

// A method to test if the particle system still has particles
return particles.isEmpty();
}
}
``````

change this

``````  FloatList xx;
FloatList yy;
ArrayList<FloatList> old_x;
ArrayList<FloatList> old_y;

Particle(PVector l) {
float vector_scale = 0.05;//ector scaling factor, we want small steps

FloatList xx = new FloatList();
FloatList yy = new FloatList();
ArrayList<FloatList> old_x = new ArrayList<FloatList>();
ArrayList<FloatList> old_y = new ArrayList<FloatList>();
``````

to this

``````  FloatList xx;
FloatList yy;
ArrayList<FloatList> old_x;
ArrayList<FloatList> old_y;

Particle(PVector l) {
float vector_scale = 0.05;//ector scaling factor, we want small steps

xx = new FloatList();
yy = new FloatList();
old_x = new ArrayList<FloatList>();
old_y = new ArrayList<FloatList>();

``````

also wouldn’t it be easier just to maintain an arraylist of PVectors instead of two seperate lists for each ordinate… just a thought.

1 Like

I also changed

to this:

``````for (int i = 0; i < xx.size(); i++) {
curveVertex(xx.get(i), yy.get(i));
}
``````

And it started to work!

Thus, adding every new curve slows down the process by a lot! Also it produces a new curve form the starting point to every new coordinate. What I want is to draw 1 curve from the beginning, following every new coordinate. And repeat that for every new origin I add.

Maybe I need to do that in ParticleSystem Class instead? Or something wrong with the for loop?

you call

every draw

``````void draw() {
background(0);
for (ParticleSystem ps : systems) {
ps.run();
}
if (systems.isEmpty()) {
fill(255, 255, 0);
}
}
``````

but that function just adds another particle at the origin of that particle system

``````  void addParticle() {
Particle p;
// Add either a Particle or CrazyParticle to the system
p = new Particle(origin);

}
``````

so basically you end up drawing multiple curves from origin. remove that and you will have a single curve i believe.

edit: i think this is what you are aiming for yeh?

``````ArrayList<Particle> particles;

void setup() {
size(640, 480);
noFill();
strokeWeight(2);
particles = new ArrayList<Particle>();
}

void draw() {
background(255);
for(int i = particles.size() - 1; i >= 0; i--) {
Particle p = particles.get(i);
p.update();
//if(p.pos.x < -100 || p.pos.x > width+100 || p.pos.y < -100 || p.pos.y > height+100)
//particles.remove(i);
p.present();
}
}

void mousePressed() {
Particle p = new Particle(mouseX, mouseY);
}

class Particle {
PVector pos;
PVector vel;
PVector acc;
ArrayList<PVector> history;
int maxHistory;
float maxWander;
float maxSpeed;

Particle(float x, float y) {
this.pos = new PVector(x, y);
this.vel = new PVector();
this.acc = new PVector();
this.history = new ArrayList<PVector>();
this.maxHistory = 50;
this.maxWander = 45 * (PI / 180);
this.maxSpeed = 2;
}

void addForce(float fx, float fy) {
this.acc.x += fx;
this.acc.y += fy;
}

void update() {
//add some wander to the particle to make it more interesting

this.vel.limit(this.maxSpeed);
this.acc.mult(0);

float dist = PVector.dist(this.pos, this.history.get(this.history.size() - 1));
if(dist > 5) {
if(this.history.size() > this.maxHistory) {
this.history.remove(0);
}
}
}

void present() {
float k = (float)this.history.size();
for(int i = 1; i < this.history.size(); i++) {
stroke(0, (i / k) * 255);
PVector p1 = this.history.get(i - 1);
PVector p2 = this.history.get(i);
line(p1.x, p1.y, p2.x, p2.y);
}
}
}
``````

it’s just you are repurposing code that has a lot of superfluous stuff for your goal making the situation a bit confusing

1 Like

Thank you so much for your help :]

Your code is wonderful, but has totally different structure than mine.
Could you please explain it a bit?
For instance, if I want to map a big noise field to draw it on, or an image to follow, how can I apply it with this code?
I tried to do that here, but it results in particles moving in circles.

``````    //add some wander to the particle to make it more interesting
float heading = 2 * map(noise(this.acc.x/500,this.acc.y/500),0,1,-1,1);
``````

Also, using this just made me so confused…

you basically have it correct. i was being lazy though and really the movement code should be removed from the particle update and instead the particles should be fed a force using the addForce method from outside. this whole thing follows Daniel’s work closely (for good reason ) so it might be worth checking out this video

and he might have actually made an updated version of that as well.
further you can read more on his book The Nature of Code website here

1 Like

Thank you again so much But I guess, if you say

Then my main question is how can I put data from particles.add into run() function, without adding new particles?
I guess the answer is somewhere in using “.this”?

``````class ParticleSystem {

ArrayList<Particle> particles;    // An arraylist for all the particles
PVector origin;    // An origin point for where particles are birthed
FloatList xx;
FloatList yy;

ParticleSystem(int num, PVector v) {
particles = new ArrayList<Particle>();   // Initialize the arraylist
origin = v.copy();            // Store the origin point
xx = new FloatList();
yy = new FloatList();

for (int i = 0; i < num; i++) {
}
}

void run() {
// Use origins of created particles here, witout creating new particles??
}

``````

have a read of chapter 4 of Daniel’s book. Nearer to the end of the chapter you should find your answer. best of luck!

Hi @hotfooted ! I red and watched everything, and I finally understood your code!

However, when reviewing the created lines from

``````line(p1.x, p1.y, p2.x, p2.y);
``````

It actually creates many many copies of the same line in the same place, so it does not create 1 constant vertex.
Here take a look for one of them

Is there a way to avoid it, to create one vertex from each origin, without making copies?

This is your code, minimally modified to just record pdf.
It creates copies of lines in the same location with geometric progression, like so:

(the amount of lines visualized)

``````import processing.pdf.*;

ArrayList<Particle> particles;

void setup() {
size(640, 480);
noFill();
strokeWeight(2);
particles = new ArrayList<Particle>();
beginRecord(PDF, "vector.pdf");
}

void draw() {
background(255);
for(int i = particles.size() - 1; i >= 0; i--) {
Particle p = particles.get(i);
p.update();
p.present();
}

if (keyPressed) {
exit();
saveFrame();
endRecord();
}

}

void mousePressed() {
Particle p = new Particle(mouseX, mouseY);
}

class Particle {
PVector pos;
PVector vel;
PVector acc;
ArrayList<PVector> history;
int maxHistory;
float maxWander;
float maxSpeed;

Particle(float x, float y) {
this.pos = new PVector(x, y);
this.vel = new PVector();
this.acc = new PVector();
this.history = new ArrayList<PVector>();
this.maxHistory = 50;
this.maxWander = 45 * (PI / 180);
this.maxSpeed = 2;
}

void addForce(float fx, float fy) {
this.acc.x += fx;
this.acc.y += fy;
}

void update() {

this.vel.limit(this.maxSpeed);
this.acc.mult(0);

float dist = PVector.dist(this.pos, this.history.get(this.history.size() - 1));
if(dist > 5) {
if(this.history.size() > this.maxHistory) {
this.history.remove(0);
}
}
}

void present() {
float k = (float)this.history.size();
for(int i = 1; i < this.history.size(); i++) {
stroke(0, (i / k) * 255);
PVector p1 = this.history.get(i - 1);
PVector p2 = this.history.get(i);
line(p1.x, p1.y, p2.x, p2.y);
}
}
}
``````

Adding this at the end of for loop in void present(0

``````this.history.remove(i-1)
``````

Helps, but it creates separated lines one by one.

I am trying to create a vertex insted, but I cannot create vertex with history.remove(i-1)…

I tried using lerp as well, but this did not help

``````    noFill();
beginShape();
for(int i = 2; i < this.history.size(); i++) {
//PVector p1 = this.history.get(i - 1);
PVector p1 = this.history.get(i-1);
PVector p2 = this.history.get(i);
float x = lerp(p1.x, p2.x, 1);
float y = lerp(p1.y, p2.y, 1);
vertex(x,y);
//this.history.remove(i-1); //remove previous origin
}
endShape();
``````

the curve is made up of many line segments. each of which is created using pairs of vertices.

here i’ve increased the line segment length by increasing the distance between vertices. i have also highlighted each vertex with an ellipse.

``````ArrayList<Particle> particles;

void setup() {
size(640, 480);
noFill();
strokeWeight(2);
particles = new ArrayList<Particle>();
}

void draw() {
background(255);
for(int i = particles.size() - 1; i >= 0; i--) {
Particle p = particles.get(i);
p.update();
//if(p.pos.x < -100 || p.pos.x > width+100 || p.pos.y < -100 || p.pos.y > height+100)
//particles.remove(i);
p.present();
}
}

void mousePressed() {
Particle p = new Particle(mouseX, mouseY);
}

class Particle {
PVector pos;
PVector vel;
PVector acc;
ArrayList<PVector> history;
int maxHistory;
float maxWander;
float maxSpeed;

Particle(float x, float y) {
this.pos = new PVector(x, y);
this.vel = new PVector();
this.acc = new PVector();
this.history = new ArrayList<PVector>();
this.maxHistory = 50;
this.maxWander = 45 * (PI / 180);
this.maxSpeed = 2;
}

void addForce(float fx, float fy) {
this.acc.x += fx;
this.acc.y += fy;
}

void update() {
//add some wander to the particle to make it more interesting

this.vel.limit(this.maxSpeed);
this.acc.mult(0);

float dist = PVector.dist(this.pos, this.history.get(this.history.size() - 1));
//this controls the length of the line segments or the resolution if you like of the curve which is made up of line segments
if(dist > 25) {
if(this.history.size() > this.maxHistory) {
this.history.remove(0);
}
}
}

void present() {
float k = (float)this.history.size();
for(int i = 1; i < this.history.size(); i++) {
stroke(0, (i / k) * 255);
PVector p1 = this.history.get(i - 1);
PVector p2 = this.history.get(i);
ellipse(p2.x, p2.y, 8, 8);
line(p1.x, p1.y, p2.x, p2.y);
}
}
}
``````

you can see the resolution of the curve is controlled by the distance between each vertex and the smaller the distance the smoother the curve. i feel like there is a misunderstanding on one or both of our ends. i cannot see where you are calculating that there is multiple lines drawn. if you could demonstrate how you arrive at that conclusion i can look further into it but until then i am unsure if there is an issue.

perhaps someone else will weigh in with a solution?