/****************************************************************************************

		Matrix33.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Vector Math Library, Release 2.0,  1/1/96 
		Copyright 1996 Alec Miller, All Rights Reserved 

		Revision History

		when		who			what & why
		==========	==========	======================================================
		09/01/99	Mathieu		GetOrthogonal()
		5/21/98		Greg		Fixed double to float warning (again?)
		5/18/98		Greg		Made Inverse() const.
		12/8/97		Ian			Removed iostream stuff altogether it's not compatible with
								Windows or MSL.
		5/15/96		Alec		new today - added vector math library to InfiniD project

*****************************************************************************************/

#ifndef H_MATRIX33
#define H_MATRIX33

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "Vector3.h"
#include "MCAssert.h"
#include "Matrix33Fwd.h"



/// \addtogroup Math
/// \{

/// Stores a 3 by 3 matrix and implements basic matrix operations.
/// The matrix coeficients are stored in the #value field

template<class T>
class TMatrix33Template : public TMCObject0
{
	// this class cannot have virtual functions for C size compatability
	
	public:
		// constant definitions
		static const TMatrix33Template<T> kIdentity;
		static const TMatrix33Template<T> kZero;
		
	public :
		// initialization
		inline TMatrix33Template		 (void);

		template<class U>
		inline TMatrix33Template		 (const TMatrix33Template<U>& original)
		{ *this = original; }

		inline TMatrix33Template		 (const T& m00, const T& m01, const T& m02,
										  const T& m10, const T& m11, const T& m12,
										  const T& m20, const T& m21, const T& m22);
		
		inline uint32 GetRowDimension	 (void) const;
		inline uint32 GetColumnDimension (void) const;
		
		// element access - since there is no [][] operator
		inline T	operator()			 (const uint32 row, const uint32 col) const;
		inline T&	operator()			 (const uint32 row, const uint32 col);
		
		// for [][] access only - second index unchecked
		inline const T*		operator[]	 (const uint32 row) const;
		inline T*			operator[]	 (const uint32 row);
		
		// row and column access
		void	GetRow					 (const uint32 row, TVector3Template<T>& v) const;
		void	SetRow					 (const uint32 row, const TVector3Template<T>& v);
		
		void	GetColumn				 (const uint32 col, TVector3Template<T>& v) const;
		void	SetColumn				 (const uint32 col, const TVector3Template<T>&	v);

		// matrix conversion
		void	SetToTranspose			 (void);
		void	SetToTransposeOf		 (const TMatrix33Template<T>& source);
		
		// standard matrix properties		
		TMatrix33Template<T> GetTranspose	 (void) const;
		TMatrix33Template<T> GetAdjoint		 () const;
		TMatrix33Template<T> GetOrthonormal	 (boolean* success, int32 keepAxis=0) const;	// orthonormalize the matrix
		TMatrix33Template<T> GetOrthgonalize (boolean* success, int32 keepAxis=0) const;	// orthogonalize the matrix
		boolean				 IsOrthogonal() const;

		void				Triangulate(TMatrix33Template<T>& orthoL, TMatrix33Template<T>& orthoR);

		T	GetTrace					 (void) const;
		T	GetDeterminant				 (void) const;
		T	GetNorm2					 (void) const;

		void Multiply					 (const TMatrix33Template<T>& m, const TMatrix33Template<T>& n);
	
		// fast matrix operation		
		TMatrix33Template<T>& operator*= (const T& scalar);

		template<class U>
		TMatrix33Template<T>& operator=	 (const TMatrix33Template<U>& original)
		{
			for (int32 x=0;x<3;x++)
			{
				for (int32 y=0;y<3;y++)
				{
					value[x][y] = (U)original(x, y);
				}
			}
			return *this;
		}

		TMatrix33Template<T>& operator=	 (const int32 i);
		TMatrix33Template<T>& operator+= (const TMatrix33Template<T>& m);
		TMatrix33Template<T>& operator-= (const TMatrix33Template<T>& m);

		TMatrix33Template<T>  operator+  (const TMatrix33Template<T>& r) const;
		TMatrix33Template<T>  operator-  (const TMatrix33Template<T>& r) const;
		TMatrix33Template<T>  operator*  (const TMatrix33Template<T>& r) const;
		
		inline TMatrix33Template<T> operator- () const
		{
			TMatrix33Template<T> out;
			for (int32 x=0;x<3;x++)
			{
				for (int32 y=0;y<3;y++)
				{
					out(x, y) = -value[x][y];
				}
			}
			return out;
		}

		inline boolean operator==	(const TMatrix33Template<T>& rhs) const
		{ return IsEqual(rhs); }

		inline boolean operator!=	(const TMatrix33Template<T>& rhs) const
		{ return ! IsEqual( rhs ); }
		
	public:
		// these routines were added to support existing code in RealMatrix33
		void SetColumns					 (const TVector3Template<T>& c0, const TVector3Template<T>& c1, const TVector3Template<T>& c2);
		void GetColumns					 (TVector3Template<T>& c0, TVector3Template<T>& c1, TVector3Template<T>& c2) const;
		
