public class Shape3D {
	public double vertices[][];
	public int faces[][];
	public Matrix3D M = new Matrix3D();

	public Shape3D() {
		cube();
	}

	public void cube() {
		vertices = new double[8][3];
		vertices[0][0] =  1; vertices[0][1] =  1; vertices[0][2] =  1;	// right, top, front
		vertices[1][0] = -1; vertices[1][1] =  1; vertices[1][2] =  1;	// left, top, front
		vertices[2][0] =  1; vertices[2][1] = -1; vertices[2][2] =  1;	// right, bottom, front
		vertices[3][0] = -1; vertices[3][1] = -1; vertices[3][2] =  1;	// left, bottom, front
		vertices[4][0] =  1; vertices[4][1] =  1; vertices[4][2] = -1;	// right, top, back
		vertices[5][0] = -1; vertices[5][1] =  1; vertices[5][2] = -1;	// left, top, back
		vertices[6][0] =  1; vertices[6][1] = -1; vertices[6][2] = -1;	// right, bottom, back
		vertices[7][0] = -1; vertices[7][1] = -1; vertices[7][2] = -1;	// left, bottom, back

		faces = new int[6][4];
		faces[0][0] = 1; faces[0][1] = 3; faces[0][2] = 2; faces[0][3] = 0;	// front
		faces[1][0] = 4; faces[1][1] = 6; faces[1][2] = 7; faces[1][3] = 5;	// back
		faces[2][0] = 5; faces[2][1] = 7; faces[2][2] = 3; faces[2][3] = 1;	// left
		faces[3][0] = 0; faces[3][1] = 2; faces[3][2] = 6; faces[3][3] = 4;	// right
		faces[4][0] = 5; faces[4][1] = 1; faces[4][2] = 0; faces[4][3] = 4;	// top
		faces[5][0] = 3; faces[5][1] = 7; faces[5][2] = 6; faces[5][3] = 2;	// bottom
	}

	public void cone() {
		final int n = 50;
		final double delta_phi = 2*Math.PI/n;

		vertices = new double[n + 2][3];
		for (int i = 0; i < n; i++) {
			vertices[i][0] = Math.cos(i*delta_phi);	// base
			vertices[i][1] = -1;			// |
			vertices[i][2] = Math.sin(i*delta_phi);	// |
		}
		vertices[n    ][0] =  0; vertices[n    ][1] = -1; vertices[n    ][2] =  0;	// center of base
		vertices[n + 1][0] =  0; vertices[n + 1][1] =  1; vertices[n + 1][2] =  0;	// tip

		faces = new int[2*n][3];
		for (int i = 0; i < n - 1; i++) {
			faces[i    ][0] = n;		// base
			faces[i    ][1] = i;		// |
			faces[i    ][2] = i + 1;	// |
			faces[i + n][0] = n + 1;	// side
			faces[i + n][1] = i + 1;	// |
			faces[i + n][2] = i;		// |
		}
		faces[  n - 1][0] = n;		// base
		faces[  n - 1][1] = n - 1;	// |
		faces[  n - 1][2] = 0;		// |
		faces[2*n - 1][0] = n + 1;	// side
		faces[2*n - 1][2] = 0;		// |
		faces[2*n - 1][2] = n - 1;	// |
	}

	public void cylinder() {
		final int n = 50;
		final double delta_phi = 2*Math.PI/n;

		vertices = new double[2*n + 2][3];
		for (int i = 0; i < n; i++) {
			vertices[i    ][0] = Math.cos(i*delta_phi);	// bottom
			vertices[i    ][1] = -1;			// |
			vertices[i    ][2] = Math.sin(i*delta_phi);	// |
			vertices[i + n][0] = Math.cos(i*delta_phi);	// top
			vertices[i + n][1] =  1;			// |
			vertices[i + n][2] = Math.sin(i*delta_phi);	// |
		}
		vertices[2*n    ][0] =  0; vertices[2*n    ][1] = -1; vertices[2*n    ][2] =  0;	// center of bottom
		vertices[2*n + 1][0] =  0; vertices[2*n + 1][1] =  1; vertices[2*n + 1][2] =  0;	// center of top

		faces = new int[4*n][3];
		for (int i = 0; i < n - 1; i++) {
			faces[i      ][0] = 2*n;	// bottom
			faces[i      ][1] = i;		// |
			faces[i      ][2] = i + 1;	// |
			faces[i +   n][0] = i;		// side (2 vertices on top)
			faces[i +   n][1] = i + n;	// |
			faces[i +   n][2] = i + n + 1;	// |
			faces[i + 2*n][0] = i + n + 1;	// side (2 vertices on bottom)
			faces[i + 2*n][1] = i + 1;	// |
			faces[i + 2*n][2] = i;		// |
			faces[i + 3*n][0] = 2*n + 1;	// top
			faces[i + 3*n][1] = i + n;	// |
			faces[i + 3*n][2] = i + n + 1;	// |
		}
		faces[  n - 1][0] = 2*n;	// bottom
		faces[  n - 1][1] = n - 1;	// |
		faces[  n - 1][2] = 0;		// |
		faces[2*n - 1][0] = n - 1;	// side (2 vertices on top)
		faces[2*n - 1][1] = 2*n - 1;	// |
		faces[2*n - 1][2] = n;		// |
		faces[3*n - 1][0] = n;		// side (2 vertices on bottom)
		faces[3*n - 1][1] = 0;		// |
		faces[3*n - 1][2] = n - 1;	// |
		faces[4*n - 1][0] = 2*n + 1;	// top
		faces[4*n - 1][1] = 2*n - 1;	// |
		faces[4*n - 1][2] = n;		// |
	}

