// ===================================================================
// $Id: vector2.h,v 1.1.1.1 2002/10/21 13:20:03 damez Exp $
//
// vector2.h
//     Header file for CVector2D class - implements 2-dimensional vector
//
// Class: CVector2D
//
// Licence and usage conditions in November 2003:
// This file can be used and modified only with written permission of
// Vlastimil Havran, Pohodli 27, 57001 Litomysl, the Czech Republic.
// This library is granted to be used by Polina Kondratieva within
// her MPI HIWI job working on BRDFLIB library. The usage condition
// may change in the next version of the library. At the moment,
// the library development is supported by Max-Planck-Institut for
// Informatik, Stuhlsatzenhausweg 85, 66123 Saarbruecken Germany
// See WWW: http://www.mpi-sb.mpg.de
// REPLACEMENT_STRING
//
// Initial coding by Jiri Bittner and Vlastimil Havran, 1998.
//
// Given for the use to BRDFLIB project for the Polina Kondratieva's
// HIWI JOB assignment in November 2003.
// ===================================================================

#ifndef __VECTOR2_H__
#define __VECTOR2_H__

// BRDFLIB headers
#include "configh.h"
#include "basic.h"


__BEGIN_BRDFLIB_HEADER

// ---------------------------------------------------------------------------
// This class describes two-dimensional vector.
// ---------------------------------------------------------------------------
class CVector2D
{
public:
  float xx, yy; // coordinates of the vector

  // constructors
  CVector2D(float xs, float ys):xx(xs), yy(ys) {}
  // default constructor
  CVector2D() {} 
  
  friend ostream& operator<< (ostream &s, const CVector2D &A);
  friend istream& operator>> (istream &s, CVector2D &A);

  const   float&   x() const { return xx; }
  const   float&   y() const { return yy; }
  float&   x() {return xx;}
  float&   y() {return yy;}
  
  // Functions to get at the vector components
  float& operator[] (int inx) {
    if (inx == 0) return xx;
    else return yy;
  }

  const float& operator[] (int inx) const {
    if (inx == 0) return xx;
    else return yy;
  }

  // returns x-coordinate for which==0, x-coordinate for which==1
  void     ExtractVerts(float *p, int which) const;

  float&   SetX(const float x) {return xx = x;}
  float&   SetY(const float y) {return yy = y;}

  CVector2D& operator=(CVector2D const &v) {
    xx = v.x(); yy = v.y(); return *this;
  }

  void     SetValue(float xs,float ys ) { xx = xs; yy = ys; }

  float    Size() const { return (float) sqrt(xx*xx + yy*yy);}

  // normalize the vector to the size=1.0
  float    Normalize();
  
  // Assignment operators
  CVector2D& operator+= (const CVector2D &a);
  CVector2D& operator-= (const CVector2D &a);
  CVector2D& operator*= (const CVector2D &a);
  CVector2D& operator*= (float a);
  CVector2D& operator/= (float a);

  CVector2D operator-(const CVector2D &) const;
  CVector2D operator+(const CVector2D &) const;
  CVector2D operator*(const float t) const;

  //  CVector2D operator*(const Matrix3C &mat) const;
  CVector2D operator-() const { return CVector2D(-x(),-y()); }

  int  operator==(const CVector2D &u) const {return Equal(u,CLimits::Small);}
  int  operator!=(const CVector2D &u) const {return !operator == (u);}

  int  Equal(const CVector2D &u,float trash) const;

  // dot product of the two vectors
  friend inline double DotProd(const CVector2D &u,
			       const CVector2D &v)
  {
    return ( u.x() * v.x()  +  u.y() * v.y() );
  }

  // the angle between two vectors $\in <0, PI>$
  float  Angle(const CVector2D &v) const;
  // cosine of the angle between the two vectors $\in <-1,1>$
  float  Cosine(const CVector2D &v) const;
  // supposes this vector is normalized
  float  CosineN(const CVector2D &v) const;

  // checks if the this vector is not opposite to a given vector
  int    IsOpposite(const CVector2D &v) const {
    return (Abs(DotProd(*this,v) + Size() * v.Size()) < CLimits::Small);
  }

  // computes the distance between this and a given vector
  float  Distance(const CVector2D &v) const { 
    return  (float) sqrt( sqr(xx-v.x()) + sqr(yy - v.y()));
  }

  // computes the squared distance between this and a given vector 
  float  SqrDistance(const CVector2D &v) const { 
    return  sqr(x()-v.x())+sqr(y()-v.y());
  }

  // if a given vector has a smaller(larger) coordinate, then this is updated
  CVector2D&  UpdateMin(const CVector2D &v);
  CVector2D&  UpdateMax(const CVector2D &v);

  // checks if both coordinates are smaller than a given one
  int operator<=(CVector2D &v) {
    return x() < (v.x() + CLimits::Small)
      && y() < (v.y()+CLimits::Small);
  }

  // checks if both coordinates are larger than a given one
  int operator>=(CVector2D &v) {
    return x() > (v.x()-CLimits::Small) &&
      y() > (v.y()-CLimits::Small);
  }

  // returns which coordinates has larger size
  int DominantAxis();
};

const CVector2D ZeroVector2(0,0);

inline CVector2D& CVector2D::operator+= (const CVector2D& a)
{
  xx += a.xx;  yy += a.yy;
  return *this;
}

inline CVector2D& CVector2D::operator-= (const CVector2D& a)
{
  xx -= a.xx;  yy -= a.yy;
  return *this;
}

inline CVector2D& CVector2D::operator*= (float a)
{
  xx *= a;  yy *= a;
  return *this;
}

inline CVector2D& CVector2D::operator/= (float a)
{
  xx /= a;  yy /= a;
  return *this;
}

inline CVector2D& CVector2D::operator*= (const CVector2D& a)
{
  xx *= a.xx;  yy *= a.yy;
  return *this;
}


__END_BRDFLIB_HEADER

#endif // __VECTOR2_H__

