p3 [] spray3D = new p3[5000];
p3 [] mirrorMesh = new p3[5000];
int [] trianglesDouble = new int[5000];

float ax=800, ay = 500, az=0;                          // camera angles
boolean showImage=false;
boolean show3D = false;
boolean showMirror = false;
boolean meshAnimating = false;

float zMax=0, zMin=0;

void convert2D(){
  spray3D = new p3[cloud.length];
  for (int i=0; i<cloud.length; i++){
    float zPos = computeZ(cloud[i]); 
//    print(spray3D[i].x + " " + spray3D[i].y + " " + spray3D[i].z + "\n");
//    print(cloud[triangles[i]] + "\n");
    spray3D[i] = new p3(cloud[i].x, cloud[i].y, zPos);
  }
  /*
  for (int i=0; i<spray3D.length; i++)
  {
    spray3D[i].z = adjustZ(spray3D[i]);
  }
  */
  
}

void myBulge(){
  convert2D();
  stitchMesh();
  doubleVertices(); 
  showTerrain();
}

float computeZ(pt p){
  float zPos=0;
  for(int i=0; i<medAxis.length; i++){
    if(medAxis[i]!=null){
      float d = d(p,medAxis[i]);
      if(d<medAxisR[i]){
        float temp = sqrt(sq(medAxisR[i])-sq(medAxis[i].x-p.x)-sq(medAxis[i].y-p.y));
        zPos = max(temp,zPos);
        if(temp>0){
          zMin = min(temp,zMin);
        }
      }
    }
  }    
  return zPos;
}

float adjustZ(p3 p)
{
  float zPos = p.z;
  if(zPos>0){
    zPos = zPos-30.0;
  }
  return zPos;
}



void stitchMesh()
{
  for (int i = 0; i<spray3D.length; i++)
  {
    for (int j = 0; j<prime.vn; j++)
    {
      if((spray3D[i].x == prime.rP(j).x) && (spray3D[i].y == prime.rP(j).y))
      {
        spray3D[i].z = 0;
        /*float minDis = 10000;
        for (int k = 0; k<medAxis.length; k++)
        {
          if(medAxis[k] != null){
            p3 med3D = new p3(medAxis[k].x, medAxis[k].y, 0);
            if ( spray3D[i].disTo(med3D)<minDis){
              minDis = spray3D[i].disTo(med3D);
              spray3D[i] = between(spray3D[i], .1, med3D);          
            }
          }
        }
        */
      }
    }
  }
}

void doubleVertices(){
  mirrorMesh = new p3[spray3D.length*2];
  trianglesDouble = new int[triangles.length*2];
  for(int i = 0; i<spray3D.length; i++)
  {
    mirrorMesh[i] = spray3D[i];
    mirrorMesh[i+spray3D.length] = new p3(spray3D[i].x, spray3D[i].y, spray3D[i].z*-1);
  }
  for(int j = 0; j<triangles.length; j++)
  {
    trianglesDouble[j] = triangles[j];
    trianglesDouble[j+triangles.length] = triangles[j]+spray3D.length;       
  }
}


void showTerrain() {
  lights();
  translate(width/2,height/2,-150);
  rotateX(PI/2.-ax*PI/height/2.);
  rotateZ(-az*PI/width/4.);
  rotateY(PI/2.-ay*PI/height/2.);
  translate(-width/2,-height/2,0);
  
  if (showImage) scale(1,1,0); 
  paintTerrain();
  }
  
  
  
void paintTerrain() {         // renders the terrain with color as a function of height
   //stroke(255);
   noStroke(); 
           
  
     beginShape(TRIANGLES);
          
       for (int i=0; i<triangles.length-2; i+=3) {
           //fill(255, int((spray3D[triangles[i]].z/zMax) * 255.0), 0);
           fill(120);  
           vertex(spray3D[triangles[i]].x, spray3D[triangles[i]].y, spray3D[triangles[i]].z);
           vertex(spray3D[triangles[n(i)]].x, spray3D[triangles[i+1]].y, spray3D[triangles[i+1]].z);
           vertex(spray3D[triangles[p(i)]].x, spray3D[triangles[i+2]].y, spray3D[triangles[i+2]].z);
                   
     }           
     endShape(); 
   };
   
   
void showMirror() {
  lights();
  translate(width/2,height/2,-150);
  rotateX(PI/2.-ax*PI/height/2.);
  rotateZ(-az*PI/width/4.);
  rotateY(PI/2.-ay*PI/height/2.);
  translate(-width/2,-height/2,0);
  if (showImage) scale(1,1,0); 
  paintMirror();
  }
  
  
  
void paintMirror() {         // renders the terrain with color as a function of height
   //stroke(255); 
   
   noStroke();    
  
     beginShape(TRIANGLES);        
       
       for (int i=0; i<trianglesDouble.length-2; i+=3) {
          //fill(255, int((mirrorMesh[trianglesDouble[i]].z/zMax) * 255.0), 0);
           fill(120);    
           vertex(mirrorMesh[trianglesDouble[i]].x, mirrorMesh[trianglesDouble[i]].y, mirrorMesh[trianglesDouble[i]].z);
           vertex(mirrorMesh[trianglesDouble[n(i)]].x, mirrorMesh[trianglesDouble[i+1]].y, mirrorMesh[trianglesDouble[i+1]].z);
           vertex(mirrorMesh[trianglesDouble[p(i)]].x, mirrorMesh[trianglesDouble[i+2]].y, mirrorMesh[trianglesDouble[i+2]].z);
           
        }           
     endShape(); 
   };   
   
void saveMesh()
{
  prime.savePts();
}

void loadMesh()
{
  prime.loadPts();
  mySpray();
  
}