	public void sphere() {
		final int n = 16;	// n = 4*k (k = 1, 2, ...)
		final double delta_angle = 2*Math.PI/n;

		vertices = new double[(n/2 - 1)*n + 2][3];
		for (int j = 0; j < n/2 - 1; j++) {
			for (int i = 0; i < n; i++) {
				vertices[j*n + i][0] = Math.sin((j + 1)*delta_angle)*Math.cos(i*delta_angle);
				vertices[j*n + i][1] = Math.cos((j + 1)*delta_angle);
				vertices[j*n + i][2] = Math.sin((j + 1)*delta_angle)*Math.sin(i*delta_angle);
			}
		}
		vertices[(n/2 - 1)*n    ][0] =  0; vertices[(n/2 - 1)*n    ][1] =  1; vertices[(n/2 - 1)*n    ][2] =  0;	// northern pole
		vertices[(n/2 - 1)*n + 1][0] =  0; vertices[(n/2 - 1)*n + 1][1] = -1; vertices[(n/2 - 1)*n + 1][2] =  0;	// southern pole

		faces = new int[2*n*(n/2 - 1)][3];
		for (int j = 0; j < n/2 - 2; j++) {
			for (int i = 0; i < n - 1; i++) {
				faces[j*2*n + i    ][0] = j*n + i;		// side (2 vertices on top)
				faces[j*2*n + i    ][1] = j*n + i + 1;		// |
				faces[j*2*n + i    ][2] = (j + 1)*n + i + 1;	// |
				faces[j*2*n + i + n][0] = j*n + i;		// side (2 vertices on bottom)
				faces[j*2*n + i + n][1] = (j + 1)*n + i + 1;	// |
				faces[j*2*n + i + n][2] = (j + 1)*n + i;	// |
			}
			faces[j*2*n + n - 1  ][0] = (j + 1)*n - 1;	// side (2 vertices on top)
			faces[j*2*n + n - 1  ][1] = (j + 1)*n;		// |
			faces[j*2*n + n - 1  ][2] = j*n;		// |
			faces[2*n*(j + 1) - 1][0] = (j + 1)*n - 1;	// side (2 vertices on bottom)
			faces[2*n*(j + 1) - 1][1] = j*n + n;		// |
			faces[2*n*(j + 1) - 1][2] = (j + 2)*n - 1;	// |
		}
		for (int i = 0; i < n - 1; i++) {
			faces[n*(n - 4) + i][0] = (n/2 - 1)*n;
			faces[n*(n - 4) + i][1] = i;
			faces[n*(n - 4) + i][2] = i + 1;
			faces[n*(n - 3) + i][0] = (n/2 - 1)*n + 1;
			faces[n*(n - 3) + i][1] = (n/2 - 2)*n + i + 1;
			faces[n*(n - 3) + i][2] = (n/2 - 2)*n + i;
		}
		faces[n*(n - 3) - 1][0] = (n/2 - 1)*n;
		faces[n*(n - 3) - 1][1] = n - 1;
		faces[n*(n - 3) - 1][2] = 0;
		faces[n*(n - 2) - 1][0] = (n/2 - 1)*n + 1;
		faces[n*(n - 2) - 1][1] = (n/2 - 2)*n;
		faces[n*(n - 2) - 1][2] = (n/2 - 2)*n + n - 1;
	}
}

