> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://fgcs.sketchpad.cc/sp/pad/view/ro.RItsaTB-n9i/rev.1951
 * 
 * authors: 
 *   Lachlan Dalaigh Wilger
 *   Markus Roberts

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



// Pressing Control-R will render this sketch.

int len = 20;
float seg_length = 3;
float [] x;
float [] y;
float [] dx;
float [] dy;
float [] m;
int ball = len-1;
float seconds_per_frame;

void setup() {
    size(300, 300);
    smooth();
    frameRate(30);
    seconds_per_frame = 1.0/30.0;
    strokeWeight(2);
    x = new float[len];
    y = new float[len];
    for (i=0; i<len; i++) y[i] = i*seg_length*3;
    dx = new float[len];
    dy = new float[len];
    m  = new float[len];
    for (i=0; i<len; i++) m[i] = 0.1;
    m[0] = 10000;
    m[ball] = 10;
}

float dist_(int p1, float x2, float y2) {
    return sqrt(sq(x[p1]-x2)+sq(y[p1]-y2));
}

float dist(int p1, int p2) {
    return dist_(p1,x[p2],y[p2]);
}

void draw() {
    // Yay, physics!
    for (step=0;step<50;step++) {
      for (i=1;i<len;i++) {
        x[i] = x[i]+dx[i]*seconds_per_frame;
        y[i] = y[i]+dy[i]*seconds_per_frame;
        float friction = (1-0.0001/m[i]);
        dx[i] = friction*(dx[i]+0.0001*random(-5,5));
        dy[i] = friction*(dy[i]+0.002); // gravity
      }
      for (i=1;i<len;i++) {
        float d = dist(i,i-1);
        if (d > seg_length) {
          float stretch = (d-seg_length)/seg_length;
          float total_m = m[i]+m[i-1];
          float ax = seconds_per_frame*10*((x[i]-x[i-1])/d)*stretch/total_m;
          float ay = seconds_per_frame*10*((y[i]-y[i-1])/d)*stretch/total_m;
          dx[i]   = dx[i  ]-m[i-1]*ax;
          dy[i]   = dy[i  ]-m[i-1]*ay;
          dx[i-1] = dx[i-1]+m[i  ]*ax;
          dy[i-1] = dy[i-1]+m[i  ]*ay;
          }
      }
    }
    // Now draw the results...
    background(255);
    stroke(0);
    middle = width/2;
    for (i=1;i<len;i++) line(middle+x[i-1], y[i-1], middle+x[i], y[i]);
    fill(0);
    ellipse(middle+x[ball],y[ball],40,40);
}

float prior_mouse_X,prior_mouse_Y;

void mouseMoved() {
    if (dist_(ball,mouseX,mouseY) <= 40) {
        dx[ball] = dx[ball] + (mouseX-prior_mouse_X);
        dy[ball] = dy[ball] + (mouseX-prior_mouse_Y);
    }
    prior_mouse_X = mouseX;
    prior_mouse_Y = mouseY;
    }

void mousePressed() {
    float delta_x = (mouseX-width/2)-x[ball];
    float delta_y =  mouseY         -y[ball];
    for (int i=1;i<len;i++) {
      x[i] = x[i]+(delta_x*sq(i))/sq(len);
      y[i] = y[i]+(delta_y*sq(i))/sq(len);
    }
}