package p5;
import anar.*;




import processing.core.PApplet;

/**
 * first example towards implementing Asynchronous Varitionnal Integrators
 * within the OOG library
 * 
 * implements a variation of the De Casteljau algorithm on a Pts
 * 
 * @author ||lluj!||
 * 
 */
public class TestAvi2d00bSpringTest extends PApplet {

  /*
   * Example for Anar library by Guillaume LaBelle + Julien Nembrini
   * http://anar.ch
   */


  Obj myObject;

  Pts line;
  Pts copy;

  public void setup(){

    // size(screen.width,screen.height, P3D);
    size(1000,500,OPENGL);
    // size(1000,500, P3D);
    background(55,33,6);

    myObject = new Obj();


    line = new Pts();

    Pt o = Anar.PtNull(0,0,0);
    // Pt a = Anar.PtNull(40,0,40);
    Pt b = Anar.PtNull(80,0,0);
    // Pt c = Anar.PtNull(80,0,80);
    // Pt d = Anar.PtNull(80,100,80);

    line.add(o);
    // line.add(a);
    line.add(b);
    // line.add(c);
    // line.add(d);

    // for (int i=0; i<100; i++) {
    // line.add(Anar.PtRnd(100,100,100));
    // }


    myObject.add(line);

    Anar.init(this);

    Anar.drawAxis(true);
    Anar.sliders(b);
    Anar.camTarget(myObject);

    copy();
    myObject.add(copy);


    Pts.globalRender = new RenderPtsAll();
    Pt.globalRender = new RenderPtShapeOriented(new AColor(100),new AColor(255,0,0,150),Anar.scene);


  }


  void subdivide(){

    // find midpoints of edges
    Pts midPts = new Pts();
    for (int i = 0; i<line.numOfPts()-1; i++){
      Pts tmp = new Pts(line.pt(i),line.pt(i+1));
      midPts.add(new PtBary(tmp));
    }


    // average old points
    Pts newPts = new Pts();
    for (int i = 1; i<line.numOfPts()-1; i++){
      Pts tmp = new Pts(midPts.pt(i-1),midPts.pt(i));
      newPts.add(new PtBary(tmp));
    }

    // construct new line
    Pts newLine = new Pts();

    newLine.add(line.pt(0));
    for (int i = 0; i<newPts.numOfPts(); i++){
      newLine.add(midPts.pt(i));
      newLine.add(newPts.pt(i));
    }
    newLine.add(midPts.ptEnd());
    newLine.add(line.ptEnd());

    line = newLine;

    println(line.numOfPts());

    myObject = new Obj();
    myObject.add(line);
    Anar.slidersReset();
    Anar.sliders(line);

  }


  /**
   * creates a copy of line loosing parametric relationships
   */
  void copy(){
    copy = new Pts();
    for (int i = 0; i<line.numOfPts(); i++){
      Pt copyP = Anar.Pt(line.pt(i).x(),line.pt(i).y(),line.pt(i).z());
      copy.add(copyP);
    }
    copy.stroke(0,0,255);

    myObject.add(copy);
  }


  /**
   * updates the copy using euler
   */
  void update(){
    float k = 10.0f;
    // assume constant length between original nodes
    float length = line.pt(0).length(line.pt(1));

    float m = 1/(float)copy.numOfPts();

    for (int i = 1; i<copy.numOfPts()-1; i++){

      Pt p = copy.pt(i);
      Pt pPrev = copy.pt(i-1);
      Pt pNext = copy.pt(i+1);

      Vertex sum = new Vertex(0,0,0);
      // compute force with previous node
      float f = k* (p.length(pPrev));
      // float f = k*(p.length(pPrev)-length);
      Vertex direct = (new Vertex(pPrev).minus(new Vertex(p))).normalize();
      direct = (Vertex)direct.multiply(f);

      sum = sum.plus(direct);

      // compute force with previous node
      f = k* (p.length(pNext));
      // f = k*(p.length(pNext)-length);
      direct = (Vertex) (new Vertex(pNext).minus(new Vertex(p))).normalize();
      direct = (Vertex)direct.multiply(f);

      sum = sum.plus(direct);

      // compute gravity with mass = 1/N
      Vertex grav = new Vertex(0,0, -9.81f*m);
      sum = sum.plus(grav);

      // euler step
      float h = 0.01f;
      sum = (Vertex)sum.multiply(h);

      p.set(p.x()+sum.x(),p.y()+sum.y(),p.z()+sum.z());

    }
  }


  public void draw(){
    background(255);
    myObject.draw();
    update();
  }


  public void keyPressed(){

    switch(key){
      case 'q':
        subdivide();
        copy();
      break;
      case ' ':
      break;
      case 'w':
      break;
      case 'm':
      break;
      case 'n':
      break;
      case 'e':
      break;
      case 'p':
        Scene.autoSeek = false;
      break;
      case 'o':
      break;
      case 'r':
      break;
      case 't':
      break;
      case 'a':
        TextIO.write( ((Object)this).getClass().getName()+".lsp",myObject.toAutocad());
      break;
      case 'b':
      break;
      case 'f':
        save("linearSubdiv.jpg");
      break;


    }

  }


}

