Skip to content

Instantly share code, notes, and snippets.

@peternewman22
Created July 19, 2021 08:00
Show Gist options
  • Save peternewman22/2e4ac197c4b22fca03caceacc94d4bc3 to your computer and use it in GitHub Desktop.
Save peternewman22/2e4ac197c4b22fca03caceacc94d4bc3 to your computer and use it in GitHub Desktop.
ChaikinCurveSubdivision implementation and animation
// music from https://audionautix.com/free-music/meditative
import processing.sound.*;
SoundFile file;
int ptCount, stop;
PVector[] cpts0;
int everyXFrames;
int level;
Curve[] curves;
boolean isStopped;
void setup() {
size(1000, 500);
file = new SoundFile(this, "RunningWaters.wav");
isStopped = true;
ptCount = 50;
level = 0;
everyXFrames = 2;
cpts0 = new PVector[ptCount];
for (int i = 0; i < cpts0.length; i++) {
cpts0[i] = new PVector(i*(width/ptCount)+random(-50, 50), random(-75, 75));
}
curves = new Curve[4];
curves[0] = new Curve(cpts0);
curves[1] = new Curve(subdivide(curves[0].cpts));
curves[2] = new Curve(subdivide(curves[1].cpts));
curves[3] = new Curve(subdivide(curves[2].cpts));
// the current drawing level
level = 0;
// load the soundfile
strokeWeight(1);
noFill();
noLoop();
}
void draw(){
background(#f5f5f5);
translate(15, height/2);
curves[level].drawPoints();
// draw all the other lines also
for(int i = 0; i < level+1; i++){
curves[i].drawLine();
}
if(frameCount%5 == 0){
curves[level].update();
}
}
// The Algorithm!
PVector[] subdivide(PVector[] cpts) {
// divide the thing into 3 sections: 25%, 50%, 25% or cumulatively 25%, 75%, 100%
PVector[] newCpts = new PVector[cpts.length*2];
for (int i = 0; i < cpts.length-1; i++) {
PVector original = PVector.sub(cpts[i+1], cpts[i]);
float l = original.mag();
PVector start = PVector.add(cpts[i], original.copy().normalize().setMag(0.25*l));
PVector end = PVector.add(cpts[i], original.copy().normalize().setMag(0.75*l));
// make sure they go to the right index in the next array
newCpts[2*i] = start;
newCpts[2*i + 1] = end;
}
// not actually sure what to do with the last couple of points... I just set them both to the parent's end point.
newCpts[newCpts.length -1] = cpts[cpts.length - 1];
newCpts[newCpts.length - 2] = cpts[cpts.length - 1];
return newCpts;
}
void keyPressed(){
if(keyCode == ' '){
file.play();
loop();
}
}
class Curve {
boolean isDrawn;
PVector[] cpts;
int alpha;
int stop;
Curve(PVector[] cpts_) {
cpts = cpts_;
isDrawn = false;
alpha = 255;
stop = 1;
}
// this is a bit clunky - it talks directly to global variables
// that's probably a no-no
void update() {
stop += 1;
if (stop >= cpts.length - 1) {
isDrawn = true;
level = (level + 1)%4;
println("Now progressing to level " + level);
curves[level].stop = 1;
curves[level].isDrawn = false;
}
}
void drawPoints(){
strokeWeight(4);
stroke(0, 50);
for(PVector p : cpts){
point(p.x, p.y);
}
}
void drawLine() {
strokeWeight(2);
if (isDrawn) {
alpha = 25;
} else {
alpha = 255;
}
stroke(0, alpha);
beginShape();
for (int i = 0; i < stop; i++) {
vertex(cpts[i].x, cpts[i].y);
}
endShape();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment