// Interactive 2D Bezier splines,  Evgeny Demidov 16 June 2001
import java.awt.*;
import java.awt.event.*;
import java.util.StringTokenizer;

public class Bezier extends java.applet.Applet
  implements MouseMotionListener{
Image buffImage;          Graphics buffGraphics;
int n = 4, n1,  w,h,h1,w2;
double[] Px,Py;

public void init() {
  w = Integer.parseInt(getParameter("width"));
  h = Integer.parseInt(getParameter("height"));  h1 = h-1; w2 = w/2;
  String s = getParameter("N"); if (s != null) n = Integer.parseInt(s);
  n1 = n+1;
  Px = new double[n];  Py = new double[n];
  s=getParameter("pts");
  if (s != null){
   StringTokenizer st = new StringTokenizer(s);
   for (int i = 0; i < n; i++){
    Px[i] = w2*Double.valueOf(st.nextToken()).doubleValue();
    Py[i] = h1*Double.valueOf(st.nextToken()).doubleValue();}}
  else{
   Px[0] = .1*w2; Px[1] = .1*w2; Px[2] = .9*w2; Px[3] = .9*w2;
   Py[0] = .1*h1; Py[1] = .9*h1; Py[2] = .9*h1; Py[3] = .1*h1;}
  buffImage = createImage(w, h);
  buffGraphics = buffImage.getGraphics();
  setBackground(Color.white);
  buffGraphics.clearRect(0,0, w, h);
  addMouseMotionListener(this);
  drawFun();
  drawSpline();
}

public void destroy(){ removeMouseMotionListener(this); }
public void mouseMoved(MouseEvent e){}  //1.1 event handling

public void mouseDragged(MouseEvent e) {
  int x = e.getX();  if (x < 0) x = 0;  if (x > w2-3) x = w2-3;
  int y = h1 - e.getY();  if (y < 0) y = 0;  if (y > h1) y = h1;
  int iMin = 0;
  double Rmin = 1e10, r2,xi,yi;
  for (int i = 0; i < n; i++){
   xi = (x - Px[i]); yi = (y - Py[i]);
   r2 = xi*xi + yi*yi;
   if ( r2 < Rmin ){ iMin = i; Rmin = r2;}}
  Px[iMin] = x; Py[iMin] = y;
  drawSpline();
  repaint();
}


public void drawFun(){
  double step = 1./w2, t = step;
  double[] B = new double[n1], Bo = new double[n1], Bold = new double[n1];
  B[1] = Bo[1] = h1;
  Color[] iColor = {Color.gray, Color.red, new Color(0f,.7f,0f),
   Color.blue, Color.magenta, new Color(0f,.8f,.8f), new Color(.9f,.9f,0f) };
  for (int k = 1; k < w2; k++){
   System.arraycopy(B,1,Bold,1,n);
   System.arraycopy(Bo,1,B,1,n);
   for (int j = 1; j < n; j++)
    for (int i = j+1; i > 0; i--)
     B[i] = (1-t)*B[i] + t*B[i-1];
   for (int m = 1; m <= n; m++){
    buffGraphics.setColor(iColor[m % 7]);
    buffGraphics.drawLine(w2+k-1, h1-(int)Bold[m], w2+k, h1-(int)B[m] );}
   t += step;
  }
}

public void drawSpline(){
  double step = 1./w2, t = step;
  double[] Pxi = new double[n], Pyi = new double[n];
  int X,Y, Xold = (int)Px[0], Yold = h1-(int)Py[0];
  buffGraphics.clearRect(0,0, w2, h);
  buffGraphics.setColor(Color.blue);
  for (int i = 0; i < n; i++){
   X = (int)Px[i];  Y = h1-(int)Py[i];
   buffGraphics.drawRect(X-1,Y-1, 3,3);}
  if ( n > 2 ){
   int Xo = Xold, Yo = Yold;
   for (int i = 1; i < n; i++){
    X = (int)Px[i];  Y = h1-(int)Py[i];
    buffGraphics.drawLine(Xo,Yo, X,Y);
    Xo = X;  Yo = Y;}
  }
  buffGraphics.setColor(Color.red);
  for (int k = 1; k < w2; k++){
   System.arraycopy(Px,0,Pxi,0,n);
   System.arraycopy(Py,0,Pyi,0,n);
   for (int j = n-1; j > 0; j--)
    for (int i = 0; i < j; i++){
     Pxi[i] = (1-t)*Pxi[i] + t*Pxi[i+1];
     Pyi[i] = (1-t)*Pyi[i] + t*Pyi[i+1];}
   X = (int)Pxi[0];  Y = h1-(int)Pyi[0];
   buffGraphics.drawLine(Xold,Yold, X,Y );
   Xold = X; Yold = Y;
   t += step;
  }
}

public void paint(Graphics g) {
  g.drawImage(buffImage, 0, 0, this);
//  showStatus( " " + x +"  " + y);
}

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

}