import java.util.Vector;
import java.util.*;

class threeedpoint
{
    double x, y, z;
}

class Test
{
    threeedpoint p;
    double value;
    int ok;
}

class Vertex
{
    threeedpoint position, normal;
}

class Vertices
{
    int count, max;
    Vertex ptr;
}

class Corner
{
    int i, j, k;
    double x, y, z, value;
}

class Cube
{
    int i, j, k;
    Corner[] corners = new Corner[8];
}

class Cubes
{
    Cube cube;
    Cubes next;
}

class CenterList
{
    int i, j, k;
    CenterList next;
}

class CornerList
{
    int i, j, k;
    double value;
    CornerList next;
}

class EdgeList
{
    int i1, j1, k1, i2, j2, k2;
    int vid;
    EdgeList next;
}

class IntList
{
    int i;
    IntList next;
}

class IntLists
{
    IntList list;
    IntLists next;
}

class Implicit
{
 int  gntris;
 int  bounds, i1, i2, i3;
 double size, delta;

 threeedpoint  start;
 Vector  cubes = new Vector();
 Vector  vertices = new Vector();
 Vector  centers = new Vector();
 Vector  corners = new Vector();
 Vector  edges = new Vector();
 Vector  gVertices = new Vector();
 Vector  tVertices = new Vector();

 final int TET = 0;
 final int NOTET = 1;
 final int RES = 10;
 final int L = 0;
 final int R = 1;
 final int B = 2;
 final int T = 3;
 final int N = 4;
 final int F = 5;
 final int LBN = 0;
 final int LBF = 1;
 final int LTN = 2;
 final int LTF = 3;
 final int RBN = 4;
 final int RBF = 5;
 final int RTN = 6;
 final int RTF = 7;
 final int HASHBIT = 5;
 final int LB = 0;
 final int LT = 1;
 final int LN = 2;
 final int LF = 3;
 final int RB = 4;
 final int RT = 5;
 final int RN = 6;
 final int RF = 7;
 final int BN = 8;
 final int BF = 9;
 final int TN = 10;
 final int TF = 11;
 static Vector Cubetable= new Vector(256);
 int[] Corner1 = new int[12];
 int[] Corner2 = new int[12];
 int[] leftface = new int[12];
 int[] rightface = new int[12];
 int RAND()
 {
  return (int)Math.random();
 }
 
 int HASHSIZE()
 {
  return (1<<(3*HASHBIT));
 }
 
 int MASK()
 {
  return ((1<<HASHBIT)-1);
 }

 int HASH(int i, int j, int k)
 {
  return ((((((i)&MASK())<<HASHBIT)|((j)&MASK()))<<HASHBIT)|((k)&MASK()));
 }

 int BIT(int i, int bit)
 {
  return (((i)>>(bit))&1);
 }
 
 int FLIP(int i, int bit)
 {
  return ((i)^1<<(bit));
 }

