//
// NhVector3f.h
//
// ベクトル（頂点）クラス
// 
// Written by Nobuki HIRAMINE
// Last modified : 2009/09/21
//
#ifndef	_NHVECTOR3F_H
#define	_NHVECTOR3F_H

#include <assert.h>	// assert()
#include <FLOAT.H>	// FLT_EPSILON
#include <math.h>	// sqrt()

class CNhVector3f
{
public:
	float	x, y, z;

	// コンストラクタ
	// デフォルト
	CNhVector3f() : x(0), y(0), z(0)
	{}
	// 初期化
	CNhVector3f( const float a, const float b, const float c ) : x(a), y(b), z(c)
	{}

	// 配列アクセス
	// 読み取り用
	const float& operator [] ( const long i ) const
	{
		return *((&x) + i);
	}
	// 書き込み用
	float& operator [] ( const long i )
	{
		return *((&x) + i);
	}

	// 代入
	CNhVector3f& operator = ( const CNhVector3f& b )
	{
		x = b.x;
		y = b.y;
		z = b.z;
		return *this;
	}

	// 正負反転
	const CNhVector3f operator - () const
	{
		return CNhVector3f( -x, -y, -z );
	}

	// 和差積商
	// 和
	const CNhVector3f operator + ( const CNhVector3f& b ) const
	{
		return CNhVector3f( x + b.x, y + b.y, z + b.z );
	}
	// 差
	const CNhVector3f operator - ( const CNhVector3f& b ) const
	{
		return CNhVector3f( x - b.x, y - b.y, z - b.z );
	}
	// ベクトル x 数値
	const CNhVector3f operator * ( const float t ) const
	{
		return CNhVector3f( x * t, y * t, z * t );
	}
	//  数値 x ベクトル
	friend inline const CNhVector3f operator * ( const float t, const CNhVector3f& b )
	{
		return b * t;
	}
	// 商
	const CNhVector3f operator / ( const float t ) const
	{
		if( 0.0 == t )
		{	// ゼロ割は、非常に小さい数で割りたいと解釈して、適当にFLT_EPSILONで割り算を実施
			assert( !"ゼロ割" );	// アサートになるケースは、呼び出し側で本呼び出し『前』に対処する方針で。
			return CNhVector3f( x/FLT_EPSILON, y/FLT_EPSILON, z/FLT_EPSILON );
		}
		return CNhVector3f( x / t, y / t, z / t );
	}

	// 自身に対する和差積商
	// 和
	CNhVector3f& operator += ( const CNhVector3f& b ) 
	{
		x += b.x;
		y += b.y;
		z += b.z;
		return *this;
	}
	// 差
	CNhVector3f& operator -= ( const CNhVector3f& b ) 
	{
		x -= b.x;
		y -= b.y;
		z -= b.z;
		return *this;
	}
	// 積
	CNhVector3f& operator *= ( const float t ) 
	{
		x *= t;
		y *= t;
		z *= t;
		return *this;
	}
	// 商
	CNhVector3f& operator /= ( const float t )
	{
		if( 0.0 == t )
		{	// ゼロ割は、非常に小さい数で割りたいと解釈して、適当にFLT_EPSILONで割り算を実施
			assert( !"ゼロ割" );	// アサートになるケースは、呼び出し側で本呼び出し『前』に対処する方針で。
			x /= FLT_EPSILON;
			y /= FLT_EPSILON;
			z /= FLT_EPSILON;
			return *this;
		}
		x /= t;
		y /= t;
		z /= t;
		return *this;
	}

	// 内積
	float CalcInnerProduct( const CNhVector3f& b ) const
	{
		return x * b.x + y * b.y + z * b.z;
	}

	// 外積
	const CNhVector3f CalcOuterProduct( const CNhVector3f& b ) const
	{
		return CNhVector3f( y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x );
	}

	// 長さ
	float CalcLengthSquared() const
	{
		return this->CalcInnerProduct(*this);
	}
	float CalcLength() const
	{
		return (float)sqrt( this->CalcLengthSquared() );
	}

	// 単位ベクトルの取得
	const CNhVector3f CalcNormal() const
	{
		assert( 0 != this->CalcLength() );
		return  (*this) / this->CalcLength();
	}

	// 単位ベクトル化
	const CNhVector3f& Normalize()
	{
		assert( 0 != this->CalcLength() );
		(*this) /= this->CalcLength();
		return *this;
	}

	// 比較
	// 同じか
	bool operator == ( const CNhVector3f& b ) const
	{
		return( b.x==x && b.y==y && b.z == z );
	}

	// 異なるか
	bool operator != ( const CNhVector3f& b ) const
	{
		return !( b == *this );
	}
	// 小さいか
	bool operator < ( const CNhVector3f& b ) const
	{
		if( z < b.z )		{ return true; }
		else if( z > b.z )	{ return false; }
		else{	// Ｚが等しいときはＹで比較
			if( y < b.y )		{ return true; }
			else if( y > b.y )	{ return false; }
			else{	// Ｙ、Ｚが等しいときはＸで比較
				if( x < b.x )		{ return true; }
				else if( x > b.x )	{ return false; }
				else				{ return false; }// Ｘ、Ｙ、Ｚが等しいときは、FALSE
			}
		}
	}
	// 大きいか
	bool operator > ( const CNhVector3f& b ) const
	{
		if( z > b.z )		{ return true; }
		else if( z < b.z )	{ return false; }
		else{	// Ｚが等しいときはＹで比較
			if( y > b.y )		{ return true; }
			else if( y < b.y )	{ return false; }
			else{	// Ｙ、Ｚが等しいときはＸで比較
				if( x > b.x )		{ return true; }
				else if( x < b.x )	{ return false; }
				else				{ return false; }// Ｘ、Ｙ、Ｚが等しいときは、FALSE
			}
		}
	}

};

typedef CNhVector3f	CNhPoint3f;

#endif	/*_NHVECTOR3F_H*/

