//Jeffery Kaye

//Kinetic Scuplture


int numPoints = 40;
int counter = -1;
int curPoint = 0;
int curNode = 0;
int curPeg = 0;
int pegCounter = 0;
boolean beenDragged = false;
boolean firstTime = true;
PImage startImage;
PFont arial;

Lattice myLattice;

void setup() {
  size(600,300);
  framerate(60);
  startImage = loadImage("final_title.gif");
  arial = loadFont("ArialMT-11.vlw");
  myLattice = new Lattice();
}

void draw() {
  if(firstTime) {
    image(startImage, 0, 0);
  } else {
    background(255);
    if (beenDragged) {
      drawAgain();
      myLattice.updateNodes();
      myLattice.updatePegs();
      myLattice.display();
    }
  }
}

void mouseDragged() {
  myLattice.update();
  beenDragged = true;
}

void mousePressed()
{
  firstTime = false;
}

void drawAgain() {
  push();
  fill(0);
  textFont(arial, 11);
  text("press 'r' to restart applet", 450, 20);
  pop();
  if(keyPressed) {
    if(key == 'r' || key == 'R') {
      firstTime = true;
    }
  }
}

/****** CLASSES ******/

class Node {
  Position p = new Position();
  Vector v = new Vector();
  float x, y, rad, myAngle;
  float x1, y1, x2, y2;
  float speed = .5;
  int numPegs = 0;
  int pointGroup;
  int r = 200;
  int g = 255;
  int b = 255;
  boolean flip = true;
  boolean first = true;
  int range = 10;

  Node(float $x, float $y, float $rad) {
    p.set($x, $y);
    rad = $rad;
  }
  
  void update(float $x, float $y, float $rad) {
    p.set($x, $y);
    rad = $rad;
  }
  
  void makeColor(float $distValue) {
    float tempValue = ($distValue/30)*255;
    //println(tempValue);
    r = int(random(tempValue));
    g = int(random(tempValue));
    b = int(random(tempValue));
  }
  
  void make(float $x, float $y) {
    p.set($x, $y);
  }
  
  float getX() {
    return p.x;
  }
  
  float getY() {
    return p.y;
  }
  
  void addPeg() {
    if(numPegs+1 < 5) {
      numPegs++;
    }
  }
  
  void addAngle(float $x1, float $y1, float $x2, float $y2) {
    //println($x1 + " " + $y1 + " " + $x2 + " " + $y2);
    myAngle = atan2($y1-$y2, $x1-$x2);
    //println(myAngle);
    x1 = p.x + range*cos(myAngle);
    y1 = p.y + range*sin(myAngle);
    x2 = p.x - range*cos(myAngle*PI);
    y2 = p.y - range*cos(myAngle*PI);
    //println(p.x + " " + x1 + " " + p.y + " " + y1);
  }
  
  float getX1() {
    return x1;
  }
  float getY1() {
    return y1;
  }
  float getX2() {
    return x2;
  }
  float getY2() {
    return y2;
  }
  
  float getAngle() {
    return myAngle;
  }
  
  //keeps track of which Node is associated to with point
  void addToGroup(int $pointGroup) {
    pointGroup = $pointGroup;
  }
  
  int getGroup() {
    return pointGroup;
  }
  
  void makeJiggle() {
    if(flip) {
      if(p.close_to(x1, y1, 1)) {
        flip = false;
      }
      if(!p.close_to(x1, y1, 1)) {
        float a = atan2(y1 - p.y, x1 - p.x); 
        v.set(speed, a);
        p.add(v);
      }
    } else {
      if(p.close_to(x2, y2, 1)) {
        flip = true;
      }
      if(!p.close_to(x2, y2, 1)) {
        float a = atan2(y2 - p.y, x2 - p.x); 
        v.set(speed, a);
        p.add(v);
      }
    }
  }
  
  void go_to(float $x, float $y) {
    /*if(first) {
      getXYs();
      first = false;
    }*/
    if(!p.close_to($x, $y, .05)) {
      float a = atan2($y - p.y, $x - p.x);
      v.set(speed, a);
      p.add(v);
    }
  }
  
  void getXYs() {
    x1 = range*cos(myAngle);
    y1 = range*sin(myAngle);
    println(x1);
    println(y1);
  }
  
  void findJiggleValues() {
    x1 = range*cos(myAngle);
    y1 = range*sin(myAngle);
    x2 = range*cos(myAngle*PI);
    y2 = range*sin(myAngle*PI);
    println(x1);
    println(y1);
    println(x2);
    println(y2);
  }
  
