/*
   Applet: Hillovy ekvipotencialy
   Autor:  Ondrej Psencik
*/


import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.math.*;

public class Hillovy_ekvipotencialy extends Applet implements TextListener, ActionListener{
	static final int sirkaapletu=480;
	static final int vyskaapletu=380;
	
	static final int sir=480;
	static final int vys=330;		
	
	KresliciPanel pan;
	
	Font f;
	
	TextField tf1,tf2,tf3;
	Label l1,l2,l3,l4;
	Button tlacitko;
	
	public void init(){
	  resize(sirkaapletu+4,vyskaapletu);
	  setLayout(null);
	  setBackground(Color.lightGray);
	  
	  f=new Font("Arial",Font.PLAIN,10);
	  FontMetrics fm=getFontMetrics(f);
	  setFont(f);
	  int vf=fm.getHeight();
	  
    pan=new KresliciPanel();
    add(pan);
    pan.setSize(sir,300);
    pan.setLocation(2,32);

	  l1=new Label("hmotnost 1. telesa");
	  l2=new Label("hmotnost 2. telesa");
	  l3=new Label("relativni vzdalenost pruseciku ekvipotencial s osou x");
	  l4=new Label("Hillovy ekvipotencialy");
	  

	  add(l1);
	  add(l2);
	  add(l3);
	  add(l4);
	  
	  l4.setFont(new Font("Arial",Font.BOLD,16));
	  FontMetrics fm2=getFontMetrics(l4.getFont());
	  
	  
	  l1.setSize(fm.stringWidth(l1.getText()),vf);
	  l2.setSize(fm.stringWidth(l2.getText()),vf);
	  l3.setSize(fm.stringWidth(l3.getText()),vf);
	  l4.setSize(fm2.stringWidth(l4.getText()),fm2.getHeight());
	  
	  l1.setLocation(5,342);
	  l2.setLocation(200,342);
	  l3.setLocation(5,362);	  
	  l4.setLocation((int)(sirkaapletu/2-fm2.stringWidth(l4.getText())/2),(int)(15-fm2.getHeight()/2));	  

	  
	  
	  
	  
	  
	  
	  tf1=new TextField("1.0",10);
	  add(tf1);
	  tf1.setFont(f);
	  tf1.setSize(tf1.getMinimumSize());	  
	  tf1.setLocation(100,337);

 	  tf2=new TextField("1.0",10);
	  add(tf2);
	  tf2.setFont(f);	  
	  tf2.setSize(tf2.getMinimumSize());	  
	  tf2.setLocation(295,337);
	  
 	  tf3=new TextField("0.2",10);
	  add(tf3);
	  tf3.setFont(f);	  
	  tf3.setSize(tf3.getMinimumSize());	  
	  tf3.setLocation(295,357);
	  
	  tf1.addTextListener(this);
	  tf2.addTextListener(this);
	  tf3.addTextListener(this);

		tlacitko=new Button("Prekresli");
		add(tlacitko);
		tlacitko.setSize(80,40);
		tlacitko.setLocation(401,337);
		tlacitko.addActionListener(this);

	  repaint();
	}
	
	public void textValueChanged(TextEvent e){
	  
  }
	
  public void actionPerformed(ActionEvent e) {
  	  Double d;
  	  
  	  d=new Double(tf1.getText());
  	  pan.m1=d.doubleValue();
  	  d=new Double(tf2.getText());
  	  pan.m2=d.doubleValue();
  	  d=new Double(tf3.getText());
  	  pan.mi=d.doubleValue();
  	  pan.pamn=0;

    pan.repaint();

  	  
  }


	public void paint(Graphics g) {
	  g.setColor(Color.black);
	  g.drawRect(0,0,sirkaapletu+4,vyskaapletu+2);
	  g.drawRect(1,1,sirkaapletu+2,vyskaapletu);
	  g.drawLine(0,vys+2,sir+4,vys+2);	
	  g.drawLine(tf2.getMinimumSize().width+295+20,vys+2,tf2.getMinimumSize().width+295+20,vyskaapletu);
	  g.drawLine(0,29,sir+4,29);
	}



//vypocetni funkce

  class KresliciPanel extends Panel implements MouseListener{
  	  int hx1=160;
  	  int hx2=320;
  	  int hy1=150;
  	  int hy2=150;
  	  
  	  boolean pocitej=true;
  	  
  	  double pamet[][]=new double[200][2];
  	  int pamn=0;

//konstanty a promenne urcene pro vypocet
  double m1=1.0;
  double m2=1.0;
  double mi=0.2;
  
  int maxx,maxy;		//pro grafiku
  int xasp,yasp;		//pro grafiku
  int i,j,k;				//pro cykly
  int a,b;					//souradnice bodu na obrazovce
  double x,y,x0,y0,oldx,oldy;  //body akt,prv,min
  double fi,fi0,fiold;				//uhly
  double psi0;			//potencial ve vnitr. L. bode
  double r1;				//x L. b
  double t;					//krok
  double q1,q2;			//normovane hmotnosti
//------	
    	 int a1,a2,b1,b2;
    	 double k1,k2,o1,o2; 
//------
      double nx,ny;
  boolean err=false;

