/////////////////////////////////////////////////////////////////////////
//                                                                     //
// This file holds a simple vector class with basic operators.         //
//                                                                     //
/////////////////////////////////////////////////////////////////////////
#ifndef __CVECTOR3_HPP__
#define __CVECTOR3_HPP__

#include <cmath>


// Vector class
template <typename T>
class CVector3
{
public:
  T x, y, z;

  inline CVector3(T a = 0, T b = 0, T c = 0)
    : x(a), y(b), z(c) {}

  inline T norm() const;
  inline void normalize();

  inline CVector3  operator +   (const CVector3 &v) const;
  inline CVector3  operator -   (const CVector3 &v) const;
  inline T         operator *   (const CVector3 &v) const;
  inline CVector3  operator ^   (const CVector3 &v) const;
  inline CVector3  operator *   (T k) const;
  inline CVector3  operator /   (T k) const;
  inline CVector3  operator >>  (const CVector3 &v) const;
  inline CVector3  operator <<  (const CVector3 &v) const;
  inline CVector3  operator -   () const;

  inline CVector3& operator +=  (const CVector3 &v);
  inline CVector3& operator -=  (const CVector3 &v);
  inline CVector3& operator ^=  (const CVector3 &v);
  inline CVector3& operator *=  (T k);
  inline CVector3& operator /=  (T k);
  inline CVector3& operator >>= (const CVector3 &v);
  inline CVector3& operator <<= (const CVector3 &v);
};




////////////////////////
//                    //
//  Inline functions  //
//                    //
////////////////////////
template <typename T>
inline T CVector3<T>::norm() const
{
  return(sqrt(x*x + y*y + z*z));
}

template <typename T>
inline void CVector3<T>::normalize()
{
  T Norm = norm();
  if (Norm != 0.0f)
    {
      x /= Norm;
      y /= Norm;
      z /= Norm;
    }
}



template <typename T>
inline CVector3<T> CVector3<T>::operator + (const CVector3<T> &v) const
{
  return CVector3<T>(x + v.x, y + v.y, z + v.z);
}

template <typename T>
inline CVector3<T> CVector3<T>::operator - (const CVector3<T> &v) const
{
  return CVector3<T>(x - v.x, y - v.y, z - v.z);
}

template <typename T>
inline T CVector3<T>::operator * (const CVector3<T> &v) const
{
  return (x*v.x + y*v.y + z*v.z);
}

template <typename T>
inline CVector3<T> CVector3<T>::operator ^ (const CVector3<T> &v) const
{
  return CVector3<T>(y*v.z - z*v.y,
                     z*v.x - x*v.z,
                     x*v.y - y*v.x);
}

template <typename T>
inline CVector3<T> CVector3<T>::operator * (T k) const
{
  return CVector3<T>(k*x, k*y, k*z);
}

template <typename T>
inline CVector3<T> operator * (T k, const CVector3<T> &v)
{
  return CVector3<T>(k*v.x, k*v.y, k*v.z);
}

template <typename T>
inline CVector3<T> CVector3<T>::operator / (T k) const
{
  return CVector3<T>(x/k, y/k, z/k);
}

template <typename T>
inline CVector3<T> CVector3<T>::operator >> (const CVector3<T> &v) const
{
  T Norm = (x*v.x + y*v.y + z*v.z) / (v.x*v.x + v.y*v.y + v.z*v.z);
  return CVector3<T>(Norm*v.x, Norm*v.y, Norm*v.z);
}

template <typename T>
inline CVector3<T> CVector3<T>::operator << (const CVector3<T> &v) const
{
  T Norm = (x*v.x + y*v.y + z*v.z) / (x*x + y*y + z*z);
  return CVector3<T>(Norm*x, Norm*y, Norm*z);
}

template <typename T>
inline CVector3<T> CVector3<T>::operator - () const
{
  return CVector3<T>(-x, -y, -z);
}



template <typename T>
inline CVector3<T>& CVector3<T>::operator += (const CVector3<T> &v)
{
  x += v.x;
  y += v.y;
  z += v.z;
  return (*this);
}

template <typename T>
inline CVector3<T>& CVector3<T>::operator -= (const CVector3<T> &v)
{
  x -= v.x;
  y -= v.y;
  z -= v.z;
  return (*this);
}

template <typename T>
inline CVector3<T>& CVector3<T>::operator ^= (const CVector3<T> &v)
{
  return ((*this) = CVector3<T>(y*v.z - z*v.y,
                                z*v.x - x*v.z,
                                x*v.y - y*v.x));
}

template <typename T>
inline CVector3<T>& CVector3<T>::operator *= (T k)
{
  x *= k;
  y *= k;
  z *= k;
  return (*this);
}

template <typename T>
inline CVector3<T>& CVector3<T>::operator /= (T k)
{
  x /= k;
  y /= k;
  z /= k;
  return (*this);
}

template <typename T>
inline CVector3<T>& CVector3<T>::operator >>= (const CVector3<T> &v)
{
  T Norm = (x*v.x + y*v.y + z*v.z) / (v.x*v.x + v.y*v.y + v.z*v.z);
  x = v.x * Norm;
  y = v.y * Norm;
  z = v.z * Norm;
  return (*this);
}

template <typename T>
inline CVector3<T>& CVector3<T>::operator <<= (const CVector3<T> &v)
{
  T Norm = (x*v.x + y*v.y + z*v.z) / (x*x + y*y + z*z);
  x = x * Norm;
  y = y * Norm;
  z = z * Norm;
  return (*this);
}


#endif // __CVECTOR3_HPP__
