
package curve;
import java.awt.*;

public class BezierCurve extends Curve {

  protected NumericTextField xText[],yText[];
  protected int numPoints;


  // Creates new BezierCurve
  public BezierCurve(DrawCurve aDrawCurve,int aNumPoints) {
    int ctr;
    String s;
    Dimension d;

    numPoints=aNumPoints;
    color=Color.black;
    drawCurve=aDrawCurve;
    if(drawCurve!=null) drawCurve.addCurve(this);
    marker=new Coordinate[numPoints];

    GridBagLayout layout=new GridBagLayout();
    setBackground(Color.lightGray);
    setLayout(layout);
    GridBagConstraints constraints=new GridBagConstraints();

    //Set some defaults
    constraints.weightx=constraints.weighty=1.0;
    constraints.insets=new Insets(1,1,1,1);
    constraints.fill=GridBagConstraints.NONE;

    //Title row
    titleLabel=new Label("Bezier Curve");
    titleLabel.setFont(new Font("Dialog",Font.BOLD,12));
    constraints.gridwidth=GridBagConstraints.REMAINDER;
    layout.setConstraints(titleLabel,constraints);
    add(titleLabel);

    //Add listeners
    MyActionListener actionListener=new MyActionListener();

    //Numbers to substitute into equation
    xText=new NumericTextField[numPoints];
    yText=new NumericTextField[numPoints];

    for(ctr=0;ctr<numPoints;ctr++) {
      s=new Integer(ctr).toString();
      xText[ctr]=addNewVariable(layout,"P"+s+"=",s,actionListener,false);
      yText[ctr]=addNewVariable(layout,null,s,actionListener,true);
    };

    for(ctr=0;ctr<numPoints;ctr++)
    marker[ctr]=new Coordinate(xText[ctr].asDouble(),yText[ctr].asDouble());
  }

  //Get maximum and minimum values of x,y on curve
  public DoubleRect getMinMax() {
    int ctr;
    double yMin,yMax;
    DoubleRect result;

    xMin=xMax=marker[0].x;
    yMin=yMax=marker[0].y;
    for(ctr=1;ctr<numPoints;ctr++) {
      if(marker[ctr].x<xMin) xMin=marker[ctr].x;
      if(marker[ctr].x>xMax) xMax=marker[ctr].x;
      if(marker[ctr].y<yMin) yMin=marker[ctr].y;
      if(marker[ctr].y>yMax) yMax=marker[ctr].y;
    };

    result=new DoubleRect(xMin,yMin,xMax-xMin,yMax-yMin);
    return result;
  };

  //fuction to set a marker, overrides Curve
  public void setMarker(int i,double x,double y) {
    int ctr;
    Coordinate co;

    if(marker!=null) //array initialised
    if(i>=0 && i<marker.length) {
      marker[i].x=x;
      marker[i].y=y;
      xText[i].setText(new PrintableDouble(x).asStringSF(3));
      yText[i].setText(new PrintableDouble(y).asStringSF(3));
    };
  };

  public void setExercise() {
    int ctr;
    for(ctr=0;ctr<numPoints;ctr++) {
      marker[ctr].x=Math.random()*5;
      marker[ctr].y=Math.random()*5;
    };
  }
  
  
  //returns a casteljau calculation for number of knots in an array from
  //firstKnot onwards using parameter t
  //This is public for Bezier DrawCurve to show constructs during animation
  public Coordinate casteljau(Coordinate knot[],int firstKnot,
  int numKnots,double t) {
    Coordinate result,temp;

    if(numKnots==2) {
      result=new Coordinate(knot[firstKnot]);
      result.mul(1-t);
      temp=new Coordinate(knot[firstKnot+1]);
      temp.mul(t);
      result.add(temp);
    } else {
      result=casteljau(knot,firstKnot,numKnots-1,t);
      result.mul(1-t);
      temp=casteljau(knot,firstKnot+1,numKnots-1,t);
      temp.mul(t);
      result.add(temp);
    };
    return result;
  };

  //for param t 0 to 1, return x and y
  public Coordinate getValue(double t) {
    Coordinate result;
    result=casteljau(marker,0,numPoints,t);
    return result;
  };

  //fuction to draw markers and construction lines when called
  public void drawConstructs() {
    int ctr;
    if(drawCurve!=null) {
      for(ctr=0;ctr<numPoints;ctr++) {
        if(ctr>0) {
          drawCurve.drawMarker(this,marker[ctr]);
          drawCurve.drawLine(this,marker[ctr-1],marker[ctr]);
        } else
        drawCurve.drawMarkerP0(this,marker[ctr]);
      }
    }
  }

  //function dealing with changes in numbers
  protected void onActionPerformed(java.awt.event.ActionEvent event) {
    int ctr;
    for(ctr=0;ctr<numPoints;ctr++)
    marker[ctr]=new Coordinate(xText[ctr].asDouble(),yText[ctr].asDouble());
    if(drawCurve!=null) drawCurve.repaint();
  };

  //Function to draw construction lines for animation sequences
  public void drawAnimationConstructs(double t) {
    Coordinate point[][];
    int ctr,ctr2;

    if(drawCurve!=null) {
      point=new Coordinate[2][numPoints];

      //Get markers into array 1
      for(ctr=0;ctr<numPoints;ctr++)
      point[numPoints%2][ctr]=new Coordinate(marker[ctr]);

      //Draw construct stages
      for(ctr=numPoints-1;ctr>=0;ctr--)
      for(ctr2=0;ctr2<ctr;ctr2++) {
        point[ctr%2][ctr2]=casteljau(point[1-ctr%2],ctr2,2,t);
        drawCurve.drawMarker(this,point[ctr%2][ctr2]);
        if(ctr2>0) drawCurve.drawLine(this,point[ctr%2][ctr2-1],
        point[ctr%2][ctr2]);
      }
    }
  }
}