aboutsummaryrefslogblamecommitdiffstats
path: root/meowpp/math/LinearTransformations.h
blob: 4bf9a366203e93b06e7d45798642dcd2e91d63a6 (plain) (tree)
1
2
3
4
5
6
7
8



                                        



                           


                  












                                                                             
 
                                            
     
 
                                                               
     
 
               
     
    
 
                          
 

                           








                                                         
 










                                                                        


                            
 



                                 
                                                                  
   
 



                                                                   
                                         
   
 




                 
 










                                              
 
























                                                   
 










                                       
 

















                                                  
 











                                                                   
 









                                                  
 

                               
 
































                                                                                
                 

                                                      
 

























                                                                            
                 

                                                  
 








































































                                                                            
                 






















                                                                 
                           
   
 






                                                                               
                       
   
 







                                                                               
                 












                                            

                                             









                                                                             
                 

                                                              
 





                                              
         

                                        
#ifndef   math_LinearTransformations_H__
#define   math_LinearTransformations_H__

#include "LinearTransformation.h"
#include "Matrix.h"
#include "utility.h"
#include "../Self.h"
#include "../geo/Vectors.h"

#include <cstdlib>

namespace meow {

/*!
 * @brief Rotation a point/vector alone an axis with given angle in 3D world.
 *
 * @author cat_leopard
 */
template<class Scalar>
class Rotation3D: public LinearTransformation<Scalar> {
private:
  struct Myself {
    Vector3D<Scalar> theta_;
    bool              need_;

    Myself(): theta_(0, 0, 0), need_(true) {
    }

    Myself(Myself const& b): theta_(b.theta_), need_(b.need_) {
    }

    ~Myself() {
    }
  };

  Self<Myself> const self;

  void calcMatrix() const {
    if (self->need_) {
      Matrix<Scalar> tmp(3, 3, 0.0);
      if (noEPS(self->theta_.length2()) == 0) {
        tmp.identitied();
      }
      else {
        Vector3D<double> axis (self->theta_.normalize());
        double           angle(self->theta_.length());
        double           cs(cos(angle / 2.0));
        double           sn(sin(angle / 2.0));

        tmp.entry(0, 0, 2*(squ(axis.x())-1.0)*squ(sn) + 1);
        tmp.entry(1, 1, 2*(squ(axis.y())-1.0)*squ(sn) + 1);
        tmp.entry(2, 2, 2*(squ(axis.z())-1.0)*squ(sn) + 1);
        tmp.entry(0, 1, 2*axis.x()*axis.y()*squ(sn) - 2*axis.z()*cs*sn);
        tmp.entry(1, 0, 2*axis.y()*axis.x()*squ(sn) + 2*axis.z()*cs*sn);
        tmp.entry(0, 2, 2*axis.x()*axis.z()*squ(sn) + 2*axis.y()*cs*sn);
        tmp.entry(2, 0, 2*axis.z()*axis.x()*squ(sn) - 2*axis.y()*cs*sn);
        tmp.entry(1, 2, 2*axis.y()*axis.z()*squ(sn) - 2*axis.x()*cs*sn);
        tmp.entry(2, 1, 2*axis.z()*axis.y()*squ(sn) + 2*axis.x()*cs*sn);
      }
      ((Rotation3D*)this)->LinearTransformation<Scalar>::matrix(tmp);
      self()->need_ = false;
    }
  }

public:
  /*!
   * Constructor with no rotation
   */
  Rotation3D(): LinearTransformation<Scalar>(3u, 3u, 3u), self() {
  }

  /*!
   * Constructor and copy data
   */
  Rotation3D(Rotation3D const& b): LinearTransformation<Scalar>(b),
  self(b.self, Self<Myself>::COPY_FROM) {
  }

  /*!
   * Destructor
   */
  ~Rotation3D() {
  }

  /*!
   * @brief Copy data
   *
   * @param [in] b another Rotation3D class.
   * @return \c *this
   */
  Rotation3D& copyFrom(Rotation3D const& b) {
    LinearTransformation<Scalar>::copyFrom(b);
    self().copyFrom(b.self);
    return *this;
  }

