// -*- C++ -*-
#ifndef RIVECTOR3_H
#define RIVECTOR3_H
/* Copyright 1996 
 * Mon Jun 22 10:20:18 1998  Brian Edward Smits  (bes@phoenix.cs.utah.edu)
 * 
 * RiVector3.H
 * 
 *	
 * 
 * $Id: RiVector3.H,v 1.15 1999/10/01 18:22:45 bes Exp $ 
 * 
 */
#ifndef RICOMMON_H
#include <RiCommon.H>
#endif

#ifndef   RIMATH_H
#include <RiMath.H>
#endif

class ostream;
class istream;
/************************************************************
 * 3D vector class declaration
 ************************************************************/

class RiUnitVector3;

class RiVector3 {
public:

				// constructors
    RiVector3();
    RiVector3(const RiVector3 &v);
    RiVector3(const RiUnitVector3 &v);
    RiVector3(const RiReal *v);
    RiVector3(RiReal x, RiReal y, RiReal z);

				// assignment operator
    const RiVector3 &operator=(const RiVector3 &v);

				// member access
    RiReal X() const { return V[0]; }
    RiReal Y() const { return V[1]; }
    RiReal Z() const { return V[2]; }
    RiReal operator[](int n) const;
    operator RiReal *() {return V;}
    operator const RiReal *() const {return V;}
				// vector operators
    RiVector3 operator+=(const RiVector3 &v);
    RiVector3 operator-=(const RiVector3 &v);

				// scalar operators
    const RiVector3 &operator*=(RiReal n);
    const RiVector3 &operator/=(RiReal n);

				// unary minus
    RiVector3 operator-() const;
				// useful miscellany
    RiReal Length() const;

    friend  bool operator==(const RiVector3 &lhs, const RiVector3 &rhs);
    friend  RiVector3 operator+(const RiVector3 &lhs, const RiVector3 &rhs);
    friend  RiVector3 operator-(const RiVector3 &lhs, const RiVector3 &rhs);
    friend  RiReal    operator*(const RiVector3 &lhs, const RiVector3 &rhs);
    friend  RiVector3 operator^(const RiVector3 &lhs, const RiVector3 &rhs);
    friend  RiVector3 operator*(const RiVector3 &lhs, RiReal f);
    friend  RiVector3 operator/(const RiVector3 &lhs, RiReal f);

private:
    
    RiReal V[3];

};

extern ostream &operator<<(ostream &os, const RiVector3 &v);
extern istream &operator>>(istream &is, RiVector3 &v);

class RiUnitVector3 {
public:

				// constructors
    RiUnitVector3();
    RiUnitVector3(const RiVector3 &v);
    RiUnitVector3(const RiReal *v);
    RiUnitVector3(RiReal x, RiReal y, RiReal z);

				// assignment operators
    const RiUnitVector3 &operator=(const RiUnitVector3 &v);

				// member access
    RiReal X() const { return V[0]; }
    RiReal Y() const { return V[1]; }
    RiReal Z() const { return V[2]; }
    RiReal operator[](int n) const;

				// unary minus
    RiUnitVector3 operator-() const;

private:

    RiReal V[3];
    void normalize();

};



/**********************************************************
// Functions called by RiVector Class
// 
// ********************************************************/

inline void RiUnitVector3::normalize() {
   RiReal invLength = 1 / sqrt( V[0]*V[0] + V[1]*V[1] + V[2]*V[2] );
   V[0] *= invLength;
   V[1] *= invLength;
   V[2] *= invLength;
}

inline RiUnitVector3::RiUnitVector3() {
#ifndef NDEBUG
    V[0] = V[1] = V[2] = RI_NAN;
#endif
}

inline RiUnitVector3::RiUnitVector3(const RiVector3 &v) {
    V[0] = v.X();
    V[1] = v.Y();
    V[2] = v.Z();
    normalize();
}

inline RiUnitVector3::RiUnitVector3(const RiReal *v) {
    V[0] = v[0];
    V[1] = v[1];
    V[2] = v[2];
    normalize();
}

inline RiUnitVector3::RiUnitVector3(RiReal x, RiReal y, RiReal z) {
    V[0] = x;
    V[1] = y;
    V[2] = z;
    normalize();
}

inline const RiUnitVector3 &RiUnitVector3::operator=(const RiUnitVector3 &v) {
    V[0] = v.X();
    V[1] = v.V[1];
    V[2] = v.V[2];
    return *this;
}


/************************************************************
 * 3D vector class implementation
 ************************************************************/

inline RiVector3::RiVector3() {
#ifdef NDEBUG
    V[0] = V[1] = V[2] = RI_NAN;
#endif
}

