#ifndef VEC3F_HXX
#define VEC3F_HXX

#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif

#define max(a,b) MAX(a,b)
#define min(a,b) MIN(a,b)

#define Epsilon 1E-4f
#define Infinity FLT_MAX

using namespace std;

class Vec3f 
{
public:
	float x,y,z;

	Vec3f() 
	{x = y = z = 0.0f;};
	Vec3f(float x,float y, float z) 
		: x(x),y(y),z(z) 
	{};
	Vec3f(float f)
		: x(f),y(f),z(f)
	{};

	inline const float &operator[](const int i) const
	{ return *(&x+i); }; 

	inline float &operator[](const int i)
	{ return *(&x+i); }; //((float *)(this))[i]; };

	inline Vec3f &operator=(const Vec3f &b)
	{ x = b.x; y = b.y; z = b.z; return *this;};

	inline int MaxDim() const
	{
		return (x > y)?((x > z)?0:2):((y > z)?1:2);
	}
	inline void SetMin(Vec3f &other)
	{ 
		x = min(x,other.x);
		y = min(y,other.y);
		z = min(z,other.z);
	};
	inline void SetMax(Vec3f &other)
	{ 
		x = max(x,other.x);
		y = max(y,other.y);
		z = max(z,other.z);
	};
};

/*! dot product */
inline float Dot(const Vec3f &a, const Vec3f &b)
{ return a.x*b.x+a.y*b.y+a.z*b.z; };

/*! component-wise product */
inline Vec3f Product(const Vec3f &a, const Vec3f &b)
{ return Vec3f(a.x*b.x,a.y*b.y,a.z*b.z); };

/*! vector product */
inline Vec3f Cross(const Vec3f &a, const Vec3f &b)
{ return Vec3f(a.y*b.z-a.z*b.y,
			   a.z*b.x-a.x*b.z,
			   a.x*b.y-a.y*b.x); };


inline Vec3f operator-(const Vec3f &v)
{ return Vec3f(-v.x,-v.y,-v.z); };

inline float Length(const Vec3f &v)
{ return sqrt(Dot(v,v)); };

/*! still undocumented */
inline Vec3f operator*(const float f, const Vec3f &v)
{ return Vec3f(f*v.x, f*v.y, f*v.z); };

/*! still undocumented */
inline Vec3f operator*(const Vec3f &v, const float f)
{ return Vec3f(f*v.x, f*v.y, f*v.z); };

/*! still undocumented */
inline void operator*=(Vec3f &v, const float f)
{ v.x *= f; v.y*=f; v.z*=f; };

/*! still undocumented */
inline void operator*=(Vec3f &v, const Vec3f &f)
{ v.x *= f.x; v.y*=f.y; v.z*=f.z; };


/*! still undocumented */
inline Vec3f operator/(const Vec3f &v, const float f)
{ return (1/f)*v; };

/*! still undocumented */
inline void operator/=(Vec3f &v, const float f)
{ v *= (1/f); };

/*! still undocumented */
inline Vec3f operator+(const Vec3f &a, const Vec3f &b)
{ return Vec3f(a.x+b.x, a.y+b.y, a.z+b.z); };

inline Vec3f &operator+=(Vec3f &a, const Vec3f &b)
{
	a.x += b.x;
	a.y += b.y;
	a.z += b.z;
	return a;
}

inline Vec3f operator^(const Vec3f &a, const Vec3f &b)
{ return Vec3f(a.y*b.z-a.z*b.y,
			   a.z*b.x-a.x*b.z,
			   a.x*b.y-a.y*b.x); };


inline Vec3f operator-(const Vec3f &a, const Vec3f &b)
{ return Vec3f(a.x-b.x, a.y-b.y, a.z-b.z); };

inline void Normalize(Vec3f &v)
{ v *= (1.f/Length(v)); };

inline ostream &operator<<(ostream &o,const Vec3f &v)
{ o << "(" << v.x << "," << v.y << "," << v.z << ")"; return o; }

inline Vec3f Min(const Vec3f a, const Vec3f b)
{ return Vec3f(MIN(a.x,b.x),MIN(a.y,b.y),MIN(a.z,b.z)); }

inline Vec3f Max(const Vec3f a, const Vec3f b)
{ return Vec3f(MAX(a.x,b.x),MAX(a.y,b.y),MAX(a.z,b.z)); }

#endif


