import java.awt.*;
import java.awt.image.*;
import java.net.*;
import java.applet.Applet;

/*
   horn.java by Marius Watz (amoeba@pobox.com)

   Applet that generates endless series of "horn" shapes,  
   inspired by William Latham's work. The shapes are generated by 
   a set of parameters (number of arms, degree of bend, x-y 
   transformations etc.), creating organic, flower-shapes 
   forms.

   For information on similar algorithmic shapes, see 
   "Evolutionary Art", by William Latham and Stephen Todd.

   Permission is granted to experiment with and modify this applet.
   Redistribution of code based on this applet is allowed as long
   as the code states that it is based on my work. Let me know if
   you do something interesting with it.

   Marius Watz, October 1996.
   amoeba@pobox.com - http://www.pobox.com/~amoeba/ 

*/

public class horn extends java.applet.Applet implements Runnable {
 int xsize,ysize,xcenter,ycenter;
 int delay=1000,letters=150,maxRad,minRad=2;
 long time;
 Graphics backGC;
 Font fnt;
 Image backBuffer;
 double[] x,y,r,speed,yspeed,genes;
 Thread appletThread = null;
 double x1,xstack,ystack,r1,r2,bendDeg;
 int numpts,numarms;
 int running=1;
 Color frontColor,backColor;
 private static final double Deg=(3.14159265358979323846/180);

 void randgenes() {
  double min[]={5,3,0,15,0,0,1,1};
  double max[]={100,20,720,180,180,180,25,25};

  for(int i=0; i<8; i++) genes[i]=Math.random()*max[i]+min[i];
  numpts=(int)genes[0];
  numarms=(int)genes[1];
  bendDeg=genes[2];
  x1=genes[3];
  xstack=genes[4]-min[4]/2;
  ystack=genes[5]-min[5]/2;
  r1=genes[6];
  r2=genes[7];
 }

 void stack(double sx,double sy) {
  double dX,dY;

  dX=sx/(double)(numpts-1);
  dY=sy/(double)(numpts-1);

  for(int i=0; i<numpts; i++) {
   x[i]+=dX*(double)i; y[i]+=dY*(double)i;
  }  
 } 

 void bend(double deg) {
  double D,cosdeg,sindeg,px,py;

  D=(deg/(double)numpts)*Deg;
  for (int i=0;i<numpts;i++) {
   sindeg=Math.sin(D*(double)i); cosdeg=Math.cos(D*(double)i);
   px=x[i]*cosdeg-y[i]*sindeg;
   py=x[i]*sindeg+y[i]*cosdeg;
   x[i]=px; y[i]=py;
  }  
 } 

 void grow(double deg) {
  double D;

  D=(r2-r1)/(double)(numpts-1);

  for(int i=0; i<numpts; i++) {
   r[i]+=D*(double)i;
  }  
 } 

 void fillPointData(int num,double rad) {
  for(int i=0; i<num; i++) {
   x[i]=0; y[i]=0; r[i]=rad;
  }
 }

 public void init() {
  MediaTracker tracker;

  xsize=size().width;
  ysize=size().height;
  xcenter=xsize/2;
  ycenter=ysize/2;

  maxRad=xcenter-10;

  x=new double[300];
  y=new double[300];
  r=new double[300];
  genes=new double[8];

  //Double-buffering
  backBuffer = createImage(xsize, ysize);
  backGC = backBuffer.getGraphics();

  fnt=new Font("Courier",Font.PLAIN,8);
	
  frontColor=new Color(0,0,0);
  backColor=new Color(255,255,255);
 }

 public void start() {
  if(appletThread == null) {
   appletThread = new Thread(this);
   appletThread.start();
  }
 }

 public void stop() {
  appletThread = null;
 }

 public void run() {
  while (appletThread != null) {
   time = System.currentTimeMillis();
   try {
    time += delay;
    Thread.sleep(Math.max(0, time - System.currentTimeMillis()));
   }
   catch (InterruptedException e);

    if(running==1) {
     randgenes();
     fillPointData(numpts,r1);
     grow(r2);
     stack(x1,0);
     bend(bendDeg);
     stack(xstack,ystack);
     repaint();
    }
  }
 }

 public void paint(Graphics g) {
  int which,px,py;
  double D,cosdeg,sindeg;

  //Clear screen
  backGC.setColor(backColor);
  backGC.fillRect(0,0,xsize,ysize);

  backGC.setFont(fnt);
  backGC.setColor(frontColor);

  D=(360/(double)numarms)*Deg;
  for (int i=0;i<numpts;i++) 
   for (int j=0;j<numarms;j++) {
    sindeg=Math.sin(D*(double)j); cosdeg=Math.cos(D*(double)j);
    px=(int)(x[i]*cosdeg-y[i]*sindeg);
    py=(int)(x[i]*sindeg+y[i]*cosdeg);
    backGC.drawOval(xcenter-px,xcenter-py,(int)r[i],(int)r[i]);
   }
  backGC.drawString(numarms+" "+numpts+" "+bendDeg+" "+x1+
   " "+xstack+" "+ystack+" "+r1+" "+r2,5,10);
  //Draw buffer to screen
  g.drawImage(backBuffer, 0, 0, this);
 }


 public void update(Graphics g) {
  paint(g);
 }

 public boolean mouseDown(Event evt, int x, int y) {
  URL url;

  if(running==1) running=0; else running=1;

  if(evt.metaDown()==true)
  try {
   url = new URL("http://www.hok.no/marius/");
   getAppletContext().showDocument(url);
  } catch (Exception e) {};

  return true;
 }  

 public boolean mouseMove(Event evt, int x, int y) {
  getAppletContext().showStatus("horns - marius watz");
  return true;
 }  


}
