// Vector3.cpp: implementation of the Vector3 class.
//
//////////////////////////////////////////////////////////////////////

#include "Vector3.h"
#include <math.h>
#include <stdio.h>

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Vector3::Vector3()
{

	x = y = z = d = 0;
	len = 0;
}

Vector3::Vector3(float tx, float ty, float tz)
{
	x = tx;
	y = ty;
	z = tz;
	d = 0;
	len = (float)sqrt(tx*tx + ty*ty + tz*tz);
}
Vector3::Vector3(Point3 p)
{
	x=p.x;
	y=p.y;
	z=p.z;
	d=0;
	len = (float)sqrt(x*x + y*y + z*z);
}

Vector3::~Vector3()
{

}

void Vector3::set(float tx, float ty, float tz)
{
	x = tx;
	y = ty;
	z = tz;
	d = 0;
	len = (float)sqrt(tx*tx + ty*ty + tz*tz);
}

void Vector3::set(Vector3 vc)
{
	x = vc.x;
	y = vc.y;
	z = vc.z;
	d = 0;
	len = len;
}

void Vector3::set(Point3 vc)
{
	x = vc.x;
	y = vc.y;
	z = vc.z;
	d = 0;
	len = (float)sqrt(x*x + y*y + z*z);
}

Vector3 Vector3::operator+(Vector3 v){
	Vector3 ret(x + v.x, y + v.y, z + v.z);
	return ret;
}

Vector3 Vector3::operator-(Vector3 v){
	Vector3 ret(x - v.x, y - v.y, z - v.z);
	return ret;
}

Vector3 Vector3::operator*(float f){
	Vector3 ret(x*f,y*f,z*f);
	return ret;
}
// Vector3 methods
Vector3 Vector3::cross(Vector3 b) //return this cross b
{
	Vector3 c(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x);
	return c;
}
float Vector3::dot(Vector3 b){ // return this dotted with b
	return x * b.x + y * b.y + z * b.z + d*b.d;
}

void Vector3::normalize() //adjust this vector to unit length
{
	float l = (float)sqrt(x*x + y*y + z*z);

	if(l > 0)
	{
		float SF = 1/l;
		x *= SF; y *= SF; z *= SF;
	}
	// otherwise len is 0 and we can't divide by 0
	//cerr << "\nnormalize() sees vector (0,0,0)!";
	//return; // does nothing to zero vectors;
}

void Vector3::flip() // reverse this vector
{
	x = -x;
	y = -y;
	z = -z;
}

void Vector3::mult(float* m){
	//Mw using inverse transform matrix
	/*	[0 4 8  12] * [x] = [t.x]
		[1 5 9  13]   [y]   [t.y]
		[2 6 10 14]   [z]   [t.z]
		[3 7 11 15]   [d]   [t.d]
	*/
//	printf("Matrix1:\n");
//	printf(" %f %f %f %f\n",m[0],m[4],m[8], m[12]);
//	printf(" %f %f %f %f\n",m[1],m[5],m[9], m[13]);
//	printf(" %f %f %f %f\n",m[2],m[6],m[10],m[14]);
//	printf(" %f %f %f %f\n",m[3],m[7],m[11],m[15]);

//	printf("original ray:\n");
//	print();

	Vector3 t;
	t.x = x*m[0] + y*m[4] + z*m[8] + d*m[12];
	t.y = x*m[1] + y*m[5] + z*m[9] + d*m[13];
	t.z = x*m[2] + y*m[6] + z*m[10] + d*m[14];
	t.d = x*m[3] + y*m[7] + z*m[11] + d*m[15];

//	t.print();

	x = t.x;
	y = t.y;
	z = t.z;
	d = t.d;
	len = (float) sqrt(x*x + y*y + z*z);
}

void Vector3::print(){
 printf("Vector: X: %3f Y: %3f Z: %3f D: %3f\n",x,y,z,d);
}

/********** POINT CLASS ****************/
Point3::Point3(){
	x = y = z = 0;
	d = 1.0;
}

Point3::Point3(float tx, float ty, float tz){
	x = tx; y = ty; z = tz; d=1.0;
}

Point3::Point3(float tx, float ty, float tz, float td){
 	x = tx; y = ty; z = tz; d=td;
}

Point3::~Point3(){

}

void Point3::set(const Point3& pt){
	x = pt.x;
	y = pt.y;
	z = pt.z;
	d = pt.d;
}

void Point3::set(float tx, float ty, float tz){
	x = tx; y = ty; z = tz; d = 1.0;
}

void Point3::build4tuple(float v[]){ // load 4-tuple with this color: v[3] = 1 for homogeneous
	v[0] = x; v[1] = y; v[2] = z; v[3] = d;
}

float Point3::dot(const Point3 p){
	return (x*p.x + y*p.y + z*p.z);
}

float Point3::dot(const Vector3 v){
	return (x*v.x + y*v.y + z*v.z);
}

void Point3::times(float c){
	x *= c;
	y *= c;
	z *= c;
}

void Point3::mult(float* m){
	//Mw using inverse transform matrix
	/*	[0 4 8  12] * [x] = [t.x]
		[1 5 9  13]   [y]   [t.y]
		[2 6 10 14]   [z]   [t.z]
		[3 7 11 15]   [d]   [t.d]
	*/
	Point3 t;
	t.x = x*m[0] + y*m[4] + z*m[8]  + d*m[12];
	t.y = x*m[1] + y*m[5] + z*m[9]  + d*m[13];
	t.z = x*m[2] + y*m[6] + z*m[10] + d*m[14];
	t.d = x*m[3] + y*m[7] + z*m[11] + d*m[15];
	x = t.x;
	y = t.y;
	z = t.z;
	d = t.d;
}

//Point3 Point3::operator+(float f){
//	return Point3(x+f,y+f,z+f,1);
//}
Point3 Point3::operator+(const Vector3 v){
	return Point3(x+v.x, y+v.y, z+v.z, d+v.d);
}

Point3 Point3::operator+(float f){
	return Point3(x+f, y+f, z+f);
}

Vector3 Point3::operator-(const Point3 p){
	Vector3 ret;
	ret.x = x-p.x;
	ret.y = y-p.y;
	ret.z = z-p.z;
	ret.d = d-p.d;
	return ret;
}

void Point3::print(){
 printf("Point: X: %3f Y: %3f Z: %3f D: %3f\n",x,y,z,d);
}
