/***************************************************************************
 *   Copyright (C) 2007 by A.J. Tavakoli                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef VECTOR2_H
#define VECTOR2_H

#include <cmath>

#include "numeric.h"


namespace Math3D {


template<class Real>
class Vector2 {
public:
  // components of vector
  Real m[2];

  inline Vector2() { }
  inline Vector2(const Vector2 &v) { m[0] = v.m[0]; m[1] = v.m[1]; }
  inline Vector2(Real x, Real y) { m[0] = x; m[1] = y; }
  inline Vector2(const Real *v) { m[0] = v[0]; m[1] = v[1]; }

   // overloaded operators  
  inline Real & operator [] (int i);
  inline const Real & operator [] (int i) const;
  inline Vector2 operator + (const Vector2 &v) const;
  inline Vector2 operator - (const Vector2 &v) const;
  inline const Vector2 & operator += (const Vector2 &v);
  inline const Vector2 & operator -= (const Vector2 &v);
  inline Real operator * (const Vector2 &v) const;
  inline Vector2 operator * (Real s) const;
  inline Vector2 operator / (Real s) const;
  inline const Vector2& operator *= (Real s);
  inline const Vector2& operator /= (Real s);

  // methods  
  inline Real mag() const;
  inline void normalize();
  inline void set(Real _x, Real _y);
  inline Real sqrMag() const;
};


template<class Real>
inline Real & Vector2<Real>::operator [] (int i) {
  // no error checking done for the sake of speed
  return m[i];
}


template<class Real>
inline const Real & Vector2<Real>::operator [] (int i) const {
  // no error checking done for the sake of speed
  return m[i];
}


// This overloaded + operator performs vector addition.  The Vector2 object is added
// to another Vector2 object, v, and the result is returned.
template<class Real>
inline Vector2<Real> Vector2<Real>::operator + (const Vector2<Real> &v) const {
   return Vector2(m[0] + v.m[0], m[1] + v.m[1]);
}


// This overloaded - operator performs vector subtraction.  v is subtracted from the Vector2
// object, and the result is returned.
template<class Real>
inline Vector2<Real> Vector2<Real>::operator - (const Vector2<Real> &v) const {
  return Vector2<Real>(m[0] - v.m[0], m[1] - v.m[1]);
}


// vector addition, adds v to the Vector2 object and stores the result in
// itself.
template<class Real>
inline const Vector2<Real>& Vector2<Real>::operator += (const Vector2<Real> &v) {
  m[0] += v.m[0];
  m[1] += v.m[1];

  return (*this);
}


// vector subtraction, subtracts v from the Vector2 object and stores the result in
// itself.
template<class Real>
inline const Vector2<Real>& Vector2<Real>::operator -= (const Vector2<Real> &v) {
  m[0] -= v.m[0];
  m[1] -= v.m[1];

  return (*this);
}


// overloaded * operator for scalar multiplication, multiplies this Vector2 object by
// the scalar and returns the resulting Vector2.
template<class Real>
inline Vector2<Real> Vector2<Real>::operator * (Real s) const {
  return Vector2<Real>(m[0]*s, m[1]*s);
}


// overloaded / operator for scalar division, divides this Vector2 object by
// the scalar and returns the resulting Vector2.
template<class Real>
inline Vector2<Real> Vector2<Real>::operator / (Real s) const {
  return Vector2<Real>(m[0]/s, m[1]/s);
}


// another overloaded * for scalar multiplication, but with vector on right side
template<class Real>
inline Vector2<Real> operator * (Real s, const Vector2<Real> &v) {
  return Vector2<Real>(v.m[0]*s, v.m[1]*s);
}


// multiplies Vector2 by a scalar, and stores the result in itself.
template<class Real>
inline const Vector2<Real>& Vector2<Real>::operator *= (Real s) {
  m[0] *= s;
  m[1] *= s;

  return (*this);
}


// divides Vector2 by a scalar, and stores the result in itself
template<class Real>
inline const Vector2<Real>& Vector2<Real>::operator /= (Real s) {
  m[0] /= s;
  m[1] /= s;

  return (*this);
}


// This overloaded * operator returns the dot product of the vector, and another vector v.
template<class Real>
inline Real Vector2<Real>::operator *(const Vector2<Real> &v) const {
  return m[0]*v.m[0] + m[1]*v.m[1];
}


// returns the magnitude of the vector
template<class Real>
inline Real Vector2<Real>::mag() const {
  return rsqrt(m[0]*m[0] + m[1]*m[1]);
}


// normalizes the vector
template<class Real>
inline void Vector2<Real>::normalize() {
  Real len = mag();

  m[0] /= len;
  m[1] /= len;
}


// returns the squared magnitude of the vector (this is faster than mag(), since it
// does not involve the computation of a square root).  useful in calculations where
// magnitude can be left squared.
template<class Real>
inline Real Vector2<Real>::sqrMag() const {
  return m[0]*m[0] + m[1]*m[1];
}


// assign the values of the vector's components to x, y, and z
template<class Real>
inline void Vector2<Real>::set(Real x, Real y) {
  m[0] = x;
  m[1] = y;
}


} // namespace Math3D


#endif
