import netscape.javascript.*;
import processing.opengl.*;

int cap=10000;                    // size of arrays
float Px = 0.0; float Py = 0.0; // current mouse position

int cam=0;
int vertnum;
int mode=0;
int radius = 100;
float[] x= new float[cap];
float[] y= new float[cap];
float[] z= new float[cap];


int vertprox=0; //index of close verts;
int[] closeverts =new int[cap];

int[] triangles= new int[cap];
int trinum=0;


int[] Vtable= new int[cap];
int[] Otable= new int[cap];
int bluecorn = 0;

float[] xblue=new float[cap];
float[] yblue=new float[cap];
int bluecount=0;

color black = color(0, 0, 0); 
color red = color(200, 0, 0); 
color green = color(0, 200, 0); 
color blue = color(0, 0, 200); 
color yellow = color(250, 250, 130);

int count = 2;                                 // number of original vertices
int bi=0;                                      // index of selected vertex 
int cornum=0;                                  //index of current courner num
int courcount= 2;
  
void setup() { 
    size(600, 600);          // window size and 3D 
      
    
    x[0]= 150.0; y[0]=150.0;
    x[1]= 200.0; y[1]=150.0;
    x[2]= 175.0; y[2]=175.0;
   
   
    Vtable[0]=1;
    Vtable[1]=3;
    Vtable[2]=2;
    for(int i=0; i<cap; i++){Otable[i]=-1;}

    strokeJoin(ROUND); strokeCap(ROUND);
  }