  void display() {
    push();
    fill(r, g, b);
    strokeWeight(1);
    stroke(0);
    ellipse(p.x, p.y, rad*2, rad*2);
    pop();
  }
}

class Peg {
  float x1, x2, y1, y2;
  int begin, end;
  
  Peg() {};
  Peg(float $x1, float $y1, float $x2, float $y2) {
    x1 = $x1;
    x2 = $x2;
    y1 = $y1;
    y2 = $y2;
  }
  
  void modPeg(float $x1, float $y1, float $x2, float $y2) {
    x1 = $x1;
    x2 = $x2;
    y1 = $y1;
    y2 = $y2;
  }
  
  void addBegin(int $begin) {
    begin = $begin;
  }
  void addEnd(int $end) {
    end = $end;
  }
  int getBegin() {
    return begin;
  }
  int getEnd() {
    return end;
  }
  
  void connect() {
    push();
    strokeWeight(1);
    stroke(0);
    line(x1, y1, x2, y2);
    pop();
  }
  
  
}

class Lattice {
  Node myNodes[];
  Peg myPegs[];
  int pegGroupNums[];
  int pegCycle = 0;
  float mx[];
  float my[];
  float pointAngles[];
  float x, y;
  boolean temp = false;
  
  int pegGroups = 0;
  int pegBegin = 0;
  int pegEnd = 0;
  int totalPegs = 0;
  
  Lattice() {
    myNodes = new Node[numPoints*4];
    myPegs = new Peg[numPoints*12];
    pegGroupNums = new int[numPoints*2];
    mx = new float[numPoints];
    my = new float[numPoints];
    pointAngles = new float[numPoints];
    for(int i=0; i<(numPoints*4); i++) {
      myNodes[i] = new Node(0, 0, 3);
    }
  }
  
  void updateNodes() {
    for(int k=0; k<curNode; k++) {
      myNodes[k+2].makeJiggle();
      //myNodes[k].go_to(myNodes[k].getX1(), myNodes[k].getY1());
    }
  }
  
  void updatePegs() {
    for(int k=0; k<curPeg; k++) {
      int begin = myPegs[k].getBegin();
      int end = myPegs[k].getEnd();
      myPegs[k].modPeg(myNodes[begin].getX(), myNodes[begin].getY(), myNodes[end].getX(), myNodes[end].getY());
    }
  }
  
  void update() {
    if (counter < ((5*numPoints) - 1)) {  // looking to fetch numPoints of points
      counter++;
      if ((counter % 5) == 0) {  // use every 7th mouse location
        //println(counter + " " + curPoint + " " + curNode);
        mx[curPoint] = mouseX;
        my[curPoint] = mouseY;
        
        if (curPoint == 0) {  // first focus point
          for (int i=0; i<2; i++) {
            makeRadiusNodes(15);
            curNode++;
          }
        } else { // all other points
          float posDif = dist(mx[curPoint], my[curPoint], mx[curPoint-1], my[curPoint-1]);
          //println(mx[curPoint] + " " + my[curPoint] + " " + mx[curPoint-1] + " " + my[curPoint-1]);
          float hypot = posDif;
          if (posDif < 0) {  // always get positive distance
            posDif *= (-1);
          }
          int randNumNodes = int(random(2,4.9));
          for (int i=0; i<randNumNodes; i++) {
            makeRadiusNodes(hypot);
            myNodes[curNode].addToGroup(curPoint);
            myNodes[curNode].makeColor(hypot);
            myNodes[curNode].addAngle(mx[curPoint], my[curPoint], mx[curPoint-1], my[curPoint-1]);
            //println(mx[curPoint] + " " + my[curPoint] + " " + mx[curPoint-1] + " " + my[curPoint-1]);
            //println(myNodes[curNode].getGroup());
            //myNodes[curNode].make((mx[curPoint]+random(-30,30)), (my[curPoint]+random(-30,30)));
            curNode++;
          }
          createPegs();
        }
        curPoint++;
      }
    }
    display();
  }
  
  float offspring() {
    float jiggleAngle = atan2((my[curPoint]-my[curPoint-1]), (mx[curPoint]-mx[curPoint-1]));
    return jiggleAngle;
  }
  
