#pragma once

#include "Mdesk.h"
#include "McGeContext.h"
#include "Mgegblge.h"
#include "McArray.h"
#include "McGeScale3d.h"

class McGeMatrix3d;
class McGeVector2d;
class McGePlane;
class McGePlanarEnt;
class McGeVector3dFloat;
class McGePoint3d;

// -------------------------------------------------------------------------
// Summary:
// 		McGeVector3d类表示3D空间的一个矢量
// Remarks:
// 		例如: 求失量与X轴的夹角
// 		<code>
// 		double d = vetT.angleTo(AcGeVector3d::kXAxis,-AcGeVector3d::kZAxis);
// 		</code>
// 		<code> 后面的代码求出vetFx逆时针到vetT的角度
// 		double d = vetFX.angleTo(vetT,AcGeVector3d::kZAxis);
// 		</code>
// 		<code> 判断向量vetT在向量VetFX的左边,还是在右边的调用
// 			double d = vetFX.angleTo(vetT,AcGeVector3d::kZAxis);
// 			if(d >= 0.0 && d <= PI )
// 			{
// 				//向量vetT在vetFX的左边.
// 				
// 			}
// 			else
// 			{
// 				//向量vetT在vetFX的右边.
// 			}
// 			// 或
// 			if (vetFX.dotProduct(vetT.perpVector()) < 0)
// 				//	vetFX在vetT的左边。
// 			//m_endDir.perpVector()是m_endDir的垂直向量.
// 		</code>
// 		<code>判断两个向量方向相同还是相反调用
// 			double db = vetFXPoint.dotProduct(vetFX);
// 			if(db < 0 )
// 			{
// 				//向量返向.
// 			}
// 			两个向量点乘如果等于0,表示向量垂直。
// 			两个向量点乘如果等于1,表示向量方向完全向同。
// 			两个向量点乘如果等于-1,表示向量方向完全反向。
// 		</code>
// -------------------------------------------------------------------------
class MXGEDLL McGeVector3d
{
public:
	// -------------------------------------------------------------------------
	// Summary:
	// 		构造函数
	// -------------------------------------------------------------------------
	McGeVector3d();

	// -------------------------------------------------------------------------
	// Summary:
	// 		用于坐标x和y,z建构一个3D矢量
	// -------------------------------------------------------------------------
	McGeVector3d(double x, double y, double z);
	//:Ignore
	McGeVector3d(const McGeVector3d& vec);

	McGeVector3d(const McGeVector3dFloat& vec);

	McGeVector3d(const McGeVector2d& vec);

	McGeVector3d(const McGePlanarEnt&, const McGeVector2d&);
	//:End Ignore

	// -------------------------------------------------------------------------
	// Summary:
	// 		零长度向量
	// -------------------------------------------------------------------------
	static const   McGeVector3d kIdentity;

	// -------------------------------------------------------------------------
	// Summary:
	// 		X方向的单位向量
	// -------------------------------------------------------------------------
	static const   McGeVector3d kXAxis;

	// -------------------------------------------------------------------------
	// Summary:
	// 		Y方向的单位向量
	// -------------------------------------------------------------------------
	static const   McGeVector3d kYAxis;

	// -------------------------------------------------------------------------
	// Summary:
	// 		Z方向的单位向量
	// -------------------------------------------------------------------------
	static const   McGeVector3d kZAxis;

	friend
MXGEDLL McGeVector3d   operator *  (const McGeMatrix3d& mat, const McGeVector3d& vec);

	// -------------------------------------------------------------------------
	// Summary:
	// 		将这个矢量设置为矩阵mat和矢量vec的积。积的顺序是矩阵*矢量，其中矢量作为列矢量。
	// Parameters:
	//		mat		-	输入矩阵
	//		vec		-	输入矢量
	// Returns:
	// 		返回这个矢量的引用
	// -------------------------------------------------------------------------
	McGeVector3d&  setToProduct(const McGeMatrix3d& mat, const McGeVector3d& vec);

	// -------------------------------------------------------------------------
	// Summary:
	// 		把向量与矩阵变换，结果和setToProduct(mat, *this)相同
	// Parameters:
	// 		leftSide - 变换矩阵
	// Returns:
	// 		返回这个矢量的引用
	// -------------------------------------------------------------------------
	McGeVector3d&  transformBy (const McGeMatrix3d& leftSide);

