import java.applet.Applet;
import java.awt.*;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Event;
import java.io.StreamTokenizer;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
 

/** The representation of a 3D model */
class NewModel3D
{
 boolean transformed;
 int tvert[];
 int nvert, maxvert;
 int con[];
 int ncon = 0, maxcon;
 float vert[];
 float xmin, xmax, ymin, ymax, zmin, zmax;
 
 String XCoord, YCoord, ZCoord;
 String message = null;
 
 Matrix3D mat;
 
 NewModel3D ()
 {
  mat = new Matrix3D ();
  mat.xrot(20);
  mat.yrot(30);
 }
 
 // Create a 3D model by parsing the input equations for the X, Y and Z coordinates.
 // The surface is assumed to be a 'ures' by 'vres' grid.
 // The 'U' and 'V' PI values range between 'ulow' to 'uhigh' and 'vlow' to 'vhigh'
 // respectively. The X, Y and Z coordinate equations are input as XCoord, YCoord
 // and ZCoord resp.
 NewModel3D (int item,double ulow, double uhigh, double vlow, double vhigh,
  int ures, int vres, double r1, double r2, double dx, double dy, double dz,
  String XCoord, String YCoord, String ZCoord)
  throws IOException, FileFormatException
 {
     this();

  double x = 0, y = 0, z = 0;
  double x1 = 0, y1 = 0, z1 = 0, x2 = 0, y2 = 0, z2 = 0;
  double d = Math.sqrt(dx*dx+dy*dy+dz*dz);
  double s1 = r1 * 3;
  double s2=r1+d-2*r2;
 
  if(d >= (2*(r1+r2)))
  {
   for (int u=0;u<ures/2;u++)
   {
    for (int v=0;v<=vres;v++)
    {
     x=r1*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.sin((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow));
     y=r1*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.cos((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow));
     z=r1*Math.cos((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow));
     addVert((float)x, (float)y, (float)z);
    }
   }
   for (int u=ures/2;u<ures;u++)
   {
    for (int v=0;v<=vres;v++)
    {
     x=r2*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.sin((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow));
     y=r2*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.cos((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow));
     z=r2*Math.cos((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))+d;
     addVert((float)x, (float)y, (float)z);
    }
   }
  }
  else
  {
   double udelta = (d*ures)/(r1+d+r2);
   double uend = s2*(r1+d+r2)/ures;

   if((d>r1) && (d>r2))
   {
   for (int u=0;u<ures/2;u++)
   {
    for (int v=0;v<=vres;v++)
    {
     z=-u+uend;
     x=z*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.sin((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow));
     y=z*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.cos((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow));
     if(z <= 0)
      addVert((float) x, (float) y, (float) z);
    }
   }

   for (int u=ures/2;u<ures;u++)
   {
    for (int v=0;v<=vres;v++)
    {
     z=-u+ures;
     x=z*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.sin((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow));
     y=z*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.cos((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow));
      z=z-40+d*10;
     addVert((float) x, (float) y, (float) z);
    }
   }
   }
  else
  {
   for (int u=0;u<ures/2;u++)
   {
    for (int v=0;v<=vres*2;v++)
    {
     x=s1*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.sin((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow));
     y=s1*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.cos((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow));
     z=s1*Math.cos((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow));

      addVert((float) x, (float) y, (float) z);
    }
   }

   for (int u=ures/2;u<ures;u++)
   {
    for (int v=0;v<=vres*2;v++)
    {
     x=r2*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.sin((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow))+d;
     y=r2*Math.sin((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))*Math.cos((double)((v*(vhigh-vlow)*Math.PI)/vres + Math.PI*vlow))+d;
     z=r2*Math.cos((double)((u*(uhigh-ulow)*Math.PI)/ures+Math.PI*ulow))+d;
 
     addVert((float) x, (float) y, (float) z);
    }
   }
  }
 }

    // Form the face list of the surface
    int index = 0;
    int check = vres - 1;
    for (int i = 0; i < ures; i++)
 {
  for (int j = 0; j < vres; j++)
  {

   add(index, index + 1);
   add(index + 1, index + vres + 2);
   add(index + vres + 2, index + vres + 1);
   add(index + vres + 1, index);
   if (index == check)
   {
    index+=2;
    check+=vres+1;
   }
   else
    index++;
  }
   }
}
 
