import processing.core.*; import java.applet.*; import java.awt.*; import java.awt.image.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.text.*; import java.util.*; import java.util.zip.*; public class virtual_plant extends PApplet {//***************************************************************************************************/
//* Author: Joo Youn Paek                                                                           */
//* Description: ICM Midterm Assignment verson 1. for Monday's 3:30 PM Class                        */
//*             A surface filled with Asian waterpainting animation                                 */ 
//*             interaction with mouse release and mouse move                                               */
//* Date: 10/31/2005                                                                                */        
//***************************************************************************************************/


//Declare global variable
boolean start;
boolean grow;
float growingX;
float growingY;

//creating leafs
boolean startLeaf;
int numLeaf = 5; //amount of lines for the leaf


//declaring the object(Leafs) from class Leaf
Leaf[] Leafs = new Leaf[numLeaf]; 

//creating seed to trunk
//Declare and construct a object "seeds" from the class "Seed"
Seed seeds = new Seed();


public void setup() 
{
  framerate(100);
  size(800,600);
  smooth();
  noStroke();
  background(255);

  start = true;
  grow = false;
  startLeaf = false;  
}

//planting the seed 
//Distinguish the first mouse press(inflanting seed) between next mouse release(growing the trunk)
//using boolean start
public void mousePressed() 
{
  if (start == true)
  {
    seeds = new Seed(mouseX, mouseY, random(3,7));
  }
  else if (start == false)
  {
    growingX = mouseX;
    growingY = mouseY;
  }  
}


public void mouseMoved()
{
if (start == true)
  {
    seeds = new Seed(mouseX, mouseY, random(3,7));
  }
  else if (start == false)
  {
    growingX = mouseX;
    growingY = mouseY;
  }  
}



public void mouseReleased() 
{
  
    //position the leafs at mouseX and mouseY

   for(int i = 0; i < numLeaf; i++) 
    { 
      Leafs[i] = new Leaf(mouseX, mouseY, PApplet.toInt(random(2, 6))*10, random(-0.25f, 0.25f), random(-0.25f, 0.25f), i);                                                                         
      seeds= new Seed(mouseX, mouseY, random(3,7)); 
    }

    ellipseMode(CENTER); 

    startLeaf = true;
    grow = true;
    start = false;
  
}



//growing the trunk
//Using function growAgain,
public void draw() 
{
  seeds.growAgain(growingX, growingY);
  seeds.display();


  //with the boolean (start) continue to create leafs at same location     
  if (startLeaf == true)
  {
    stroke(0, 10); 
    //updating the location of the leaf
    for(int i=0; i < numLeaf; i++) 
    { 
      Leafs[i].update(); 
    } 
    //moving the lines each time to create various leaf images  
    for(int i=0; i<numLeaf; i++) 
    {   
      Leafs[i].move(); 
    }
  } 
}









 
 


 
//creating leaf animation with drawing lines 
class Leaf 
{ 
  float x, y, r, r2, sp, ysp; 
  int id; 
 
  Leaf( float px, float py, float pr, float psp, float pysp, int pid ) 
  { 
    x = px; 
    y = py; 
    r = pr; 
    r2 = r*r; 
    id = pid; 
    sp = psp; 
    ysp = pysp; 
  } 
  
  public void update() 
  { 
    for(int i = 0; i< numLeaf; i++) 
    { 
      if(i != id) 
      { 
        intersect( this, Leafs[i] ); 
      } 
    } 
  } 
  
  public void move() 
  { 
    x += sp; 
    y += ysp; 
    
    if(sp > 0) 
    { 
      if(x > width+r) 
      { 
        x = -r; 
      }   
    } 
    else 
    { 
      if(x < -r) 
      { 
        x = width+r; 
      } 
    } 
    if(ysp > 0) 
    { 
      if(y > height+r) 
      { 
        y = -r; 
      } 
    } 
    else 
    { 
      if(y < -r) 
      { 
        y = height+r; 
      } 
    } 
  } 
} 
 
 
public void intersect( Leaf cA, Leaf cB ) 
{ 
  float dx = cA.x - cB.x; 
  float dy = cA.y - cB.y; 
  float d2 = dx*dx + dy*dy; 
  float d = sqrt( d2 ); 
 
  if ( d>cA.r+cB.r || d<abs(cA.r-cB.r) ) 
  { 
    return;  
  } 
  
  float a = (cA.r2 - cB.r2 + d2) / (2*d); 
  float h = sqrt( cA.r2 - a*a ); 
  float x2 = cA.x + a*(cB.x - cA.x)/d; 
  float y2 = cA.y + a*(cB.y - cA.y)/d; 
 
  float paX = x2 + h*(cB.y - cA.y)/d; 
  float paY = y2 - h*(cB.x - cA.x)/d; 
  float pbX = x2 - h*(cB.y - cA.y)/d; 
  float pbY = y2 + h*(cB.x - cA.x)/d; 
 
  stroke(dist(paX, paY, pbX, pbY)*4, 80); 
  line(paX, paY, pbX, pbY); 
} 
 
 


//seed & trunk object
//growAgain & display function

class Seed 
{
  float bx, by;
  float sSize;
  int sColor;

  //minimum distance between the ellipse
  int MIN_DISTANCE = 1;
  float angle = 1;



 Seed()
  {
  }

  Seed(float x, float y, float s) 
  {
    bx = x;

    by = y;

    sSize = s;
    
    sColor = color(random(200),40);
  }

  

//using boolean (grow) to check the second or more release
//growing toward the next mouse release
  public void growAgain(float xx, float yy)
  {
    if (grow == true) 
    {
      float x = xx;
      float y = yy;

      if ( sqrt( sq(x - bx) + sq(y - by)) > MIN_DISTANCE ) 
      {
        angle = atan2(x - bx, y - by);

        bx += MIN_DISTANCE * sin(angle); 

        by += MIN_DISTANCE * cos(angle);
        
        bx += noise(bx);

        by += noise(by);
      }
    }  
  }


//displaying the ellipse to make the grow animation  
//translating the 0,0 position to move the ellipse
  public void display()
  {

    fill(sColor);

    pushMatrix();

    translate(bx, by);

    ellipse(0, 0, sSize, sSize);

    popMatrix();
  }
}
}