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

//-------------Version Oktober 2002-----------------------------


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

public class HypConstruction extends Thread
{
  HypMover A,B;
  dPoint C,M;
  TCanvas tc;
  Label tl;
  Color dcol=Color.white;   //Depend-Color
  Color mcol=Color.yellow;  //Move-Color
  Color hcol=Color.blue;    //Horizon-Color
  Color[] pcol=new Color[3];  //Points-Colors  
  boolean visible=true;
  boolean e1=true;
  boolean e2=true;
  boolean e3=true;
  boolean mustdrawW=false;
      
  int [][] erzeuger=new int[3][256];
  int dots,iter,ak,bn,cm;
  double alpha,beta,gamma,delta;
  double r,s;

  HypConstruction(TCanvas c,Label l,int d,HypMover ha,HypMover hb)
  {
    tc=c; tl=l;
    A=ha; B=hb;   
    init(); 
    C=new dPoint(dcol,d,tc);
    M=new dPoint(dcol,d,tc);
    defineValues();
  }
  
  void defineValues()
  {
    dPoint F=new dPoint();
    if (dots<=0){dots=100;}    
    if ((ak<=0)|(bn<=0)|(cm<=0)
        |(1.0/(double)ak+1.0/(double)bn+1.0/(double)cm==1.0))
    {
      ak=4; bn=3; cm=3;
    }    
    alpha=Math.PI/ak; beta=Math.PI/bn; gamma=Math.PI/cm;
    delta=Math.PI-(alpha+beta+gamma);
    C.setdPoint(getTrianglePoint(dP(A),dP(B),alpha,beta,gamma));
    F.x=B.getX()+(C.x-B.getX())/2; F.y=B.getY()+(C.y-B.getY())/2;
    M.setdPoint(getTrianglePoint(F,dP(B),Math.PI/2,Math.PI/2-delta/2,delta/2));
    r=abstand(dP(B),M);
    s=Math.sqrt(Math.abs(sqr(abstand(dP(A),M))-sqr(r)));    
  }
  
  void init()
  {
    for (int i=0;i<3;i++)
      for (int j=0;j<256;j++)
        {erzeuger[i][j]=0;}
    erzeuger[0][0]=1;
    erzeuger[1][0]=2;
    erzeuger[2][0]=3;
    dots=500; iter=100;
    ak=4; bn=3; cm=3; 
    pcol[0]=Color.red;
    pcol[1]=Color.blue;
    pcol[2]=Color.orange;       
  }
    
  public void setColors(Color dc,Color mc,Color hc,
                      Color[] pc)
  {
    dcol=dc; mcol=mc; hcol=hc; 
    pcol=pc;
  }
  
  int getint(String z)
  {
    int i=0;
    try
    {
      i=Integer.valueOf(z).intValue();      
    }
    catch (NumberFormatException e){}
    return i;
  }
  
  public void setParams(int k,int n,int m,boolean kv,boolean nv,
     boolean mv,String ek,String en, String em,int dots, int iter)
  {
    int l;
    init();
    ak=k; bn=n; cm=m;
    e1=kv; e2=nv; e3=mv;
    this.dots=dots; this.iter=iter;
    l=ek.length();
    for (int j=0;j<l;j++)
    {
      erzeuger[0][j]=getint(ek.substring(j,j+1));
    }
    l=en.length();
    for (int j=0;j<l;j++)
    {
      erzeuger[1][j]=getint(en.substring(j,j+1));
    }
    l=em.length();
    for (int j=0;j<l;j++)
    {
      erzeuger[2][j]=getint(em.substring(j,j+1));
    }
    defineValues();    
  }       
  
  public void setVisible(boolean v)
  {
    visible=v;
  }
  
  public void setWorld(boolean b)
  {
    mustdrawW=b;
  }
  
  public void run()
  {
    while (true)
    {
      try {sleep(50);}
      catch(InterruptedException e) {}
      if (mustdrawW) drawWorld();      
    }
  }
  
  public void draw()
  {
    defineValues();
    if (visible)
    {
      C.draw(); M.draw();      
      A.draw(); B.draw();
      Point p=A.getPoint();
      Point q=B.getPoint();
      Graphics g=tc.getGraphics();
      g.setColor(dcol);
      g.drawLine(p.x,p.y,q.x,q.y);
      q=C.getPoint();
      g.drawLine(p.x,p.y,q.x,q.y);
            
      int cs=(int)Math.round(s);
      g.setColor(hcol);
      g.drawOval(p.x-cs,p.y-cs,2*cs,2*cs);
      
      q=M.getPoint();
      int cr=(int)Math.round(r);
      g.setColor(dcol);
      g.drawOval(q.x-cr,q.y-cr,2*cr,2*cr);
    }    
  }      
    
  void zSp(dPoint P,int qu,Graphics g)
  {
    int j;    
    Point p;
    g.setColor(pcol[qu]);
    for (int i=0;i<iter;i++)
    {
      j=(int)(Math.random()*3);
      P=transPoint(P,j); 
      p=P.getPoint();      
      g.drawLine(p.x,p.y,p.x,p.y);      
    }     
  }  
  