		void SetToDiagonalTfm			 (const T& x, const T& y, const T& z);
		void SetPhyThetaPsy				 (const T& phy, const T& theta, const T& psy, boolean isDirect);
		void GetPhyThetaPsy				 (T& phy, T& theta, T& psy, boolean& isDirect) const;
		
		boolean IsEqual					 (const TMatrix33Template<T>& rhs, const T& zeroTolerance = 0.0) const;
		boolean IsEqualRelative			 (const TMatrix33Template<T>& rhs, const T& zeroTolerance = 0.0) const;
	
	public:
		// these are the depricated names from RealMatrix33, use the direct equivs for new code
		inline void SetIJK				 (const TVector3Template<T>& c0, const TVector3Template<T>& c1, const TVector3Template<T>& c2)
			{ SetColumns( c0, c1, c2 ); }	
		
		inline void GetIJK				 (TVector3Template<T>& c0, TVector3Template<T>& c1, TVector3Template<T>& c2) const
			{ GetColumns( c0, c1, c2 ); }
		
		inline void SetDiagonal			 (const T& x, const T& y, const T& z)
			{ SetToDiagonalTfm( x, y, z ); }	
		
		inline void Reset				 ()
			{ *this = TMatrix33Template<T>::kIdentity; }
	 		
	 	inline boolean IsIdentity		 () const
	 		{ 
	 			return ( this == &TMatrix33Template<T>::kIdentity ) ||
	 					 this->IsEqual( TMatrix33Template<T>::kIdentity );
	 		}
	 	
	 	inline TMatrix33Template<T> Transpose () const
	 		{ return GetTranspose(); }
		
		// use TMtxMath::SolveInverseGeneralCR instead of this
		TMatrix33Template<T> Inverse			(boolean* success) const;
				
	protected:
		T value[3][3];	///< Stores the coeficients of the matrix in the form value[row][col]
};

/// \}

// [operator definitions] --------------------------------------------------------------//

//  TMatrix33 operations
template<class T>
TMatrix33Template<T> operator*  (const real s, const TMatrix33Template<T>& r)
{ return TMatrix33Template<T>(r) *= (T)s; }

template<class T>
TMatrix33Template<T> operator*  (const real64& s, const TMatrix33Template<T>& r)
{ return TMatrix33Template<T>(r) *= (T)s; }

//  TVector3 operations
template<class T, class U>
inline TVector3Template<U>	 operator * (const TVector3Template<U>&  v, const TMatrix33Template<T>& m) 
{
	return TVector3Template<U>
				   (v(0)*m(0,0) + v(1)*m(1,0) + v(2)*m(2,0),
					v(0)*m(0,1) + v(1)*m(1,1) + v(2)*m(2,1),
					v(0)*m(0,2) + v(1)*m(1,2) + v(2)*m(2,2));
}

template<class T, class U>
inline TVector3Template<U> operator * (const TMatrix33Template<T>& m, const TVector3Template<U>&  v) 
{
	return TVector3Template<U>
				   (v(0)*m(0,0) + v(1)*m(0,1) + v(2)*m(0,2),
					v(0)*m(1,0) + v(1)*m(1,1) + v(2)*m(1,2),
					v(0)*m(2,0) + v(1)*m(2,1) + v(2)*m(2,2));
}



// [inline implementation] -------------------------------------------------------------//

template<class T>
inline TMatrix33Template<T>::TMatrix33Template (void)
	{ }

template<class T>
inline TMatrix33Template<T>::TMatrix33Template (
							 const T& m00, const T& m01, const T& m02,
							 const T& m10, const T& m11, const T& m12,
							 const T& m20, const T& m21, const T& m22 )
	{
		value[0][0] = m00; value[0][1] = m01; value[0][2] = m02; 
		value[1][0] = m10; value[1][1] = m11; value[1][2] = m12;
		value[2][0] = m20; value[2][1] = m21; value[2][2] = m22;
	}

template<class T>
inline uint32 TMatrix33Template<T>::GetRowDimension	(void) const
	{ return 3; }
	
template<class T>
inline uint32 TMatrix33Template<T>::GetColumnDimension (void) const	
	{ return 3; }

template<class T>
inline T	  TMatrix33Template<T>::operator()			(const uint32 row,const uint32 col) const
	{ return value[row][col]; }

template<class T>
inline T&	TMatrix33Template<T>::operator()		(const uint32 row, const uint32 col)
	{ return value[row][col]; }

template<class T>
inline const T* TMatrix33Template<T>::operator[]	(const uint32 row) const
	{ return value[row]; }
	
template<class T>
inline T*    TMatrix33Template<T>::operator[]		(const uint32 row)
	{ return value[row]; }
	
template<class T>
inline TMatrix33Template<T>& TMatrix33Template<T>::operator=	(const int32 i)
{
	MCAssert(i==0);

	for (int32 x=0;x<3;x++)
	{
		for (int32 y=0;y<3;y++)
		{
			value[x][y]=i;
		}
	}
	return *this;
}


#endif /* H_MATRIX33 */	