  /*!
   * @brief Reference data
   *
   * @param [in] b another Rotation3D class.
   * @return \c *this
   */
  Rotation3D& referenceFrom(Rotation3D const& b) {
    LinearTransformation<Scalar>::referenceFrom(b);
    self().referenceFrom(b.self);
    return *this;
  }

  /*!
   * @brief same as \c theta(i)
   */
  Scalar parameter(size_t i) const {
    return theta(i);
  }

  /*!
   * @brief same as \c theta(i, s)
   */
  Scalar parameter(size_t i, Scalar const& s) {
    return theta(i, s);
  }

  /*!
   * @brief Get the \c i -th theta
   *
   * \c i can only be 1, 2 or 3
   *
   * @param [in] i index
   * @return \c i -th theta
   */
  Scalar const& theta(size_t i) const {
    return self->theta_(i);
  }

  /*!
   * @brief Set the \c i -th theta
   *
   * \c i can only be 1, 2 or 3
   *
   * @param [in] i index
   * @param [in] s new theta value
   * @return \c i -th theta
   */
  Scalar const& theta(size_t i, Scalar const& s) {
    if (theta(i) != s) {
      if      (i == 0) self()->theta_.x(s);
      else if (i == 1) self()->theta_.y(s);
      else if (i == 2) self()->theta_.z(s);
      self()->need_ = true;
    }
    return theta(i);
  }

  /*!
   * @brief Setting
   *
   * @param [in] axis  axis
   * @param [in] angle angle
   */
  void axisAngle(Vector<Scalar> const& axis, Scalar const& angle) {
    Vector<Scalar> n(axis.normalize());
    for (size_t i = 0; i < 3; i++) {
      theta(i, n(i) * angle);
    }
  }

  /*!
   * @brief Concat another rotation transformation
   * @param [in] r another rotation transformation
   */
  Rotation3D& add(Rotation3D const& r) {
    for (size_t i = 0; i < 3; i++) {
      theta(i, r.theta(i));
    }
    return *this;
  }

  /*!
   * @brief Do the transformate

   * Assume:
   *  - The input  vector is \f$ (x ,y ,z ) \f$
   *  - The output vector is \f$ (x',y',z') \f$
   *  - The parameters theta is\f$ \vec{\theta}=(\theta_x,\theta_y,\theta_z) \f$
   *  .
   * Then we have:
   * \f[
   *   \left[ \begin{array}{c} x' \\ y' \\ z' \\ \end{array} \right]
   *   =
   *   \left[ \begin{array}{ccc}
   *     2(n_x^2 - 1) \sin^2\phi + 1                  &
   *     2n_x n_y \sin^2\phi - 2n_z\cos \phi\sin \phi &
   *     2n_x n_z \sin^2\phi + 2n_y\cos \phi\sin \phi \\
   *     2n_y n_x \sin^2\phi + 2n_z\cos \phi\sin \phi &
   *     2(n_y^2 - 1) \sin^2\phi + 1                  &
   *     2n_y n_z \sin^2\phi - 2n_x\cos \phi\sin \phi \\
   *     2n_z n_x \sin^2\phi - 2n_y\cos \phi\sin \phi &
   *     2n_z n_y \sin^2\phi + 2n_x\cos \phi\sin \phi &
   *     2(n_z^2 - 1) \sin^2\phi + 1                  \\
   *   \end{array} \right]
   *   \left[ \begin{array}{c} x \\ y \\ z \\ \end{array} \right]
   * \f]
   * Where:
   *  - \f$ \phi \f$ is the helf of length of \f$ \vec{\theta} \f$ ,
   *    which means \f$ \phi = \frac{\left|\vec{\theta}\right|}{2}
   *           = \frac{1}{2}\sqrt{\theta_x^2 + \theta_y^2 + \theta_z^2} \f$
   *  - \f$ \vec{n} \f$ is the normalized form of \f$ \vec{\theta} \f$ ,
   *    which means \f$ \vec{n} = (n_x,n_y,n_z) = \vec{\theta} / 2\phi \f$
   *
   * @param [in] x the input vector
   * @return the output matrix
   */
  Matrix<Scalar> transformate(Matrix<Scalar> const& x) const {
    calcMatrix();
    return LinearTransformation<Scalar>::matrix() * x;
  }

