
template< typename T >
Aftr::AxisAngleT<T>::AxisAngleT() noexcept {}

template< typename T >
Aftr::AxisAngleT<T>::AxisAngleT( VectorT<T> const& axis, T angleDeg ) noexcept : 
   axis_( axis.normalizeMe() ), 
   deg_( AxisAngleImpl::modulus_deg_180_to_neg180(angleDeg) )
{
   if( deg_ < 0 )
   {
      deg_ = -deg_;
      axis_ = -axis_;
   }
}

template< typename T >
Aftr::AxisAngleT<T>::AxisAngleT( Aftr::AxisAngleT<T> const& toCopy ) noexcept
{
   *this = toCopy;
}

template< typename T >
Aftr::AxisAngleT<T>::AxisAngleT( Aftr::VectorT<T> const& rodrigues_rot_vec ) noexcept
{
   T angleDeg = rodrigues_rot_vec.length() * T( Aftr::RADtoDEGd );
   deg_ = AxisAngleImpl::modulus_deg_180_to_neg180( angleDeg );
   this->axis_ = rodrigues_rot_vec.normalizeMe();
   if( this->axis_.isEqual( { 0,0,0 } ) )
      this->axis_ = { 0,0,1 };
   //length / magnitude will always be positive on Vector
}

template< typename T >
Aftr::AxisAngleT<T>& Aftr::AxisAngleT<T>::operator=( const Aftr::AxisAngleT<T>& aa ) noexcept
{
   if( this != &aa )
   {
      this->axis_ = aa.axis_;
      this->deg_ = aa.deg_;
   }
   return *this;
}

template< typename T >
bool Aftr::AxisAngleT<T>::isEqual( AxisAngleT<T> const& b, T epsilon ) const noexcept
{
   return AxisAngleImpl::isEqual( *this, b, epsilon );
}

//template< typename T >
//void Aftr::AxisAngleT<T>::toRotationMatrix(T m[]) const
//{
//   m[3]  = m[7]  = m[11] = 0;
//   m[12] = m[13] = m[14] = 0;
//   m[15] = 1;
//   m[0] = a * a + b * b - c * c - d * d;
//   m[1] = T(2.0) * b * c - T(2.0) * a * d;
//   m[2] = T(2.0) * a * c + T(2.0) * b * d;
//   m[4] = T(2.0) * a * d + T(2.0) * b * c;
//   m[5] = a * a - b * b + c * c - d * d;
//   m[6] = T(2.0) * c * d - T(2.0) * a * b;
//   m[8] = T(2.0) * b * d - T(2.0) * a * c;
//   m[9] = T(2.0) * a * b + T(2.0) * c * d;
//   m[10] = a * a - b * b - c * c + d * d;
//}

template< typename T >
std::string Aftr::AxisAngleT<T>::toString( size_t length) const
{
   return AxisAngleImpl::toString( *this, length );
}

template< typename T >
Aftr::VectorT<T> const& Aftr::AxisAngleT<T>::axis() const noexcept
{
   return this->axis_;
}

template< typename T >
T Aftr::AxisAngleT<T>::deg() const noexcept
{
   return this->deg_;
}

template< typename T >
T Aftr::AxisAngleT<T>::rad() const noexcept
{
   return this->deg_ * T( Aftr::DEGtoRADd );
}

template< typename T >
Aftr::VectorT<T> Aftr::AxisAngleT<T>::toRodrigues() const noexcept
{
   //if the radian measure is nearly exactly 180, like 180.00000000003,
   //we have to be careful to handle the normalization into rodrigues properly


   VectorT<T> rod{ this->axis_ * this->rad() };
   return rod;
}

template< typename T >
Aftr::VectorT<T> Aftr::AxisAngleT<T>::toVec() const noexcept
{
   VectorT<T> v = VectorT<T>{ T(1),T(0),T(0) }.rotate( this->axis_, this->rad() );
   return v;
}