#include "amra_vector.h"
#include "conversions.h"
#include <cmath>

Vector Vector::invert() const
//constructor
{
	return Vector(-X,-Y,-Z);
}

Vector::Vector(float x, float y, float z)
//constructor
{
	X = x;
	Y = y;
	Z = z;
}

Vector::Vector(const Vector& p)
//initialisation from another Vector
{
	X = p.X;
	Y = p.Y;
	Z = p.Z;
}

Vector& Vector::operator=(const Vector& p)
//assignment
{
	
	if(this == &p) return *this;
	
	X = p.X;
	Y = p.Y;
	Z = p.Z;
	
	return *this;
}

float Vector::squarednorm() const
{
	return X*X+Y*Y+Z*Z;
}

void Vector::rotate2D_Z (float angle)
{
	angle = d2r(angle);
	X = X * cos(angle) + Y * sin(angle);
	Y = -X * sin(angle) + Y * cos(angle);
}

void Vector::rotate2D_X (float angle)
{
	angle = d2r(angle);
	Y = Y * cos(angle) + Z * sin(angle);
	Z = -Y * sin(angle) + Z * cos(angle);
}

float Vector::norm() const
//returns norm of vector
{
	return (float)sqrt(squarednorm());
}

void Vector::normalise()
//normalises the vector
{
	float d = this->norm();
	
	X /= d;
	Y /= d;
	Z /= d;
}
void Vector::normalise(float& norm)
//normalises the vector
{
	norm = this->norm();
	
	X /= norm;
	Y /= norm;
	Z /= norm;
}

Vector Vector::normalised() const
//returns the normalised vector
{
	float d = this->norm();
	return Vector(X / d,Y / d,Z / d);
}
Vector Vector::normalised(float& norm) const
//returns the normalised vector
{
	norm = this->norm();
	return Vector(X / norm,Y / norm,Z / norm);
}

ostream& operator<<(ostream& s, const Vector p)
//writing
{	
	s << "[" << p.X << "," << p.Y << "," << p.Z << "]";
	return s;
}


istream& operator>>(istream& s, Vector& p)
//reading
{
	s >> p.X;
	s >> p.Y;
	s >> p.Z;
	return s;
}

Vector operator-(const Point& p1,const Point& p2)
//returns p1 - p2
{
	return Vector(p1.x()-p2.x(),p1.y()-p2.y(),p1.z()-p2.z());
}

Vector operator+(const Vector & p1, const Vector& p2)
{
	return Vector(p1.x()+p2.x(),p1.y()+p2.y(),p1.z()+p2.z());
}
Vector operator+(const Point& p1, const Point& p2)
//returns p1 + p2
{
	return Vector(p1.x()+p2.x(),p1.y()+p2.y(),p1.z()+p2.z());
}

Point operator+(const Point& p1, const Vector& p2)
//returns p1 + p2
{
	return Point(p1.x()+p2.x(),p1.y()+p2.y(),p1.z()+p2.z());
}

Vector add(const Vector& p1, const Vector& p2)
//returns p1 + p2
{
	return Vector(p1.x()+p2.x(),p1.y()+p2.y(),p1.z()+p2.z());}

Vector minus(const Vector& p1, const Vector& p2)
//returns p1 + p2
{
	return Vector(p1.x()-p2.x(),p1.y()-p2.y(),p1.z()-p2.z());
}

float operator^(const Vector& u,const Vector& v)
//returns dot product
{
	return u.x()*v.x() + u.y()*v.y() + u.z()*v.z();
}

#if 0
// operatorloading for cross product considered harmful [tw]
Vector operator*(const Vector& v1, const Vector& v2)
//returns cross product
{
	return Vector(v1.Y*v2.Z - v1.Z*v2.Y,v1.Z*v2.X - v1.X*v2.Z,v1.X*v2.Y - v1.Y*v2.X);
}
#endif
	
Vector operator*(const Vector& v1, float a)
//vector by scalar
{
	return Vector(v1.X*a,v1.Y*a,v1.Z*a);
}
	
Vector operator*(float a, const Vector& v1)
//vector by scalar
{
	return Vector(v1.X*a,v1.Y*a,v1.Z*a);
}
