Vortex

Jun’s thought process for this project:
Need something creative to project on -> ceiling lamp in room with dome shaped shades look cool -> need to find place on campus with similar lamp -> Porter has ceiling fans, ceiling fans are objects on ceiling too -> ceiling fans spin, so need to make something that plays on the spinning motion of the fan

And I ended up with something like this.

The final product did end up looking more like a planetary system than I intended to. This is just because the initial velocity of the particles are set to be tangent to the circles, and the gravity toward the center makes the particles orbit. I also didn’t foresee the projection would be projected onto the ceiling too, but I think in a way that made it look cooler. This is a projection that can’t live without the place it is projected on. AKA, if you run the program on your computer, it looks very simple, to the point of being boring/dull. However, once it is projected onto the fan, the motion of the fan makes the projection seem mesmerizing.

Code (non-Keystone version):

import pbox2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.contacts.*;

PBox2D box2d;

ArrayList allParticles;

Surface surface;

boolean showOutline;
boolean showCircles;
float outerR;
float innerR;

void setup() {
  size (600, 600);
  showOutline = true;
  showCircles = true;
  outerR = 500;
  innerR = 80;

  smooth();

  box2d = new PBox2D(this);
  box2d.createWorld();
  //  box2d.setGravity(width/2, -height/2);

  allParticles = new ArrayList();
  surface = new Surface(innerR/2);
}

void draw() {
  background(0);

  float make = random(0, 1.0);
  if (make<0.1) {
    float angle = random(0, TWO_PI);
    float x = width/2+cos(angle)*outerR/2;
    float y = height/2+sin(angle)*outerR/2;
    Particle p = new Particle(x, y, 5, angle);
    allParticles.add(p);
  }

  if (keyPressed) {
    if (key=='r' || key=='R') {
      for (Particle p: allParticles) {
        p.done();
      }
      allParticles.clear();
    }
    else if (key=='c' || key=='C') {
      if (showCircles) showCircles = false;
      else showCircles = true;
    }
    else if (key=='o' || key=='O') {
      if (showOutline) showOutline = false;
      else showOutline = true;
    }
    else if (key==CODED) {
      if (keyCode==UP) {
        innerR+=2;
      }
      else if (keyCode==DOWN) {
        innerR-=2;
      }
      else if (keyCode==LEFT) {
        outerR-=2;
      }
      else if (keyCode==RIGHT) {
        outerR+=2;
      }
    }
  }

  if (showCircles) {
    float r;  
    noFill();

    stroke(255);
    strokeWeight(3);
    r = innerR+0.95*(outerR-innerR);
    ellipse(width/2, height/2, r, r);

    stroke(245);
    strokeWeight(2.5);
    r = innerR+0.90*(outerR-innerR);
    ellipse(width/2, height/2, r, r);

    stroke(225);
    strokeWeight(2.2);
    r = innerR+0.82*(outerR-innerR);
    ellipse(width/2, height/2, r, r);

    stroke(195);
    strokeWeight(1.5);
    r = innerR+0.70*(outerR-innerR);
    ellipse(width/2, height/2, r, r);

    stroke(155);
    strokeWeight(1.0);
    r = innerR+0.55*(outerR-innerR);
    ellipse(width/2, height/2, r, r);

    stroke(105);
    strokeWeight(1.0);
    r = innerR+0.40*(outerR-innerR);
    ellipse(width/2, height/2, r, r);

    stroke(45);
    strokeWeight(0.8);
    r = innerR+0.20*(outerR-innerR);
    ellipse(width/2, height/2, r, r);
  }

  if (showOutline) {
    surface.display();

    noFill();
    stroke(0, 255, 0);
    strokeWeight(1);
    ellipse(width/2, height/2, outerR, outerR);
  }

  box2d.step();

  for (Particle p: allParticles) {
    Vec2 pos = new Vec2();
    pos = box2d.getBodyPixelCoord(p.body);
    //Find distance from center
    float dx = width/2-pos.x;
    float dy = -height/2+pos.y;
    Vec2 grav = new Vec2(dx, dy);
    float dfc = sqrt(dx*dx+dy*dy);
    float r0 = p.r0;
    float newR = map(dfc, 0, outerR/2, r0/5, r0);
    p.applyForce(grav);
    //    p.r = newR;
    if (dfc height+r*2) {
      killBody();
      return true;
    }
    return false;
  }

  // 
  void display() {
    // We look at each body and get its screen position
    Vec2 pos = box2d.getBodyPixelCoord(body);
    // Get its angle of rotation
    float a = body.getAngle();
    pushMatrix();
    translate(pos.x,pos.y);
    rotate(-a);
    fill(100,140,200);
    noStroke();
    strokeWeight(1);
    ellipse(0,0,r*2,r*2);
    popMatrix();
  }

  // Here's our function that adds the particle to the Box2D world
  void makeBody(float x, float y, float r) {
    // Define a body
    BodyDef bd = new BodyDef();
    // Set its position
    bd.position = box2d.coordPixelsToWorld(x,y);
    bd.type = BodyType.DYNAMIC;
    bd.linearDamping = 0.1f;
    body = box2d.world.createBody(bd);

    // Make the body's shape a circle
    CircleShape cs = new CircleShape();
    cs.m_radius = box2d.scalarPixelsToWorld(r);
    
    FixtureDef fd = new FixtureDef();
    fd.shape = cs;
    // Parameters that affect physics
    fd.density = 1;
    fd.friction = 0.01;
    fd.restitution = 0.3;
    
    // Attach fixture to body
    body.createFixture(fd);

    // Give it a random initial velocity (and angular velocity)
    body.setLinearVelocity(new Vec2((50*cos(PI/2-a0)),(50*sin(PI/2-a0))));
    body.setAngularVelocity(0);
  }
  
  void applyForce(Vec2 force) {
    Vec2 pos = body.getWorldCenter();
    body.applyForce(force, pos);
  }
}

class Surface {
  Body body;
  float r;
  
  Surface(float r_) {
    r = r_;
    makeBody(width/2,height/2,r);
    body.setUserData(this);
  }
  
  void display() {
    // We look at each body and get its screen position
    Vec2 pos = box2d.getBodyPixelCoord(body);
    pushMatrix();
    noFill();
    stroke(0,255,0);
    strokeWeight(1);
    ellipse(width/2, height/2, r*2, r*2);
    popMatrix();
  }
  
  // Here's our function that adds the particle to the Box2D world
  void makeBody(float x, float y, float r) {
    // Define a body
    BodyDef bd = new BodyDef();
    // Set its position
    bd.position = box2d.coordPixelsToWorld(x, y);
    bd.type = BodyType.STATIC;
    body = box2d.createBody(bd);

    // Make the body's shape a circle
    CircleShape cs = new CircleShape();
    cs.m_radius = box2d.scalarPixelsToWorld(r);

    FixtureDef fd = new FixtureDef();
    fd.shape = cs;

    // Attach fixture to body
    body.createFixture(fd);
  }
} 

Author: jun

[Insert enlightening stuff here] OpenProcessing: http://www.openprocessing.org/user/31167