import java.lang.Math;



public class Curve extends Object {



 /* following variables are class variables */

 static double xsc, ysc;		// x and y scaling factors

 static int Ox, Oy;			// position of origin on screen (in pixels)

 static int xsize, ysize;		// width and height (in pixels) of drawing area



 /* following methods are class methods */

 // setting the scaling factors

 static void setScale(double xs, double ys) {

  xsc = xs;

  ysc = ys;

 }

 // altering present scaling factors (two forms of arguments)

 static void factorScale(double xf, double yf) {

  xsc *= xf;

  ysc *= yf;

 }

 static void factorScale(double f) {

  xsc *= f;

  ysc *= f;

 }

 // setting the origin's pixel coordinates

 static void setOrigin(int ox, int oy) {

  Ox = ox;

  Oy = oy;

 }

 // altering present origin pixel coordinates

 static void translateOrigin(int tx, int ty) {

  Ox += tx;

  Oy -= ty;

 }

 // various conversion methods

 static double xPixelToPoint(int xpix) {

  return (xpix - Ox)/xsc;

 }

 static double yPixelToPoint(int ypix) {

  return (Oy - ypix)/ysc;

 }

 static int xPointToPixel(double xpt) {

  return (int)(xpt*xsc + Ox);

 }

 static int yPointToPixel(double ypt) {

  return (int)(-ypt*ysc + Oy);

 }

 // the sign of a double dt; i.e. +1 if d>0, -1 if d<0 and 0 if d=0

 static double sign(double d) {

  if (d>0) {

   return 1;

  } else {

   if (d<0) {

    return -1;

   } else {

    return 0;

   }

  }

 }

 // some maths methods

 static double sinh(double t) {

  return (Math.exp(t) - Math.exp(-t))/2;

 }

 static double cosh(double t) {

  return (Math.exp(t) + Math.exp(-t))/2;

 }

 static double tanh(double t) {

  return sinh(t)/cosh(t);

 }

 static double sec(double t) {

  return 1/Math.cos(t);

 }

 static double cosec(double t) {

  return 1/Math.sin(t);

 }

 static double cot(double t) {

  return 1/Math.tan(t);

 }

 // two extreme points of a line given gradient and constant m and c of y=mx+c

 static int[][] lineEnds (double m, double c) {

  int endpoints[][] = new int[2][2];

  double xb = xPixelToPoint(0);

  double xt = xPixelToPoint(xsize);

  double yt = yPixelToPoint(0);

  endpoints[0][0] = 0;

  endpoints[1][0] = yPointToPixel(xb*m+c);

  endpoints[0][1] = xsize;

  endpoints[1][1] = yPointToPixel(xt*m+c);

  return endpoints;

 } 

   

 

 /* following variables are member variables */

 String name;				// name of curve

 double fx[];				// array of x-coords

 double fy[];				// array of y-coords

 double dt;				// the distance for before and after pts

 double fxbefore[];			// arrays of coordinates of

 double fybefore[];			// before and after a point

 double fxafter[];

 double fyafter[];

 int fxpixels[];			// array of x-pixels (for speed)

 int fypixels[];			// array of y-pixels (for speed)

 double tmin;				// parameter start

 double tmax;				// parameter finish

 double t[];				// array of parameter vals

 double td;				// parameter increment

 int nop;					// number of points plotted

 double a, b, c, d, e, f, h, k, m, n, p;// constant variables in equations

 boolean ap, bp, cp, dp, ep, fp, hp, kp, mp, np, pp;//whether variable is used

 double xb, xt, yb, yt;		// x and y max and min values (not necessarily of the curve points

 double xrange, yrange, scalingfactor;	// range of values



 /* Constructor methods (4 in total) */



 public Curve (String name, double tmin, double tmax, double td) {

  this.name = name;

  this.tmin = tmin;

  this.tmax = tmax;

  this.td = td;

  this.nop = (int)((this.tmax - this.tmin)/(this.td));

  this.dt = this.td/10;

  this.t = new double[this.nop+3];

  this.fx = new double[this.nop+3];

  this.fy = new double[this.nop+3];

  this.fxpixels = new int[this.nop+1];

  this.fypixels = new int[this.nop+1];

  this.fxbefore = new double[this.nop+3];

  this.fybefore = new double[this.nop+3];

  this.fxafter = new double[this.nop+3];

  this.fyafter = new double[this.nop+3];

  this.a = 1.0;

  this.b = 0.5;

  this.c = 3.0;

  this.d = -4.0;

  this.e = 1;

  this.f = -1;

  this.h = 2;

  this.k = 2;

  this.m = 5;

  this.n = 3;

  this.p = 4/7;

  this.xb = -5;

  this.xt = 5;

  this.yb = -5;

  this.yt = 5;



  // evaluates parameter array

  for (int i=0; i<=this.nop+2; i++) {

   this.t[i] = this.tmin + (i-1)*this.td;

  }

   

  xrange = xt - xb;

  yrange = yt - yb;



  this.setCurve();



 }