  void makeRadiusNodes(float $hypot) {
    float randomAngle = random(TWO_PI);
    float yValue = sin(randomAngle)*$hypot;
    float xValue = cos(randomAngle)*$hypot;
    myNodes[curNode].make(mx[curPoint]+xValue, my[curPoint]+yValue);
  }
  
  void createPegs() {
    int curPointGroup = myNodes[curNode-1].getGroup();
    
    for (int i=curNode-1; i>=0; i--) {  // for every node in curPointGroup
      if (myNodes[i].getGroup() == curPointGroup) {
      
        float Max = 0;
        int MaxIndex = 0;
        float Min = 100000;
        int MinIndex = 0;
        float tempDist = 0;
        
        int counter1 = 0;
        int counter2 = 0;
        int r1 = 0;
        int r2 = 0;

        for (int j=0; j<curNode; j++) {  // for every node in curPointGroup and curPointGroup-1
          if ((myNodes[j].getGroup() == curPointGroup) || (myNodes[j].getGroup() == (curPointGroup - 1)) ) {
            tempDist = dist(myNodes[i].getX(), myNodes[i].getY(), myNodes[j].getX(), myNodes[j].getY());
            if (tempDist < 0) {
              tempDist *= (-1);
            }
            if (tempDist > Max) {
              Max = tempDist;
              MaxIndex = j;
            }
            if (tempDist < Min) {
              Min = tempDist;
              MinIndex = j;
            }
          }
        }
        /*for(int k=0; k<curNode; k++) {
          myNodes[i].makeJiggle();
        }*/
        myPegs[curPeg] = new Peg(myNodes[i].getX(), myNodes[i].getY(), myNodes[MinIndex].getX(), myNodes[MinIndex].getY());
        myPegs[curPeg].addBegin(i);
        myPegs[curPeg].addEnd(MinIndex);
        curPeg++;
        myPegs[curPeg] = new Peg(myNodes[i].getX(), myNodes[i].getY(), myNodes[MaxIndex].getX(), myNodes[MaxIndex].getY());
        myPegs[curPeg].addBegin(i);
        myPegs[curPeg].addEnd(MaxIndex);
        curPeg++;
        
        //r1 = int(random(counter1));
        //r2 = int(random(counter2));
        //println(r1 + " " + r2);
        //myPegs[curPeg] = new Peg(myNodes[curNode-r1].getX(), myNodes[curNode-r1].getY(), myNodes[curNode-counter1-r2].getX(), myNodes[curNode-counter1-r2].getY());
        //curPeg++;
      }
      //else
        //break;
    }
  }
      
  void display() {
    for(int i=0; i<curNode; i++) {
      myNodes[i].display();
    }
    for (int i=0; i<curPeg; i++) { //for every peg
      myPegs[i].connect();
    }
  }
}


void mouseReleased()
{

}
 


/*********************************************************************/

/*** POSITION AND VECTOR CLASSES ***/
/******* compliments of Lenny *******/
class Position
{
 float x,y;

 Position() {}
 Position(float $x, float $y)
 {
   x = $x; y = $y;
 }
 Position(Position p)
 {
   x = p.x; y = p.y;
 }

 void add(Vector v)
 {
   x += cos(v.a)*v.m;
   y += sin(v.a)*v.m;
 }
 
 void sub(Vector v)
 {
   x -= cos(v.a)*v.m;
   y -= sin(v.a)*v.m;
 }

 void set(float $x, float $y)
 {
   x = $x; y = $y;
 }
 void set(Position p)
 {
   x = p.x; y = p.y;
 }

 boolean close_to(float $x, float $y, float $c)
 {
   if ( dist(x, y, $x, $y) < $c) {
     return true;
   } else {
     return false;
   }
 }
}

class Vector
{
 float m,a;

 Vector() {}
 Vector(float $m, float $a)
 {
   m = $m; a = $a;
 }

 void add(Vector v)
 {
   float x = cos(a)*m + cos(v.a)*v.m;
   float y = sin(a)*m + sin(v.a)*v.m;
   m = dist(0,0,x,y);
   a = atan2(y,x);
 }
 void add(float $m, float $a)
 {
   float x = cos(a)*m + cos($a)*$m;
   float y = sin(a)*m + sin($a)*$m;
   m = dist(0,0,x,y);
   a = atan2(y,x);
 }

 void set(float $m, float $a)
 {
   m = $m; a = $a;
 }
}
Project 4: Context
Extend an idea you've explored previously in your life, but adapt it to the context of an interactive system which requires the viewer to engage with the material.