Skip to content
Snippets Groups Projects
Forked from gmsh / gmsh
11315 commits behind the upstream repository.
stat_coordsys.h 10.55 KiB
// -*-c++-*-
#ifndef IG_STAT_COORDSYS_H
#define IG_STAT_COORDSYS_H

// $Id: stat_coordsys.h,v 1.1.2.6 2005/05/30 09:14:25 hkuiper Exp $

// CwMtx matrix and vector math library
// Copyright (C) 1999-2001  Harry Kuiper
// Copyright (C) 2000  Will DeVore (template conversion)

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA

#ifndef IG_STAT_SMATRIX_H
#include "stat_smatrix.h"
#endif

#ifndef IG_STAT_QUATERNION_H
#include "stat_quatern.h"
#endif

#ifndef IG_STAT_SVECTOR_H
#include "stat_svector.h"
#endif

// CWTSSquareMatrix utilities for use in coordinate systems

namespace CwMtx
{

  // NOTE: These template functions only work with floating point
  // template arguments due to the use of sin(3), cos(3), tan(3), etc.

  // PLEASE, READ THIS!!!

  // Function smatFromEuler321(sclrAbout3, sclrAbout2, sclrAbout1)
  // returns a transformation matrix which transforms coordinates from
  // the reference axis system to coordinates in an axis system with
  // Euler angles: sclrAbout3, sclrAbout2, sclrAbout1 relative to that
  // reference axis system DO NOT CHANGE THIS DEFINITION!!!

  // rotation about axis 3 (yaw angle), axis 2 (pitch angle) axis 1
  // (roll angle)
  template <class T>
  CWTSSquareMatrix<3, T>
  smatFromEuler321Angles(T sclrAbout3,
			 T sclrAbout2,
			 T sclrAbout1)
  {
    CWTSSquareMatrix<3, T> smat;

    // to reduce the number of calls to CPU expensive sin(..) and
    // cos(..) functions
    T sin3 = sin(sclrAbout3);
    T sin2 = sin(sclrAbout2);
    T sin1 = sin(sclrAbout1);

    T cos3 = cos(sclrAbout3);
    T cos2 = cos(sclrAbout2);
    T cos1 = cos(sclrAbout1);

    // first row
    smat[0][0] =  cos3*cos2;
    smat[0][1] =  sin3*cos2;
    smat[0][2] = -sin2;

    // second row
    smat[1][0] = -sin3*cos1 + cos3*sin2*sin1;
    smat[1][1] =  cos3*cos1 + sin3*sin2*sin1;
    smat[1][2] =  cos2*sin1;

    // third row
    smat[2][0] =  sin3*sin1 + cos3*sin2*cos1;
    smat[2][1] = -cos3*sin1 + sin3*sin2*cos1;
    smat[2][2] =  cos2*cos1;

    return smat;
  }

  // Next three functions calculate Euler angles from a transformation matrix
  // WARNING!!! They suffer from the ubiquitos singularities at 0, pi, 2*pi,
  // etc.

  // yaw angle, rotation angle about Z-axis
  template <class T>
  T
  euler321Angle3FromSmat(const CWTSSquareMatrix<3, T> &smat)
  {
    return atan2(smat[0][1], smat[0][0]);
  }

  // pitch angle, rotation angle about Y-axis
  template <class T>
  T
  euler321Angle2FromSmat(const CWTSSquareMatrix<3, T> &smat)
  {
    return asin(-smat[0][2]);
  }

  // roll angle, rotation angle about X-axis
  template <class T>
  T
  euler321Angle1FromSmat(const CWTSSquareMatrix<3, T> &smat)
  {
    return atan2(smat[1][2], smat[2][2]);
  }

  // CWTSQuaternion utilities for use in coordinate systems

  // PLEASE, READ THIS!!!

  // next three functions calculate Euler angles from a quaternion
  // that represents a rigid body's attitude WARNING!!! They do suffer
  // from the ubiquitos singularities around 0, pi and 2*pi.

  // yaw angle, rotation angle about Z-axis
  template <class T>
  T
  euler321Angle3FromQtn(const CWTSQuaternion<T> &qtn)
  {
    // to reduce the number of calls to the subscript operator
    T qtn0 = qtn[0];
    T qtn1 = qtn[1];
    T qtn2 = qtn[2];
    T qtn3 = qtn[3];

    // NOTE: Speed tip from Jeffrey T Duncan: use the identity: 1 =
    // q0^2 + q1^2 + q2^2 + q3^2 which simplifies: q0^2 - q1^2 -
    // q2^2 + q3^2 down to: 2*(q0^2 + q3^2) - 1
    return atan2(2*(qtn0*qtn1 + qtn2*qtn3),
		 2*(qtn0*qtn0 + qtn3*qtn3) - 1);
  }

