pt pickedPoint = P();
int vc=32, kc=8;             // vertex and keyframe counts
int k=0;                     // current key frame
pt[] spray = new pt[vc*100];
Polyloop prime = new Polyloop();
pt[] cloud = new pt[vc*100];

Polyloop C= new Polyloop();  // used to cut and paste
Polyloop P= new Polyloop();  // reference for editing
Polyloop D= new Polyloop();  // used to capture the curve drawn by the user
int style=0;                 // animation style: 0=stroboscopic, 1=linear, 2=...
boolean showFrames=false;        // toggle show all frames
boolean showKeys=false;          // toggle show all keys
boolean animate=false;          // toggle show all keys
boolean showMouseProjection=false;          // toggle show mouse projection
boolean sketching=false;     // toggle indicating that the user is sketching the selected curve
boolean showVertices=true;   // show control vertices
boolean showEkey=true;    // show edited curve
boolean showTriangles=false;
boolean showBorder=false;
boolean notSet=false;
boolean laplaceTolerance=false;
float t=0;                   // current time for animation

void myInit() {prime = new Polyloop();  myReset(); mySelected(0); };
void myReset() {prime.reset(vc); mySpray();};
 
void myDenoise() {P.smoothen(5);}
void mySample() {P.resample(vc/2);}
void myRefine() {P.refine(0,0); mySpray();} //setTriangles();} //setAxis();}

void mySpray() {
  float area=prime.area();
  //int count=(int)((area/15000)*64);
  int count=(int)((area/9100)*64);
  spray = new pt[count];
  for(int i=0; i<spray.length; i++){
    pt temp = new pt(int(random(width)),int(random(height)));
    boolean clear = false;
    while(!clear){
      if(prime.contains(temp)){spray[i] = temp; clear=!clear;}
      else{temp = new pt(int(random(width)),int(random(height)));}
    }
  }
  myLaplace(); 
  if(count < 450){setCloud(); setTriangles(); setAxis(); setO(triangles); notSet=false;}
  else{notSet=true;}
}
void mySet(){
  setCloud();
  setTriangles();
  setAxis();
  setO(triangles);
  notSet=false;
}
void drawSpray(){
  for(int i=0; i<spray.length; i++){
    if(prime.contains(spray[i])){
      spray[i].show(1.0);
    }
  }
}
   
void mySelected(int n) {P=prime;}     // user selects curve by typing its number n: select curve
void myStartAcquisition() {D.empty(); D.appendPt(Mouse()); sketching=true; }  // start acquisition processd
void myEndAcquisition() {if(sketching) {D.smoothen(5); for(int i=0; i<4; i++); D.refine(0,0); D.smoothen(10); D.resample(vc); P.setTo(D); sketching=false; mySpray();}; }      // finish acquisition process
void myMousePressed() {
   if (Mouse().isInWindow()&&!keyPressed&&!sketching) pickedPoint=P.pickPoint(); 
   else if (Mouse().isInWindow()&&keyPressed&&(key=='d')) myStartAcquisition(); 
   } 
