//
//	Copyright © 2005 Nemetschek North America 
//	All Rights Reserved.
//
// Created by Vladislav Stanev

#pragma once

namespace VWFC
{
	namespace Math
	{
		class VWTransformMatrix
		{
		public:
									VWTransformMatrix();
									VWTransformMatrix(const VWPoint3D& uVec, const VWPoint3D& vVec, const VWPoint3D& wVec, bool bTransponse=false);
									VWTransformMatrix(const VWPoint3D& uVec, const VWPoint3D& vVec, const VWPoint3D& wVec, const VWPoint3D& offset, bool bTransponse=false);
									VWTransformMatrix(const VWPoint3D& offset);
									VWTransformMatrix(double scaleX, double scaleY, double scaleZ);
									VWTransformMatrix(const TransformMatrix& mat);
									VWTransformMatrix(const VWTransformMatrix& mat);
			virtual					~VWTransformMatrix();

			VWTransformMatrix&		operator=(const VWTransformMatrix& mat);

			bool					operator==(const VWTransformMatrix& mat) const;

		public:
			void					SetIdentity();
			bool					IsIdentity() const;

			bool					IsEqual(const VWTransformMatrix& mat) const;

			void					SetRotation(double angleDeg, VWPoint3D axisRot);
			void					SetTranslation(double x, double y, double z);
			void					SetTranslation(const VWPoint3D& pt);
			void					SetMatrix(const VWPoint3D& uVec, const VWPoint3D& vVec, const VWPoint3D& wVec, bool bTransponse=false);
			void					SetMatrix(const VWPoint3D& uVec, const VWPoint3D& vVec, const VWPoint3D& wVec, const VWPoint3D& offset, bool bTransponse=false);
			void					SetMatrix(const VWPoint3D& offset);
			void					SetMatrix(double scaleX, double scaleY, double scaleZ);

			VWPoint3D				GetUVector() const;
			void					SetUVector(double x, double y, double z);
			void					SetUVector(const VWPoint3D& uVec);
			VWPoint3D				GetVVector() const;
			void					SetVVector(double x, double y, double z);
			void					SetVVector(const VWPoint3D& vVec);
			VWPoint3D				GetWVector() const;
			void					SetWVector(double x, double y, double z);
			void					SetWVector(const VWPoint3D& wVec);

			VWPoint3D				GetOffset() const;
			void					SetOffset(double x, double y, double z);
			void					SetOffset(const VWPoint3D& off);

			VWTransformMatrix&		Invert();
			VWTransformMatrix		Invert() const;
			VWTransformMatrix		GetInverted() const;

			bool					IsFlipped() const;
			void					FlipMatrix();

			void					TranslateAfter(double x, double y, double z);
			void					TranslateAfter(const VWPoint3D& offset);

			void					TranslateBefore(double x, double y, double z);
			void					TranslateBefore(const VWPoint3D& offset);

			void					RotateXAfter(double angleDeg); 
			void					RotateYAfter(double angleDeg);
			void					RotateZAfter(double angleDeg);

			void					RotateXBefore(double angleDeg);
			void					RotateYBefore(double angleDeg);
			void					RotateZBefore(double angleDeg);

			void					RotateRoundPoint(const VWPoint3D& centerPt, double angXDeg, double angYDeg, double angZDeg);

			void					ScaleAfter(double scaleX, double scaleY, double scaleZ);

			void					ScaleWithCenter(const VWPoint3D& centerPt, double scaleX, double scaleY, double scaleZ);

			VWPoint2D				PointTransform(const VWPoint2D& point) const;
			VWPoint3D				PointTransform(const VWPoint3D& point) const;
			VWPoint2D				InversePointTransform(const VWPoint2D& point) const;
			VWPoint3D				InversePointTransform(const VWPoint3D& point) const;

			// operations
			VWPoint2D				operator*(const VWPoint2D& point) const;
			VWPoint3D				operator*(const VWPoint3D& point) const;
			VWTransformMatrix		operator*(const VWTransformMatrix& matrix) const;
			VWTransformMatrix&		operator*=(const VWTransformMatrix& matrix);

		public:
			// compatibility with SDK
									operator const TransformMatrix&() const;
									operator TransformMatrix&();


		public:
			bool					CalcTransformFromOneTriToAnother(
											const VWPoint3D& inPt1, const VWPoint3D& inPt2, const VWPoint3D& inPt3,
											const VWPoint3D& transfPt1, const VWPoint3D& transfPt2, const VWPoint3D& transfPt3);

			// matrix data
		public:
			// m[0][0] m[0][1] m[0][2]	- u(x, y, z) 
			// m[1][0] m[1][1] m[1][2]	- v(x, y, z)
			// m[2][0] m[2][1] m[2][2]	- w(x, y, z)
			// m[3][0] m[3][1] m[3][2]  - offset(x,y,z)
			double		m[4][3];

		private:
			// SDK matrix kept for casting
			TransformMatrix		fMatrix;
		};
	}
}

