module y4d_math.vector3d;

//----------------------------------------------------------------------------
//	3次元vectorライブラリ
//----------------------------------------------------------------------------
private import std.math;	// sqrt

///	3次元vectorライブラリ
struct vector3D {
public:
	///	保持しているベクター(x,y,z)
	double x=0.0,y=0.0,z=0.0;

/+
	//	変数x,y,zを初期化しないコンストラクタ(D言語の規約により0で初期化される)
	this() {}

	//	変数x,yを初期化するコンストラクタ
	this(double x_,double y_,double z_)
	{	x = x_; y = y_; z = z_; }

	//	他のvectorで初期化するためのコンストラクタ
	this(vector3D v)
	{	x = v.x; y = v.y; z = v.z; }
+/

	///	(x,y,z)を設定するsetter
	void set(double x_,double y_,double z_)
	{	x = x_; y = y_; z = z_; }

	///	内積を求める
	double innerProduct(vector3D v)
	{
		return x * v.x + y * v.y + z * v.z;
	}

	///	外積を求める(3次元の外積の結果はベクトル)
	void outerProduct(vector3D v)
	{
		double x_,y_,z_;
		x_ = y * v.z - z * v.y;
		y_ = z * v.x - x * v.z;
		z_ = x * v.y - y * v.x;
		set(x_,y_,z_);
	}

	///	他のベクトルを加算する
	void add(vector3D v)
	{
		x += v.x;
		y += v.y;
		z += v.z;
	}

	///	他のベクトルを減算する
	void sub(vector3D v)
	{
		x -= v.x;
		y -= v.y;
		z -= v.z;
	}

	///	スカラー値を乗算する
	void mul(double a)
	{
		x *= a;
		y *= a;
		z *= a;
	}

	///	スカラー値で除算する
	public void div(double a)
	{
		x /= a;
		y /= a;
		z /= a;
	}

	///	絶対値を求める(sqrtが入るので遅い)
	double size()
	{
		return sqrt(x * x + y * y + z * z);
	}

	///	絶対値の二乗を求める(大小比較をする目的ならこちらで十分)
	double size2()
	{
		return x * x + y * y + z * z;
	}

	///	近似による距離(絶対値)の算出。sqrtを使っていない分だけ速い
	double dist(vector3D v)
	{
		double ax = fabs(x - v.x);
		double ay = fabs(y - v.y);
		double az = fabs(z - v.z);

		//	一番長い距離 + 二つ目の/2 + ３つ目の/2ぐらいでいいんじゃ?
		if ( ax > ay ) {
			if ( ax > az )
				return ax + ay / 2 + az / 2;
		} else {
			if ( ay > az )
				return ay + ax / 2 + az / 2;
		}
		return az + ax / 2 + ay / 2;
	}

	//	以下は、各種オペレータ

	/// +=
	void opAddAssign(vector3D v) { add(v); }

	///	-=
	void opSubAssign(vector3D v) { sub(v); }

	/// *= (定数倍)
	void opMulAssign(double a) { mul(a); }

	/// /= (定数倍)
	void opDivAssign(double a) { div(a); }

	/// /= (外積)
	void opDivAssign(vector3D v) { outerProduct(v); }

	/// +
	vector3D opAdd(vector3D v)
	{ vector3D r = *this; r+=v; return r; }

	/// -
	vector3D opSub(vector3D v)
	{ vector3D r = *this; r-=v; return r; }

	/// * 内積
	double opMul(vector3D v)
	{ return innerProduct(v); }

	/// / 外積
	vector3D opDiv(vector3D v)
	{ vector3D r = *this; r/=v; return r; }

	/// * 定数倍
	vector3D opMul(double a)
	{ vector3D r = *this; r*=a; return r; }

	/// / 定数割
	vector3D opDiv(double a)
	{ vector3D r = *this; r/=a; return r; }

	///	== , != operator
	bool opEquals(vector3D v) { return cast(bool) ((x==v.x) && (y==v.y) && (z==v.z)); }

	///	デバッグ用に標準出力に値を表示する→「(5,10)」のように出力される
	void output()
	{ printf("(%f,%f,%f)",x,y,z); }
}

