import java.applet.Applet;
import java.awt.*;
import java.lang.*;
import java.io.DataInputStream;

abstract class RungeKutta{
      double lag=0.1;
      abstract double[] function(double time,double v[]);
      
      RungeKutta(){}
      RungeKutta(double _lag){lag=_lag;}
      void setLag(double _lag){lag=_lag;}
      static double[] plus(double a[],double b[]){
	    int d=Math.min(a.length,b.length);
	    double ans[]=new double[d];
	    for(int i=0;i<=d-1;i++)ans[i]=a[i]+b[i];
	    return(ans);
      }
      static double[] times(double a[],double b){
	    double ans[]=new double[a.length];
	    for(int i=0;i<=a.length-1;i++)ans[i]=a[i]*b;
	    return(ans);
      }
      static void copy(double a[],double b[]){
	    int d=Math.min(a.length,b.length);
	    for(int i=0;i<=d-1;i++)a[i]=b[i];
      }
      public double update(double time,double v[]){
	    int d=v.length;
	    double f1[],f2[],f3[],f4[],s[];
	    f1=times(function(time,v),lag);
	    f2=times(function(time+lag/2,plus(v,times(f1,0.5))),lag);
	    f3=times(function(time+lag/2,plus(v,times(f2,0.5))),lag);
	    f4=times(function(time+lag,plus(v,f3)),lag);
	    s=times(v,1.0);
	    s=plus(s,times(f1,1.0/6.0));
	    s=plus(s,times(f2,1.0/3.0));
	    s=plus(s,times(f3,1.0/3.0));
	    s=plus(s,times(f4,1.0/6.0));
	    copy(v,s);
	    return(time+lag);
      }
}

class Pendulum extends RungeKutta{
      double g=9.8,mu=1.5;
      public double l1=8.0,l2=5.0;
      Pendulum(){}
      double[] function(double time,double v[]){
	    double ans[]=new double[v.length];
	    double s1=Math.sin(v[0]),c1=Math.cos(v[0]);
	    double s2=Math.sin(v[2]),c2=Math.cos(v[2]);
	    double s12=Math.sin(v[0]-v[2]),c12=Math.cos(v[0]-v[2]);
	    ans[0]=v[1];
	    ans[1]=(g*(s2*c12-mu*s1)-(l2*v[3]*v[3]+l1*v[1]*v[1]*c12)*s12)
	      /l1/(mu-c12*c12);
	    ans[2]=v[3];
	    ans[3]=(g*mu*(s1*c12-s2)+(mu*l1*v[1]*v[1]+l2*v[3]*v[3]*c12)*s12)
	      /l2/(mu-c12*c12);
	    return(ans);
      }
      double[] change(double v[]){
	    double ans[]=new double[v.length];
	    double t=l1+l2;
	    ans[0]=l1*Math.sin(v[0])/t;
	    ans[1]=l1*Math.cos(v[0])/t;
	    ans[2]=l2*Math.sin(v[2])/t+ans[0];
	    ans[3]=l2*Math.cos(v[2])/t+ans[1];
	    return(ans);
      }
}

class PendulumCanvas extends Canvas{
      public int center;
      double points[];

      PendulumCanvas(int size){
	    resize(size,size);
	    center=(int)((double)size/2.0);
      }
      public void paint(Graphics g){
	    int x1,y1,x2,y2;
	    if(points!=null){
		  x1=center+(int)(points[0]*(double)center);
		  y1=center+(int)(points[1]*(double)center);
		  x2=center+(int)(points[2]*(double)center);
		  y2=center+(int)(points[3]*(double)center);
		  g.drawLine(center,center,x1,y1);
		  g.drawLine(x1,y1,x2,y2);
	    }
      }     
}
	    

public class DoublePendulum extends Applet implements Runnable{
      int ranflag=1;
      Pendulum pen;
      double time;
      double v[];
      Thread thread;
      PendulumCanvas canvas;
      Scrollbar penlength1,penlength2;

      public void init(){
	    pen=new Pendulum();
	    v=new double[4];
	    pen.setLag(0.05);
	    v[0]=Math.PI*0.9;
	    v[1]=0.0;
	    v[2]=0.0;
	    v[3]=0.0;
	    time=0.0;
	    setLayout(new BorderLayout());
	    canvas=new PendulumCanvas(200);
	    canvas.setBackground(Color.gray);
	    add("Center",canvas);

	    penlength1=new Scrollbar(Scrollbar.VERTICAL,8,1,1,10);
	    penlength2=new Scrollbar(Scrollbar.VERTICAL,5,1,1,10);
	    add("West",penlength1);
	    add("East",penlength2);
	    Panel p=new Panel();
	    p.add(new Button("start"));
	    p.add(new Button("stop"));
	    add("South",p);

	    canvas.points=pen.change(v);
	    canvas.repaint();
      }

      public void start(){}

      public void stop(){
	    if(thread!=null){
		  thread.stop();
		  thread=null;
	    }
      }

      public void run(){
	    while(true){
		  try{
			Thread.sleep(50);
		  }catch(InterruptedException e){
			break;
		  }
		  time=pen.update(time,v);
		  canvas.points=pen.change(v);

		  canvas.repaint();
	    }
      }

      public boolean action(Event e,Object o){
	    if(e.target instanceof Button){
		  if("start".equals(o)){
			if(thread==null){
			      thread=new Thread(this);
			      thread.start();
			}
		  }
		  else if("stop".equals(o)){
			if(thread!=null){
			      thread.stop();
			      thread=null;
			}
		  }
		  return(true);
	    }
	    return(false);
      }	    
      public boolean mouseDrag(Event e,int x,int y){
	    x=x-canvas.location().x-canvas.center;
	    y=y-canvas.location().y-canvas.center;
	    v[0]=Math.atan((double)x/(double)y);
	    if(y<0.0)v[0]+=Math.PI;
	    v[1]=0.0;
	    canvas.points=pen.change(v);
	    canvas.repaint();
	    return(true);
      }
      public boolean handleEvent(Event e){
	    if(e.target instanceof Scrollbar){
		  pen.l1=(double)penlength1.getValue();
		  pen.l2=(double)penlength2.getValue();
		  v[1]=v[3]=0.0;
		  canvas.points=pen.change(v);
		  canvas.repaint();
		  return(true);
	    }
	    return(super.handleEvent(e));
      }
		  
}

