package simogl.geometry;


import simogl.texture.TextureCoordinate;

/**
 * This class represents a triangle (polygon) that can be part of
 * a mesh
 * @author Frank Bruns
 *
 */
public class Triangle
{

	private Point3D vertex1 = null;
	private Point3D vertex2 = null;
	private Point3D vertex3 = null;
	
	private Point3D normal = null;
	
	private TextureCoordinate texCoordVertex1 = null;
	private TextureCoordinate texCoordVertex2 = null;
	private TextureCoordinate texCoordVertex3 = null;
	
	/**
	 * Creates a triangle with the specified points as vertices.
	 * The triangle can be used as a face of a mesh.
	 * <br>
	 * <b>Note: </b>Please specify point counter-clockwise
	 * @param p1 point that will be vertex1
	 * @param p2 point that will be vertex2
	 * @param p3 point that will be vertex3
	 */
	public Triangle(Point3D p1, Point3D p2, Point3D p3)
	{
		this.vertex1 = p1;
		this.vertex2 = p2;
		this.vertex3 = p3;
		
		this.texCoordVertex1 = new TextureCoordinate(0f,0f);
		this.texCoordVertex2 = new TextureCoordinate(0f,0f);
		this.texCoordVertex3 = new TextureCoordinate(0f,0f);
	}
	
	/**
	 * Returns a point/vector representing the triangle's normal
	 * @return normal of the triangle
	 */
	public Point3D getNormal()
	{
		/*
		 * Berechnung der Normalen eines Dreiecks p0,p1,p2
		 *	1) v0 = p0 - p1 // Vektor von p1 nach p0
		 *	2) v1 = p2 - p1 // Vektor von p1 nach p2
		 *	3) n0 = v0 x v1 // ohne Normierung
		 *	4) n = ( n0.X/Length, n0.Y/Length, n0.Z/Length ), d.h. Normalisieren
		 */
		
		
		if(this.normal == null) this.normal = new Point3D();
		
		Point3D v0 = new Point3D();
		Point3D v1 = new Point3D();
		
		v0 = v0.subtract(this.vertex1, this.vertex2);
		v1 = v1.subtract(this.vertex3, this.vertex2);
		
		this.normal.setToCrossProduct(v0, v1);			
		this.normal.normalize();
		
		return this.normal;
	}
	
	/**
	 * Sets the normal of this triangle to the specified values
	 * @param x x-coordinate
	 * @param y y-coordinate
	 * @param z z-coordinate
	 */
	public void setNormal(float x, float y, float z)
	{
		if(this.normal == null) this.normal = new Point3D();
		this.normal.setX(x);
		this.normal.setY(y);
		this.normal.setZ(z);
	}
	
	/**
	 * Sets the normal of the triangle to the specified point/vector
	 * @param normal value to set the normal to
	 */
	public void setNormal(Point3D normal)
	{
		this.normal.setTo(normal);
	}
	
	/**
	 * Returns the length of the edge between vertex1 and vertex2
	 * @return length of edge between vertex1 and vertex2
	 */
	public float getLengthV1V2()
	{
		Point3D point = new Point3D();
		point = this.vertex1.subtract(this.vertex2,this.vertex1);
		
		return point.getLength();
	}
	
	/**
	 * Returns the length of the edge between vertex1 and vertex3
	 * @return length of edge between vertex1 and vertex3
	 */
	public float getLengthV1V3()
	{
		Point3D point = new Point3D();
		point = this.vertex1.subtract(this.vertex3,this.vertex1);
		
		return point.getLength();
	}
	
	/**
	 * Returns the length of the edge between vertex2 and vertex3
	 * @return length of edge between vertex2 and vertex3
	 */
	public float getLengthV2V3()
	{
		Point3D point = new Point3D();
		point = this.vertex2.subtract(this.vertex3,this.vertex2);
		
		return point.getLength();
	}

	/**
	 * Gets the first vertex of the triangle
	 * @return first vertex
	 */
	public Point3D getVertex1()
	{
		return this.vertex1;
	}

	/**
	 * Sets the first vertex if the triangle
	 * @param point point that will be the first vertex
	 */
	public void setVertex1(Point3D point)
	{
		this.vertex1 = point;
	}

