Forked from
gmsh / gmsh
11315 commits behind the upstream repository.
-
Francois Henrotte authoredFrancois Henrotte authored
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