    public KresliciPanel() {
    	  addMouseListener(this);
    	  setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
    }

    public void mouseClicked (MouseEvent e)  { 
    	  double x=e.getX();
    	  double y=e.getY();
    	  double roz=hx2-hx1;
    	  
    	  double sx=(x-hx1)/roz;
    	  double sy=(y-hy1)/roz;
    	  this.x=sx; this.y=sy;
    	  pamn+=1;
    	  pamet[pamn][0]=sx;
    	  pamet[pamn][1]=sy;
    	  if ((sx!=r1)&&(sy!=0)) {One_Line(getGraphics(),Color.black);};
    	  
    }
    public void mouseEntered (MouseEvent e)  { 
    }
    public void mouseExited  (MouseEvent e)  { 
    }
    
    public void mouseReleased(MouseEvent e)  {
    }  
 
 	 public void mousePressed(MouseEvent e) {
	 }

//----------






  	  public void paint(Graphics g) {
  	  	 	g.setColor(Color.blue);
  	  	 	g.drawLine(hx1,0,hx1,vys);
  	  	 	g.drawLine(0,hy1,sir,hy1);
  	  	 		
  	  	 	g.setColor(Color.orange);
  	  	 	g.fillOval(hx1-7,hy1-7,14,14);
  	  	 	g.fillOval(hx2-7,hy2-7,14,14);
  	  	 	 
  	
       normovani();
       r1=LBod(q1,q2);
       psi0=potencial(r1,0);
       
       if(mi==0) return;
       /*
  	  	 	x=r1-r1/1000;
  	  	 	y=0;
  	  	 	One_Line();  	  	 	
  	  	 	x=r1+r1/1000;
  	  	 	y=0;
  	  	 	One_Line();  	  	 	
  	  	 	x=r1;y=r1;
  	  	 	One_Line();  	  	 	
			x=r1/2;y=0;  	  	 	
  	  	 	One_Line();
  	  	 	x=r1+r1/2; y=0;
  	  	 	One_Line();  	  	 	*/
  	  	 	for(int i=1;i<(1/mi);i++){
  	  	 	  x=r1; y=1.0-i*(mi);
  	  	 	  One_Line(g,Color.getHSBColor( (float) (i*mi),(float)1,(float)0.5));
  	  	 	}
  	  	 	
  	  	 	for(int i=1;i<(r1/mi);i++){
  	  	 	  x=r1-i*mi; y=0;	
  	  	 	  One_Line(g,Color.getHSBColor( (float) (i*mi),(float)1,(float)0.5));
  	  	 	}

  	  	 	for(int i=1;i<((1-r1)/mi);i++){
  	  	 	  x=r1+i*mi; y=0;	
  	  	 	  One_Line(g,Color.getHSBColor( (float) (i*mi),(float)1,(float)0.5));
  	  	 	}
  	  	 	
					//Lagrange!
  	  	 	x=r1-r1/100;
  	  	 	y=0;
  	  	 	One_Line(g,Color.red);  	  	 	
  	  	 	x=r1+r1/100;
  	  	 	y=0;
  	  	 	One_Line(g,Color.red);
  	  	 	for(int i=1;i<=pamn;i++){
  	  	 	  x=pamet[i][0]; y=pamet[i][1];
  	  	 	  One_Line(g,Color.black);	
  	  	 	}  	  	 	
	  	 	  	  	 	
  	  	 	
  	  }
  	  
    public void normovani(){
      if(m1>m2){
      	  q2=m2/m1;
      	  q1=1;
      } else {
    	    q1=m1/m2;
    	    q2=1;
      }	
    }
    
    public double potencial(double x,double y) {
    	  double denom1,denom2;
    	  denom1=Math.sqrt(x*x+y*y);
    	  denom2=Math.sqrt((x-1)*(x-1)+y*y);
    	  return(q1/denom1+q2/denom2);
    }

    public double uhel(double x, double y) {
        if(potencial(x,y)<psi0) {x=x-r1;}
        else
    	   {if(x>r1){x=x-1;}}
    	 if(x>0){
    	 	   if(y>0){return(Math.atan(y/x));}
    	 	   else {return(2*Math.PI+Math.atan(y/x));}
    	 	   }
    	 if(x<0){
    	     if(y>=0){return(Math.PI+Math.atan(y/x));}
    	     else {return(Math.PI+Math.atan(y/x));}	
    	 }
    	 if(x==0){
    	 	   if(y>0){return(Math.PI/2);}
    	 	   else {return(3*Math.PI/2);}
    	 }
    	 return(0);    	
    } 
    
