/** \defgroup Utilities Utility classes */

/** @addtogroup Utilities
    @{
*/

/** @file CVector3f.h
    \brief This file contains the declaration and implementation of
    a 3D vector (with float precision) class.
*/

#ifndef CVECTOR3F_H
#define CVECTOR3F_H


/** 
    \brief This class represents a 3D vector (with float precision) class.
*/

class CVector3f
{
 public:
  float x; /**< x coordinate. */
  float y; /**< y coordinate. */
  float z; /**< z coordinate. */

  /**
     The CVector3f class parameter constructor.
     It does only simple member assignment.
  */
  inline CVector3f(float a = 0, float b = 0, float c = 0)
    { x = a; y = b; z = c; }

  /**
     The CVector3f class copy constructor.
     It does only simple member assignment.
  */
  inline CVector3f(const CVector3f& v)
    { x = v.x; y = v.y; z = v.z; }

  /**
     This operator return a reference to the coordinate
     corresponding to the index.
  */
  inline float& operator[] (int i)
    {
      switch(i)
        {
        case 0: return x;
        case 1: return y;
        case 2: return z;
        default: POP_ILLEGAL("Component index not valid."); return x;
        }
    }

  /**
     This function calculates the lenght of the vector.

     \f$ | \vec{a} | = \sqrt{a_x^2 + a_y^2 + a_z^2}\f$.
  */
  inline float Norm() const
    { return(sqrtf(x*x + y*y + z*z)); }

  /**
     This function normalizes the vector.
     
     \f$ normalized( \vec{a} ) = \left ( \frac{a_x}{| \vec{a} | } ,
     \frac{a_y}{| \vec{a} | } ,
     \frac{a_z}{| \vec{a} | } \right ) \f$.
  */
  inline void Normalize()
    { float Temp = sqrtf(x*x + y*y + z*z); x /= Temp; y /= Temp; z /= Temp; }


  /**
     This operator adds two vectors.

     \f$ \vec{a} + \vec{b} = \left ( a_x+b_x , a_y+b_y , a_z+b_z \right ) \f$
  */
  inline CVector3f operator + (const CVector3f &v) const
    {
      return CVector3f(x + v.x, y + v.y, z + v.z);
    }

  /**
     This operator substracts two vectors.

     \f$ \vec{a} - \vec{b} = \left ( a_x-b_x , a_y-b_y , a_z-b_z \right ) \f$
  */
  inline CVector3f operator - (const CVector3f &v) const
    {
      return CVector3f(x - v.x, y - v.y, z - v.z);
    }

  /**
     This operator returns the dot product of two vectors.

     \f$ \vec{a} \cdot \vec{b} = a_x b_x + a_y b_y + a_z b_z \f$.
  */
  inline float operator * (const CVector3f &v) const
    {
      return (x*v.x + y*v.y + z*v.z);
    }

  /**
     This operator returns the cross product of two vectors.

     \f$ \vec{a} \times \vec{b}                                =
     \left | \begin{array}{ccc}
     \vec{i} & \vec{j} & \vec{k} \\
     a_x     & a_y     & a_z     \\
     b_x     & b_y     & b_z \end{array} \right |  =
     \left ( a_y b_z - a_z b_y ,
     a_z b_x - a_x b_z ,
     a_x b_y - a_y b_z \right ) \f$
  */
  inline CVector3f operator ^ (const CVector3f &v) const
    {
      return CVector3f(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
    }

  /**
     This operator returns the product of a vector and a scalar.

     \f$ k \vec{a} = \left ( k a_x , k a_y , k a_z \right ) \f$
  */
  inline CVector3f operator * (float k) const
    {
      return CVector3f(k*x, k*y, k*z);
    }

  /**
     This operator returns a vector divised by a scalar.

     \f$ \frac{\vec{a}}{k} = \left ( \frac{a_x}{k} ,
     \frac{a_y}{k} ,
     \frac{a_z}{k} \right ) \f$
  */
  inline CVector3f operator / (float k) const
    {
      return CVector3f(x/k, y/k, z/k);
    }

  /**
     This operator projects a vector on another one.

     \f$ \vec{a} _{\vec{b}} = \frac{ \vec{a} \cdot \vec{b}}
     { \vec{b} \cdot \vec{b}} \vec{b} \f$
  */
  inline CVector3f operator >> (const CVector3f &v) const
    {
      float Temp = (x*v.x + y*v.y + z*v.z) / (v.x*v.x + v.y*v.y + v.z*v.z);
      return CVector3f(Temp*v.x, Temp*v.y, Temp*v.z);
    }

  /**
     This operator returns the opposite of a vector

     \f$ - \vec{a} = \left ( - a_x, - a_y, - a_z \right ) \f$
  */
  inline CVector3f operator - () const
    {
      return CVector3f(-x, -y, -z);
    }


  /**
     This operator is the same as + with an additionnal assignment.
  */
  inline CVector3f& operator += (const CVector3f &v)
    {
      x += v.x;
      y += v.y;
      z += v.z;
      return (*this);
    }

  /**
     This operator is the same as - with an additionnal assignment.
  */
  inline CVector3f& operator -= (const CVector3f &v)
    {
      x -= v.x;
      y -= v.y;
      z -= v.z;
      return (*this);
    }

  /**
     This operator is the same as ^ with an additionnal assignment.
  */
  inline CVector3f& operator ^= (const CVector3f &v)
    {
      (*this) = CVector3f(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
      return (*this);
    }

  /**
     This operator is the same as * with an additionnal assignment.
  */
  inline CVector3f& operator *= (float k)
    {
      x *= k;
      y *= k;
      z *= k;
      return (*this);
    }

  /**
     This operator is the same as / with an additionnal assignment.
  */
  inline CVector3f& operator /= (float k)
    {
      x /= k;
      y /= k;
      z /= k;
      return (*this);
    }

  /**
     This operator is the same as >> with an additionnal assignment.
  */
  inline CVector3f& operator >>= (const CVector3f &v)
    {
      float Temp = (x*v.x + y*v.y + z*v.z) / (v.x*v.x + v.y*v.y + v.z*v.z);
      x = v.x * Temp;
      y = v.y * Temp;
      z = v.z * Temp;
      return (*this);
    }

  friend CVector3f operator * (float k, const CVector3f &v);
};

/**
   This operator returns the product of a scalar and a vector.

   \f$ \vec{a} k = \left ( k a_x , k a_y , k a_z \right ) \f$
*/
inline CVector3f operator * (float k, const CVector3f &v)
{
  return CVector3f(k*v.x, k*v.y, k*v.z);
}

/**
   This operator prints the value of the vector.
*/
inline std::ostream& operator << (std::ostream& o, const CVector3f &v)
{
  o << "( " << v.x << " , " << v.y << " , " << v.z << " )";
  return o;
}


#endif  // CVECTOR3F_H

/** @} */
