|
@@ -0,0 +1,289 @@
|
|
1
|
+/*!
|
|
2
|
+ * \file src/utils/Quaternion.cpp
|
|
3
|
+ * \brief Quaternion
|
|
4
|
+ *
|
|
5
|
+ * \author Mongoose
|
|
6
|
+ */
|
|
7
|
+
|
|
8
|
+#include <math.h>
|
|
9
|
+
|
|
10
|
+#include "utils/Quaternion.h"
|
|
11
|
+
|
|
12
|
+Quaternion::Quaternion() {
|
|
13
|
+ mW = 0;
|
|
14
|
+ mX = 0;
|
|
15
|
+ mY = 0;
|
|
16
|
+ mZ = 0;
|
|
17
|
+}
|
|
18
|
+
|
|
19
|
+Quaternion::Quaternion(vec_t w, vec_t x, vec_t y, vec_t z) {
|
|
20
|
+ mW = w;
|
|
21
|
+ mX = x;
|
|
22
|
+ mY = y;
|
|
23
|
+ mZ = z;
|
|
24
|
+}
|
|
25
|
+
|
|
26
|
+Quaternion::Quaternion(vec4_t v) {
|
|
27
|
+ mW = v[0];
|
|
28
|
+ mX = v[1];
|
|
29
|
+ mY = v[2];
|
|
30
|
+ mZ = v[3];
|
|
31
|
+}
|
|
32
|
+
|
|
33
|
+void Quaternion::getMatrix(matrix_t m) {
|
|
34
|
+ m[ 0] = 1.0f - 2.0f * (mY*mY + mZ*mZ);
|
|
35
|
+ m[ 1] = 2.0f * (mX*mY - mW*mZ);
|
|
36
|
+ m[ 2] = 2.0f * (mX*mZ + mW*mY);
|
|
37
|
+ m[ 3] = 0.0f;
|
|
38
|
+
|
|
39
|
+ m[ 4] = 2.0f * (mX*mY + mW*mZ);
|
|
40
|
+ m[ 5] = 1.0f - 2.0f * (mX*mX + mZ*mZ);
|
|
41
|
+ m[ 6] = 2.0f * (mY*mZ - mW*mX);
|
|
42
|
+ m[ 7] = 0.0f;
|
|
43
|
+
|
|
44
|
+ m[ 8] = 2.0f * (mX*mZ - mW*mY);
|
|
45
|
+ m[ 9] = 2.0f * (mY*mZ + mW*mX);
|
|
46
|
+ m[10] = 1.0f - 2.0f * (mX*mX + mY*mY);
|
|
47
|
+ m[11] = 0.0f;
|
|
48
|
+
|
|
49
|
+ m[12] = 0.0f;
|
|
50
|
+ m[13] = 0.0f;
|
|
51
|
+ m[14] = 0.0f;
|
|
52
|
+ m[15] = 1.0f;
|
|
53
|
+}
|
|
54
|
+
|
|
55
|
+Quaternion Quaternion::operator *(const Quaternion &q) {
|
|
56
|
+ return multiply(*this, q);
|
|
57
|
+}
|
|
58
|
+
|
|
59
|
+Quaternion Quaternion::operator /(const Quaternion &q) {
|
|
60
|
+ return divide(*this, q);
|
|
61
|
+}
|
|
62
|
+
|
|
63
|
+Quaternion Quaternion::operator +(const Quaternion &q) {
|
|
64
|
+ return add(*this, q);
|
|
65
|
+}
|
|
66
|
+
|
|
67
|
+Quaternion Quaternion::operator -(const Quaternion &q) {
|
|
68
|
+ return subtract(*this, q);
|
|
69
|
+}
|
|
70
|
+
|
|
71
|
+bool Quaternion::operator ==(const Quaternion &q) {
|
|
72
|
+ //return (mX == q.mX && mY == q.mY && mZ == q.mZ && mW == q.mW);
|
|
73
|
+ return (equalEpsilon(mX, q.mX) && equalEpsilon(mY, q.mY) &&
|
|
74
|
+ equalEpsilon(mZ, q.mZ) && equalEpsilon(mW, q.mW));
|
|
75
|
+}
|
|
76
|
+
|
|
77
|
+Quaternion Quaternion::conjugate() {
|
|
78
|
+ return Quaternion(mW, -mX, -mY, -mZ);
|
|
79
|
+}
|
|
80
|
+
|
|
81
|
+Quaternion Quaternion::scale(vec_t s) {
|
|
82
|
+ return Quaternion(mW * s, mX * s, mY * s, mZ * s);
|
|
83
|
+}
|
|
84
|
+
|
|
85
|
+Quaternion Quaternion::inverse() {
|
|
86
|
+ return conjugate().scale(1/magnitude());
|
|
87
|
+}
|
|
88
|
+
|
|
89
|
+vec_t Quaternion::dot(Quaternion a, Quaternion b) {
|
|
90
|
+ return ((a.mW * b.mW) + (a.mX * b.mX) + (a.mY * b.mY) + (a.mZ * b.mZ));
|
|
91
|
+}
|
|
92
|
+
|
|
93
|
+vec_t Quaternion::magnitude() {
|
|
94
|
+ return sqrtf(dot(*this, *this));
|
|
95
|
+}
|
|
96
|
+
|
|
97
|
+void Quaternion::setIdentity() {
|
|
98
|
+ mW = 1.0;
|
|
99
|
+ mX = 0.0;
|
|
100
|
+ mY = 0.0;
|
|
101
|
+ mZ = 0.0;
|
|
102
|
+}
|
|
103
|
+
|
|
104
|
+void Quaternion::set(vec_t angle, vec_t x, vec_t y, vec_t z) {
|
|
105
|
+ vec_t temp, dist;
|
|
106
|
+
|
|
107
|
+ // Normalize
|
|
108
|
+ temp = x*x + y*y + z*z;
|
|
109
|
+
|
|
110
|
+ dist = 1.0f / sqrtf(temp);
|
|
111
|
+
|
|
112
|
+ x *= dist;
|
|
113
|
+ y *= dist;
|
|
114
|
+ z *= dist;
|
|
115
|
+
|
|
116
|
+ mX = x;
|
|
117
|
+ mY = y;
|
|
118
|
+ mZ = z;
|
|
119
|
+
|
|
120
|
+ mW = cosf(angle / 2.0f);
|
|
121
|
+}
|
|
122
|
+
|
|
123
|
+void Quaternion::normalize() {
|
|
124
|
+ vec_t dist, square;
|
|
125
|
+
|
|
126
|
+ square = mX * mX + mY * mY + mZ * mZ + mW * mW;
|
|
127
|
+
|
|
128
|
+ if (square > 0.0) {
|
|
129
|
+ dist = 1.0f / sqrtf(square);
|
|
130
|
+ } else {
|
|
131
|
+ dist = 1;
|
|
132
|
+ }
|
|
133
|
+
|
|
134
|
+ mX *= dist;
|
|
135
|
+ mY *= dist;
|
|
136
|
+ mZ *= dist;
|
|
137
|
+ mW *= dist;
|
|
138
|
+}
|
|
139
|
+
|
|
140
|
+void Quaternion::copy(Quaternion q) {
|
|
141
|
+ mW = q.mW;
|
|
142
|
+ mX = q.mX;
|
|
143
|
+ mY = q.mY;
|
|
144
|
+ mZ = q.mZ;
|
|
145
|
+}
|
|
146
|
+
|
|
147
|
+Quaternion Quaternion::slerp(Quaternion a, Quaternion b, vec_t time) {
|
|
148
|
+ /*******************************************************************
|
|
149
|
+ * Spherical Linear Interpolation algorthim
|
|
150
|
+ *-----------------------------------------------------------------
|
|
151
|
+ *
|
|
152
|
+ * Interpolate between A and B rotations ( Find qI )
|
|
153
|
+ *
|
|
154
|
+ * qI = (((qB . qA)^ -1)^ Time) qA
|
|
155
|
+ *
|
|
156
|
+ * http://www.magic-software.com/Documentation/quat.pdf
|
|
157
|
+ *
|
|
158
|
+ * Thanks to digiben for algorithms and basis of the notes in
|
|
159
|
+ * this func
|
|
160
|
+ *
|
|
161
|
+ *******************************************************************/
|
|
162
|
+
|
|
163
|
+ vec_t result, scaleA, scaleB;
|
|
164
|
+ Quaternion i;
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+ // Don't bother if it's the same rotation, it's the same as the result
|
|
168
|
+ if (a == b)
|
|
169
|
+ return a;
|
|
170
|
+
|
|
171
|
+ // A . B
|
|
172
|
+ result = dot(a, b);
|
|
173
|
+
|
|
174
|
+ // If the dot product is less than 0, the angle is greater than 90 degrees
|
|
175
|
+ if (result < 0.0f) {
|
|
176
|
+ // Negate quaternion B and the result of the dot product
|
|
177
|
+ b = Quaternion(-b.mW, -b.mX, -b.mY, -b.mZ);
|
|
178
|
+ result = -result;
|
|
179
|
+ }
|
|
180
|
+
|
|
181
|
+ // Set the first and second scale for the interpolation
|
|
182
|
+ scaleA = 1 - time;
|
|
183
|
+ scaleB = time;
|
|
184
|
+
|
|
185
|
+ // Next, we want to actually calculate the spherical interpolation. Since this
|
|
186
|
+ // calculation is quite computationally expensive, we want to only perform it
|
|
187
|
+ // if the angle between the 2 quaternions is large enough to warrant it. If the
|
|
188
|
+ // angle is fairly small, we can actually just do a simpler linear interpolation
|
|
189
|
+ // of the 2 quaternions, and skip all the complex math. We create a "delta" value
|
|
190
|
+ // of 0.1 to say that if the cosine of the angle (result of the dot product) between
|
|
191
|
+ // the 2 quaternions is smaller than 0.1, then we do NOT want to perform the full on
|
|
192
|
+ // interpolation using. This is because you won't really notice the difference.
|
|
193
|
+
|
|
194
|
+ // Check if the angle between the 2 quaternions was big enough
|
|
195
|
+ // to warrant such calculations
|
|
196
|
+ if (1 - result > 0.1f) {
|
|
197
|
+ // Get the angle between the 2 quaternions, and then
|
|
198
|
+ // store the sin() of that angle
|
|
199
|
+ vec_t theta = (float)acos(result);
|
|
200
|
+ vec_t sinTheta = (float)sin(theta);
|
|
201
|
+
|
|
202
|
+ // Calculate the scale for qA and qB, according to
|
|
203
|
+ // the angle and it's sine value
|
|
204
|
+ scaleA = (float)sin((1 - time) * theta) / sinTheta;
|
|
205
|
+ scaleB = (float)sin((time * theta)) / sinTheta;
|
|
206
|
+ }
|
|
207
|
+
|
|
208
|
+ // Calculate the x, y, z and w values for the quaternion by using a special
|
|
209
|
+ // form of linear interpolation for quaternions.
|
|
210
|
+ return (a.scale(scaleA) + b.scale(scaleB));
|
|
211
|
+}
|
|
212
|
+
|
|
213
|
+void Quaternion::setByMatrix(matrix_t matrix) {
|
|
214
|
+ float diagonal = matrix[0] + matrix[5] + matrix[10] + 1.0f;
|
|
215
|
+ float scale = 0.0f;
|
|
216
|
+ float w = 0.0f, x = 0.0f, y = 0.0f, z = 0.0f;
|
|
217
|
+
|
|
218
|
+ if (diagonal > 0.00000001) {
|
|
219
|
+ // Calculate the scale of the diagonal
|
|
220
|
+ scale = (float)(sqrt(diagonal) * 2);
|
|
221
|
+
|
|
222
|
+ w = 0.25f * scale;
|
|
223
|
+ x = (matrix[9] - matrix[6]) / scale;
|
|
224
|
+ y = (matrix[2] - matrix[8]) / scale;
|
|
225
|
+ z = (matrix[4] - matrix[1]) / scale;
|
|
226
|
+ } else {
|
|
227
|
+ // If the first element of the diagonal is the greatest value
|
|
228
|
+ if (matrix[0] > matrix[5] && matrix[0] > matrix[10]) {
|
|
229
|
+ // Find the scale according to the first element, and double it
|
|
230
|
+ scale = (float)sqrt(1.0f + matrix[0] - matrix[5] - matrix[10])*2.0f;
|
|
231
|
+
|
|
232
|
+ // Calculate the quaternion
|
|
233
|
+ w = (matrix[9] - matrix[6]) / scale;
|
|
234
|
+ x = 0.25f * scale;
|
|
235
|
+ y = (matrix[4] + matrix[1]) / scale;
|
|
236
|
+ z = (matrix[2] + matrix[8]) / scale;
|
|
237
|
+ } else if (matrix[5] > matrix[10]) {
|
|
238
|
+ // The second element of the diagonal is the greatest value
|
|
239
|
+ // Find the scale according to the second element, and double it
|
|
240
|
+ scale = (float)sqrt(1.0f + matrix[5] - matrix[0] - matrix[10])*2.0f;
|
|
241
|
+
|
|
242
|
+ // Calculate the quaternion
|
|
243
|
+ w = (matrix[2] - matrix[8]) / scale;
|
|
244
|
+ x = (matrix[4] + matrix[1]) / scale;
|
|
245
|
+ y = 0.25f * scale;
|
|
246
|
+ z = (matrix[9] + matrix[6]) / scale;
|
|
247
|
+ } else { // The third element of the diagonal is the greatest value
|
|
248
|
+ // Find the scale according to the third element, and double it
|
|
249
|
+ scale = (float)sqrt(1.0f + matrix[10] - matrix[0] - matrix[5])*2.0f;
|
|
250
|
+
|
|
251
|
+ // Calculate the quaternion
|
|
252
|
+ w = (matrix[4] - matrix[1]) / scale;
|
|
253
|
+ x = (matrix[2] + matrix[8]) / scale;
|
|
254
|
+ y = (matrix[9] + matrix[6]) / scale;
|
|
255
|
+ z = 0.25f * scale;
|
|
256
|
+ }
|
|
257
|
+ }
|
|
258
|
+
|
|
259
|
+ mW = w;
|
|
260
|
+ mX = x;
|
|
261
|
+ mY = y;
|
|
262
|
+ mZ = z;
|
|
263
|
+}
|
|
264
|
+
|
|
265
|
+Quaternion Quaternion::multiply(Quaternion a, Quaternion b) {
|
|
266
|
+ return Quaternion(a.mW * b.mW - a.mX * b.mX - a.mY * b.mY - a.mZ * b.mZ,
|
|
267
|
+ a.mW * b.mX + a.mX * b.mW + a.mY * b.mZ - a.mZ * b.mY,
|
|
268
|
+ a.mW * b.mY + a.mY * b.mW + a.mZ * b.mX - a.mX * b.mZ,
|
|
269
|
+ a.mW * b.mZ + a.mZ * b.mW + a.mX * b.mY - a.mY * b.mX);
|
|
270
|
+}
|
|
271
|
+
|
|
272
|
+Quaternion Quaternion::divide(Quaternion a, Quaternion b) {
|
|
273
|
+ return (a * (b.inverse()));
|
|
274
|
+}
|
|
275
|
+
|
|
276
|
+Quaternion Quaternion::add(Quaternion a, Quaternion b) {
|
|
277
|
+ return Quaternion(a.mW + b.mW,
|
|
278
|
+ a.mX + b.mX,
|
|
279
|
+ a.mY + b.mY,
|
|
280
|
+ a.mZ + b.mZ);
|
|
281
|
+}
|
|
282
|
+
|
|
283
|
+Quaternion Quaternion::subtract(Quaternion a, Quaternion b) {
|
|
284
|
+ return Quaternion(a.mW - b.mW,
|
|
285
|
+ a.mX - b.mX,
|
|
286
|
+ a.mY - b.mY,
|
|
287
|
+ a.mZ - b.mZ);
|
|
288
|
+}
|
|
289
|
+
|