  // pitch angle, rotation angle about Y-axis
  template <class T>
  T
  euler321Angle2FromQtn(const CWTSQuaternion<T> &qtn)
  {
    return asin(-2*(qtn[0]*qtn[2] - qtn[1]*qtn[3]));
  }

  // roll angle, rotation angle about X-axis
  template <class T>
  T
  euler321Angle1FromQtn(const CWTSQuaternion<T> &qtn)
  {
    // to reduce the number of calls to the subscript operator
    T qtn0 = qtn[0];
    T qtn1 = qtn[1];
    T qtn2 = qtn[2];
    T qtn3 = qtn[3];

    return atan2(2*(qtn1*qtn2 + qtn0*qtn3),
		 2*(qtn2*qtn2 + qtn3*qtn3) - 1);
  }

  // Function QtnFromEulerAxisAndAngle returns a quaternion
  // representing a rigid body's attitude from its Euler axis and
  // angle. NOTE: Argument vector svecEulerAxis MUST be a unit vector.
  template <class T>
  CWTSQuaternion<T>
  qtnFromEulerAxisAndAngle(const CWTSSpaceVector<T> &svecEulerAxis,
			   const T &sclrEulerAngle)
  {
    return CWTSQuaternion<T>(1, svecEulerAxis, 0.5*sclrEulerAngle);
  }

  // returns Euler axis
  template <class T>
  CWTSSpaceVector<T>
  eulerAxisFromQtn(const CWTSQuaternion<T> &qtn)
  {
    T sclrTmp = sqrt(1 - qtn[3]*qtn[3]);

    return CWTSSpaceVector<T>(qtn[0]/sclrTmp,
			      qtn[1]/sclrTmp,
			      qtn[2]/sclrTmp);
  }

  // returns Euler angle
  template <class T>
  T
  eulerAngleFromQtn(const CWTSQuaternion<T> &qtn)
  {
    return 2*acos(qtn[3]);
  }

  // Function QtnFromEuler321 returns a quaternion representing a
  // rigid body's attitude. The quaternion elements correspond to the
  // Euler symmetric parameters of the body. The body's attitude must
  // be entered in Euler angle representation with rotation order
  // 3-2-1, i.e. first about Z-axis next about Y-axis and finally
  // about X-axis.

  // rotation about axis 3 (yaw angle), axis 2 (pitch angle) axis 1
  // (roll angle)
  template <class T>
  CWTSQuaternion<T>
  qtnFromEuler321Angles(T sclrAbout3,
			T sclrAbout2,
			T sclrAbout1)
  {
    return
      CWTSQuaternion<T>(1, CWTSSpaceVector<T>(0, 0, 1), 0.5*sclrAbout3)
      *CWTSQuaternion<T>(1, CWTSSpaceVector<T>(0, 1, 0), 0.5*sclrAbout2)
      *CWTSQuaternion<T>(1, CWTSSpaceVector<T>(1, 0, 0), 0.5*sclrAbout1);
  }

  // SmatFromQtn returns the transformation matrix corresponding to a
  // quaternion
  template <class T>
  CWTSSquareMatrix<3, T>
  smatFromQtn(const CWTSQuaternion<T> &qtn)
  {
    CWTSSquareMatrix<3, T> smat;

    // to reduce the number of calls to the subscript operator
    T qtn0 = qtn[0];
    T qtn1 = qtn[1];
    T qtn2 = qtn[2];
    T qtn3 = qtn[3];

    smat[0][0] = 1 - 2*(qtn1*qtn1 + qtn2*qtn2);
    smat[0][1] = 2*(qtn0*qtn1 + qtn2*qtn3);
    smat[0][2] = 2*(qtn0*qtn2 - qtn1*qtn3);

    smat[1][0] = 2*(qtn0*qtn1 - qtn2*qtn3);
    smat[1][1] = 1 - 2*(qtn0*qtn0 + qtn2*qtn2);
    smat[1][2] = 2*(qtn1*qtn2 + qtn0*qtn3);

    smat[2][0] = 2*(qtn0*qtn2 + qtn1*qtn3);
    smat[2][1] = 2*(qtn1*qtn2 - qtn0*qtn3);
    smat[2][2] = 1 - 2*(qtn0*qtn0 + qtn1*qtn1);

    return smat;
  }