 public Curve (String name, double tmin, double tmax, int nop) {

  this.name = name;

  this.tmin = tmin;

  this.tmax = tmax;

  this.nop = nop;

  this.td = (this.tmax - this.tmin)/(this.nop);

  this.dt = this.td/10;

  this.t = new double[this.nop+3];

  this.fx = new double[this.nop+3];

  this.fy = new double[this.nop+3];

  this.fxpixels = new int[this.nop+1];

  this.fypixels = new int[this.nop+1];

  this.fxbefore = new double[this.nop+3];

  this.fybefore = new double[this.nop+3];

  this.fxafter = new double[this.nop+3];

  this.fyafter = new double[this.nop+3];

  this.a = 1.0;

  this.b = 0.5;

  this.c = 3.0;

  this.d = -4.0;

  this.e = 1;

  this.f = -1;

  this.h = 2;

  this.k = 2;

  this.m = 5;

  this.n = 3;

  this.p = 4/7;

  this.xb = -5;

  this.xt = 5;

  this.yb = -5;

  this.yt = 5;

  

  // evaluates parameter array

  for (int i=0; i<=this.nop+2; i++) {

   this.t[i] = this.tmin + (i-1)*this.td;

  }



  xrange = xt - xb;

  yrange = yt - yb;



  this.setCurve();



 }



 public Curve (String name, double tmin, double tmax, double td, double dt, double xb, double xt, double yb, double yt, double a, double b, double c, double d, double e, double f, double h, double k, double m, double n, double p) {

  this.name = name;

  this.tmin = tmin;

  this.tmax = tmax;

  this.td = td;

  this.nop = (int)((this.tmax - this.tmin)/(this.td));

  this.dt = dt;

  this.t = new double[this.nop+3];

  this.fx = new double[this.nop+3];

  this.fy = new double[this.nop+3];

  this.fxpixels = new int[this.nop+1];

  this.fypixels = new int[this.nop+1];

  this.fxbefore = new double[this.nop+3];

  this.fybefore = new double[this.nop+3];

  this.fxafter = new double[this.nop+3];

  this.fyafter = new double[this.nop+3];

  this.xb = xb;

  this.xt = xt;

  this.yb = yb;

  this.yt = yt;

  this.a = a;

  this.b = b;

  this.c = c;

  this.d = d;

  this.e = e;

  this.f = f;

  this.h = h;

  this.k = k;

  this.m = m;

  this.n = n;

  this.p = p;



  // evaluates parameter array

  for (int i=0; i<=this.nop+2; i++) {

   this.t[i] = this.tmin + (i-1)*this.td;

  }

   

  xrange = xt - xb;

  yrange = yt - yb;



  this.setCurve();



 }



 public Curve (String name, double tmin, double tmax, int nop, double dt, double xb, double xt, double yb, double yt, double a, double b, double c, double d, double e, double f, double h, double k, double m, double n, double p) {

  this.name = name;

  this.tmin = tmin;

  this.tmax = tmax;

  this.nop = nop;

  this.td = (this.tmax - this.tmin)/(this.nop);

  this.dt = dt;

  this.t = new double[this.nop+3];

  this.fx = new double[this.nop+3];

  this.fy = new double[this.nop+3];

  this.fxpixels = new int[this.nop+1];

  this.fypixels = new int[this.nop+1];

  this.fxbefore = new double[this.nop+3];

  this.fybefore = new double[this.nop+3];

  this.fxafter = new double[this.nop+3];

  this.fyafter = new double[this.nop+3];

  this.xb = xb;

  this.xt = xt;

  this.yb = yb;

  this.yt = yt;

  this.a = a;

  this.b = b;

  this.c = c;

  this.d = d;

  this.e = e;

  this.f = f;

  this.h = h;

  this.k = k;

  this.m = m;

  this.n = n;

  this.p = p;



  // evaluates parameter array

  for (int i=0; i<=this.nop+2; i++) {

   this.t[i] = this.tmin + (i-1)*this.td;

  }

   

  xrange = xt - xb;

  yrange = yt - yb;



  this.setCurve();



 } /* end of Constructor methods */



 /* these are the member methods */



 // evaluates coordinate arrays choosing values by name

