//
//  TroisDee.java
//  raytracing
//
//  Created by Martin RobinSon on 12/07/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

public class TroisDee {
		double x,y,z;
		double xx,yy,zz;
		Point points[];
		Poly polys[];
		int pointpivot, polypivot;
		//-----------------------------------------------------------------------
		//init-------------
		//-----------------------------------------------------------------------
		public TroisDee(double x, double y, double z, int numpoint, int numpoly){
			this.x = x;			this.y = y;			this.z = z;
			this.xx = x;		this.yy = y;		this.zz = z;
			this.polys = new Poly[numpoly];
			this.points = new Point[numpoint];
			this.polypivot = 0;
			this.pointpivot = 0;
		}
		public void construct(String str) {
			String[] polys = str.split("\n");				//extract polygon from string (separated by newline)
			for (int i=0; i<polys.length; i++) {
				String[] points = polys[i].split(" ");		//extract point from polygon string (sparated by whitespace)
				Poly poly = this.addPoly(points.length);
				for (int j = 0; j<points.length; j++) {
					String[] comps = points[j].split(":");	//extract x,y,z from point string (separated by : like x:y:z) 
					double x = Double.parseDouble(comps[0]);
					double y = Double.parseDouble(comps[1]);
					double z = Double.parseDouble(comps[2]);
					//if it is the first trio , then it is the color
					if (j == 0) {
						poly.r = (int)(x*255); poly.g = (int)(y*255); poly.b = (int)(z*255);
					}
					else if (j == 1) {
						//poly.dr = (int)(x*255); poly.dg = (int)(y*255); poly.db = (int)(z*255);
					}
					else {
						//add point only if not already in list
						Point point = null;
						for (int h = 0; h < this.pointpivot; h++) {
							if ( (this.points[h].x == x)&&(this.points[h].y == y)&&(this.points[h].z == z) ) {
								point = this.points[h];
							}
						}//because many polygons can share the same point
						if (point == null) {
							point = this.addPoint(x,y,z);
						}
						//the second argument is not to plug but the face vector
						//still on the point list, but un connected with other in polygon
						//polygon keep it in face argument, use it for back face culling
						this.plugPoint(poly, point);
					}
				}
			}
		}
		//-----------------------------------------------------------------------
		//operation-------------
		//-----------------------------------------------------------------------
		public void move_ip(double x, double y, double z){
			this.x += x; this.y += y; this.z += z;
		}
		public void move(double x, double y, double z){
			this.x = x; this.y = y; this.z = z;
		}
		public void rotate_x(double radianX){
			for(int i = 0; i < this.pointpivot; i++){
				double radian = Math.atan2( this.points[i].y, this.points[i].z );
				double radius = Math.sqrt( this.points[i].y*this.points[i].y + this.points[i].z*this.points[i].z );
				this.points[i].y = radius * Math.sin(radian+radianX);
				this.points[i].z = radius * Math.cos(radian+radianX);
			}
		}
		public void rotate_y(double radianY){
			for(int i = 0; i < this.pointpivot; i++){
				double radian = Math.atan2( this.points[i].x, this.points[i].z );
				double radius = Math.sqrt( this.points[i].x*this.points[i].x + this.points[i].z*this.points[i].z );
				this.points[i].x = radius * Math.sin(radian+radianY);
				this.points[i].z = radius * Math.cos(radian+radianY);
			}
		}
		public void rotate_z(double radianZ){
			for(int i = 0; i < this.pointpivot; i++){
				double radian = Math.atan2( this.points[i].x, this.points[i].y );
				double radius = Math.sqrt( this.points[i].x*this.points[i].x + this.points[i].y*this.points[i].y );
				this.points[i].x = radius * Math.sin(radian+radianZ);
				this.points[i].y = radius * Math.cos(radian+radianZ);
			}
		}
		//-----------------------------------------------------------------------
		//object----------------------------------
		//-----------------------------------------------------------------------
		public class Point{
			double x,y,z;
			double xx,yy,zz;		//because some transformationi just for rendering, need to revert back
			public Point(double x, double y, double z){
				this.x = x; this.y = y; this.z = z;
				this.xx = x; this.yy = y; this.zz = z;
			}
		}
		public class Poly{
			Point liste[];
			int pivot;
			int r,g,b;		//a polygone is a colored shape
			int dr,dg,db;	//polygon contour
			public Poly(int size){
				this.liste = new Point[size];
				this.pivot = 0;
				this.r = 255; this.g = 255; this.b = 255;	//default fill white
				this.dr = 0; this.dg = 0; this.db = 0;		//default draw black
			}
		}
		//-----------------------------------------------------------------------
		//constructor
		//-----------------------------------------------------------------------
		public Point addPoint(double x, double y, double z){
			if ( this.pointpivot < this.points.length ) {
				this.points[pointpivot] = new Point(x,y,z);
				this.pointpivot += 1;
			}
			return this.points[pointpivot-1];
		}
		public Poly addPoly(int size){
			if ( this.polypivot < this.polys.length ) {
				this.polys[polypivot] = new Poly(size);
				this.polypivot += 1;
			}
			return this.polys[polypivot-1];
		}
		public void plugPoint(Poly poly, Point point){
			if ( poly.pivot < poly.liste.length ) {
				poly.liste[poly.pivot] = point;
				poly.pivot += 1;
			}
		}
		//-----------------------------------------------------------------------
		//safety
		//-----------------------------------------------------------------------
		public void getReal() {
			for ( int i = 0; i < this.pointpivot; i++ ) {
				this.points[i].x += this.x;
				this.points[i].y += this.y;
				this.points[i].z += this.z;
			}
		}
		public void getUnreal() {
			for ( int i = 0; i < this.pointpivot; i++ ) {
				this.points[i].x -= this.x;
				this.points[i].y -= this.y;
				this.points[i].z -= this.z;
			}
		}
		public void Save() {
			this.xx = this.x; this.yy =this.y; this.zz=this.z;
			for ( int i = 0; i < this.pointpivot; i++ ) {
				this.points[i].xx = this.points[i].x;
				this.points[i].yy = this.points[i].y;
				this.points[i].zz = this.points[i].z;
			}
		}
		public void Undo() {
			this.x = this.xx; this.y =this.yy; this.z=this.zz;
			for ( int i = 0; i < this.pointpivot; i++ ) {
				this.points[i].x = this.points[i].xx;
				this.points[i].y = this.points[i].yy;
				this.points[i].z = this.points[i].zz;
			}
		}
}