inline RiVector3::RiVector3(const RiVector3 &v) {
    V[0] = v.V[0];
    V[1] = v.V[1];
    V[2] = v.V[2];
}

inline RiVector3::RiVector3(const RiUnitVector3 &v) {
    V[0] = v.X();
    V[1] = v.Y();
    V[2] = v.Z();
}

inline RiVector3::RiVector3(const RiReal *v) {
    V[0] = v[0];
    V[1] = v[1];
    V[2] = v[2];
}

inline RiVector3::RiVector3(RiReal x, RiReal y, RiReal z) {
    V[0] = x;
    V[1] = y;
    V[2] = z;
}

inline const RiVector3 &RiVector3::operator=(const RiVector3 &v) {
    V[0] = v.V[0];
    V[1] = v.V[1];
    V[2] = v.V[2];
    return *this;
}

inline RiReal RiVector3::operator[](int n) const {
    assert(n >= 0 && n <= 2);
    return V[n];
}

inline RiVector3 RiVector3::operator+=(const RiVector3 &v) {
    V[0] += v.V[0];
    V[1] += v.V[1];
    V[2] += v.V[2];
    return *this;
}

inline RiVector3 RiVector3::operator-=(const RiVector3 &v) {
    V[0] -= v.V[0];
    V[1] -= v.V[1];
    V[2] -= v.V[2];
    return *this;
}

inline const RiVector3 &RiVector3::operator*=(RiReal n) {
    V[0] *= n;
    V[1] *= n;
    V[2] *= n;
    return *this;
}

inline const RiVector3 &RiVector3::operator/=(RiReal n) {
    assert(n != 0);
    V[0] /= n;
    V[1] /= n;
    V[2] /= n;
    return *this;
}

inline RiReal RiVector3::Length() const {
    return sqrt(V[0]*V[0] + V[1]*V[1] + V[2]*V[2]);
}

				// unary minus
inline RiVector3 RiVector3::operator-() const {
    return RiVector3(-V[0], -V[1], -V[2]);
}


/**********************************************************
// Inlines that take either RiVector3 or RiUnitVector3
// 
// ********************************************************/



				// equality operator
inline bool operator==(const RiVector3 &lhs, const RiVector3 &rhs) {
    return ( RiClose(lhs.V[0], rhs.V[0]) &&
	     RiClose(lhs.V[1], rhs.V[1]) &&
	     RiClose(lhs.V[2], rhs.V[2]) );
}

inline RiVector3 operator+(const RiVector3 &lhs, const RiVector3 &rhs) {
    return RiVector3(lhs.V[0]+rhs.V[0], lhs.V[1]+rhs.V[1], lhs.V[2]+rhs.V[2]);
}

inline RiVector3 operator-(const RiVector3 &lhs, const RiVector3 &rhs) {
    return RiVector3(lhs.V[0]-rhs.V[0], lhs.V[1]-rhs.V[1], lhs.V[2]-rhs.V[2]);
}


inline RiVector3 operator*(const RiVector3 &lhs, RiReal n) {
    return RiVector3(lhs.V[0]*n, lhs.V[1]*n, lhs.V[2]*n);
}

inline RiVector3 operator/(const RiVector3 &lhs, RiReal n) {
    assert(n != 0);
    return RiVector3(lhs.V[0]/n, lhs.V[1]/n, lhs.V[2]/n);
}

				// dot product
inline RiReal operator*(const RiVector3 &lhs, const RiVector3 &rhs) {
    return (lhs.V[0] * rhs.V[0] + lhs.V[1] * rhs.V[1] + lhs.V[2] * rhs.V[2]);
}

				// cross product
inline RiVector3 operator^(const RiVector3 &lhs, const RiVector3 &rhs) {
    return RiVector3(
	+(lhs.V[1] * rhs.V[2]  -  rhs.V[1] * lhs.V[2]),
	-(lhs.V[0] * rhs.V[2]  -  rhs.V[0] * lhs.V[2]),
	+(lhs.V[0] * rhs.V[1]  -  rhs.V[0] * lhs.V[1])
    );
}


inline RiVector3 operator*(RiReal t, const RiVector3& rhs) {
    return RiVector3( t*rhs.X(), t*rhs.Y(), t*rhs.Z() );
}


/************************************************************
 * 3D unit vector class implementation
 ************************************************************/


inline RiReal RiUnitVector3::operator[](int n) const {
    assert(n >= 0 && n <= 2);
    return V[n];
}

                                // unary minus
inline RiUnitVector3 RiUnitVector3::operator-() const {
    RiUnitVector3 temp;
    temp.V[0] = -V[0];
    temp.V[1] = -V[1];
    temp.V[2] = -V[2];
    return temp;
}

#endif /* RIVECTOR3_H */