	// -------------------------------------------------------------------------
	// Summary:
	// 		把向量围绕向量axis旋转ang角度,旋转的正方向由右手定则定义
	// Parameters:
	// 		angle- 旋转角度
	// Returns:
	// 		返回这个矢量的引用
	// -------------------------------------------------------------------------
	McGeVector3d&  rotateBy    (double ang , const McGeVector3d& axis );

	// -------------------------------------------------------------------------
	// Summary:
	// 		把矢量相对平面normalToPlane镜向
	// Parameters:
	// 		normalToPlane	- 输入平面法向矢量
	// Returns:
	// 		返回这个矢量的引用
	// -------------------------------------------------------------------------
	McGeVector3d&  mirror      (const McGeVector3d& normalToPlane);

	// -------------------------------------------------------------------------
	// Summary:
	// 		把一个3d向量变换成2d向量
	// Parameters:
	// 		pln - 输入平面
	// Returns:
	// 		返回变换成2d的向量
	// -------------------------------------------------------------------------
	McGeVector2d   convert2d   (const McGePlane& pln) const;

	McGeVector3d   operator *  (double scl) const;
	friend
MXGEDLL McGeVector3d   operator *  (double scl, const McGeVector3d& vec);

	McGeVector3d&  operator *= (double scl);
	McGeVector3d&  setToProduct(const McGeVector3d& vec, double scl);
	McGeVector3d   operator /  (double scl) const;
	McGeVector3d&  operator /= (double scl);


	McGeVector3d   operator +  (const McGeVector3d& vec) const;
	McGeVector3d&  operator += (const McGeVector3d& vec);
	McGeVector3d   operator -  (const McGeVector3d& vec) const;
	McGeVector3d&  operator -= (const McGeVector3d& vec);
	McGeVector3d&  setToSum    (const McGeVector3d& vec1, const McGeVector3d& vec2);
	McGeVector3d   operator -  () const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		求这个矢量的反矢量，即设置此矢量为矢量(-x, -y,-z)
	// -------------------------------------------------------------------------
	McGeVector3d&  negate      ();


	// -------------------------------------------------------------------------
	// Summary:
	// 		返回与这个矢量正交的一个矢量，即矢量( -y, x)
	// Returns:
	// 		返回这个矢量的引用
	// -------------------------------------------------------------------------
	McGeVector3d   perpVector  () const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		返回这个矢量和矢量vec在[0, Pi]范围内所夹的角度
	// Parameters:
	// 		vec - 输入矢量
	// -------------------------------------------------------------------------
	double         angleTo     (const McGeVector3d& vec) const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		返回这个矢量和矢量vec在[0, 2 x Pi]范围内所夹的角度
	// Parameters:
	// 		vec		-	输入矢量
	//		refVec	-	输入参考矢量
	// Returns:
	// 		返回角度
	// -------------------------------------------------------------------------
	double         angleTo     (const McGeVector3d& vec,
		const McGeVector3d& refVec) const;

	//:Ignore
	
	double         angleOnPlane(const McGePlane& pln) const;
	//:End Ignore

	// -------------------------------------------------------------------------
	// Summary:
	// 		返回平行于这个矢量的一个单位矢量
	// -------------------------------------------------------------------------
	McGeVector3d   normal      (const McGeTol& tol = McGeContext::gTol) const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		把该失量单位化
	// -------------------------------------------------------------------------
	McGeVector3d&  normalize   (const McGeTol& tol = McGeContext::gTol);

	// -------------------------------------------------------------------------
	// Summary:
	// 		把该失量单位化
	// -------------------------------------------------------------------------
	McGeVector3d&  normalize   (const McGeTol& tol, McGeError& flag);

	// -------------------------------------------------------------------------
	// Summary:
	// 		返回这个矢量的长度
	// -------------------------------------------------------------------------
	double         length      () const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		返回这个矢量长度的平方
	// -------------------------------------------------------------------------
	double         lengthSqrd  () const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		这个矢量是否为单位失量
	// -------------------------------------------------------------------------
	Mdesk::Boolean isUnitLength(const McGeTol& tol = McGeContext::gTol) const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		这个失量是否为零长度
	// -------------------------------------------------------------------------
	Mdesk::Boolean isZeroLength(const McGeTol& tol = McGeContext::gTol) const;