		public double DeltaFi(double fi, double fiold) {
			if( (fiold<(Math.PI/2)) && (fi>(3*Math.PI/2)) )
			{return( 2*Math.PI+fiold-fi );}
			else {return(fi-fiold);}
		}
		
    public double LBod(double q1, double q2){
    	  if(q1==q2){return(0.5);}
    	  else {return( (q1-Math.sqrt(q1*q2))/(q1-q2) );} 
    }

    public void next_xy() throws Exception {
    	 double x1,y1,x2,y2,r,r0,chyba;
    	 int i=0; err=false;
    	 do {
        next_x(x,y,t);
        x2=nx;
        y2=ny;
        next_x(x,y,t/2);
   	 	 x1=nx;
   	 	 y1=ny;
   	 	 next_x(x1,y1,t/2);
        x1=nx;
        y1=ny;
        r0=Math.sqrt( (x2-x)*(x2-x)+(y2-y)*(y2-y) );
        r=Math.sqrt( (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1) );
        chyba=r/r0;
        if(chyba>1e-4){t=t/2;};
        if(chyba<1e-6){t=2*t;};
        i+=1;
        if((i>100) || (Double.isNaN(x)) || (Double.isNaN(y))){
        	err=true;
        	throw new Exception();}
  	 	
    	 } while ( ((chyba<1e-6) || (chyba>1e-4)) );
    	  x=x2;
    	  y=y2;
    }

    public double f(double x, double y) {
    	  return( +y*q1*Math.pow((x*x+y*y),-1.5)+y*q2*Math.pow((x-1)*(x-1)+y*y,-1.5) );
    }
    
    public double g(double x, double y) {
    	 return( ( -x*q1*Math.pow((x*x+y*y),-1.5)-(x-1)*q2*Math.pow((x-1)*(x-1)+y*y,-1.5) ));
    }
    
    public void next_x(double x,double y, double t){
    	  //return(x-f(x,y)*t);
    	  double K1,K2,K3,K4,L1,L2,L3,L4;
    	  K1=f(x,y);
    	  L1=g(x,y);
    	  K2=f(x+t*K1/2,y+t*L1/2);
    	  L2=g(x+t*K1/2,y+t*L1/2);
    	  K3=f(x+t*K2/2,y+t*L2/2);
    	  L3=g(x+t*K2/2,y+t*L2/2);
    	  K4=f(x+t*K3,y+t*L3);
    	  L4=g(x+t*K3,y+t*L3);
    	  nx=x+(0.166666666666666)*(K1+2*K2+2*K3+K4)*t;
    	  ny=y+(0.166666666666666)*(L1+2*L2+2*L3+L4)*t;
    }


    public void One_Line(Graphics g,Color c){
    	 boolean indikace=false;
    	 int oldx,oldy;
    	 double v=0;

    	 a1=a2=b1=b2=0;
    	 fi0=0;
    	 
    	 t=0.5;
    	 x0=x; y0=y;
    	 k1=x;o1=y;
    	 trans();
    	 oldx=a1;
    	 oldy=b1;
    	 
    	 fi0=0;
    	 fi=uhel(x,y);
 		 g.setColor(c);    	 
		 do 
	   {
        k1=x; o1=y;
   	 	 fiold=fi;
        try{  	
      	 	 next_xy();
     	 	 fi=uhel(x,y);
     	 	 k2=x;o2=y;
     	 	 trans();
	        
				

     		 if((err==false)&&(k1!=0)&&(o1!=0)) {
     		 	
       	 	 fi0=fi0+Math.abs(DeltaFi(fi,fiold));
       	 	 v=vzdal(a1,b1,oldx,oldy);
       	 	 if (fi0>(2*Math.PI) && (y0!=0) && (v<50))  {
       	 	 	       	 	 	g.drawLine(a1,b1,oldx,oldy); break;}
       	 	 else
      		    g.drawLine(a1,b1,a2,b2);

     		 }
       }
        catch (Exception e){
          return;	
        }
    	 }
    	 while ((fi0<=2.0*Math.PI) || v>50 );
    	 k1=x; o1=y;
    	 x=x0;
    	 y=y0;
    	 k2=x; o2=y;
  	 	 trans();
  	 //	 g.setColor(c);
     // g.drawLine(a1,b1,oldx,oldy);

    }
    
    public double vzdal(double k1, double o1, double k2, double o2) {
    	  return(Math.sqrt((k1-k2)*(k1-k2)+(o1-o2)*(o1-o2)));
    }
    
    
    public void trans(){
    	 int roz=hx2-hx1;
    	 Double d1=new Double(k1*roz+hx1);
    	 a1=d1.intValue();
    	 d1=new Double(hy1-o1*roz);
    	 b1=d1.intValue();
    	 d1=new Double(k2*roz+hx1);
    	 a2=d1.intValue();
    	 d1=new Double(hy1-o2*roz);
    	 b2=d1.intValue();

    }

  
  } //KresliciPanel
  	  
  	
}//Applet