2010-09-09 22:06:57 +00:00
|
|
|
/********************************************************************************
|
|
|
|
* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ *
|
2013-03-02 15:26:18 +00:00
|
|
|
* Copyright (c) 2010-2013 Daniel Chappuis *
|
2010-09-09 22:06:57 +00:00
|
|
|
*********************************************************************************
|
|
|
|
* *
|
2011-11-13 17:49:03 +00:00
|
|
|
* This software is provided 'as-is', without any express or implied warranty. *
|
|
|
|
* In no event will the authors be held liable for any damages arising from the *
|
|
|
|
* use of this software. *
|
2010-09-09 22:06:57 +00:00
|
|
|
* *
|
2011-11-13 17:49:03 +00:00
|
|
|
* Permission is granted to anyone to use this software for any purpose, *
|
|
|
|
* including commercial applications, and to alter it and redistribute it *
|
|
|
|
* freely, subject to the following restrictions: *
|
|
|
|
* *
|
|
|
|
* 1. The origin of this software must not be misrepresented; you must not claim *
|
|
|
|
* that you wrote the original software. If you use this software in a *
|
|
|
|
* product, an acknowledgment in the product documentation would be *
|
|
|
|
* appreciated but is not required. *
|
|
|
|
* *
|
|
|
|
* 2. Altered source versions must be plainly marked as such, and must not be *
|
|
|
|
* misrepresented as being the original software. *
|
|
|
|
* *
|
|
|
|
* 3. This notice may not be removed or altered from any source distribution. *
|
2010-09-09 22:06:57 +00:00
|
|
|
* *
|
|
|
|
********************************************************************************/
|
|
|
|
|
|
|
|
// Libraries
|
|
|
|
#include "Quaternion.h"
|
2011-08-18 21:02:48 +00:00
|
|
|
#include "Vector3.h"
|
2010-09-09 22:06:57 +00:00
|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
// Namespace
|
|
|
|
using namespace reactphysics3d;
|
|
|
|
|
|
|
|
// Constructor of the class
|
2013-02-28 19:03:37 +00:00
|
|
|
Quaternion::Quaternion() : x(0.0), y(0.0), z(0.0), w(0.0) {
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Constructor with arguments
|
2013-02-28 19:03:37 +00:00
|
|
|
Quaternion::Quaternion(decimal newX, decimal newY, decimal newZ, decimal newW)
|
|
|
|
:x(newX), y(newY), z(newZ), w(newW) {
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Constructor with the component w and the vector v=(x y z)
|
2013-02-28 19:03:37 +00:00
|
|
|
Quaternion::Quaternion(decimal newW, const Vector3& v) : x(v.x), y(v.y), z(v.z), w(newW) {
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-06-24 21:31:13 +00:00
|
|
|
// Constructor which convert Euler angles (in radians) to a quaternion
|
|
|
|
Quaternion::Quaternion(decimal angleX, decimal angleY, decimal angleZ) {
|
|
|
|
initWithEulerAngles(angleX, angleY, angleZ);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Constructor which convert Euler angles (in radians) to a quaternion
|
|
|
|
Quaternion::Quaternion(const Vector3& eulerAngles) {
|
|
|
|
initWithEulerAngles(eulerAngles.x, eulerAngles.y, eulerAngles.z);
|
|
|
|
}
|
|
|
|
|
2010-09-09 22:06:57 +00:00
|
|
|
// Copy-constructor
|
|
|
|
Quaternion::Quaternion(const Quaternion& quaternion)
|
2013-02-28 19:03:37 +00:00
|
|
|
:x(quaternion.x), y(quaternion.y), z(quaternion.z), w(quaternion.w) {
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a unit quaternion from a rotation matrix
|
|
|
|
Quaternion::Quaternion(const Matrix3x3& matrix) {
|
|
|
|
|
|
|
|
// Get the trace of the matrix
|
2012-01-18 23:06:33 +00:00
|
|
|
decimal trace = matrix.getTrace();
|
2010-09-09 22:06:57 +00:00
|
|
|
|
2012-01-18 23:06:33 +00:00
|
|
|
decimal r;
|
|
|
|
decimal s;
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
if (trace < 0.0) {
|
2013-03-13 19:55:10 +00:00
|
|
|
if (matrix[1][1] > matrix[0][0]) {
|
|
|
|
if(matrix[2][2] > matrix[1][1]) {
|
2013-03-17 16:07:09 +00:00
|
|
|
r = sqrt(matrix[2][2] - matrix[0][0] - matrix[1][1] + decimal(1.0));
|
|
|
|
s = decimal(0.5) / r;
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Compute the quaternion
|
2013-03-17 16:07:09 +00:00
|
|
|
x = (matrix[2][0] + matrix[0][2]) * s;
|
|
|
|
y = (matrix[1][2] + matrix[2][1]) * s;
|
|
|
|
z = decimal(0.5) * r;
|
|
|
|
w = (matrix[1][0] - matrix[0][1]) * s;
|
2010-09-09 22:06:57 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-17 16:07:09 +00:00
|
|
|
r = sqrt(matrix[1][1] - matrix[2][2] - matrix[0][0] + decimal(1.0));
|
|
|
|
s = decimal(0.5) / r;
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Compute the quaternion
|
2013-03-17 16:07:09 +00:00
|
|
|
x = (matrix[0][1] + matrix[1][0]) * s;
|
|
|
|
y = decimal(0.5) * r;
|
|
|
|
z = (matrix[1][2] + matrix[2][1]) * s;
|
|
|
|
w = (matrix[0][2] - matrix[2][0]) * s;
|
2010-09-09 22:06:57 +00:00
|
|
|
}
|
|
|
|
}
|
2013-03-13 19:55:10 +00:00
|
|
|
else if (matrix[2][2] > matrix[0][0]) {
|
2013-03-17 16:07:09 +00:00
|
|
|
r = sqrt(matrix[2][2] - matrix[0][0] - matrix[1][1] + decimal(1.0));
|
|
|
|
s = decimal(0.5) / r;
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Compute the quaternion
|
2013-03-17 16:07:09 +00:00
|
|
|
x = (matrix[2][0] + matrix[0][2]) * s;
|
|
|
|
y = (matrix[1][2] + matrix[2][1]) * s;
|
|
|
|
z = decimal(0.5) * r;
|
|
|
|
w = (matrix[1][0] - matrix[0][1]) * s;
|
2010-09-09 22:06:57 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-17 16:07:09 +00:00
|
|
|
r = sqrt(matrix[0][0] - matrix[1][1] - matrix[2][2] + decimal(1.0));
|
|
|
|
s = decimal(0.5) / r;
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Compute the quaternion
|
2013-03-17 16:07:09 +00:00
|
|
|
x = decimal(0.5) * r;
|
|
|
|
y = (matrix[0][1] + matrix[1][0]) * s;
|
|
|
|
z = (matrix[2][0] - matrix[0][2]) * s;
|
|
|
|
w = (matrix[2][1] - matrix[1][2]) * s;
|
2010-09-09 22:06:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2013-03-17 16:07:09 +00:00
|
|
|
r = sqrt(trace + decimal(1.0));
|
|
|
|
s = decimal(0.5) / r;
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Compute the quaternion
|
2013-03-13 19:55:10 +00:00
|
|
|
x = (matrix[2][1] - matrix[1][2]) * s;
|
|
|
|
y = (matrix[0][2] - matrix[2][0]) * s;
|
|
|
|
z = (matrix[1][0] - matrix[0][1]) * s;
|
2013-03-17 16:07:09 +00:00
|
|
|
w = decimal(0.5) * r;
|
2010-09-09 22:06:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destructor
|
|
|
|
Quaternion::~Quaternion() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-03-05 22:09:50 +00:00
|
|
|
// Compute the rotation angle (in radians) and the rotation axis
|
|
|
|
/// This method is used to get the rotation angle (in radian) and the unit
|
|
|
|
/// rotation axis of an orientation quaternion.
|
2012-01-18 23:06:33 +00:00
|
|
|
void Quaternion::getRotationAngleAxis(decimal& angle, Vector3& axis) const {
|
2010-09-09 22:06:57 +00:00
|
|
|
Quaternion quaternion;
|
|
|
|
|
|
|
|
// If the quaternion is unit
|
|
|
|
if (length() == 1.0) {
|
|
|
|
quaternion = *this;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// We compute the unit quaternion
|
|
|
|
quaternion = getUnit();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the roation angle
|
2013-03-17 16:07:09 +00:00
|
|
|
angle = acos(quaternion.w) * decimal(2.0);
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Compute the 3D rotation axis
|
2013-02-28 19:03:37 +00:00
|
|
|
Vector3 rotationAxis(quaternion.x, quaternion.y, quaternion.z);
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Normalize the rotation axis
|
|
|
|
rotationAxis = rotationAxis.getUnit();
|
|
|
|
|
|
|
|
// Set the rotation axis values
|
2013-02-27 21:10:10 +00:00
|
|
|
axis.setAllValues(rotationAxis.x, rotationAxis.y, rotationAxis.z);
|
2010-09-09 22:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return the orientation matrix corresponding to this quaternion
|
|
|
|
Matrix3x3 Quaternion::getMatrix() const {
|
|
|
|
|
2013-02-28 19:03:37 +00:00
|
|
|
decimal nQ = x*x + y*y + z*z + w*w;
|
2012-01-18 23:06:33 +00:00
|
|
|
decimal s = 0.0;
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
if (nQ > 0.0) {
|
2013-03-17 16:07:09 +00:00
|
|
|
s = decimal(2.0) / nQ;
|
2010-09-09 22:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Computations used for optimization (less multiplications)
|
2013-02-28 19:03:37 +00:00
|
|
|
decimal xs = x*s;
|
|
|
|
decimal ys = y*s;
|
|
|
|
decimal zs = z*s;
|
|
|
|
decimal wxs = w*xs;
|
|
|
|
decimal wys = w*ys;
|
|
|
|
decimal wzs = w*zs;
|
|
|
|
decimal xxs = x*xs;
|
|
|
|
decimal xys = x*ys;
|
|
|
|
decimal xzs = x*zs;
|
|
|
|
decimal yys = y*ys;
|
|
|
|
decimal yzs = y*zs;
|
|
|
|
decimal zzs = z*zs;
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Create the matrix corresponding to the quaternion
|
2013-03-17 16:07:09 +00:00
|
|
|
return Matrix3x3(decimal(1.0) - yys - zzs, xys-wzs, xzs + wys,
|
|
|
|
xys + wzs, decimal(1.0) - xxs - zzs, yzs-wxs,
|
|
|
|
xzs-wys, yzs + wxs, decimal(1.0) - xxs - yys);
|
2010-09-09 22:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the spherical linear interpolation between two quaternions.
|
2013-03-05 22:09:50 +00:00
|
|
|
/// The t argument has to be such that 0 <= t <= 1. This method is static.
|
2012-10-09 20:21:02 +00:00
|
|
|
Quaternion Quaternion::slerp(const Quaternion& quaternion1,
|
|
|
|
const Quaternion& quaternion2, decimal t) {
|
2010-09-09 22:06:57 +00:00
|
|
|
assert(t >= 0.0 && t <= 1.0);
|
|
|
|
|
2012-01-18 23:06:33 +00:00
|
|
|
decimal invert = 1.0;
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Compute cos(theta) using the quaternion scalar product
|
2012-01-18 23:06:33 +00:00
|
|
|
decimal cosineTheta = quaternion1.dot(quaternion2);
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Take care of the sign of cosineTheta
|
|
|
|
if (cosineTheta < 0.0) {
|
|
|
|
cosineTheta = -cosineTheta;
|
|
|
|
invert = -1.0;
|
|
|
|
}
|
|
|
|
|
2012-10-09 20:21:02 +00:00
|
|
|
// Because of precision, if cos(theta) is nearly 1,
|
|
|
|
// therefore theta is nearly 0 and we can write
|
2010-09-09 22:06:57 +00:00
|
|
|
// sin((1-t)*theta) as (1-t) and sin(t*theta) as t
|
2013-03-17 16:07:09 +00:00
|
|
|
const decimal epsilon = decimal(0.00001);
|
2012-01-18 23:06:33 +00:00
|
|
|
if(1-cosineTheta < epsilon) {
|
2013-03-17 16:07:09 +00:00
|
|
|
return quaternion1 * (decimal(1.0)-t) + quaternion2 * (t * invert);
|
2010-09-09 22:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the theta angle
|
2012-01-18 23:06:33 +00:00
|
|
|
decimal theta = acos(cosineTheta);
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Compute sin(theta)
|
2012-01-18 23:06:33 +00:00
|
|
|
decimal sineTheta = sin(theta);
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Compute the two coefficients that are in the spherical linear interpolation formula
|
2013-03-17 16:07:09 +00:00
|
|
|
decimal coeff1 = sin((decimal(1.0)-t)*theta) / sineTheta;
|
2012-01-18 23:06:33 +00:00
|
|
|
decimal coeff2 = sin(t*theta) / sineTheta * invert;
|
2010-09-09 22:06:57 +00:00
|
|
|
|
|
|
|
// Compute and return the interpolated quaternion
|
|
|
|
return quaternion1 * coeff1 + quaternion2 * coeff2;
|
|
|
|
}
|
2014-06-24 21:31:13 +00:00
|
|
|
|
|
|
|
// Initialize the quaternion using Euler angles
|
|
|
|
void Quaternion::initWithEulerAngles(decimal angleX, decimal angleY, decimal angleZ) {
|
|
|
|
|
|
|
|
decimal angle = angleX * decimal(0.5);
|
|
|
|
const decimal sinX = std::sin(angle);
|
|
|
|
const decimal cosX = std::cos(angle);
|
|
|
|
|
|
|
|
angle = angleY * decimal(0.5);
|
|
|
|
const decimal sinY = std::sin(angle);
|
|
|
|
const decimal cosY = std::cos(angle);
|
|
|
|
|
|
|
|
angle = angleZ * decimal(0.5);
|
|
|
|
const decimal sinZ = std::sin(angle);
|
|
|
|
const decimal cosZ = std::cos(angle);
|
|
|
|
|
|
|
|
const decimal cosYcosZ = cosY * cosZ;
|
|
|
|
const decimal sinYcosZ = sinY * cosZ;
|
|
|
|
const decimal cosYsinZ = cosY * sinZ;
|
|
|
|
const decimal sinYsinZ = sinY * sinZ;
|
|
|
|
|
|
|
|
x = sinX * cosYcosZ - cosX * sinYsinZ;
|
|
|
|
y = cosX * sinYcosZ + sinX * cosYsinZ;
|
|
|
|
z = cosX * cosYsinZ - sinX * sinYcosZ;
|
|
|
|
w = cosX * cosYcosZ + sinX * sinYsinZ;
|
|
|
|
|
|
|
|
// Normalize the quaternion
|
|
|
|
normalize();
|
|
|
|
}
|