void myMouseReleased() {pickedPoint=null; myEndAcquisition();}
void myScale() {P.scaleWithMouse();}  
void myTranslate() {P.translateWithMouse();}
void myRotate() {P.rotateWithMouse();}
void myLaplace() {
  float var=8.0;
  int bCheck=0;
  boolean a = true;
  while(a){
    a = laplace(spray,var,prime); bCheck++;
    if(bCheck>1000){laplaceTolerance=true; break;}
    laplaceTolerance=false;
  }
}
void setTriangles(){
  int[] tri = new int[5000];
  tri = drawTriangles(cloud);
  triangles = tri;
}
void displayTriangles(){
  for(int i=0;i<triangles.length-2;i+=3){
    strokeWeight(1); stroke(dred,50); fill(metal,50); beginShape(POLYGON);  cloud[triangles[i]].v(); cloud[triangles[i+1]].v(); cloud[triangles[i+2]].v(); cloud[triangles[i]].v(); endShape(); noFill(); noStroke();
  }
  fill(dgreen,75);
  cloud[triangles[trav]].show(5.0);
  noFill();
}
void setAxis(){
  Polyloop primeTemp = prime;
  //primeTemp.refine(0,0);
  pt[] cloudP = cloud(primeTemp);
  medAxis=medialAxis(cloudP);
}
void displayAxis(){
  for(int i=0; i<medAxis.length; i++){
    //println(+medAxis.length+", i="+i);
    if(medAxis[i]==null){
      break;
    }
    fill(dblue,85);
    medAxis[i].show(3.0);
    noFill();
  }
}
void setCloud(){
  cloud=cloud(prime,spray);
}
void drawBorder(){
  /*
  for(int i=0; i<triangles.length; i++){
    stroke(dgreen,50); beginShape(POLYGON);  cloud[triangles[i]].v(); cloud[triangles[p(i)]].v(); cloud[triangles[p(p(i))]].v(); cloud[triangles[p(p(p(i)))]].v(); endShape(); noStroke();
  }
  */
  for(int i=0; i<O.length; i++){
    if(O[i]==i){ strokeWeight(3); stroke(dgreen);
      line(cloud[triangles[p(i)]].x,cloud[triangles[p(i)]].y,cloud[triangles[n(i)]].x,cloud[triangles[n(i)]].y);
      strokeWeight(1); noStroke();
    }
    //line(cloud[triangles[i]].x,cloud[triangles[i]].y,cloud[triangles[O[i]]].x,cloud[triangles[O[i]]].y);
  }
}
      

void myActions() { // actions to be executed at each frame 
   if(meshAnimating){
     ay+=20;
   }
   if(show3D){
     showTerrain();
     if((mousePressed)&&!keyPressed)  {ax+=mouseY-pmouseY;  az+=mouseX-pmouseX;}
   }
   else if(showMirror){
       showMirror();
       if((mousePressed)&&!keyPressed)  {ax+=mouseY-pmouseY;  az+=mouseX-pmouseX;}
   }
   
   else{
   if((mousePressed)&&!keyPressed) {if(pickedPoint!=null) pickedPoint.trackMouse(); };
   if((mousePressed)&&keyPressed) {if(key=='x') myTranslate(); if(key=='z') myScale(); if(key=='d') D.extendToMouse();};
   if(showFrames) {
     cS.reset(2);
       stroke(cS.next()); 
       prime.drawCurve();
   }
   if(laplaceTolerance){
     //textMode(SCREEN);
     scribe("Laplace tolerance exceeded. Hit 's' to rerun smoothing.",0);
     scribe("If 's' yields no result, try resampling using 't'.",1);
   }
   if(notSet){
     //textMode(SCREEN);
     scribe("Mesh, medial axis samples, and corner tables not set.",2);
     scribe("Press 'e' to compute or draw a smaller figure.",3);
   }
   if(spray[0]==null){mySpray();}
   drawSpray();
   if(showTriangles){
     displayTriangles();
     displayAxis();
   }
   if(showBorder){
     drawBorder();
   }
   if(prime.length()>950.0 && prime.vn<64){
     scribe("Warning: Potential holes in 3D render.",0);
     scribe("Consider refining the polyloop with 'r'.",1);
   }
   if(sketching) {showTriangles=false; stroke(dred,50); noFill(); P.drawSmooth(0,5); fill(red,50); P.rP(0).show(4); fill(yellow,50); P.rP(1).show(3); stroke(red); noFill(); D.drawOpen(); noStroke();}
   if (showEkey) {stroke(red); P.drawCurve(); fill(white); if(showVertices) P.showVertices(); fill(red); P.rP(0).show(4); noFill(); P.rP(1).show(3); };
   if(showMouseProjection) P.showMouseProjection(0,5);  // show closest point on P to mouse green if mouse is inside and red otherwise
   };
};

