/*
 * $Id: Vector3.h,v 1.3 2000/05/16 19:17:38 yamauchi Exp $
 *
 *	(M\pi)^2 Vector3 class 
 *	Copyright (C) 1993--2000 Copyright YAMAUCHI Hitoshi 山内 斉
 *	平成５年９月３日(金) -> 平成５年９月６日(月)
 *	平成６年６月１８日(土) 	add setByArray, getAsArray
 * 	2000年4月28日(金) 	update to Java class like 
 */
#ifndef _Vector3_h
#define _Vector3_h 1

#include <stdio.h>
#include <iostream.h>
#include <math.h>		// for sqrt()
#include "myString.h"

#ifdef MEMORY_REDUCE_DOUBLE	// メモリを節約する
#define double float
#endif

class Vector3 {
public:
    enum Direction{	X,	Y,	Z,	ELEM    };

private:
    double mE[Vector3::ELEM];
    
public:
    Vector3(void)
    {
	this->mE[Vector3::X] = 0.0;
	this->mE[Vector3::Y] = 0.0;
	this->mE[Vector3::Z] = 0.0;
    }
    Vector3(const Vector3& rhs)
    {
	this->mE[Vector3::X] = rhs.mE[Vector3::X];
	this->mE[Vector3::Y] = rhs.mE[Vector3::Y];
	this->mE[Vector3::Z] = rhs.mE[Vector3::Z];
    }
    Vector3(const double aX, const double aY, const double aZ)
    {
	this->mE[Vector3::X] = aX;
	this->mE[Vector3::Y] = aY;
	this->mE[Vector3::Z] = aZ;    
    }
    Vector3(const double aVec[])
    {
	this->mE[Vector3::X] = aVec[Vector3::X];
	this->mE[Vector3::Y] = aVec[Vector3::Y];
	this->mE[Vector3::Z] = aVec[Vector3::Z];    
    }
    void set(const double aX, const double aY, const double aZ)
    {
	this->mE[Vector3::X] = aX;
	this->mE[Vector3::Y] = aY;
	this->mE[Vector3::Z] = aZ;    
    }
    double get(const int sc) const
    {
#ifndef NDEBUG
	if((sc < int(Vector3::X)) || (sc > Vector3::Z))
	{
	    // extern void breakpoint(void);
	    cerr << "Error!: Illegal Vector3 direction number " << sc << endl;
	    // breakpoint();
	    return(0.0);
	}
#endif
	return(this->mE[sc]);
    }
    void getAsArray(double ret[])
    {
	ret[Vector3::X] = this->mE[Vector3::X];
	ret[Vector3::Y] = this->mE[Vector3::Y];
	ret[Vector3::Z] = this->mE[Vector3::Z];
    }
    void setByArray(double v[])
    {
	this->mE[Vector3::X] = v[Vector3::X];
	this->mE[Vector3::Y] = v[Vector3::Y];
	this->mE[Vector3::Z] = v[Vector3::Z];
    }
    const Vector3& operator=(const Vector3& rhs)
    {
	if(this != &rhs)
	{
	    this->mE[Vector3::X] = rhs.mE[Vector3::X];
	    this->mE[Vector3::Y] = rhs.mE[Vector3::Y];
	    this->mE[Vector3::Z] = rhs.mE[Vector3::Z];
	}
	return(*this);
    }

    /*
     * operators
     */
    friend Vector3 operator + (const Vector3& v1, const Vector3& v2)
    {  
	return (Vector3(v1.mE[Vector3::X] + v2.mE[Vector3::X],
			v1.mE[Vector3::Y] + v2.mE[Vector3::Y],
			v1.mE[Vector3::Z] + v2.mE[Vector3::Z]));
    }
    friend Vector3 operator - (const Vector3& v1, const Vector3& v2)
    {
	return (Vector3(v1.mE[Vector3::X] - v2.mE[Vector3::X],
			v1.mE[Vector3::Y] - v2.mE[Vector3::Y],
			v1.mE[Vector3::Z] - v2.mE[Vector3::Z]));
    }

