Double Bobs on Springs

At the end of class, on Thursday, Feb. 17, we started on the complex example below.

I have completed it. This is too complex to spend more time on right now, but it is a pleasantly rich example to view.

Implementation

final float DELTA_T = 0.6;
final float AIR_RESISTANCE = 0.0005;

interface Location {
  PVector location();
}

class Anchor implements Location {

  PVector anchorPoint;

  Anchor(PVector anchorPoint_) {
    anchorPoint = anchorPoint_.copy();
  }

  PVector location() {
    return anchorPoint;
  }    
}

class Bob implements Location {

  PVector location;
  PVector velocity;
  PVector acceleration;
  float mass;

  Bob(float m, float x, float y, float vx, float vy) {
    mass = m;
    location = new PVector(x, y);
    velocity = new PVector(vx, vy);
    acceleration = new PVector(0, 0);
  }

  PVector location() {
    return location;
  }

  void applyForce(PVector force) {
    PVector f = PVector.div(force, mass);
    acceleration.add(f);
  }

  void update() {
    velocity.add(acceleration.mult(DELTA_T));
    location.add(velocity.copy().mult(DELTA_T));
    acceleration.mult(0);
  }

  void display() {
    stroke(0);
    fill(175);
    ellipseMode(CENTER);
    ellipse(location.x, location.y, mass*16, mass*16);
  }
}

class Spring {
  float len;
  float k;
  Location anchor;

  Spring(float k_, float len_, Location l_) {
    k = k_;
    len = len_;
    anchor = l_;
  }

  PVector forceAtLocation(Location l) {
    PVector force = PVector.sub(l.location(), anchor.location());
    float d = force.mag();
    float stretch = d - len;
    force.normalize();
    return force.mult(-1 * k * stretch);
  }

  PVector forceAtAnchor(Location l) {
    return forceAtLocation(l).mult(-1);
  }

  void displayAnchor() {
    fill(100);
    rectMode(CENTER);
    PVector location = anchor.location();
    rect(location.x, location.y, 10, 10);
  }

  void displayLine(Location l) {
    stroke(255);
    PVector end = anchor.location();
    PVector otherEnd = l.location();
    line(end.x, end.y, otherEnd.x, otherEnd.y);
  }
}

Bob bob;
Bob bob2;
Spring spring;
Spring spring2;

void setup() {
  size(800, 800);
  Anchor anchor = new Anchor(new PVector(400, 50)); 
  spring = new Spring(1, 400, anchor);
  bob = new Bob(1, 100, 100, 0, 0);
  spring2 = new Spring(1, 160, bob);
  bob2 = new Bob(0.5, 150, 125, 0, 0);
}

void draw() {
  push();
  fill(188, 20);
  noStroke();
  rectMode(CORNERS);
  rect(0, 0, width, height);
  pop();
  PVector gravity = new PVector(0, bob.mass);
  bob.applyForce(gravity);
  bob.applyForce(spring.forceAtLocation(bob));
  bob.applyForce(spring2.forceAtAnchor(bob2));
  PVector airResistance = bob.velocity.copy();
  airResistance.mult(-AIR_RESISTANCE * airResistance.mag());
  bob.applyForce(airResistance);
  PVector gravity2 = new PVector(0, bob2.mass);
  bob2.applyForce(gravity2);
  bob2.applyForce(spring2.forceAtLocation(bob2));
  PVector airResistance2 = bob2.velocity.copy();
  airResistance2.mult(-AIR_RESISTANCE * airResistance2.mag());
  bob2.applyForce(airResistance2);
  bob.update();
  bob2.update();
  bob.display();
  bob2.display();
  spring.displayAnchor();
  spring.displayLine(bob);
  spring2.displayLine(bob2);
}