	void setLength(double length);
	
//:Ignore
	double normalizeGetLength(double tol = 1.e-300);

	Mdesk::Boolean isParallelTo(const McGeVector3d& vec,
		const McGeTol& tol = McGeContext::gTol) const;
	Mdesk::Boolean isParallelTo(const McGeVector3d& vec,
		const McGeTol& tol, McGeError& flag) const;

	Mdesk::Boolean isCodirectionalTo(const McGeVector3d& vec,
		const McGeTol& tol = McGeContext::gTol) const;
	Mdesk::Boolean isCodirectionalTo(const McGeVector3d& vec,
		const McGeTol& tol, McGeError& flag) const;

	Mdesk::Boolean isPerpendicularTo(const McGeVector3d& vec,
		const McGeTol& tol = McGeContext::gTol) const;
	Mdesk::Boolean isPerpendicularTo(const McGeVector3d& vec,
		const McGeTol& tol, McGeError& flag) const;
//:End Ignore

	// -------------------------------------------------------------------------
	// Summary:
	// 		返回这个矢量和矢量度v点积
	// Parameters:
	// 		vec - 输入矢量
	// -------------------------------------------------------------------------
	double         dotProduct  (const McGeVector3d& vec) const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		返回这个矢量和矢量vec的cross积
	// Parameters:
	// 		vec - 输入矢量
	// -------------------------------------------------------------------------
	McGeVector3d   crossProduct(const McGeVector3d& vec) const;



	McGeVector3d   project      (const McGeVector3d& planeNormal,
		const McGeVector3d& projectDirection) const;
	
	McGeVector3d   orthoProject (const McGeVector3d& planeNormal) const;

	Mdesk::Boolean operator == (const McGeVector3d& vec) const;
	Mdesk::Boolean operator != (const McGeVector3d& vec) const;

	// -------------------------------------------------------------------------
	// Summary:
	// 		两个失量是否相等
	// -------------------------------------------------------------------------
	Mdesk::Boolean isEqualTo   (const McGeVector3d& vec,
		const McGeTol& tol = McGeContext::gTol) const;

	
	double         operator [] (unsigned int i) const;
	double&        operator [] (unsigned int i);

	// -------------------------------------------------------------------------
	// Summary:
	// 		设置失量的x,y,z值
	// -------------------------------------------------------------------------
	McGeVector3d&  set         (double x, double y, double z);
	McGeVector3d&  set         (const McGePlanarEnt& pln, const McGeVector2d& vec);

	// -------------------------------------------------------------------------
	// Summary:
	// 		由这个矢量返回变换矩阵
	// -------------------------------------------------------------------------
	operator       McGeMatrix3d() const;

	McGePoint3d asPoint() const;

	double         x, y, z;
};

inline
McGeVector3d::McGeVector3d() : x(0.0), y(0.0), z(0.0)
{
}

inline
McGeVector3d::McGeVector3d(const McGeVector3d& src) : x(src.x),y(src.y),z(src.z)
{
}





inline
McGeVector3d::McGeVector3d(double xx, double yy, double zz) : x(xx),y(yy),z(zz)
{
}


inline McGeVector3d
McGeVector3d::operator + (const McGeVector3d& v) const
{
	return McGeVector3d (x + v.x, y + v.y, z + v.z);
}


inline McGeVector3d&
McGeVector3d::operator += (const McGeVector3d& v)
{
	x += v.x;
	y += v.y;
	z += v.z;
	return *this;
}


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


inline McGeVector3d&
McGeVector3d::operator -= (const McGeVector3d& v)
{
	x -= v.x;
	y -= v.y;
	z -= v.z;
	return *this;
}

inline McGeVector3d&
McGeVector3d::setToSum(const McGeVector3d& v1, const McGeVector3d& v2)
{
	x = v1.x + v2.x;
	y = v1.y + v2.y;
	z = v1.z + v2.z;
	return *this;
}


inline McGeVector3d
McGeVector3d::operator - () const
{
	return McGeVector3d (-x, -y, -z);
}

inline McGeVector3d&
McGeVector3d::negate()
{
	x = -x;
	y = -y;
	z = -z;
	return *this;
}

inline McGeVector3d
McGeVector3d::operator * (double s) const
{
	return McGeVector3d (x * s, y * s, z * s);
}


