/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 *
 * The iWear Framework is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation as in version 2 of the License.

 * 
 * The iWear Framework is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWEAR_TRANSFORMATIONMATRIX_H
#define __IWEAR_TRANSFORMATIONMATRIX_H

#ifndef __IWEAR_MMATRIX_H
#include <iwear/mmatrix.h>
#endif

namespace iwear
{
    namespace math
    {

template<class T>	
class TransformationMatrix : public MathMatrix<T>
{
private:
protected:
    T Cos( const T& ) const;
    T Sin( const T& ) const;
    T Tan( const T& ) const;
    T ACos( const T& ) const;
    T ASin( const T& ) const;
    T ATan( const T& ) const;
    T ATan2( const T&, const T& ) const;
public:
    TransformationMatrix( const T& dx, const T& dy, const T& dz, 
	    const T& rotx, const T& roty, const T& rotz );
    template<class S> TransformationMatrix& operator=( const MathMatrix<S>& mm );
    TransformationMatrix<T>& operator=( const MathMatrix<T>& mm );
};

template<class T>
template<class S>
TransformationMatrix<T>& TransformationMatrix<T>::operator=( const MathMatrix<S>& mm )
{
    MathMatrix<T>::operator=(mm);
    return *this;
}

template<class T>
TransformationMatrix<T>& TransformationMatrix<T>::operator=( const MathMatrix<T>& mm )
{
    MathMatrix<T>::operator=(mm);
    return *this;
}

template<class T>
TransformationMatrix<T>::TransformationMatrix( const T& dx, const T& dy, const T& dz, const T& rotx, const T& roty, const T& rotz )/*{{{*/
	: MathMatrix<T>(MathMatrix<T>::unit(4))
{
    this->elem(0,3) = dx;
    this->elem(1,3) = dy;
    this->elem(2,3) = dz;

    T cos_rotz( Cos(rotz) );
    T cos_roty( Cos(roty) );
    T cos_rotx( Cos(rotx) );

    T sin_rotz( Sin(rotz) );
    T sin_roty( Sin(roty) );
    T sin_rotx( Sin(rotx) );
    //rotate movement
    T cos_rotz_sin_roty ( cos_rotz * sin_roty );
    T sin_rotz_sin_roty ( sin_rotz * sin_roty );

    this->elem(0,0) = cos_rotz * cos_roty;

    this->elem(0,1) = cos_rotz_sin_roty * sin_rotx -sin_rotz * cos_rotx;
    this->elem(0,2) = cos_rotz_sin_roty * cos_rotx +sin_rotz * sin_rotx;

    this->elem(1,0) = sin_rotz * cos_roty ;

    this->elem(1,1) = sin_rotz_sin_roty * sin_rotx +cos_rotz * cos_rotx;
    this->elem(1,2) = sin_rotz_sin_roty * cos_rotx -cos_rotz * sin_rotx;

    this->elem(2,0) = -sin_roty ;
    this->elem(2,1) = cos_roty * sin_rotx ;
    this->elem(2,2) = cos_roty * cos_rotx ;
}/*}}}*/

/*{{{*/ /*Trigonometric functions for double*/
template<>
inline double TransformationMatrix<double>::Cos( const double& t) const
{
    return cos(t);
}

template<>
inline double TransformationMatrix<double>::Sin( const double& t) const
{
    return sin(t);
}

template<>
inline double TransformationMatrix<double>::Tan( const double& t) const
{
    return tan(t);
}

template<>
inline double TransformationMatrix<double>::ACos( const double& t) const
{
    return acos(t);
}

template<>
inline double TransformationMatrix<double>::ASin( const double& t) const
{
    return asin(t);
}

template<>
inline double TransformationMatrix<double>::ATan( const double& t) const
{
    return atan(t);
}

template<>
inline double TransformationMatrix<double>::ATan2( const double& t, const double& n) const
{
    return atan2(t,n);
}
/*}}}*/

/*{{{*/ /*Trigonometric functions for float*/
template<>
inline float TransformationMatrix<float>::Cos( const float& t) const
{
    return cosf(t);
}

template<>
inline float TransformationMatrix<float>::Sin( const float& t) const
{
    return sinf(t);
}

template<>
inline float TransformationMatrix<float>::Tan( const float& t) const
{
    return tanf(t);
}

template<>
inline float TransformationMatrix<float>::ACos( const float& t) const
{
    return acosf(t);
}

template<>
inline float TransformationMatrix<float>::ASin( const float& t) const
{
    return asinf(t);
}

template<>
inline float TransformationMatrix<float>::ATan( const float& t) const
{
    return atanf(t);
}

template<>
inline float TransformationMatrix<float>::ATan2( const float& t, const float& n) const
{
    return atan2f(t,n);
}
/*}}}*/

/*{{{*/ /*Trigonometric functions for long double*/
template<>
inline long double TransformationMatrix<long double>::Cos( const long double& t) const
{
    return cosl(t);
}

template<>
inline long double TransformationMatrix<long double>::Sin( const long double& t) const
{
    return sinl(t);
}

template<>
inline long double TransformationMatrix<long double>::Tan( const long double& t) const
{
    return tanl(t);
}

template<>
inline long double TransformationMatrix<long double>::ACos( const long double& t) const
{
    return acosl(t);
}

template<>
inline long double TransformationMatrix<long double>::ASin( const long double& t) const
{
    return asinl(t);
}

template<>
inline long double TransformationMatrix<long double>::ATan( const long double& t) const
{
    return atanl(t);
}

template<>
inline long double TransformationMatrix<long double>::ATan2( const long double& t, const long double& n) const
{
    return atan2l(t,n);
}
/*}}}*/

}
}

#endif