  /*!
   * @brief Return the jacobian matrix (derivate by the input vector)
   *        of this transformate
   *
   * The matrix we return is:
   * \f[
   *   \left[ \begin{array}{ccc}
   *     2(n_x^2 - 1) \sin^2\phi + 1                  &
   *     2n_x n_y \sin^2\phi - 2n_z\cos \phi\sin \phi &
   *     2n_x n_z \sin^2\phi + 2n_y\cos \phi\sin \phi \\
   *     2n_y n_x \sin^2\phi + 2n_z\cos \phi\sin \phi &
   *     2(n_y^2 - 1) \sin^2\phi + 1                  &
   *     2n_y n_z \sin^2\phi - 2n_x\cos \phi\sin \phi \\
   *     2n_z n_x \sin^2\phi - 2n_y\cos \phi\sin \phi &
   *     2n_z n_y \sin^2\phi + 2n_x\cos \phi\sin \phi &
   *     2(n_z^2 - 1) \sin^2\phi + 1                  \\
   *   \end{array} \right]
   * \f]
   * Where the definition of \f$ \vec{n} \f$ and \f$ \phi \f$
   * is the same as the definition in the description of
   * the method \b transformate() .
   *
   * @param [in] x the input vector (in this case it is a useless parameter)
   * @return a matrix
   */
  Matrix<Scalar> jacobian(Matrix<Scalar> const& x) const {
    calcMatrix();
    return LinearTransformation<Scalar>::matrix();
  }

  /*!
   * @brief Return the jacobian matrix of this transformate
   *
   * Here we need to discussion in three case:
   *  - \a i = 0, derivate by the x axis of the vector theta
   *   \f[
   *     \left[ \begin{array}{ccc}
   *        0 &  0 &  0 \\
   *        0 &  0 & -1 \\
   *        0 &  1 &  0 \\
   *     \end{array} \right]
   *     \left[ \begin{array}{ccc}
   *     2(n_x^2 - 1) \sin^2\phi + 1                  &
   *     2n_x n_y \sin^2\phi - 2n_z\cos \phi\sin \phi &
   *     2n_x n_z \sin^2\phi + 2n_y\cos \phi\sin \phi \\
   *     2n_y n_x \sin^2\phi + 2n_z\cos \phi\sin \phi &
   *     2(n_y^2 - 1) \sin^2\phi + 1                  &
   *     2n_y n_z \sin^2\phi - 2n_x\cos \phi\sin \phi \\
   *     2n_z n_x \sin^2\phi - 2n_y\cos \phi\sin \phi &
   *     2n_z n_y \sin^2\phi + 2n_x\cos \phi\sin \phi &
   *     2(n_z^2 - 1) \sin^2\phi + 1                  \\
   *     \end{array} \right]
   *     \left[ \begin{array}{c} x \\ y \\ z \\ \end{array} \right]
   *   \f]
   *  - \a i = 1, derivate by the y axis of the vector theta
   *   \f[
   *     \left[ \begin{array}{ccc}
   *        0 &  0 &  1 \\
   *        0 &  0 &  0 \\
   *       -1 &  0 &  0 \\
   *     \end{array} \right]
   *     \left[ \begin{array}{ccc}
   *     2(n_x^2 - 1) \sin^2\phi + 1                  &
   *     2n_x n_y \sin^2\phi - 2n_z\cos \phi\sin \phi &
   *     2n_x n_z \sin^2\phi + 2n_y\cos \phi\sin \phi \\
   *     2n_y n_x \sin^2\phi + 2n_z\cos \phi\sin \phi &
   *     2(n_y^2 - 1) \sin^2\phi + 1                  &
   *     2n_y n_z \sin^2\phi - 2n_x\cos \phi\sin \phi \\
   *     2n_z n_x \sin^2\phi - 2n_y\cos \phi\sin \phi &
   *     2n_z n_y \sin^2\phi + 2n_x\cos \phi\sin \phi &
   *     2(n_z^2 - 1) \sin^2\phi + 1                  \\
   *     \end{array} \right]
   *     \left[ \begin{array}{c} x \\ y \\ z \\ \end{array} \right]
   *   \f]
   *  - \a i = 2, derivate by the z axis of the vector theta
   *   \f[
   *     \left[ \begin{array}{ccc}
   *        0 & -1 &  0 \\
   *        1 &  0 &  0 \\
   *        0 &  0 &  0 \\
   *     \end{array} \right]
   *     \left[ \begin{array}{ccc}
   *     2(n_x^2 - 1) \sin^2\phi + 1                  &
   *     2n_x n_y \sin^2\phi - 2n_z\cos \phi\sin \phi &
   *     2n_x n_z \sin^2\phi + 2n_y\cos \phi\sin \phi \\
   *     2n_y n_x \sin^2\phi + 2n_z\cos \phi\sin \phi &
   *     2(n_y^2 - 1) \sin^2\phi + 1                  &
   *     2n_y n_z \sin^2\phi - 2n_x\cos \phi\sin \phi \\
   *     2n_z n_x \sin^2\phi - 2n_y\cos \phi\sin \phi &
   *     2n_z n_y \sin^2\phi + 2n_x\cos \phi\sin \phi &
   *     2(n_z^2 - 1) \sin^2\phi + 1                  \\
   *     \end{array} \right]
   *     \left[ \begin{array}{c} x \\ y \\ z \\ \end{array} \right]
   *   \f]
   *  .
   * Where \f$ (x,y,z) \f$ is the input vector, \f$ \vec{n}, \phi \f$ is the
   * same one in the description of \b transformate().
   *
   * @param [in] x the input vector
   * @param [in] i the index of the parameters(theta) to dervite
   * @return a matrix
   */
  Matrix<Scalar> jacobian(Matrix<Scalar> const& x, size_t i) const {
    calcMatrix();
    Matrix<Scalar> mid(3u, 3u, Scalar(0.0));
    if (i == 0) {
      mid.entry(1, 2, Scalar(-1.0));
      mid.entry(2, 1, Scalar( 1.0));
    }
    else if(i == 1) {
      mid.entry(0, 2, Scalar( 1.0));
      mid.entry(2, 0, Scalar(-1.0));
    }
    else {
      mid.entry(0, 1, Scalar(-1.0));
      mid.entry(1, 0, Scalar( 1.0));
    }
    return mid * LinearTransformation<Scalar>::matrix() * x;
  }