  // QtnFromSmat returns the quaternion corresponding to a
  // transformation matrix
  template <class T>
  CWTSQuaternion<T>
  qtnFromSmat(const CWTSSquareMatrix<3, T> &smat)
  {
    // Check trace to prevent loss of accuracy
    T sclrTmp = tr(smat);
    CWTSQuaternion<T> qtn;

    if(sclrTmp > 0)
      {
	// No trouble, we can use standard expression
	sclrTmp = 0.5*sqrt(1 + sclrTmp);
	qtn[0] = 0.25*(smat[1][2] - smat[2][1])/sclrTmp;
	qtn[1] = 0.25*(smat[2][0] - smat[0][2])/sclrTmp;
	qtn[2] = 0.25*(smat[0][1] - smat[1][0])/sclrTmp;
	qtn[3] = sclrTmp;
      }
    else
      {
	// We could be in trouble, so we have to take
	// precautions. NOTE: Parts of this piece of code were taken
	// from the example in the article "Rotating Objects Using
	// Quaternions" in Game Developer Magazine written by Nick
	// Bobick, july 3, 1998, vol. 2, issue 26.
	int i = 0;
	if (smat[1][1] > smat[0][0]) i = 1;
	if (smat[2][2] > smat[i][i]) i = 2;

	switch (i)
	  {
	  case 0:
	    sclrTmp = 0.5*sqrt(1 + smat[0][0] - smat[1][1] - smat[2][2]);
	    qtn[0] = sclrTmp;
	    qtn[1] = 0.25*(smat[0][1] + smat[1][0])/sclrTmp;
	    qtn[2] = 0.25*(smat[0][2] + smat[2][0])/sclrTmp;
	    qtn[3] = 0.25*(smat[1][2] - smat[2][1])/sclrTmp;
	    break;

	  case 1:
	    sclrTmp = 0.5*sqrt(1 - smat[0][0] + smat[1][1] - smat[2][2]);
	    qtn[0] = 0.25*(smat[1][0] + smat[0][1])/sclrTmp;
	    qtn[1] = sclrTmp;
	    qtn[2] = 0.25*(smat[1][2] + smat[2][1])/sclrTmp;
	    qtn[3] = 0.25*(smat[2][0] - smat[0][2])/sclrTmp;
	    break;

	  case 2:
	    sclrTmp = 0.5*sqrt(1 - smat[0][0] - smat[1][1] + smat[2][2]);
	    qtn[0] = 0.25*(smat[2][0] + smat[0][2])/sclrTmp;
	    qtn[1] = 0.25*(smat[2][1] + smat[1][2])/sclrTmp;
	    qtn[2] = sclrTmp;
	    qtn[3] = 0.25*(smat[0][1] - smat[1][0])/sclrTmp;

	    break;
	  }
      }

    return qtn;
  }

  // NOTE: This function duplicates eulerAxisFromQtn(qtn) it only has
  // a different return type.
  template <class T>
  CWTSVector<3, T>
  axisAngleFromQtn( const CWTSQuaternion<T> &qtn )
  {
    return eulerAxisFromQtn(qtn);
  }

  // NOTE: This function duplicates qtnFromEulerAxisAndAngle(..) it
  // only has a different function profile.
  template <class T>
  CWTSQuaternion<T>
  qtnFromAxisAndAngle(const CWTSVector<3, T> &vAxis,
                      const T sAngle)
  {
    return qtnFromEulerAxisAndAngle(vAxis, sAngle);
  }

  template <class T>
  CWTSSquareMatrix<3, T>
  changeOfBasis(CWTSSpaceVector< CWTSSpaceVector<T> >&from, 
		CWTSSpaceVector< CWTSSpaceVector<T> >&to)
  {
    CWTSSquareMatrix<3, T> A;

    // This is a "change of basis" from the "from" frame to the "to"
    // frame.  the "to" frame is typically the "Standard basis"
    // frame.  The "from" is a frame that represents the current
    // orientation of the object in the shape of an orthonormal
    // tripod.

    enum { x , y , z };

    // _X,_Y,_Z is typically the standard basis frame.

    //  | x^_X , y^_X , z^_X |
    //  | x^_Y , y^_Y , z^_Y |
    //  | x^_Z , y^_Z , z^_Z |
	
    A[0][0] = from[x]*to[x];
    A[0][1] = from[y]*to[x];
    A[0][2] = from[z]*to[x];

    A[1][0] = from[x]*to[y];
    A[1][1] = from[y]*to[y];
    A[1][2] = from[z]*to[y];

    A[2][0] = from[x]*to[z];
    A[2][1] = from[y]*to[z];
    A[2][2] = from[z]*to[z];
	
    // This is simply the transpose done manually which would save
    // and inverse call.
    //	| x ^ _X , x ^ _Y , x ^ _Z |
    //	| y ^ _X , y ^ _Y , y ^ _Z |
    //	| z ^ _X , z ^ _Y , z ^ _Z |
	
    // And finally we return the matrix that takes the "from" frame
    // to the "to"/"Standard basis" frame.
    return A;
  }

}

#endif   // IG_STAT_COORDSYS_H