 double sphere (double x, double y, double z)
{
    double rsq = x*x+y*y+z*z;
    return 1.0/(rsq < 0.00001? 0.00001 : rsq);
}
 

double blob (double x, double y, double z)
{
    return 4.0-sphere(x+1.0,y,z)-sphere(x,y+1.0,z)-sphere(x,y,z+1.0);
}

int triproc(int i1, int i2, int i3, Vector tVertices)
{
    gVertices = tVertices;
    gntris++;
    return 1;
}
 

String polygonize (double size, double bounds, double x, double y, double z, int mode)
{
    int n;
 int noabort=0;
    Test in = new Test();
 Test out = new Test();

    makeCubetable();

    in = find(1, x, y, z);
    out = find(0, x, y, z);

 Cube c = new Cube();
    cubes.addElement(c);
 

    while (cubes != null)
 {
  Cubes temp = new Cubes();

  doCube(c);
  if (noabort==1)
   return "aborted";
  Testface(c.i-1, c.j, c.k, c, L, LBN, LBF, LTN, LTF);
  Testface(c.i+1, c.j, c.k, c, R, RBN, RBF, RTN, RTF);
  Testface(c.i, c.j-1, c.k, c, B, LBN, LBF, RBN, RBF);
  Testface(c.i, c.j+1, c.k, c, T, LTN, LTF, RTN, RTF);
  Testface(c.i, c.j, c.k-1, c, N, LBN, LTN, RBN, RTN);
  Testface(c.i, c.j, c.k+1, c, F, LBF, LTF, RBF, RTF);
    }
    return null;
}
 

void Testface (int i, int j, int k, Cube old, int face, int c1, int c2, int c3, int c4)
{
    Cube newCube = new Cube();
    Cubes oldCubes = new Cubes();
    int[] facebit = new int[6];
    int n, pos = old.corners[c1].value > 0.0 ? 1 : 0, bit = facebit[face];

    if (((old.corners[c2].value > 0)) &&
 ((old.corners[c3].value > 0)) &&
 ((old.corners[c4].value > 0)))
  return;
    if (Math.abs(i) > bounds || Math.abs(j) > bounds || Math.abs(k) > bounds)
  return;

    for (n = 0; n < 8; n++)
  newCube.corners[n] = null;
    newCube.corners[FLIP(c1, bit)] = old.corners[c1];
    newCube.corners[FLIP(c2, bit)] = old.corners[c2];
    newCube.corners[FLIP(c3, bit)] = old.corners[c3];
    newCube.corners[FLIP(c4, bit)] = old.corners[c4];

}
 

Corner setCorner(int i, int j, int k)
{
    Corner c = new Corner();
    int index = HASH(i, j, k);
    CornerList l = new CornerList();
 
 c.i = i;
 c.x = start.x+((double)i-.5)*size;
    c.j = j;
 c.y = start.y+((double)j-.5)*size;
    c.k = k;
 c.z = start.z+((double)k-.5)*size;

    for (; l != null; l = l.next)
 if (l.i == i && l.j == j && l.k == k)
 {
     c.value = l.value;
     return c;
 }

    l = new CornerList();
    l.i = i;
 l.j = j;
 l.k = k;
 c.value = blob(c.x, c.y, c.z);
    l.value = c.value;
    return c;
}
 

Test find(int sign, double x, double y, double z)
{
    int i;
    Test test = new Test();
    double range = size;
 
 test.ok = 1;
    for (i = 0; i < 10000; i++)
 {
  test.p.x = x+range*(RAND()-0.5);
  test.p.y = y+range*(RAND()-0.5);
  test.p.z = z+range*(RAND()-0.5);
  test.value = blob(test.p.x, test.p.y, test.p.z);

  if(sign == test.value )
   return test;
  range = range*1.0005;
    }
    test.ok = 0;
    return test;
}
 

int dotet(Cube c0, int c1, int c2, int c3, int c4)
{
    Corner a = new Corner();
    Corner b = new Corner();
    Corner c = new Corner();
    Corner d = new Corner();

    int index =0;
 int apos=0;
 int bpos=0;
 int cpos=0;
 int dpos=0;
 int e1=0;
 int e2=0;
 int e3=0;
 int e4=0;
 int e5=0;
 int e6=0;

    if (apos > 0.0)
  index += 8;
    if (bpos > 0.0)
  index += 4;
    if (cpos  > 0.0)
  index += 2;
    if (dpos  > 0.0)
  index += 1;
 
    if (apos != bpos)
  e1 = vertid(a, b);
    if (apos != cpos)
  e2 = vertid(a, c);
    if (apos != dpos)
  e3 = vertid(a, d);
    if (bpos != cpos)
  e4 = vertid(b, c);
    if (bpos != dpos)
  e5 = vertid(b, d);
    if (cpos != dpos)
  e6 = vertid(c, d);

    switch (index)
 {
  case 1:
   return triproc(e5, e6, e3, vertices);
  case 2:
   return triproc(e2, e6, e4, vertices);
  case 3:
   return triproc(e3, e5, e4, vertices);
  case 4:
   return triproc(e1, e4, e5, vertices);
  case 5:
   return triproc(e3, e1, e4, vertices);
  case 6:
   return triproc(e1, e2, e6, vertices);
  case 7:
   return triproc(e1, e2, e3, vertices);
  case 8:
   return triproc(e1, e3, e2, vertices);
  case 9:
   return triproc(e1, e5, e6, vertices);
  case 10:
   return triproc(e1, e3, e6, vertices);
  case 11:
   return triproc(e1, e5, e4, vertices);
  case 12:
   return triproc(e3, e2, e4, vertices);
  case 13:
   return triproc(e6, e2, e4, vertices);
  case 14:
   return triproc(e5, e3, e6, vertices);
    }
    return 1;
}

int doCube(Cube c)
{
    IntLists polys;
    int i, index = 0;
 
 for (i = 0; i < 8; i++)
  if (c.corners[i].value > 0.0)
   index += (1<<i);
    for (i = 0; i <8; i++)
 {
  IntList edges;
  int a = -1, b = -1, count = 0;
 
  for (i=0; i<8;i++)
  {
   if (count < 3)
    a = b;
  }
    }
    return 1;
}
 

int nextcwedge(int edge, int face)
{
    switch (edge)
 {
  case LB:
   return (face == L)? LF : BN;
  case LT:
   return (face == L)? LN : TF;
  case LN:
   return (face == L)? LB : TN;
  case LF:
   return (face == L)? LT : BF;
  case RB:
   return (face == R)? RN : BF;
  case RT:
   return (face == R)? RF : TN;
  case RN:
   return (face == R)? RT : BN;
  case RF:
   return (face == R)? RB : TF;
  case BN:
   return (face == B)? RB : LN;
  case BF:
   return (face == B)? LB : RF;
  case TN:
   return (face == T)? LT : RN;
  case TF:
   return (face == T)? RT : LF;
  default:
   return 1;
    }
}
 

int otherface (int edge, int face)
{
    int other = leftface[edge];
    return face == other? rightface[edge] : other;
}
 

void makeCubetable()
{
    int i, e, c;
 int[] done= new int[12];
 int[] pos = new int[8];

    for (i = 0; i < 256; i++)
 {
  for (e = 0; e < 12; e++)
   done[e] = 0;
  for (c = 0; c < 8; c++)
   pos[c] = BIT(i, c);
  for (e = 0; e < 12; e++)
  {
    IntList ints = new IntList();
    ints.i = 0;
    IntLists lists = new IntLists();
    int start = e;
    int edge = e;
    int face = pos[Corner1[e]];
     edge = nextcwedge(edge, face);
     done[edge] = 1;
     if(pos[Corner1[edge]] != pos[Corner2[edge]])
     {
      IntList tmp = new IntList();
      tmp.i = ints.i;
      ints.i = edge;
      ints.next = tmp;
      if (edge == start)
       break;
      face = otherface(edge, face);
     }
   lists.list = ints;
  }
    }
}
 

int setcenter(CenterList table, int i, int j, int k)
{
    int index = HASH(i, j, k);
    CenterList newList, l;
 CenterList q = new CenterList();

    for (l = q; l != null; l = l.next)
  if (l.i == i && l.j == j && l.k == k)
   return 1;
    newList = new CenterList();
    newList.i = i;
 newList.j = j;
 newList.k = k;
 newList.next = q;
    return 0;
}
 

void setedge (EdgeList table, int i1, int j1, int k1, int i2, int j2, int k2, int vid)
{
    int index;
    EdgeList newEdgeList;

    if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2))))
 {
  int t=i1; i1=i2; i2=t; t=j1; j1=j2; j2=t; t=k1; k1=k2; k2=t;
    }
    index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
    newEdgeList = new EdgeList();
    newEdgeList.i1 = i1;
 newEdgeList.j1 = j1;
 newEdgeList.k1 = k1;
    newEdgeList.i2 = i2;
 newEdgeList.j2 = j2;
 newEdgeList.k2 = k2;
    newEdgeList.vid = vid;
}