  /*!
   * @brief Do the inverse transformate
   *
   * @param [in] x the input vector
   * @return the output vector
   */
  Matrix<Scalar> transformateInv(Matrix<Scalar> const& x) const {
    return matrixInv() * x;
  }

  /*!
   * @brief Return the jacobian matrix of the inverse form of this transformate
   *
   * @param [in] x the input vector
   * @return a matrix
   */
  Matrix<Scalar> jacobianInv(Matrix<Scalar> const& x) const {
    return matrixInv();
  }

  /*!
   * @brief Return the jacobian matrix of the inverse form of this transformate
   *
   * @param [in] x the input vector
   * @param [in] i the index of the parameters(theta) to dervite
   * @return a matrix
   */
  Matrix<Scalar> jacobianInv(Matrix<Scalar> const& x, size_t i) const {
    calcMatrix();
    Matrix<Scalar> mid(3u, 3u, Scalar(0.0));
    if (i == 0) {
      mid.entry(1, 2, Scalar(-1.0));
      mid.entry(2, 1, Scalar( 1.0));
    }
    else if(i == 1) {
      mid.entry(0, 2, Scalar( 1.0));
      mid.entry(2, 0, Scalar(-1.0));
    }
    else {
      mid.entry(0, 1, Scalar(-1.0));
      mid.entry(1, 0, Scalar( 1.0));
    }
    return matrixInv() * mid.transpose() * x;
    return (-mid) * matrixInv() * x;
  }

  /*!
   * @brief Return the inverse matrix
   *
   * In this case, the inverse matrix is equal to the transpose of the matrix
   *
   * @return a matrix
   */
  Matrix<Scalar> matrixInv() const {
    calcMatrix();
    return LinearTransformation<Scalar>::matrix().transpose();
  }

  //! @brief same as \c copyFrom(b)
  Rotation3D& operator=(Rotation3D const& b) {
    return copyFrom(b);
  }
};

} // meow

#endif // math_LinearTransformations_H__