  public void drawWorld()
  {
    double k;
    dPoint A1=dP(A);
    dPoint B1=dP(B);
    String h=tl.getText();
    tl.setText("drawing..");
    Graphics g=tc.getGraphics();    
    if (e1) for (int i=0;i<dots;i++)
    {
      yield(); if (!mustdrawW) break;
      k=(double)i/(double)dots;
      zSp(getPointOfLine(A1,B1,k),0,g);     
    } 
    if (e2) for (int i=0;i<dots;i++)
    {
      yield(); if (!mustdrawW) break;
      k=(double)i/(double)dots;
      zSp(getPointOfLine(A1,C,k),1,g);      
    }
    if (e3) for (int i=0;i<dots;i++)
    {
      yield(); if (!mustdrawW) break;
      k=(double)i*delta/(double)dots;
      zSp(getPointOfArc(M,B1,k),2,g);
    } 
    tl.setText(h);
    mustdrawW=false;
  }
  
  //----------Mathe-und Hilfs-Routinen----------------------
  
  public dPoint dP(HypMover H)
  {
    double x,y;
    x=H.getX(); y=H.getY();
    dPoint A=new dPoint(x,y);
    return A;
  }
  
  public double sqr(double x)
  {
    return x*x;
  }
  
  public double abstand(dPoint A,dPoint B)
  {
    return Math.sqrt(sqr(B.x-A.x)+sqr(B.y-A.y));
  }  
  
  public dPoint getPointOfLine(dPoint A,dPoint B,double k)
  {
    dPoint p=new dPoint();
    p.x=A.x+k*(B.x-A.x);
    p.y=A.y+k*(B.y-A.y);
    return p;
  }
  
  public dPoint getPointOfArc(dPoint M,dPoint B,double w)
  {
    // M ist der Mittelpunkt des Kreises, B ein Punkt auf 
    // dem Kreisrand
    dPoint p=new dPoint();
    p.x=(B.x-M.x)*Math.cos(w)-(B.y-M.y)*Math.sin(w)+M.x;
    p.y=(B.x-M.x)*Math.sin(w)+(B.y-M.y)*Math.cos(w)+M.y;
    return p;
  }
  
  public dPoint getTrianglePoint(dPoint A,dPoint B,double wa,double wb,double wc)
  {
    double m,z1,z2,z3,z4,wb1,wd;
    dPoint p=new dPoint();
    wd=Math.PI-(wa+wb+wc);
    wb1=wb+wd/2;
    z1=(B.x-A.x)*Math.cos(wa)+(B.y-A.y)*Math.sin(wa);
    z2=(A.x-B.x)*Math.cos(wb1)-(A.y-B.y)*Math.sin(wb1);
    z3=-(B.x-A.x)*Math.sin(wa)+(B.y-A.y)*Math.cos(wa);
    z4=(A.x-B.x)*Math.sin(wb1)+(A.y-B.y)*Math.cos(wb1);
    m=(z4*B.x-z2*B.y-z4*A.x+z2*A.y)/(z1*z4-z2*z3);
    p.x=A.x+m*z1; p.y=A.y+m*z3;
    return p;
  }
  
  public dPoint gSpiegelung(dPoint P,dPoint A,dPoint B)
  {
    double k;
    dPoint p=new dPoint();
    dPoint Q=new dPoint();
    k=(P.x*(B.x-A.x)+P.y*(B.y-A.y)-(A.x*(B.x-A.x)+A.y*(B.y-A.y)))
     /(sqr(B.x-A.x)+sqr(B.y-A.y));
    Q.x=A.x+k*(B.x-A.x); Q.y=A.y+k*(B.y-A.y);
    p.x=2*Q.x-P.x;  p.y=2*Q.y-P.y;
    return p;
  }
  
  public dPoint kSpiegelung(dPoint P,dPoint M,double r)
  {
    double k=(r*r)/(sqr(P.x-M.x)+sqr(P.y-M.y));
    dPoint p=new dPoint();
    p.x=M.x+k*(P.x-M.x);
    p.y=M.y+k*(P.y-M.y);
    return p;
  }
  
  public dPoint transPoint(dPoint P,int z)
  {
    int nr,i;
    i=0;    
    do 
    { 
      nr=erzeuger[z][i];
      switch (nr)
      {
        case 1: P=gSpiegelung(P,dP(A),C); break;        
        case 2: P=gSpiegelung(P,dP(A),dP(B)); break;
        case 3: P=kSpiegelung(P,M,r); break;
      }
      i++;
    } while (nr>0);  
    return P;
  } 
  
//-------------------------------  
//Mathe-Routinen, nicht verwendet
//-------------------------------
  
/*public dPoint dvector(dPoint A,dPoint B)
  {
    dPoint p=new dPoint();
    p.x=B.x-A.x; p.y=B.y-A.y;
    return p;
  }
  
  public double skalar(dPoint A,dPoint B)
  {
    return A.x*B.x+A.y*B.y;
  }
  
  public dPoint vOp(dPoint A,dPoint B,char op,double m,double n)
  {
    dPoint p=new dPoint();
    if (op=='+')
    {
      p.x=m*A.x+n*B.x;
      p.y=m*A.y+n*B.y;
    }
    if (op=='-')
    {
      p.x=m*A.x-n*B.x;
      p.y=m*A.y-n*B.y;
    } 
    return p;   
  }
  
  public double getAngle(dPoint v,dPoint w)
  {
    return Math.acos((v.x*w.x+v.y*w.y)
                /Math.sqrt((v.x*v.x+v.y*v.y)*(w.x*w.x+w.y*w.y)));
  }
  
  public dPoint rotate(dPoint P,dPoint M,double w)
  {
    dPoint p=new dPoint();
    p.x=(P.x-M.x)*Math.cos(w)-(P.y-M.y)*Math.sin(w)+M.x;
    p.y=(P.x-M.x)*Math.sin(w)+(P.y-M.y)*Math.cos(w)+M.y;
    return p;
  }*/
  
}