	/**
	 * Gets the second vertex of the triangle
	 * @return second vertex
	 */
	public Point3D getVertex2()
	{
		return this.vertex2;
	}

	/**
	 * Sets the second vertex if the triangle
	 * @param point point that will be the second vertex
	 */
	public void setVertex2(Point3D point)
	{
		this.vertex2 = point;
	}

	/**
	 * Gets the third vertex of the triangle
	 * @return third vertex
	 */
	public Point3D getVertex3()
	{
		return this.vertex3;
	}

	/**
	 * Sets the third vertex if the triangle
	 * @param point that will be the third vertex
	 */
	public void setVertex3(Point3D point)
	{
		this.vertex3 = point;
	}
	
	/**
	 * Sets the triangle's texture coordinates
	 * @param vert1_s vertex1 s-coordinate
	 * @param vert1_t vertex1 t-coordinate
	 * @param vert2_s vertex2 s-coordinate
	 * @param vert2_t vertex2 t-coordinate
	 * @param vert3_s vertex3 s-coordinate
	 * @param vert3_t vertex3 t-coordinate
	 * <br><br>
	 * <b>Note: </b>Never set the texture coordinates to the triangle
	 * object directly. Alway use a face object and then get the triangle
	 * from that face object, because it it neccessary to create the face
	 * object before assigning texture coordinates to the triangle. 
	 */
	public void setTexCoords(float vert1_s, float vert1_t, float vert2_s, float vert2_t, float vert3_s, float vert3_t)
	{
		this.texCoordVertex1.setS(vert1_s);
		this.texCoordVertex1.setT(vert1_t);
		
		this.texCoordVertex2.setS(vert2_s);
		this.texCoordVertex2.setT(vert2_t);
		
		this.texCoordVertex3.setS(vert3_s);
		this.texCoordVertex3.setT(vert3_t);
	}
	
	/**
	 * Returs the texture coordinate of vertex1
	 * @return texture coordinate of vertex1
	 */
	public TextureCoordinate getTexCoordVertex1()
	{
		return this.texCoordVertex1;
	}
	
	/**
	 * Sets the texture coordinates of vertex1 to the 
	 * specifies s and t values.
	 * @param s s-coordinate
	 * @param t t-coordinate
	 * <br><br>
	 * <b>Note: </b>Never set the texture coordinates to the triangle
	 * object directly. Alway use a face object and then get the triangle
	 * from that face object, because it it neccessary to create the face
	 * object before assigning texture coordinates to the triangle.
	 */
	public void setTexCoordsVertex1(float s, float t)
	{
		this.texCoordVertex1.setS(s);
		this.texCoordVertex1.setT(t);
	}
	
	/**
	 * Returs the texture coordinate of vertex2
	 * @return texture coordinate of vertex2
	 */
	public TextureCoordinate getTexCoordVertex2()
	{
		return this.texCoordVertex2;
	}
	
	/**
	 * Sets the texture coordinates of verte2 to the 
	 * specifies s and t values.
	 * @param s s-coordinate
	 * @param t t-coordinate
	 * <br><br>
	 * <b>Note: </b>Never set the texture coordinates to the triangle
	 * object directly. Alway use a face object and then get the triangle
	 * from that face object, because it it neccessary to create the face
	 * object before assigning texture coordinates to the triangle.
	 */
	public void setTexCoordsVertex2(float s, float t)
	{
		this.texCoordVertex2.setS(s);
		this.texCoordVertex2.setT(t);
	}
	
	/**
	 * Returs the texture coordinate of vertex3
	 * @return texture coordinate of vertex3
	 */
	public TextureCoordinate getTexCoordVertex3()
	{
		return this.texCoordVertex3;
	}
	
	/**
	 * Sets the texture coordinates of vertex3 to the 
	 * specifies s and t values.
	 * @param s s-coordinate
	 * @param t t-coordinate
	 * <br><br>
	 * <b>Note: </b>Never set the texture coordinates to the triangle
	 * object directly. Alway use a face object and then get the triangle
	 * from that face object, because it it neccessary to create the face
	 * object before assigning texture coordinates to the triangle.
	 */
	public void setTexCoordsVertex3(float s, float t)
	{
		this.texCoordVertex3.setS(s);
		this.texCoordVertex3.setT(t);
	}
}