  /** Add a vertex to this model */
  int addVert(float x, float y, float z)
  {
    int i = nvert;
 
    if (i >= maxvert)
  if (vert == null)
  {
   maxvert = 100;
   vert = new float[maxvert * 3];
  }
  else
  {
   maxvert *= 2;
   float nv[] = new float[maxvert * 3];
   System.arraycopy(vert, 0, nv, 0, vert.length);
   vert = nv;
  }
    i *= 3;
    vert[i] = x;
    vert[i + 1] = y;
    vert[i + 2] = z;
 
    return nvert++;
  }
 
 
  /** Add a line from vertex p1 to vertex p2 */
  void add(int p1, int p2)
  {
    int i = ncon;
    if (p1 >= nvert || p2 >= nvert)
      return;
    if (i >= maxcon)
  if (con == null)
  {
   maxcon = 100;
   con = new int[maxcon];
  }
 else
 {
  maxcon *= 2;
  int nv[] = new int[maxcon];
  System.arraycopy(con, 0, nv, 0, con.length);
  con = nv;
    }
    if (p1 > p2)
 {
  int t = p1;
  p1 = p2;
  p2 = t;
    }
    con[i] = (p1 << 16) | p2;
    ncon = i + 1;
  }
 
 
  /** Transform all the points in this model */
  void transform()
  {
 if (transformed || nvert <= 0)
      return;
    if (tvert == null || tvert.length < nvert * 3)
      tvert = new int[nvert*3];
    mat.transform(vert, tvert, nvert);
    transformed = true;
  }
 
 /** Sort the array of lines **/
 private void sort(int lo0, int hi0)
 {
  int a[] = con;
  int lo = lo0;
  int hi = hi0;
 
  if (lo >= hi)
   return;
  int mid = a[(lo + hi) / 2];
  while (lo < hi)
  {
   while (lo < hi && a[lo] < mid)
    lo++;
   while (lo < hi && a[hi] >= mid)
   {
    hi--;
   }
   if (lo < hi)
   {
    int T = a[lo];
    a[lo] = a[hi];
    a[hi] = T;
   }
  }
  if (hi < lo)
  {
   int T = hi;
   hi = lo;
   lo = T;
  }
  sort(lo0, lo);
  sort(lo == lo0 ? lo + 1 : lo, hi0);
 }
 
 /** eliminate duplicate lines */
 void compress()
 {
  int limit = ncon;
  int c[] = con;
  sort(0, ncon - 1);
  int d = 0;
  int pp1 = -1;
  for (int i = 0; i < limit; i++)
  {
   int p1 = c[i];
   if (pp1 != p1)
   {
    c[d] = p1;
    d++;
   }
   pp1 = p1;
  }
  ncon = d;
 }
 
 
 /** Find the bounding box of this model */
 void findBB()
 {
  if (nvert <= 0)
   return;
  float v[] = vert;
  float xmin = v[0], xmax = xmin;
  float ymin = v[1], ymax = ymin;
  float zmin = v[2], zmax = zmin;
  for (int i = nvert * 3; (i -= 3) > 0;)
  {
   float x = v[i];
   if (x < xmin)
    xmin = x;
   if (x > xmax)
    xmax = x;
   float y = v[i + 1];
   if (y < ymin)
    ymin = y;
   if (y > ymax)
    ymax = y;
   float z = v[i + 2];
   if (z < zmin)
    zmin = z;
   if (z > zmax)
    zmax = z;
  }
 
  this.xmax = xmax;
  this.xmin = xmin;
  this.ymax = ymax;
  this.ymin = ymin;
  this.zmax = zmax;
  this.zmin = zmin;
 }
}