void draw() {  background(255);

  
  x[bi]=mouseX; 
  y[bi]=mouseY;                  // snap selected vertex to mouse position
  x[0]=x[count]; 
  y[0]=y[count];
  //merge();
  int order=0;               // replicate tail up front avoiding end-conditions
  for(int i=2; i<=courcount+1; i=i+3)
  {
   drawTriangle(x[Vtable[i]],y[Vtable[i]],x[Vtable[i-1]],y[Vtable[i-1]],x[Vtable[i-2]],y[Vtable[i-2]],i);
  }
  dispBlue(bluecorn);
  stroke(blue);
  strokeWeight(3.0);
  beginShape(LINE_STRIP);
    for(int i=1; i<=bluecount; i++)
      {
        vertex(xblue[i],yblue[i]);
      }
  endShape();
  
    if(mode==1)
      {
           stroke(red);
           noFill();
           ellipse(mouseX,mouseY,radius,radius);
            
           
             for(int i=0; i<=trinum; i++)
             {
                strokeWeight(2.0);
                stroke(red);
                beginShape(LINE_STRIP);
                vertex(x[Vtable[triangles[i]*3]], y[Vtable[triangles[i]*3]]);
                vertex(x[Vtable[triangles[i]*3 + 1]], y[Vtable[triangles[i]*3 +1]]);
                vertex(x[Vtable[triangles[i]*3 + 2]], y[Vtable[triangles[i]*3 +2]]);
                vertex(x[Vtable[triangles[i]*3]], y[Vtable[triangles[i]*3]]);
                endShape();
               
               }
          stroke(red);
          strokeWeight(7.0);
          beginShape(POINTS);
          for(int j=0; j<=vertprox; j++)
          {
            vertex(x[closeverts[j]],y[closeverts[j]]);
          }
          endShape();
          
                  
      }
  }



 void subdivide(int startvert)
 {
   
   int vertcount= 0;
   int offset=0;
   int nextvert=startvert;
   for(int j=0; j<=vertprox; j++)
     {
       if(x[closeverts[j]]==x[Vtable[startvert]] && y[closeverts[j]]==y[Vtable[startvert]])
       {
         vertcount++;
         offset=0;
       }
       if(x[closeverts[j]]==x[Vtable[next(startvert)]] && y[closeverts[j]]==y[Vtable[next(startvert)]])
       {
         vertcount++;
         offset=1;
       }       
       if(x[closeverts[j]]==x[Vtable[next(next(startvert))]] && y[closeverts[j]]==y[Vtable[next(next(startvert))]])
       {
         vertcount++;
         offset=2;
       }       
      }
     
   float mid1x= (x[Vtable[startvert]]+x[Vtable[next(startvert)]])/2;
   float mid1y= (y[Vtable[startvert]]+y[Vtable[next(startvert)]])/2;
   
   float mid2x= (x[Vtable[next(startvert)]]+x[Vtable[next(next(startvert))]])/2;
   float mid2y= (y[Vtable[next(startvert)]]+y[Vtable[next(next(startvert))]])/2;
   
   float mid3x= (x[Vtable[startvert]]+x[Vtable[next(next(startvert))]])/2;
   float mid3y= (y[Vtable[startvert]]+y[Vtable[next(next(startvert))]])/2;
   
   if(vertcount<2)
    {
       if(offset==0)
       {
         nextvert=startvert;
         count++;
         x[count]= mid1x; 
         y[count]=mid1y; 
         count++;
         x[count]= mid3x; 
         y[count]=mid3y;
        }
        
         if(offset==1)
         {
           nextvert=next(startvert);
           count++;
           x[count]= mid2x; 
           y[count]=mid2y; 
           count++;
           x[count]= mid1x; 
           y[count]=mid1y;
         }
         
         if(offset==2)
         {
           nextvert=next(next(startvert));
           count++;
           x[count]= mid2x; 
           y[count]=mid2y; 
           count++;
           x[count]= mid3x; 
           y[count]=mid3y;
         } 
       
       courcount=courcount+3;
       Vtable[courcount-2]=Vtable[nextvert];
       Vtable[courcount-1]=count-1;
       Vtable[courcount]=count;
       
       courcount=courcount+3;
       Vtable[courcount-2]=Vtable[next(nextvert)];
       Vtable[courcount-1]=Vtable[next(next(nextvert))];
       Vtable[courcount]=count-1;
       
       Vtable[nextvert]=Vtable[next(next(startvert))];
       Vtable[next(startvert)]=count;
       Vtable[next(next(startvert))]=count-1;
       
    
    
    }
    
    else{
    
       count++;
       x[count]= mid1x; 
       y[count]=mid1y; 
       
       count++;
       x[count]= mid2x; 
       y[count]=mid2y;
       
       count++;
       x[count]= mid3x; 
       y[count]=mid3y;    


      
   courcount=courcount+3;
   Vtable[courcount-2]=Vtable[startvert];
   Vtable[courcount-1]=count-2;
   Vtable[courcount]=count;
   
   courcount=courcount+3;
   Vtable[courcount-2]=Vtable[startvert+1];
   Vtable[courcount-1]=count-1;
   Vtable[courcount]=count-2;
   
   courcount=courcount+3;
   Vtable[courcount-2]=Vtable[startvert+2];
   Vtable[courcount-1]=count;
   Vtable[courcount]=count-1;
   
   Vtable[startvert]=count-2;
   Vtable[startvert+1]=count-1;
   Vtable[startvert+2]=count;
   
   Otable[courcount-8] = Vtable[startvert+2];
   Otable[startvert+2]= Vtable[courcount-8];
   Otable[courcount-5] = Vtable[startvert+1];
   Otable[startvert+1]=Vtable[courcount-5];
   Otable[courcount-2]=Vtable[startvert+2];
   Otable[startvert+2]=Vtable[courcount-2];
   }
  merge(); 
  reo(); 
 
  
 }
 void inradius()
 {
     int duplicate=0;
     for(int i=0; i<=vertprox; i++)   //iterate through all close vertexs
     {                                  //find all corners with verts
       for(int j=0;j<=courcount; j++)
       {
         if(closeverts[i]==Vtable[j])
         {
           for(int k=0; k<=trinum; k++)
           {
             if(triangles[k]==floor(j/3))    //check and see if this tri is already selected
               {
                 duplicate=1;
               }
           }
           if(duplicate==0)                //if not, then add it to the selected triangle table
             {
               triangles[trinum]=floor(j/3);
               trinum++;
             }  
           duplicate=0;
         }
       }
     }
 

 }
       