int getedge (EdgeList table, int i1, int j1, int k1, int i2, int j2, int k2)
{
    EdgeList q= new EdgeList();
    if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2))))
 {
  int t=i1;
  i1=i2;
  i2=t;
  t=j1;
  j1=j2;
  j2=t;
  t=k1;
  k1=k2;
  k2=t;
    }
    for (; q != null; q = q.next)
  if (q.i1 == i1 && q.j1 == j1 && q.k1 == k1 &&
     q.i2 == i2 && q.j2 == j2 && q.k2 == k2)
     return q.vid;
    return -1;
}

int vertid (Corner c1, Corner c2)
{
    Vertex v = new Vertex();
    threeedpoint a= new threeedpoint();
 threeedpoint b= new threeedpoint();
 
    a.x = c1.x;
 a.y = c1.y;
 a.z = c1.z;
    b.x = c2.x;
 b.y = c2.y;
 b.z = c2.z;

    converge(a, b, c1.value, v.position);
    vnormal(v.position, v.normal);
    return (int)c1.value;
}
 

void addtoVertices (Vertices vlist, Vertex v)
{
    if (vlist.count == vlist.max)
 {
  int i;
  Vertex newVertex;

  vlist.max = vlist.count == 0 ? 10 : 2*vlist.count;
  newVertex = new Vertex();
  for (i = 0; i < vlist.count; i++)
  vlist.ptr = newVertex;
    }
}
 

void vnormal (threeedpoint point, threeedpoint v)
{
    double f = blob(point.x, point.y, point.z);

    v.x = blob(point.x+v.x, point.y, point.z)-f;
    v.y = blob(point.x, point.y+v.y, point.z)-f;
    v.z = blob(point.x, point.y, point.z+v.z)-f;
    f = Math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
    if (f != 0.0)
 {
  v.x /= f;
  v.y /= f;
  v.z /= f;
 }
}
 

void converge (threeedpoint p1, threeedpoint p2, double v, threeedpoint p)
{
    int i = 0;
    threeedpoint pos = new threeedpoint();
 threeedpoint neg = new threeedpoint();

    if (v < 0)
 {
  pos.x = p2.x;
  pos.y = p2.y;
  pos.z = p2.z;
 
  neg.x = p1.x;
  neg.y = p1.y;
  neg.z = p1.z;
    }
    else
 {
  pos.x = p1.x;
  pos.y = p1.y;
  pos.z = p1.z;

  neg.x = p2.x;
  neg.y = p2.y;
  neg.z = p2.z;
    }
  p.x = 0.5*(pos.x + neg.x);
  p.y = 0.5*(pos.y + neg.y);
  p.z = 0.5*(pos.z + neg.z);
  if(i++ == RES)
   return;
  if ((blob(p.x, p.y, p.z)) > 0.0)
     {
   pos.x = p.x;
   pos.y = p.y;
   pos.z = p.z;
  }
  else
  {
   neg.x = p.x;
   neg.y = p.y;
   neg.z = p.z;
  }
 
}
}