2
Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/
4
This software is provided 'as-is', without any express or implied warranty.
5
In no event will the authors be held liable for any damages arising from the use of this software.
6
Permission is granted to anyone to use this software for any purpose,
7
including commercial applications, and to alter it and redistribute it freely,
8
subject to the following restrictions:
10
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.
11
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
12
3. This notice may not be removed or altered from any source distribution.
17
#ifndef BT_SIMD__QUATERNION_H_
18
#define BT_SIMD__QUATERNION_H_
21
#include "btVector3.h"
22
#include "btQuadWord.h"
24
/**@brief The btQuaternion implements quaternion to perform linear algebra rotations in combination with btMatrix3x3, btVector3 and btTransform. */
25
class btQuaternion : public btQuadWord {
27
/**@brief No initialization constructor */
30
// template <typename btScalar>
31
// explicit Quaternion(const btScalar *v) : Tuple4<btScalar>(v) {}
32
/**@brief Constructor from scalars */
33
btQuaternion(const btScalar& x, const btScalar& y, const btScalar& z, const btScalar& w)
34
: btQuadWord(x, y, z, w)
36
/**@brief Axis angle Constructor
37
* @param axis The axis which the rotation is around
38
* @param angle The magnitude of the rotation around the angle (Radians) */
39
btQuaternion(const btVector3& axis, const btScalar& angle)
41
setRotation(axis, angle);
43
/**@brief Constructor from Euler angles
44
* @param yaw Angle around Y unless BT_EULER_DEFAULT_ZYX defined then Z
45
* @param pitch Angle around X unless BT_EULER_DEFAULT_ZYX defined then Y
46
* @param roll Angle around Z unless BT_EULER_DEFAULT_ZYX defined then X */
47
btQuaternion(const btScalar& yaw, const btScalar& pitch, const btScalar& roll)
49
#ifndef BT_EULER_DEFAULT_ZYX
50
setEuler(yaw, pitch, roll);
52
setEulerZYX(yaw, pitch, roll);
55
/**@brief Set the rotation using axis angle notation
56
* @param axis The axis around which to rotate
57
* @param angle The magnitude of the rotation in Radians */
58
void setRotation(const btVector3& axis, const btScalar& angle)
60
btScalar d = axis.length();
61
btAssert(d != btScalar(0.0));
62
btScalar s = btSin(angle * btScalar(0.5)) / d;
63
setValue(axis.x() * s, axis.y() * s, axis.z() * s,
64
btCos(angle * btScalar(0.5)));
66
/**@brief Set the quaternion using Euler angles
67
* @param yaw Angle around Y
68
* @param pitch Angle around X
69
* @param roll Angle around Z */
70
void setEuler(const btScalar& yaw, const btScalar& pitch, const btScalar& roll)
72
btScalar halfYaw = btScalar(yaw) * btScalar(0.5);
73
btScalar halfPitch = btScalar(pitch) * btScalar(0.5);
74
btScalar halfRoll = btScalar(roll) * btScalar(0.5);
75
btScalar cosYaw = btCos(halfYaw);
76
btScalar sinYaw = btSin(halfYaw);
77
btScalar cosPitch = btCos(halfPitch);
78
btScalar sinPitch = btSin(halfPitch);
79
btScalar cosRoll = btCos(halfRoll);
80
btScalar sinRoll = btSin(halfRoll);
81
setValue(cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw,
82
cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw,
83
sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw,
84
cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw);
86
/**@brief Set the quaternion using euler angles
87
* @param yaw Angle around Z
88
* @param pitch Angle around Y
89
* @param roll Angle around X */
90
void setEulerZYX(const btScalar& yaw, const btScalar& pitch, const btScalar& roll)
92
btScalar halfYaw = btScalar(yaw) * btScalar(0.5);
93
btScalar halfPitch = btScalar(pitch) * btScalar(0.5);
94
btScalar halfRoll = btScalar(roll) * btScalar(0.5);
95
btScalar cosYaw = btCos(halfYaw);
96
btScalar sinYaw = btSin(halfYaw);
97
btScalar cosPitch = btCos(halfPitch);
98
btScalar sinPitch = btSin(halfPitch);
99
btScalar cosRoll = btCos(halfRoll);
100
btScalar sinRoll = btSin(halfRoll);
101
setValue(sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, //x
102
cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, //y
103
cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, //z
104
cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); //formerly yzx
106
/**@brief Add two quaternions
107
* @param q The quaternion to add to this one */
108
SIMD_FORCE_INLINE btQuaternion& operator+=(const btQuaternion& q)
110
m_floats[0] += q.x(); m_floats[1] += q.y(); m_floats[2] += q.z(); m_floats[3] += q.m_floats[3];
114
/**@brief Subtract out a quaternion
115
* @param q The quaternion to subtract from this one */
116
btQuaternion& operator-=(const btQuaternion& q)
118
m_floats[0] -= q.x(); m_floats[1] -= q.y(); m_floats[2] -= q.z(); m_floats[3] -= q.m_floats[3];
122
/**@brief Scale this quaternion
123
* @param s The scalar to scale by */
124
btQuaternion& operator*=(const btScalar& s)
126
m_floats[0] *= s; m_floats[1] *= s; m_floats[2] *= s; m_floats[3] *= s;
130
/**@brief Multiply this quaternion by q on the right
131
* @param q The other quaternion
132
* Equivilant to this = this * q */
133
btQuaternion& operator*=(const btQuaternion& q)
135
setValue(m_floats[3] * q.x() + m_floats[0] * q.m_floats[3] + m_floats[1] * q.z() - m_floats[2] * q.y(),
136
m_floats[3] * q.y() + m_floats[1] * q.m_floats[3] + m_floats[2] * q.x() - m_floats[0] * q.z(),
137
m_floats[3] * q.z() + m_floats[2] * q.m_floats[3] + m_floats[0] * q.y() - m_floats[1] * q.x(),
138
m_floats[3] * q.m_floats[3] - m_floats[0] * q.x() - m_floats[1] * q.y() - m_floats[2] * q.z());
141
/**@brief Return the dot product between this quaternion and another
142
* @param q The other quaternion */
143
btScalar dot(const btQuaternion& q) const
145
return m_floats[0] * q.x() + m_floats[1] * q.y() + m_floats[2] * q.z() + m_floats[3] * q.m_floats[3];
148
/**@brief Return the length squared of the quaternion */
149
btScalar length2() const
154
/**@brief Return the length of the quaternion */
155
btScalar length() const
157
return btSqrt(length2());
160
/**@brief Normalize the quaternion
161
* Such that x^2 + y^2 + z^2 +w^2 = 1 */
162
btQuaternion& normalize()
164
return *this /= length();
167
/**@brief Return a scaled version of this quaternion
168
* @param s The scale factor */
169
SIMD_FORCE_INLINE btQuaternion
170
operator*(const btScalar& s) const
172
return btQuaternion(x() * s, y() * s, z() * s, m_floats[3] * s);
176
/**@brief Return an inversely scaled versionof this quaternion
177
* @param s The inverse scale factor */
178
btQuaternion operator/(const btScalar& s) const
180
btAssert(s != btScalar(0.0));
181
return *this * (btScalar(1.0) / s);
184
/**@brief Inversely scale this quaternion
185
* @param s The scale factor */
186
btQuaternion& operator/=(const btScalar& s)
188
btAssert(s != btScalar(0.0));
189
return *this *= btScalar(1.0) / s;
192
/**@brief Return a normalized version of this quaternion */
193
btQuaternion normalized() const
195
return *this / length();
197
/**@brief Return the angle between this quaternion and the other
198
* @param q The other quaternion */
199
btScalar angle(const btQuaternion& q) const
201
btScalar s = btSqrt(length2() * q.length2());
202
btAssert(s != btScalar(0.0));
203
return btAcos(dot(q) / s);
205
/**@brief Return the angle of rotation represented by this quaternion */
206
btScalar getAngle() const
208
btScalar s = btScalar(2.) * btAcos(m_floats[3]);
212
/**@brief Return the axis of the rotation represented by this quaternion */
213
btVector3 getAxis() const
215
btScalar s_squared = btScalar(1.) - btPow(m_floats[3], btScalar(2.));
216
if (s_squared < btScalar(10.) * SIMD_EPSILON) //Check for divide by zero
217
return btVector3(1.0, 0.0, 0.0); // Arbitrary
218
btScalar s = btSqrt(s_squared);
219
return btVector3(m_floats[0] / s, m_floats[1] / s, m_floats[2] / s);
222
/**@brief Return the inverse of this quaternion */
223
btQuaternion inverse() const
225
return btQuaternion(-m_floats[0], -m_floats[1], -m_floats[2], m_floats[3]);
228
/**@brief Return the sum of this quaternion and the other
229
* @param q2 The other quaternion */
230
SIMD_FORCE_INLINE btQuaternion
231
operator+(const btQuaternion& q2) const
233
const btQuaternion& q1 = *this;
234
return btQuaternion(q1.x() + q2.x(), q1.y() + q2.y(), q1.z() + q2.z(), q1.m_floats[3] + q2.m_floats[3]);
237
/**@brief Return the difference between this quaternion and the other
238
* @param q2 The other quaternion */
239
SIMD_FORCE_INLINE btQuaternion
240
operator-(const btQuaternion& q2) const
242
const btQuaternion& q1 = *this;
243
return btQuaternion(q1.x() - q2.x(), q1.y() - q2.y(), q1.z() - q2.z(), q1.m_floats[3] - q2.m_floats[3]);
246
/**@brief Return the negative of this quaternion
247
* This simply negates each element */
248
SIMD_FORCE_INLINE btQuaternion operator-() const
250
const btQuaternion& q2 = *this;
251
return btQuaternion( - q2.x(), - q2.y(), - q2.z(), - q2.m_floats[3]);
253
/**@todo document this and it's use */
254
SIMD_FORCE_INLINE btQuaternion farthest( const btQuaternion& qd) const
256
btQuaternion diff,sum;
259
if( diff.dot(diff) > sum.dot(sum) )
264
/**@todo document this and it's use */
265
SIMD_FORCE_INLINE btQuaternion nearest( const btQuaternion& qd) const
267
btQuaternion diff,sum;
270
if( diff.dot(diff) < sum.dot(sum) )
276
/**@brief Return the quaternion which is the result of Spherical Linear Interpolation between this and the other quaternion
277
* @param q The other quaternion to interpolate with
278
* @param t The ratio between this and q to interpolate. If t = 0 the result is this, if t=1 the result is q.
279
* Slerp interpolates assuming constant velocity. */
280
btQuaternion slerp(const btQuaternion& q, const btScalar& t) const
282
btScalar theta = angle(q);
283
if (theta != btScalar(0.0))
285
btScalar d = btScalar(1.0) / btSin(theta);
286
btScalar s0 = btSin((btScalar(1.0) - t) * theta);
287
btScalar s1 = btSin(t * theta);
288
if (dot(q) < 0) // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp
289
return btQuaternion((m_floats[0] * s0 + -q.x() * s1) * d,
290
(m_floats[1] * s0 + -q.y() * s1) * d,
291
(m_floats[2] * s0 + -q.z() * s1) * d,
292
(m_floats[3] * s0 + -q.m_floats[3] * s1) * d);
294
return btQuaternion((m_floats[0] * s0 + q.x() * s1) * d,
295
(m_floats[1] * s0 + q.y() * s1) * d,
296
(m_floats[2] * s0 + q.z() * s1) * d,
297
(m_floats[3] * s0 + q.m_floats[3] * s1) * d);
306
static const btQuaternion& getIdentity()
308
static const btQuaternion identityQuat(btScalar(0.),btScalar(0.),btScalar(0.),btScalar(1.));
312
SIMD_FORCE_INLINE const btScalar& getW() const { return m_floats[3]; }
318
/**@brief Return the negative of a quaternion */
319
SIMD_FORCE_INLINE btQuaternion
320
operator-(const btQuaternion& q)
322
return btQuaternion(-q.x(), -q.y(), -q.z(), -q.w());
327
/**@brief Return the product of two quaternions */
328
SIMD_FORCE_INLINE btQuaternion
329
operator*(const btQuaternion& q1, const btQuaternion& q2) {
330
return btQuaternion(q1.w() * q2.x() + q1.x() * q2.w() + q1.y() * q2.z() - q1.z() * q2.y(),
331
q1.w() * q2.y() + q1.y() * q2.w() + q1.z() * q2.x() - q1.x() * q2.z(),
332
q1.w() * q2.z() + q1.z() * q2.w() + q1.x() * q2.y() - q1.y() * q2.x(),
333
q1.w() * q2.w() - q1.x() * q2.x() - q1.y() * q2.y() - q1.z() * q2.z());
336
SIMD_FORCE_INLINE btQuaternion
337
operator*(const btQuaternion& q, const btVector3& w)
339
return btQuaternion( q.w() * w.x() + q.y() * w.z() - q.z() * w.y(),
340
q.w() * w.y() + q.z() * w.x() - q.x() * w.z(),
341
q.w() * w.z() + q.x() * w.y() - q.y() * w.x(),
342
-q.x() * w.x() - q.y() * w.y() - q.z() * w.z());
345
SIMD_FORCE_INLINE btQuaternion
346
operator*(const btVector3& w, const btQuaternion& q)
348
return btQuaternion( w.x() * q.w() + w.y() * q.z() - w.z() * q.y(),
349
w.y() * q.w() + w.z() * q.x() - w.x() * q.z(),
350
w.z() * q.w() + w.x() * q.y() - w.y() * q.x(),
351
-w.x() * q.x() - w.y() * q.y() - w.z() * q.z());
354
/**@brief Calculate the dot product between two quaternions */
355
SIMD_FORCE_INLINE btScalar
356
dot(const btQuaternion& q1, const btQuaternion& q2)
362
/**@brief Return the length of a quaternion */
363
SIMD_FORCE_INLINE btScalar
364
length(const btQuaternion& q)
369
/**@brief Return the angle between two quaternions*/
370
SIMD_FORCE_INLINE btScalar
371
angle(const btQuaternion& q1, const btQuaternion& q2)
376
/**@brief Return the inverse of a quaternion*/
377
SIMD_FORCE_INLINE btQuaternion
378
inverse(const btQuaternion& q)
383
/**@brief Return the result of spherical linear interpolation betwen two quaternions
384
* @param q1 The first quaternion
385
* @param q2 The second quaternion
386
* @param t The ration between q1 and q2. t = 0 return q1, t=1 returns q2
387
* Slerp assumes constant velocity between positions. */
388
SIMD_FORCE_INLINE btQuaternion
389
slerp(const btQuaternion& q1, const btQuaternion& q2, const btScalar& t)
391
return q1.slerp(q2, t);
394
SIMD_FORCE_INLINE btVector3
395
quatRotate(const btQuaternion& rotation, const btVector3& v)
397
btQuaternion q = rotation * v;
398
q *= rotation.inverse();
399
return btVector3(q.getX(),q.getY(),q.getZ());
402
SIMD_FORCE_INLINE btQuaternion
403
shortestArcQuat(const btVector3& v0, const btVector3& v1) // Game Programming Gems 2.10. make sure v0,v1 are normalized
405
btVector3 c = v0.cross(v1);
406
btScalar d = v0.dot(v1);
408
if (d < -1.0 + SIMD_EPSILON)
411
btPlaneSpace1(v0,n,unused);
412
return btQuaternion(n.x(),n.y(),n.z(),0.0f); // just pick any vector that is orthogonal to v0
415
btScalar s = btSqrt((1.0f + d) * 2.0f);
416
btScalar rs = 1.0f / s;
418
return btQuaternion(c.getX()*rs,c.getY()*rs,c.getZ()*rs,s * 0.5f);
421
SIMD_FORCE_INLINE btQuaternion
422
shortestArcQuatNormalize2(btVector3& v0,btVector3& v1)
426
return shortestArcQuat(v0,v1);
429
#endif //BT_SIMD__QUATERNION_H_