void mousePressed() {                         // to do when mouse is pressed  
  float globalorder=0;
  float middist;
  float bdtemp = 600*600;
  float bd=600*600;      
  float order=0;                      // init square of smallest distance to selected point
  Px=mouseX;   Py=mouseY;                     // save current mouse location
  
  if(mode==0){
  
  for (int i=0; i<=count; i++)         //search for closest vertex
  {
    if (d2(i)<bd) 
      {
        bd=d2(i); 
        bi=i;
      };
   }//search for closest vertex
      
      if(bd>100)
      {
        bi=0;      
        bdtemp=600*600;      
        for(int i=0; i<=courcount; i++)
          {
            if(Otable[i]==-1)
            {
                  if(i<=2){order=i;}
                  else {order=i%3;}
                  
                  if(order==0)
                    {
                      bdtemp=midist(i+1,i+2);
                    }
                  else if(order==1)
                    {
                      bdtemp=midist(i+1,i-1);
                    }
                  else
                  {
                      bdtemp=midist(i-2,i-1);
                  }
                  if(bdtemp<bd)
                  {
                    cornum=i;
                    bd=bdtemp;
                    globalorder=order;
                  }
              
              }

          
            }//find nearest midpoint
            
            if(bd<1000)
            {
                  courcount=courcount+3; 
                  count++;
                  bi=count;
                  x[count]=Px;
                  y[count]=Py;
                  Vtable[courcount]=count;
               
                
                       
                if(globalorder==0)
                  {
                    
                    Otable[courcount]=cornum;
                    Vtable[courcount-2]=Vtable[cornum+2];
                    Vtable[courcount-1]=Vtable[cornum+1];
                    Otable[cornum]=courcount;
                   }
                 if(globalorder==1)
                  {
                    
                    Otable[courcount]=cornum;
                    Vtable[courcount-2]=Vtable[cornum-1];
                    Vtable[courcount-1]=Vtable[cornum+1];
                    Otable[cornum]=courcount;    
                  }
                   if(globalorder==2)
                  {
                    
                    Otable[courcount]=cornum;
                    Vtable[courcount-2]=Vtable[cornum-1];
                    Vtable[courcount-1]=Vtable[cornum-2];
                    Otable[cornum]=courcount;    
                  }
                  
            }
            else
            {
              bi=0;
            }
         
          }
    
    }
    else
      {
        
        for(int i=0;i<=count;i++)
          {
            if(d2(i)<= radius/2*radius/2)
              {
                closeverts[vertprox]=i;
                vertprox++;
              }
          
          }
           inradius();
           for(int j=0; j<trinum; j++)
             {
               subdivide(triangles[j]*3);
             }
             vertprox=0;
             
             trinum=0;
      }//if mode =1;
      
    }

void merge ()
{
    for(int i=0; i<=courcount; i++)
    {
      for(int j=0; j<=count; j++)
      {
        if(dist(x[Vtable[i]],y[Vtable[i]],x[j],y[j])< 5)
        {
          if(Vtable[i]!=j)
          {
            Vtable[i]=j;
          }
        }        
      
      }
    }
    reo();

}

void reo()
{
   for(int i=0; i<=courcount; i++)
       {
         for(int j=0; j<=courcount; j++)
         {
           if(Vtable[next(i)]==Vtable[prev(j)] && Vtable[next(i)] == Vtable[prev(j)])
             {
                 if(Vtable[prev(i)]==Vtable[next(j)] && Vtable[prev(i)] == Vtable[next(j)])
                 {
                   Otable[i]=j;
                   Otable[j]=i;  
                 }
             }    
          }
        }

}
    
void mouseReleased() {                    // do this when mouse released

     merge();
     bi=0;
    
  }
  

void drawTriangle(float x1, float y1, float x2, float y2, float x3, float y3,  int c){
      stroke(green); strokeWeight(0.0); fill(yellow);
      beginShape();  
      vertex(x1,y1);vertex(x2,y2);vertex(x3,y3);
      endShape(); // draw  internal polygon and border
      
      stroke(green); strokeWeight(10);
      beginShape(POINTS);
      vertex(x1,y1);vertex(x2,y2);vertex(x3,y3);
      endShape();
      
      if(Otable[c]==-1)              //distinguish internal and external edges
      {
          stroke(green);
          strokeWeight(3);
          line(x2,y2,x3,y3);
          
       strokeWeight(7);
       beginShape(POINTS);
       vertex((x2+x3)/2,(y2+y3)/2);
       endShape();
        
      }
      else
      {
        stroke(black);
        strokeWeight(3);
        line(x2,y2,x3,y3);
      }
      
      if(Otable[c-1]==-1)
      {
          stroke(green);
          strokeWeight(3);
          line(x1,y1,x3,y3);
          
       strokeWeight(7);
       beginShape(POINTS);
       vertex((x1+x3)/2,(y1+y3)/2);
       endShape();    
      }
      else
      {
          stroke(black);
          strokeWeight(3);
          line(x1,y1,x3,y3);
      }
      
      if(Otable[c-2]==-1)
      {
        stroke(green);
        strokeWeight(3);
        line(x1,y1,x2,y2);
        
       strokeWeight(7);
       beginShape(POINTS);
       vertex((x1+x2)/2,(y1+y2)/2);
       endShape();   
      }
      else
      {
       stroke(black);
       strokeWeight(3.0);
       line(x1,y1,x2,y2);
      }
      
  }
  
