/*
 * Copyright (C) 1998 Marcel Bosc
 *
 * 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
 *
 */
/*! \file   Vect2D.hpp */

#ifndef Vect2D_H
#define Vect2D_H

#include<stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include<string.h>
#include<ImLib3D/CppTools.hpp>


// ********************** Vect2D ********************
//! 2D Vector, with operators 
template<class Value,class Real=Value>
class Vect2D
{
public:
	Value x,y;

	~Vect2D(){;}
	Vect2D(Value xi,Value yi){x=xi;y=yi;}
	Vect2D(){;}

	Real Norme2()const {return(x*x+y*y);}
	Real Norm2() const {return(x*x+y*y);}
	Real Norme() const {return(sqrt(Norme2()));}
	Real Norm()  const {return(sqrt(Norme2()));}
	Real Unit();

	Real Dist2(const Vect2D &p2) const {return((p2.x-x)*(p2.x-x)+(p2.y-y)*(p2.y-y));}
	Real Dist(const Vect2D &p2) const {return(sqrt(Dist2(p2)));}
	Real Distance2(const Vect2D &p2) const {return((p2.x-x)*(p2.x-x)+(p2.y-y)*(p2.y-y));}
	Real Distance(const Vect2D &p2) const {return(sqrt(Dist2(p2)));}

	void Show() const {Show("","");}
	void Show(char *p) const {Show(p,"");}
	void Show(char *p,char *s) const 
	{
		if(IsInt<Value>())
		{mprintf("%s%d %d%s",p,(int)x,(int)y,s);}
		else{mprintf("%s%f %f%s",p,(float)x,(float)y,s);}
	}

	Value & operator()(int i)
	{
		switch(i)
		{case 0:return x;case 1:return y;}
		return x;
	}

	Value  operator()(int i) const
	{
		switch(i)
		{case 0:return x;case 1:return y;}
		return x;
	}
	Vect2D<Value,Real>& operator=(Value val)
	{
		x=val;
		y=val;
		return *this;
	}
	

	bool operator==(const Vect2D &other) const {return other.x==x && other.y==y;}
	bool operator!=(const Vect2D &other) const {return !((*this)==other);}
	Vect2D &operator+=(const Vect2D &v){x+=v.x;y+=v.y;return(*this);}
	Vect2D &operator/=(const Value &d) {x/=d;  y/=d;  return(*this);}
	Vect2D &operator*=(const Value &d) {x*=d;  y*=d;  return(*this);}
	Vect2D &operator-(){x=-x;y=-y;return(*this);}


};



// Repere2D
//  template<class Value,class Real>
//  struct Repere2D
//  {
//  	Vect2D<Value,Real> i,j;
//      Repere2D(Value ix,Value iy,
//  			 Value jx,Value jy );
//      Repere2D(){;}
//  };


//  extern Repere2D BONDd0;
//  extern Vect2D Vect2D_NUL;


//  template<class Value,class Real>
//  inline
//  Repere2D<Value,Real>::Repere2D(Value ix,Value iy,
//  							   Value jx,Value jy )
//  {
//      i.x=ix;i.y=iy;
//      j.x=jx;j.y=jy;
//  }

template<class Value,class Real>
inline
Real
Vect2D<Value,Real>::Unit()
{
	Value n;
	n=Norme();
	if (n==0) { ThrowError("Vect2D::Unit: UNIT FAILED");}
	x/=n;
	y/=n;
	return(n);
}


template<class Value,class Real>
inline Vect2D<Value,Real>
operator+ (const Vect2D<Value,Real>& v1,const Vect2D<Value,Real>& v2)
{
    Vect2D<Value,Real> opres;
    opres.x=v1.x+v2.x;
    opres.y=v1.y+v2.y;
    return opres;
}

template<class Value,class Real>
inline Vect2D<Value,Real>
operator- (const Vect2D<Value,Real>& v1,const Vect2D<Value,Real>& v2)
{
    Vect2D<Value,Real> opres;
    opres.x=v1.x-v2.x;
    opres.y=v1.y-v2.y;
    return opres;
}

template<class Value,class Real>
inline Value 
operator* (const Vect2D<Value,Real>& v1,const Vect2D<Value,Real>& v2)
{
    return(v1.x*v2.x+v1.y*v2.y);
}

template<class Value,class Real>
inline Vect2D<Value,Real>
operator/(const Vect2D<Value,Real>& v1,Value l)
{
    Vect2D<Value,Real> opres;
    opres.x=v1.x/l;
    opres.y=v1.y/l;
    return opres;
}


template<class Value,class Real>
inline Vect2D<Value,Real>
operator* (float l,const Vect2D<Value,Real>& v1)
{
    Vect2D<Value,Real> opres;
    opres.x=v1.x*l;
    opres.y=v1.y*l;
    return opres;
}
template<class Value,class Real>
inline Vect2D<Value,Real>
operator* (double l,const Vect2D<Value,Real>& v1)
{
    Vect2D<Value,Real> opres;
    opres.x=v1.x*l;
    opres.y=v1.y*l;
    return opres;
}

template<class Value,class Real>
inline Vect2D<Value,Real>
operator* (int l,const Vect2D<Value,Real>& v1)
{
    Vect2D<Value,Real> opres;
    opres.x=v1.x*l;
    opres.y=v1.y*l;
    return opres;
}


typedef Vect2D<float,float>   Vect2Df;
typedef Vect2D<double,double> Vect2Dd;
typedef Vect2D<int,float>     Vect2Di;

//! runtime type determination
template<class T> inline bool IsVect2Df()          {return false;}
template<>        inline bool IsVect2Df<Vect2Df>() {return true ;}
//! runtime type determination
template<>  inline string TypeName<Vect2Df>(){return "Vect2Df";}

#endif // Vect2D_H