inline McGeVector3d&
McGeVector3d::operator *= (double s)
{
	x *= s;
	y *= s;
	z *= s;
	return *this;
}

inline McGeVector3d&
McGeVector3d::setToProduct(const McGeVector3d& v, double s)
{
	x = s * v.x;
	y = s * v.y;
	z = s * v.z;
	return *this;
}


inline McGeVector3d
McGeVector3d::operator / (double val) const
{
	return McGeVector3d (x/val, y/val, z/val);
}


inline McGeVector3d&
McGeVector3d::operator /= (double val)
{
	x /= val;
	y /= val;
	z /= val;
	return *this;
}


inline double
McGeVector3d::lengthSqrd() const
{
	return x*x + y*y + z*z;
}


inline double
McGeVector3d::dotProduct(const McGeVector3d& v) const
{
	return x * v.x + y * v.y + z * v.z;
}


inline McGeVector3d&
McGeVector3d::set(double xx, double yy, double zz)
{
	x = xx;
	y = yy;
	z = zz;
	return *this;
}


inline double
McGeVector3d::operator [] (unsigned int i) const
{
	return *(&x+i);
}

inline double& McGeVector3d::operator [] (unsigned int i)
{
	return *(&x+i);
}

typedef McArray<McGeVector3d> McGeVector3dArray;


class MXGEDLL McGeVector3dFloat
{
public:
	McGeVector3dFloat();
	McGeVector3dFloat(float x, float y, float z);
	McGeVector3dFloat(double s);
	McGeVector3dFloat(double x, double y, double z);
	//:Ignore
	McGeVector3dFloat(const McGeVector3d& vec);

	McGeVector3dFloat& operator=(const McGeVector3d& vec);


	McGeVector3dFloat& operator=(const McGeScale3d& s);

	McGeVector3dFloat& operator*(double s);

	inline bool is2d() const {
		return ((-1.0E-10 <= x) && (x <= 1.0E-10)) && ((-1.0E-10 <= y) && (y <= 1.0E-10)) && (!((-1.0E-10 <= z) && (z <= 1.0E-10)));
	}

	inline operator McGeVector3d() const
	{
		return McGeVector3d(x, y, z);
	}

	inline operator McGeScale3d() const
	{
		return McGeScale3d(x, y, z);
	}

	

	McGeVector3dFloat& rotateBy(double ang, const McGeVector3d& axis)
	{
		McGeVector3d vec(x, y, z);
		vec.rotateBy(ang, axis);

		x = (float)vec.x;
		y = (float)vec.y;
		z = (float)vec.z;

		return *this;
	}

	double angleTo(const McGeVector3d& vec, const McGeVector3d& refVec) const
	{
		McGeVector3d vecThis(x, y, z);
		return vecThis.angleTo(vec, refVec);
	}

	float         x, y, z;
};



inline McGeVector3dFloat& McGeVector3dFloat::operator=(const McGeVector3d& vec)
{
	x = (float)vec.x;
	y = (float)vec.y;
	z = (float)vec.z;
	return *this;
}

inline McGeVector3dFloat& McGeVector3dFloat::operator=(const McGeScale3d& s) {
	x = (float)s.sx;
	y = (float)s.sy;
	z = (float)s.sz;
	return *this;
}

inline McGeVector3dFloat& McGeVector3dFloat::operator*(double s) {
	x = (float)(s * x);
	y = (float)(s * y);
	z = (float)(s * z);
	return *this;
}



inline
McGeVector3dFloat::McGeVector3dFloat() : x(0.0), y(0.0), z(0.0)
{
}

inline
McGeVector3dFloat::McGeVector3dFloat(const McGeVector3d& src) : x((float)(src.x)), y((float)(src.y)), z((float)(src.z))
{
}


inline
McGeVector3dFloat::McGeVector3dFloat(float xx, float yy, float zz) : x(xx), y(yy), z(zz)
{
}

inline
McGeVector3dFloat::McGeVector3dFloat(double xx, double yy, double zz) : x((float)(xx)), y((float)(yy)), z((float)(zz))
{
}

inline
McGeVector3dFloat::McGeVector3dFloat(double s) : x((float)(s)), y((float)(s)), z((float)(s))
{
}



inline
McGeVector3d::McGeVector3d(const McGeVector3dFloat& src) : x(src.x), y(src.y), z(src.z)
{
}