void dispBlue(int a)
{
 int mod= 0;
 float xpoint;
 float ypoint;
 if(a<=2)
   {
     mod=a;
   }  
  else
    {
      mod=a%3;
    }
   if(mod==2)
   {
     xpoint= ((x[Vtable[a-1]] + x[Vtable[a-2]])/2);
     ypoint= ((y[Vtable[a-1]] + y[Vtable[a-2]])/2);
   }
   else if(mod==1)
   {
     xpoint= ((x[Vtable[a-1]] + x[Vtable[a+1]])/2);
     ypoint= ((y[Vtable[a-1]] + y[Vtable[a+1]])/2);
   }
   else
   {
     xpoint= ((x[Vtable[a+1]] + x[Vtable[a+2]])/2);
     ypoint= ((y[Vtable[a+1]] + y[Vtable[a+2]])/2);
   }
   
   float deltax=(xpoint-x[Vtable[a]])/5;
   float deltay=(ypoint-y[Vtable[a]])/5;
    
     
       
   stroke(blue);
   strokeWeight(7.0);
   beginShape(POINTS);
   vertex(x[Vtable[a]]+deltax,y[Vtable[a]]+deltay);
   endShape(); 
 

}  

int next(int a)
{
 int mod= 0;
 if(a<=2)
   {
     mod=a;
   }  
  else
    {
      mod=a%3;
    }
   if(mod==2)
   {
     return a-2;
   }
   else 
   {
     return a+1;
   }
}

int prev(int a)
{
 int mod= 0;
 if(a<=2)
   {
     mod=a;
   }  
  else
    {
      mod=a%3;
    }
   if(mod==0)
   {
     return a+2;
   }
   else 
   {
     return a-1;
   }
}
int op(int a)
{
 if(Otable[a]!=-1)
 {
   return Otable[a];
 }
 else
 {
   return a;
 }
}

int right(int a)
{
  if(Otable[next(a)]!=-1)
  {
    return op(next(a));
  }
  else
  {
    return a;
  }
}
int left(int a)
{
  if(Otable[prev(a)]!=-1)
  {
    return op(prev(a));
  }
  else
  {
    return a;
  }
}

int trav(int a)
{
  
      
    return next(op(a));
    
   
  
}

    
float midist(int a, int b)
{
  return( ((x[Vtable[a]]+x[Vtable[b]])/2 - Px) * ((x[Vtable[a]]+x[Vtable[b]])/2 - Px) + 
  ((y[Vtable[a]]+y[Vtable[b]])/2 - Py) * ((y[Vtable[a]]+y[Vtable[b]])/2 - Py));

}

        

  
void keyPressed() {  
  if (key=='n') {bluecorn=next(bluecorn);}; // print coordinates
  if (key=='p') {bluecorn=prev(bluecorn);}; // saves tif image 
  if (key=='o') {bluecorn=op(bluecorn);};
  if (key=='r') {bluecorn=right(bluecorn);} 
  if (key=='l') {bluecorn=left(bluecorn);}
  if (key=='t') 
      {
          bluecount=bluecount+2;
          xblue[bluecount-1]=x[Vtable[bluecorn]];
          xblue[bluecount]=x[Vtable[trav(bluecorn)]];
          yblue[bluecount-1]=y[Vtable[bluecorn]];
          yblue[bluecount]=y[Vtable[trav(bluecorn)]];
          bluecorn=trav(bluecorn);
          
          
       }
   if(key == 'c')
   {
       if(mode==0){mode = 1;}
       else{mode=0;}
         
   }
   
   if(key == '3')
   {
       if(cam==0){cam = 1;}
       else{cam=0;}
         
   }
   
  };
 
int n(int j) {  if (j==count) {return (1);}  else {return(j+1);}  };  // next vertex in loop
   
float d2(int j) {return (x[j]-Px)*(x[j]-Px)+(y[j]-Py)*(y[j]-Py);};   //  squared distance to vertex

float dist(int x1, int y1, int x2, int y2) {return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);}; //dist two points 

float dm(int j) {return ((x[j]+x[j+1])/2-Px)*((x[j]+x[j+1])/2-Px)    // squared distance to mid-edge point
                        +((y[j]+y[j+1])/2-Py)*((y[j]+y[j+1])/2-Py);};