    friend Vector3  operator * (const Vector3& v1, const Vector3& v2)
    {
	return (Vector3(v1.mE[Vector3::X] * v2.mE[Vector3::X], 
			v1.mE[Vector3::Y] * v2.mE[Vector3::Y],
			v1.mE[Vector3::Z] * v2.mE[Vector3::Z]));
    }
    friend Vector3  operator * (const Vector3& v, const double d)
    {
	return (Vector3(v.mE[Vector3::X] * d, v.mE[Vector3::Y] * d,
			v.mE[Vector3::Z] * d));
    }
    friend Vector3  operator * (const double d, const Vector3& v)
    {
        return (Vector3(v.mE[Vector3::X] * d, v.mE[Vector3::Y] * d,
			v.mE[Vector3::Z] * d));
    }
    friend Vector3  operator / (const Vector3& v, const double d)
    {
	if(0.0 == d)
	{
	    cout << "Error! Vector can not divide by 0. ignored.\n";
	    return(v);
	}
	return(Vector3(v.mE[Vector3::X]/d, 
		       v.mE[Vector3::Y]/d, 
		       v.mE[Vector3::Z]/d));
    }
    friend int operator == (const Vector3& a, const Vector3& b)
    {
	return((a.mE[Vector3::X] == b.mE[Vector3::X]) &&
	       (a.mE[Vector3::Y] == b.mE[Vector3::Y]) &&
	       (a.mE[Vector3::Z] == b.mE[Vector3::Z]));
    }

    friend int operator != (const Vector3& a, const Vector3& b)
    {
	return((a.mE[Vector3::X] != b.mE[Vector3::X]) ||
	       (a.mE[Vector3::Y] != b.mE[Vector3::Y]) ||
	       (a.mE[Vector3::Z] != b.mE[Vector3::Z]));
    }

    const Vector3& operator += (const Vector3& rhs)
    {
	this->mE[Vector3::X] += rhs.mE[Vector3::X];
	this->mE[Vector3::Y] += rhs.mE[Vector3::Y];
	this->mE[Vector3::Z] += rhs.mE[Vector3::Z];
	return(*this);
    }

    /*
     * 内積
     */
    double dInn_prd(const Vector3& v) const
    {
	return(this->mE[Vector3::X] * v.mE[Vector3::X] + 
	       this->mE[Vector3::Y] * v.mE[Vector3::Y] + 
	       this->mE[Vector3::Z] * v.mE[Vector3::Z]);
    }

    /*
     * 外積
     */
    Vector3  VOut_prd(const Vector3& v) const
    {
	return(Vector3(this->mE[Vector3::Y] * v.mE[Vector3::Z] - 
		       this->mE[Vector3::Z] * v.mE[Vector3::Y],

		       this->mE[Vector3::Z] * v.mE[Vector3::X] - 
		       this->mE[Vector3::X] * v.mE[Vector3::Z],

		       this->mE[Vector3::X] * v.mE[Vector3::Y] - 
		       this->mE[Vector3::Y] * v.mE[Vector3::X])  );
    }

    /*
     * 正規化 
     */
    Vector3& VNormalize(void)
    {
	double d = this->getNorm();
	if(d == 0.0)
	{
	    cerr << "Warning!!!:0 vector can't normalize.Return as it is." 
		<< endl;
	    // extern void breakpoint(void);
	    // breakpoint();
	    return(*this);
	}
	this->mE[Vector3::X] /= d;
	this->mE[Vector3::Y] /= d;
	this->mE[Vector3::Z] /= d;
	return(*this);
    }

    /*
     * 大きさ : 
     * 残念だが，この 3次元 vector の norm では中間値の overflowを考え
     * ていない．2次元なら考慮したライブラリがあるんだが．．．
     */
    double getNorm(void) const
    {
	double d = sqrt(this->mE[Vector3::X] * this->mE[Vector3::X] + 
			this->mE[Vector3::Y] * this->mE[Vector3::Y] + 
			this->mE[Vector3::Z] * this->mE[Vector3::Z]);
	return(d);
    }
    
    /*
     * ostreamにある '<<' を使う。ここのprivate menberを見てるので
     * friend
     */
    friend ostream& operator<<(ostream& s, const Vector3& v)
    {
	s << v.mE[Vector3::X] << "\t" << v.mE[Vector3::Y] << "\t" 
	  << v.mE[Vector3::Z];
	return s;
    }

    /*
     * toString
     */
    myString toString()
    {
	static char buf[128];
	snprintf(buf, 128, "%g\t%g\t%g", 
		 this->mE[Vector3::X], this->mE[Vector3::Y], 
		 this->mE[Vector3::Z]);
	return(myString(buf));
    }
};


#ifdef MEMORY_REDUCE_DOUBLE	// メモリを節約する
#undef double
#endif

#endif // #ifndef _Vector3_h