 public void setCurve () {

  // evaluates the points on the curve

  double tmppoints[][] = this.offPoints(0.0);

  this.fx = tmppoints[0];

  this.fy = tmppoints[1];



  // evaluates pixel-coordinate arrays

  for (int i=0; i<=n; i++) {

   this.fxpixels[i] = xPointToPixel(this.fx[i+1]);

   this.fypixels[i] = yPointToPixel(this.fy[i+1]);

  }



  // sets before and after points

  double tmpbeforepoints[][] = this.offPoints(this.dt);

  double tmpafterpoints[][] = this.offPoints(-this.dt);

  this.fxbefore = tmpbeforepoints[0];

  this.fybefore = tmpbeforepoints[1];

  this.fxafter = tmpafterpoints[0];

  this.fyafter = tmpafterpoints[1];



 } /* end of setCurve method */



 // returns points on curve off the plotting points (coordinate array)



 public double[][] offPoints (double dd) {

  double tmpn;

  double tmppoints[][] = new double[2][this.nop+3];

  if (this.name.equals("Astroid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.pow(a*Math.cos(tt),3.0);

    tmppoints[1][i] = a*Math.pow(a*Math.sin(tt),3.0);

   }

  } else if (this.name.equals("Cardioid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*(1+Math.cos(tt));

    tmppoints[1][i] = a*Math.sin(tt)*(1+Math.cos(tt)); 

   }

  } else if (this.name.equals("Catenary")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = tt-5;

    tmppoints[1][i] = a*cosh((tt-5)/a);

   }

  } else if (this.name.equals("Cayley's Sextic")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*4*Math.pow(Math.cos(tt/3),3);

    tmppoints[1][i] = a*Math.sin(tt)*4*Math.pow(Math.cos(tt/3),3); 

   }

  } else if (this.name.equals("Circle")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt);

    tmppoints[1][i] = a*Math.sin(tt);

   }

  } else if (this.name.equals("Cissoid of Diocles")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = 2*a*Math.cos(tt)*Math.tan(tt)*Math.sin(tt);

    tmppoints[1][i] = 2*a*Math.sin(tt)*Math.tan(tt)*Math.sin(tt); 

   }

  } else if (this.name.equals("Cochleoid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*Math.sin(tt)/tt;

    tmppoints[1][i] = a*Math.pow(Math.sin(tt),2)/tt; 

   }

  } else if (this.name.equals("Conchoid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = Math.cos(tt)*(a+b*sec(tt));

    tmppoints[1][i] = Math.sin(tt)*(a+b*sec(tt)); 

   }

  } else if (this.name.equals("Conchoid of de Sluze")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = Math.cos(tt)*(-a/Math.cos(tt)+(k*k/a)*Math.cos(tt));

    tmppoints[1][i] = Math.sin(tt)*(-a/Math.cos(tt)+(k*k/a)*Math.cos(tt)); 

   }

  } else if (this.name.equals("Cycloid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*(tt-22) - h*Math.sin(tt-22);

    tmppoints[1][i] = a - h*Math.cos(tt-22);

   }

  } else if (this.name.equals("Devil's Curve")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*Math.sqrt( (25-24*Math.pow(Math.tan(tt),2))/(1-Math.pow(Math.tan(tt),2)) );

    tmppoints[1][i] = a*Math.sin(tt)*Math.sqrt( (25-24*Math.pow(Math.tan(tt),2))/(1-Math.pow(Math.tan(tt),2)) ); 

   }

  } else if (this.name.equals("Double Folium")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = 4*a*Math.cos(tt)*Math.cos(tt)*Math.pow(Math.sin(tt),2);

    tmppoints[1][i] = 4*a*Math.sin(tt)*Math.cos(tt)*Math.pow(Math.sin(tt),2); 

   }

  } else if (this.name.equals("Eight Curve")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*Math.sqrt(Math.cos(2*tt))*Math.pow(sec(tt),2);

    tmppoints[1][i] = a*Math.sin(tt)*Math.sqrt(Math.cos(2*tt))*Math.pow(sec(tt),2);

   }

  } else if (this.name.equals("Ellipse")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = this.a*Math.cos(tt);

    tmppoints[1][i] = this.b*Math.sin(tt);

   }

  } else if (this.name.equals("Epicycloid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = (a+b)*Math.cos(tt) - b*Math.cos((a/b+1)*tt);

    tmppoints[1][i] = (a+b)*Math.sin(tt) - b*Math.sin((a/b+1)*tt);

   }

  } else if (this.name.equals("Epitrochoid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = (a+b)*Math.cos(tt) - c*Math.cos((a/b+1)*tt);

    tmppoints[1][i] = (a+b)*Math.sin(tt) - c*Math.sin((a/b+1)*tt);

   }

  } else if (this.name.equals("Equiangular Spiral")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(4*(tt-Math.PI))*Math.exp(cot(b)*4*(tt-Math.PI));

    tmppoints[1][i] = a*Math.sin(4*(tt-Math.PI))*Math.exp(cot(b)*4*(tt-Math.PI));

   }

  } else if (this.name.equals("Fermat's Spiral")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt-24)*Math.sqrt(Math.abs(tt-24))*sign(tt-24);

    tmppoints[1][i] = a*Math.sin(tt-24)*Math.sqrt(Math.abs(tt-24));

   }

  } else if (this.name.equals("Folium")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = Math.cos(tt)*(-b*Math.cos(tt)+4*a*Math.cos(tt)*Math.pow(Math.sin(tt),2));

    tmppoints[1][i] = Math.sin(tt)*(-b*Math.cos(tt)+4*a*Math.cos(tt)*Math.pow(Math.sin(tt),2));

   }

  } else if (this.name.equals("Folium of Descartes")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = 3*a*(tt-10)/(1+Math.pow(tt-10,3.0));

    tmppoints[1][i] = 3*a*Math.pow(tt-10,2.0)/(1+Math.pow(tt-10,3.0));

   }

  } else if (this.name.equals("Freeth's Nephroid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*(1+2*Math.sin(tt/2));

    tmppoints[1][i] = a*Math.sin(tt)*(1+2*Math.sin(tt/2));

   }

  } else if (this.name.equals("Frequency Curve")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = (tt-4);

    tmppoints[1][i] = Math.sqrt(2)*Math.exp(-Math.pow(tt-4,2.0)/2);

   }

  } else if (this.name.equals("Hyperbola")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*sec(tt);

    tmppoints[1][i] = b*Math.tan(tt);

   }

  } else if (this.name.equals("Hyperbolic Spiral")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)/tt;

    tmppoints[1][i] = a*Math.sin(tt)/tt;

   }

  } else if (this.name.equals("Hypocycloid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = (a-b)*Math.cos(tt) + b*Math.cos((a/b-1)*tt);

    tmppoints[1][i] = (a-b)*Math.sin(tt) - b*Math.sin((a/b-1)*tt);

   }

  } else if (this.name.equals("Hypotrochoid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = (a-b)*Math.cos(tt) + c*Math.cos((a/b-1)*tt);

    tmppoints[1][i] = (a-b)*Math.sin(tt) - c*Math.sin((a/b-1)*tt);

   }

  } else if (this.name.equals("Involute of a Circle")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*(Math.cos(tt)+tt*Math.sin(tt));

    tmppoints[1][i] = a*(Math.sin(tt)-tt*Math.cos(tt));

   }

  } else if (this.name.equals("Kampyle of Eudoxus")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = b*b/(a*Math.cos(tt));

    tmppoints[1][i] = b*b*Math.sin(tt)/(a*Math.pow(Math.cos(tt),2));

   }

  } else if (this.name.equals("Kappa Curve")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*cot(tt);

    tmppoints[1][i] = a*Math.cos(tt);

   }

  } else if (this.name.equals("Lame Curves")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmpn = 1/n + 0.0;

    tmppoints[0][i] = a*Math.pow(Math.cos(tt-4)*Math.cos(tt-4),tmpn)*sign(Math.cos(tt-4));

    tmppoints[1][i] = b*Math.pow(Math.sin(tt-4)*Math.sin(tt-4),tmpn)*sign(Math.sin(tt-4));

   }

  } else if (this.name.equals("Lemniscate of Bernoulli")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*Math.sqrt(Math.cos(2*tt));

    tmppoints[1][i] = a*Math.sin(tt)*Math.sqrt(Math.cos(2*tt));

   }

  } else if (this.name.equals("Limacon of Pascal")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = Math.cos(tt)*(b+2*a*Math.cos(tt));

    tmppoints[1][i] = Math.sin(tt)*(b+2*a*Math.cos(tt));

   }

  } else if (this.name.equals("Lissajous Curves")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.sin(n*tt+c);

    tmppoints[1][i] = b*Math.sin(tt);

   }

  } else if (this.name.equals("Lituus")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt-28)/Math.sqrt(Math.abs(tt-28))*sign(tt-28);

    tmppoints[1][i] = a*Math.sin(tt-28)/Math.sqrt(Math.abs(tt-28));

   }

  } else if (this.name.equals("Neile's Semi-cubical Parabola")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = tt-30;

    tmppoints[1][i] = Math.pow(a*(tt-30)*(tt-30),0.33333);

   }

  } else if (this.name.equals("Nephroid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*(3*Math.cos(tt) - Math.cos(3*tt));

    tmppoints[1][i] = a*(3*Math.sin(tt) - Math.sin(3*tt));

   }

  } else if (this.name.equals("Parabola")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = tt-4;

    tmppoints[1][i] = a*(tt-4)*(tt-4)+b*(tt-4)+c;

   }

  } else if (this.name.equals("Pear-shaped Quartic")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = Math.abs(tt-3);

    tmppoints[1][i] = (1/b)*(tt-3)*Math.sqrt(-Math.pow((tt-3),2)+a*Math.abs(tt-3))/2;

   }

  } else if (this.name.equals("Plateau Curves")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*(Math.sin((m+n)*tt))/(Math.sin((m-n)*tt));

    tmppoints[1][i] = (2*a*Math.sin(m*tt)*Math.sin(n*tt))/(Math.sin((m-n)*tt));

   }

  } else if (this.name.equals("Pursuit Curve")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = tt;

    tmppoints[1][i] = c*tt*tt-Math.log(tt);

   }

  } else if (this.name.equals("Quadratrix of Hippias")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = tt-8;

    tmppoints[1][i] = a*cot(Math.PI*(tt-8)/(2*a));

   }

  } else if (this.name.equals("Rhodonea Curves")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*Math.sin(k*tt);

    tmppoints[1][i] = a*Math.sin(tt)*Math.sin(k*tt);

   }

  } else if (this.name.equals("Right Strophoid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(2*tt);

    tmppoints[1][i] = a*Math.cos(2*tt)*Math.tan(tt);

   }

  } else if (this.name.equals("Serpentine")) {

   if (a*b<0) {

    b = -b;

   }

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = tt-5;

    tmppoints[1][i] = a*a*(tt-5)/((tt-5)*(tt-5)+a*b);

   }

  } else if (this.name.equals("Sinusoidal Spirals")) {

   tmpn = 1/p+0.0;

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*Math.pow(Math.cos(p*tt),tmpn);

    tmppoints[1][i] = a*Math.sin(tt)*Math.pow(Math.cos(p*tt),tmpn);

   }

  } else if (this.name.equals("Spiral of Archimedes")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*tt*Math.cos(tt);

    tmppoints[1][i] = a*tt*Math.sin(tt);

   }

  } else if (this.name.equals("Straight Line")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = tt-10;

    tmppoints[1][i] = m*(tt-10)+c;

   }

  } else if (this.name.equals("Talbot's Curve")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = (a*a+f*f*Math.pow(Math.sin(tt),2))*Math.cos(tt)/a;

    tmppoints[1][i] = (1/b)*(a*a-2*f*f+f*f*Math.pow(Math.sin(tt),2))*Math.sin(tt);

   }

  } else if (this.name.equals("Tractrix")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = 1/cosh(tt-5);

    tmppoints[1][i] = tt-5-tanh(tt-5);

   }

  } else if (this.name.equals("Tricuspoid")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*(2*Math.cos(tt)+Math.cos(2*tt));

    tmppoints[1][i] = a*(2*Math.sin(tt)-Math.sin(2*tt));

   }

  } else if (this.name.equals("Trident of Newton")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = tt-4;

    tmppoints[1][i] = c*(tt-4)*(tt-4)+d*(tt-4)+e+f/(tt-4);

   }

  } else if (this.name.equals("Trifolium")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*Math.cos(tt)*(-Math.cos(tt)+4*Math.cos(tt)*Math.pow(Math.sin(tt),2));

    tmppoints[1][i] = a*Math.sin(tt)*(-Math.cos(tt)+4*Math.cos(tt)*Math.pow(Math.sin(tt),2));

   }

  } else if (this.name.equals("Trisectrix of Maclaurin")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = 2*a*Math.cos(tt)*Math.sin(3*tt)/Math.sin(2*tt);

    tmppoints[1][i] = 2*a*Math.sin(tt)*Math.sin(3*tt)/Math.sin(2*tt);

   }

  } else if (this.name.equals("Tschirnhaus' Cubic")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = Math.abs(tt-2);

    tmppoints[1][i] = (tt-2)*Math.sqrt((Math.abs(tt-2)-2*a+a*a/Math.abs(tt-2))/(3*a));

   }

  } else if (this.name.equals("Watt's Curve")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = Math.cos(tt)*Math.sqrt(b*b-Math.pow(a*Math.sin(tt)+(Math.abs(tt-2*Math.PI)/(tt-2*Math.PI))*Math.sqrt(c*c-a*a*Math.pow(Math.cos(tt),2)),2));

    tmppoints[1][i] = Math.sin(tt)*Math.sqrt(b*b-Math.pow(a*Math.sin(tt)+(Math.abs(tt-2*Math.PI)/(tt-2*Math.PI))*Math.sqrt(c*c-a*a*Math.pow(Math.cos(tt),2)),2));

   }

  } else if (this.name.equals("Witch of Agnesi")) {

   for (int i=0; i<=this.nop+2; i++) {

    double tt = this.t[i] + dd;

    tmppoints[0][i] = a*(tt-5);

    tmppoints[1][i] = a/((tt-5)*(tt-5)+1);

   }

  }

  return tmppoints;

 } /* end of offPoints method */



 // scale a curve by factor sc (note: this also works by changing the class variables

 // xsc, ysc and recalculating the pixel arrays for the curve

 public void scale(double sc) {

  xsc *= sc;

  ysc *= sc;

  for (int i=0; i<=this.nop; i++) {

   this.fxpixels[i] = xPointToPixel(this.fx[i+1]);

   this.fypixels[i] = yPointToPixel(this.fy[i+1]);

  }

 }



 // translate the origin and recalculate the curves pixel arrays by (xt,yt)

 public void translate(int xt, int yt) {

  Ox += xt;

  Oy += yt;

  for (int i=0; i<=this.nop; i++) {

   this.fxpixels[i] = xPointToPixel(this.fx[i+1]);

   this.fypixels[i] = yPointToPixel(this.fy[i+1]);

  }

 }





 // beginning of caustic method 1 (with String mode argument)



 public int[][] causticPixels (int zxpix, int zypix, String mode) {



  int causticpixels[][] = new int[2][this.nop+3];

  double x40, x0, y0, x1, y1, x2, y2, x4, y4;

  int xx4, yy4;

  double m0, m1, mm0, mm1, mmm0, mmm1, tt;

  double zx, zy;



  zx = xPixelToPoint(zxpix);

  zy = yPixelToPoint(zypix);



  for (int i=0; i<=this.nop+2; i++) {



   tt = this.t[i];

   x0 = this.fx[i];			/*point on curve*/

   y0 = this.fy[i];



   x1 = this.fxbefore[i];		/*points "before" and "after"*/

   y1 = this.fybefore[i];

   x2 = this.fxafter[i];

   y2 = this.fyafter[i];



   m0 = (y2 - y0)/(x2 - x0);		/*gradients of tangents*/

   m1 = (y1 - y0)/(x1 - x0);



   if (!mode.equals("parallel")) {

    mm0 = (zy - y0)/(zx - x0);		/*gradients of incident rays*/

    mm1 = (zy - y1)/(zx - x1);

   } else {

    if (zx == 0) {

     zx = 0.000001;

    }

    mm0 = zy/zx;			/*gradient of parallel rays*/

    mm1 = mm0;

   }



   mmm0 = (2*m0 - mm0 + mm0*m0*m0)/(1 - m0*m0 + 2*m0*mm0);

	/*grad of reflected rays*/

   mmm1 = (2*m1 - mm1 + mm1*m1*m1)/(1 - m1*m1 + 2*m1*mm1);



   if (mmm0 != mmm1 ) {			/*where reflected rays meet*/

    x4 = (-y0 + y1 + x0 * mmm0 - x1 * mmm1)/(mmm0 - mmm1);

   } else {

    x4 = 0;

   }



   y4 = y0 + mmm0 * (x4 - x0);



   xx4 = xPointToPixel(x4);

   yy4 = yPointToPixel(y4);



   causticpixels[0][i] = xx4;

   causticpixels[1][i] = yy4;



  }



  return causticpixels;



 } /* end of caustic method 1 */



 // beginning of caustic method 2 (without String mode argument)



 public int[][] causticPixels (int zxpix, int zypix) {



  int causticpixels[][] = new int[2][this.nop+3];

  double x40, x0, y0, x1, y1, x2, y2, x4, y4;

  int xx4, yy4;

  double m0, m1, mm0, mm1, mmm0, mmm1, tt;

  double zx, zy;



  zx = xPixelToPoint(zxpix);

  zy = yPixelToPoint(zypix);



  for (int i=0; i<=this.nop+2; i++) {



   tt = this.t[i];

   x0 = this.fx[i];			/*point on curve*/

   y0 = this.fy[i];



   x1 = this.fxbefore[i];			/*points "before" and "after"*/

   y1 = this.fybefore[i];

   x2 = this.fxafter[i];

   y2 = this.fyafter[i];



   //System.out.println("Before "+i1+"; Now "+i+"; After "+(i+1)%(this.nop+1));



   m0 = (y2 - y0)/(x2 - x0);		/*gradients of tangents*/

   m1 = (y1 - y0)/(x1 - x0);



   mm0 = (zy - y0)/(zx - x0);		/*gradients of incident rays*/

   mm1 = (zy - y1)/(zx - x1);



   mmm0 = (2*m0 - mm0 + mm0*m0*m0)/(1 - m0*m0 + 2*m0*mm0);

	/*grad of reflected rays*/

   mmm1 = (2*m1 - mm1 + mm1*m1*m1)/(1 - m1*m1 + 2*m1*mm1);



   if (mmm0 != mmm1 ) {			/*where reflected rays meet*/

    x4 = (-y0 + y1 + x0 * mmm0 - x1 * mmm1)/(mmm0 - mmm1);

   } else {

    x4 = 0;

   }



   y4 = y0 + mmm0 * (x4 - x0);



   xx4 = xPointToPixel(x4);

   yy4 = yPointToPixel(y4);



   causticpixels[0][i] = xx4;

   causticpixels[1][i] = yy4;



  }



  return causticpixels;



 } /* end of caustic method 2 */





 // beginning of evolute method



 public int[][] evolutePixels () {



  int evolutepixels[][] = new int[2][this.nop+3];

  double x0, y0, x1, y1, x2, y2, x4, y4;

  int xx4, yy4;

  double m0, m1, m2, tt;



  for (int i=0; i<=this.nop+2; i++) {



   tt = this.t[i];

   x0 = this.fx[i];			/*point on curve*/

   y0 = this.fy[i];



   x1 = this.fxbefore[i];			/*points "before" and "after"*/

   y1 = this.fybefore[i];

   x2 = this.fxafter[i];

   y2 = this.fyafter[i];



   m1 = -(x1-x0)/(y1-y0);		/*gradient of normals*/

   m2 = -(x2-x0)/(y2-y0);



   x4 = (m1*(x1+x0) - m2*(x2+x0) - y1 + y2)/(m1-m2)/2;

	/*centre of curvature -- where normals meet*/

   y4 = (y1+y0)/2 + m1*(x4 - (x1+x0)/2);



   xx4 = xPointToPixel(x4);

   yy4 = yPointToPixel(y4);



   evolutepixels[0][i] = xx4;

   evolutepixels[1][i] = yy4;



  }



  return evolutepixels;



 } /*end of evolute method*/





 // beginning of pedal method



 public int[][] pedalPixels (int zxpix, int zypix) {



  int pedalpixels[][] = new int[2][this.nop+3];

  double x0, y0, x1, y1, x4, y4;

  int xx4, yy4;

  double m1, m2;

  double zx,zy;



  zx = xPixelToPoint(zxpix);

  zy = yPixelToPoint(zypix);



  for (int i=0; i<=this.nop+2; i++) {

   x0 = this.fx[i];				/*point on curve*/

   y0 = this.fy[i];



   x1 = this.fxafter[i];			/*point "after"*/

   y1 = this.fyafter[i];



   m1 = (y1-y0)/(x1-x0);			/*gradient of tangent*/

   m2 = -1/m1;					/*gradient of perpendicular*/



   x4 = (m1*x0 - m2*zx - y0 + zy)/(m1-m2);	/*point on pedal curve*/

   y4 = y0 + m1*(x4-x0);



   xx4 = xPointToPixel(x4);

   yy4 = yPointToPixel(y4);



   pedalpixels[0][i] = xx4;

   pedalpixels[1][i] = yy4;

  }



 return pedalpixels;



 } /*end of pedal method*/





 // beginning of negative pedal method



 public int[][] negativePedalPixels (int zxpix, int zypix) {



  int negativepedalpixels[][] = new int[2][this.nop+3];

  double x0, y0, x1, y1, x4, y4, x00, y00, x40, y40;

  int xx0, yy0, xx4, yy4, xx00, yy00, xx40, yy40;

  double m0, m1, m2, mm0, mm1, mmm0, mmm1, tt;

  double zx, zy;



  zx = xPixelToPoint(zxpix);

  zy = yPixelToPoint(zypix);



  for (int i=0; i<=this.nop+2; i++) {

   x0 = this.fx[i];		/*point on curve*/

   y0 = this.fy[i];

   x1 = this.fxafter[i];	/*point after*/

   y1 = this.fyafter[i];



   m0 = -(zx-x0)/(zy-y0);	/*gradients of perpendicular to lines lines from points on curve to O*/

   m1 = -(zx-x1)/(zy-y1);



   if ( m0 != m1 ) {

    x4 = (-y0 + y1 + x0*m0 - x1*m1)/(m0-m1);

   } else {

    x4 = 0;

   }

   y4 = y0 + m0*(x4-x0);



   xx4 = xPointToPixel(x4);

   yy4 = yPointToPixel(y4);



   negativepedalpixels[0][i] = xx4;

   negativepedalpixels[1][i] = yy4;

  }



  return negativepedalpixels;



 } /*end of negative pedal method*/





 // beginning of inverse method



 public int[][] inversePixels (int zxpix, int zypix, int cxpix, int cypix) {



  int inversepixels[][] = new int[2][this.nop+3];

  double x0, y0, x4, y4, r0sq;

  int xx4, yy4;

  double zx, zy, cx, cy, rsq;



  zx = xPixelToPoint(zxpix);

  zy = yPixelToPoint(zypix);

  cx = xPixelToPoint(cxpix);

  cy = yPixelToPoint(cypix);

  rsq = (cx-zx)*(cx-zx) + (cy-zy)*(cy-zy);

  if (rsq == 0) {

   rsq = 0.000000001;

  }



  for (int i=0; i<=this.nop+2; i++) {



   x0 = this.fx[i];			/*point on curve*/

   y0 = this.fy[i];



   r0sq = (x0-zx)*(x0-zx) + (y0-zy)*(y0-zy);

   x4 = zx + rsq/r0sq*(x0-zx);		/*x4,y4 is inverse point of x0,y0*/

   y4 = zy + rsq/r0sq*(y0-zy);



   xx4 = xPointToPixel(x4);

   yy4 = yPointToPixel(y4);



   inversepixels[0][i] = xx4;

   inversepixels[1][i] = yy4;



  }



  return inversepixels;



 } /*end of inverse method*/



 // beginning of involute method



 public int[][] involutePixels (int rxpix, int rypix) {



  int involutepixels[][] = new int[2][this.nop+3];

  double  x0, y0, x1, y1, x2, y2, x4, y4, x00, y00, x40, y40;

  int     xx4, yy4;

  double  m, mm, m0, m1, m2, mm0, mm1, mmm0, mmm1;

  boolean start;

  double rx, ry, r;



  rx = xPixelToPoint(rxpix);

  ry = yPixelToPoint(rypix);

  r = Math.sqrt(rx*rx + ry*ry);



  start = true;



  m0  = 0; // this is arbitrary (simply to stop compile-time error of not being initialised)

  mm0 = 0; // this is arbitrary (simply to stop compile-time error of not being initialised)

  x00 = 0; // this is arbitrary (simply to stop compile-time error of not being initialised)

  y00 = 0; // this is arbitrary (simply to stop compile-time error of not being initialised)

  x40 = 0; // this is arbitrary (simply to stop compile-time error of not being initialised)

  y40 = 0; // this is arbitrary (simply to stop compile-time error of not being initialised)



  for (int i=0; i<=this.nop+2; i++) {



   x0 = this.fx[i];						/*point on curve*/

   y0 = this.fy[i];



   x1 = this.fxafter[i];					/*point "after"*/

   y1 = this.fyafter[i];



   m = (y1-y0)/(x1-x0);					

	/*gradient of latest tangent*/

   mm = (x1-x0)/(y1-y0);					/*recip of gradient*/



   if ( Math.abs(x1-x0) > Math.abs(y1-y0) ) {

    if ( ! start ) {

     if ( m != m0 ) {

      x2 = (-y0 + y00 + m*x0 - m0*x00)/(m-m0);		

	/*point where tangents meet*/

     } else {

      x2 = x1;

     }

     y2 = y0 + m*(x2-x0);

     r = Math.sqrt((x2-x40)*(x2-x40) + (y2-y40)*(y2-y40));

	/*distance along last tangent*/

     x4 = x2 + sign(x40 - x2)*r/Math.sqrt(1 + m*m);	

	/*point on latest tangent*/

     y4 = y2 + sign(x40 - x2)*m*r/Math.sqrt(1 + m*m);

    } else {

     x4 = x0 + sign(x0 - x1)*r/Math.sqrt(1 + m*m);

     y4 = y0 + sign(x0 - x1)*m*r/Math.sqrt(1 + m*m);

    }

   } else {

    if ( ! start ) {

     if ( mm != mm0 ) {

      y2 = (-x0 + x00 + mm*y0 - mm0*y00)/(mm-mm0);	

	/*point where tangents meet*/

     } else {

      y2 = y1;

     }

     x2 = x0 + mm*(y2-y0);

     r = Math.sqrt((x2-x40)*(x2-x40) + (y2-y40)*(y2-y40)); 

	/*distance along last tangent*/

     y4 = y2 + sign(y40 - y2)*r/Math.sqrt(1 + mm*mm);	

	/*point on latest tangent*/

     x4 = x2 + sign(y40 - y2)*mm*r/Math.sqrt(1 + mm*mm);

    } else {

     y4 = y0 + sign(y0 - y1)*r/Math.sqrt(1 + mm*mm);

     x4 = x0 + sign(y0 - y1)*mm*r/Math.sqrt(1 + mm*mm);

    }

   }



   x40 = x4;

   y40 = y4;

   m0 = m;

   mm0 = mm;



   xx4 = xPointToPixel(x4);

   yy4 = yPointToPixel(y4);



   involutepixels[0][i] = xx4;

   involutepixels[1][i] = yy4;



   start = false;



  }



  return involutepixels;



 } /*end of involute method */

  

} /* end of Curve class */

