]> git.jsancho.org Git - lugaru.git/blob - Source/Math/Quaternions.cpp
Rename all C++ headers with .hpp extension
[lugaru.git] / Source / Math / Quaternions.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
4
5 This file is part of Lugaru.
6
7 Lugaru is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 Lugaru is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "Math/Quaternions.hpp"
22
23 // Functions
24 quaternion Quat_Mult(quaternion q1, quaternion q2)
25 {
26     quaternion QResult;
27     float a, b, c, d, e, f, g, h;
28     a = (q1.w + q1.x) * (q2.w + q2.x);
29     b = (q1.z - q1.y) * (q2.y - q2.z);
30     c = (q1.w - q1.x) * (q2.y + q2.z);
31     d = (q1.y + q1.z) * (q2.w - q2.x);
32     e = (q1.x + q1.z) * (q2.x + q2.y);
33     f = (q1.x - q1.z) * (q2.x - q2.y);
34     g = (q1.w + q1.y) * (q2.w - q2.z);
35     h = (q1.w - q1.y) * (q2.w + q2.z);
36     QResult.w = b + (-e - f + g + h) / 2;
37     QResult.x = a - (e + f + g + h) / 2;
38     QResult.y = c + (e - f + g - h) / 2;
39     QResult.z = d + (e - f - g + h) / 2;
40     return QResult;
41 }
42
43
44
45 quaternion To_Quat(Matrix_t m)
46 {
47     // From Jason Shankel, (C) 2000.
48     static quaternion Quat;
49
50     static double Tr = m[0][0] + m[1][1] + m[2][2] + 1.0, fourD;
51     static double q[4];
52
53     static int i, j, k;
54     if (Tr >= 1.0) {
55         fourD = 2.0 * fast_sqrt(Tr);
56         q[3] = fourD / 4.0;
57         q[0] = (m[2][1] - m[1][2]) / fourD;
58         q[1] = (m[0][2] - m[2][0]) / fourD;
59         q[2] = (m[1][0] - m[0][1]) / fourD;
60     } else {
61         if (m[0][0] > m[1][1]) {
62             i = 0;
63         } else {
64             i = 1;
65         }
66         if (m[2][2] > m[i][i]) {
67             i = 2;
68         }
69         j = (i + 1) % 3;
70         k = (j + 1) % 3;
71         fourD = 2.0 * fast_sqrt(m[i][i] - m[j][j] - m[k][k] + 1.0);
72         q[i] = fourD / 4.0;
73         q[j] = (m[j][i] + m[i][j]) / fourD;
74         q[k] = (m[k][i] + m[i][k]) / fourD;
75         q[3] = (m[j][k] - m[k][j]) / fourD;
76     }
77
78     Quat.x = q[0];
79     Quat.y = q[1];
80     Quat.z = q[2];
81     Quat.w = q[3];
82     return Quat;
83 }
84 void Quat_2_Matrix(quaternion Quat, Matrix_t m)
85 {
86     // From the GLVelocity site (http://glvelocity.gamedev.net)
87     float fW = Quat.w;
88     float fX = Quat.x;
89     float fY = Quat.y;
90     float fZ = Quat.z;
91     float fXX = fX * fX;
92     float fYY = fY * fY;
93     float fZZ = fZ * fZ;
94     m[0][0] = 1.0f - 2.0f * (fYY + fZZ);
95     m[1][0] = 2.0f * (fX * fY + fW * fZ);
96     m[2][0] = 2.0f * (fX * fZ - fW * fY);
97     m[3][0] = 0.0f;
98     m[0][1] = 2.0f * (fX * fY - fW * fZ);
99     m[1][1] = 1.0f - 2.0f * (fXX + fZZ);
100     m[2][1] = 2.0f * (fY * fZ + fW * fX);
101     m[3][1] = 0.0f;
102     m[0][2] = 2.0f * (fX * fZ + fW * fY);
103     m[1][2] = 2.0f * (fX * fZ - fW * fX);
104     m[2][2] = 1.0f - 2.0f * (fXX + fYY);
105     m[3][2] = 0.0f;
106     m[0][3] = 0.0f;
107     m[1][3] = 0.0f;
108     m[2][3] = 0.0f;
109     m[3][3] = 1.0f;
110 }
111 quaternion To_Quat(angle_axis Ang_Ax)
112 {
113     // From the Quaternion Powers article on gamedev.net
114     static quaternion Quat;
115
116     Quat.x = Ang_Ax.x * sin(Ang_Ax.angle / 2);
117     Quat.y = Ang_Ax.y * sin(Ang_Ax.angle / 2);
118     Quat.z = Ang_Ax.z * sin(Ang_Ax.angle / 2);
119     Quat.w = cos(Ang_Ax.angle / 2);
120     return Quat;
121 }
122 angle_axis Quat_2_AA(quaternion Quat)
123 {
124     static angle_axis Ang_Ax;
125     static float scale, tw;
126     tw = (float)acosf(Quat.w) * 2;
127     scale = (float)sin(tw / 2.0);
128     Ang_Ax.x = Quat.x / scale;
129     Ang_Ax.y = Quat.y / scale;
130     Ang_Ax.z = Quat.z / scale;
131
132     Ang_Ax.angle = 2.0 * acosf(Quat.w) / (float)PI * 180;
133     return Ang_Ax;
134 }
135
136 quaternion To_Quat(int In_Degrees, euler Euler)
137 {
138     // From the gamasutra quaternion article
139     static quaternion Quat;
140     static float cr, cp, cy, sr, sp, sy, cpcy, spsy;
141     //If we are in Degree mode, convert to Radians
142     if (In_Degrees) {
143         Euler.x = Euler.x * (float)PI / 180;
144         Euler.y = Euler.y * (float)PI / 180;
145         Euler.z = Euler.z * (float)PI / 180;
146     }
147     //Calculate trig identities
148     //Formerly roll, pitch, yaw
149     cr = float(cos(Euler.x / 2));
150     cp = float(cos(Euler.y / 2));
151     cy = float(cos(Euler.z / 2));
152     sr = float(sin(Euler.x / 2));
153     sp = float(sin(Euler.y / 2));
154     sy = float(sin(Euler.z / 2));
155
156     cpcy = cp * cy;
157     spsy = sp * sy;
158     Quat.w = cr * cpcy + sr * spsy;
159     Quat.x = sr * cpcy - cr * spsy;
160     Quat.y = cr * sp * cy + sr * cp * sy;
161     Quat.z = cr * cp * sy - sr * sp * cy;
162
163     return Quat;
164 }
165
166 quaternion QNormalize(quaternion Quat)
167 {
168     static float norm;
169     norm =  Quat.x * Quat.x +
170             Quat.y * Quat.y +
171             Quat.z * Quat.z +
172             Quat.w * Quat.w;
173     Quat.x = float(Quat.x / norm);
174     Quat.y = float(Quat.y / norm);
175     Quat.z = float(Quat.z / norm);
176     Quat.w = float(Quat.w / norm);
177     return Quat;
178 }
179
180 XYZ Quat2Vector(quaternion Quat)
181 {
182     QNormalize(Quat);
183
184     float fW = Quat.w;
185     float fX = Quat.x;
186     float fY = Quat.y;
187     float fZ = Quat.z;
188
189     XYZ tempvec;
190
191     tempvec.x = 2.0f * (fX * fZ - fW * fY);
192     tempvec.y = 2.0f * (fY * fZ + fW * fX);
193     tempvec.z = 1.0f - 2.0f * (fX * fX + fY * fY);
194
195     return tempvec;
196 }
197
198 bool PointInTriangle(Vector *p, Vector normal, float p11, float p12, float p13, float p21, float p22, float p23, float p31, float p32, float p33)
199 {
200     static float u0, u1, u2;
201     static float v0, v1, v2;
202     static float a, b;
203     static float max;
204     static int i, j;
205     static bool bInter;
206     static float pointv[3];
207     static float p1v[3];
208     static float p2v[3];
209     static float p3v[3];
210     static float normalv[3];
211
212     bInter = 0;
213
214     pointv[0] = p->x;
215     pointv[1] = p->y;
216     pointv[2] = p->z;
217
218
219     p1v[0] = p11;
220     p1v[1] = p12;
221     p1v[2] = p13;
222
223     p2v[0] = p21;
224     p2v[1] = p22;
225     p2v[2] = p23;
226
227     p3v[0] = p31;
228     p3v[1] = p32;
229     p3v[2] = p33;
230
231     normalv[0] = normal.x;
232     normalv[1] = normal.y;
233     normalv[2] = normal.z;
234
235 #define ABS(X) (((X)<0.f)?-(X):(X) )
236 #define MAX(A, B) (((A)<(B))?(B):(A))
237     max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2]));
238 #undef MAX
239     if (max == ABS(normalv[0])) {
240         i = 1;    // y, z
241         j = 2;
242     }
243     if (max == ABS(normalv[1])) {
244         i = 0;    // x, z
245         j = 2;
246     }
247     if (max == ABS(normalv[2])) {
248         i = 0;    // x, y
249         j = 1;
250     }
251 #undef ABS
252
253     u0 = pointv[i] - p1v[i];
254     v0 = pointv[j] - p1v[j];
255     u1 = p2v[i] - p1v[i];
256     v1 = p2v[j] - p1v[j];
257     u2 = p3v[i] - p1v[i];
258     v2 = p3v[j] - p1v[j];
259
260     if (u1 > -1.0e-05f && u1 < 1.0e-05f) { // == 0.0f)
261         b = u0 / u2;
262         if (0.0f <= b && b <= 1.0f) {
263             a = (v0 - b * v2) / v1;
264             if ((a >= 0.0f) && (( a + b ) <= 1.0f))
265                 bInter = 1;
266         }
267     } else {
268         b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
269         if (0.0f <= b && b <= 1.0f) {
270             a = (u0 - b * u2) / u1;
271             if ((a >= 0.0f) && (( a + b ) <= 1.0f ))
272                 bInter = 1;
273         }
274     }
275
276     return bInter;
277 }
278
279 bool LineFacet(Vector p1, Vector p2, Vector pa, Vector pb, Vector pc, Vector *p)
280 {
281     static float d;
282     static float denom, mu;
283     static Vector n;
284
285     //Calculate the parameters for the plane
286     n.x = (pb.y - pa.y) * (pc.z - pa.z) - (pb.z - pa.z) * (pc.y - pa.y);
287     n.y = (pb.z - pa.z) * (pc.x - pa.x) - (pb.x - pa.x) * (pc.z - pa.z);
288     n.z = (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x);
289     n.Normalize();
290     d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
291
292     //Calculate the position on the line that intersects the plane
293     denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
294     if (fabs(denom) < 0.0000001)        // Line and plane don't intersect
295         return 0;
296     mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
297     p->x = p1.x + mu * (p2.x - p1.x);
298     p->y = p1.y + mu * (p2.y - p1.y);
299     p->z = p1.z + mu * (p2.z - p1.z);
300     if (mu < 0 || mu > 1)   // Intersection not along line segment
301         return 0;
302
303     if (!PointInTriangle( p, n, pa.x, pa.y, pa.z, pb.x, pb.y, pb.z, pc.x, pc.y, pc.z)) {
304         return 0;
305     }
306
307     return 1;
308 }
309
310 bool PointInTriangle(XYZ *p, XYZ normal, XYZ *p1, XYZ *p2, XYZ *p3)
311 {
312     static float u0, u1, u2;
313     static float v0, v1, v2;
314     static float a, b;
315     static float max;
316     static int i, j;
317     static bool bInter = 0;
318     static float pointv[3];
319     static float p1v[3];
320     static float p2v[3];
321     static float p3v[3];
322     static float normalv[3];
323
324     bInter = 0;
325
326     pointv[0] = p->x;
327     pointv[1] = p->y;
328     pointv[2] = p->z;
329
330
331     p1v[0] = p1->x;
332     p1v[1] = p1->y;
333     p1v[2] = p1->z;
334
335     p2v[0] = p2->x;
336     p2v[1] = p2->y;
337     p2v[2] = p2->z;
338
339     p3v[0] = p3->x;
340     p3v[1] = p3->y;
341     p3v[2] = p3->z;
342
343     normalv[0] = normal.x;
344     normalv[1] = normal.y;
345     normalv[2] = normal.z;
346
347 #define ABS(X) (((X)<0.f)?-(X):(X) )
348 #define MAX(A, B) (((A)<(B))?(B):(A))
349     max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2]));
350 #undef MAX
351     if (max == ABS(normalv[0])) {
352         i = 1;    // y, z
353         j = 2;
354     }
355     if (max == ABS(normalv[1])) {
356         i = 0;    // x, z
357         j = 2;
358     }
359     if (max == ABS(normalv[2])) {
360         i = 0;    // x, y
361         j = 1;
362     }
363 #undef ABS
364
365     u0 = pointv[i] - p1v[i];
366     v0 = pointv[j] - p1v[j];
367     u1 = p2v[i] - p1v[i];
368     v1 = p2v[j] - p1v[j];
369     u2 = p3v[i] - p1v[i];
370     v2 = p3v[j] - p1v[j];
371
372     if (u1 > -1.0e-05f && u1 < 1.0e-05f) { // == 0.0f)
373         b = u0 / u2;
374         if (0.0f <= b && b <= 1.0f) {
375             a = (v0 - b * v2) / v1;
376             if ((a >= 0.0f) && (( a + b ) <= 1.0f))
377                 bInter = 1;
378         }
379     } else {
380         b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
381         if (0.0f <= b && b <= 1.0f) {
382             a = (u0 - b * u2) / u1;
383             if ((a >= 0.0f) && (( a + b ) <= 1.0f ))
384                 bInter = 1;
385         }
386     }
387
388     return bInter;
389 }
390
391 bool LineFacet(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ *p)
392 {
393     static float d;
394     static float denom, mu;
395     static XYZ n;
396
397     //Calculate the parameters for the plane
398     n.x = (pb.y - pa.y) * (pc.z - pa.z) - (pb.z - pa.z) * (pc.y - pa.y);
399     n.y = (pb.z - pa.z) * (pc.x - pa.x) - (pb.x - pa.x) * (pc.z - pa.z);
400     n.z = (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x);
401     Normalise(&n);
402     d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
403
404     //Calculate the position on the line that intersects the plane
405     denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
406     if (fabs(denom) < 0.0000001)        // Line and plane don't intersect
407         return 0;
408     mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
409     p->x = p1.x + mu * (p2.x - p1.x);
410     p->y = p1.y + mu * (p2.y - p1.y);
411     p->z = p1.z + mu * (p2.z - p1.z);
412     if (mu < 0 || mu > 1)   // Intersection not along line segment
413         return 0;
414
415     if (!PointInTriangle( p, n, &pa, &pb, &pc)) {
416         return 0;
417     }
418
419     return 1;
420 }
421
422 float LineFacetd(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ *p)
423 {
424     static float d;
425     static float denom, mu;
426     static XYZ n;
427
428     //Calculate the parameters for the plane
429     n.x = (pb.y - pa.y) * (pc.z - pa.z) - (pb.z - pa.z) * (pc.y - pa.y);
430     n.y = (pb.z - pa.z) * (pc.x - pa.x) - (pb.x - pa.x) * (pc.z - pa.z);
431     n.z = (pb.x - pa.x) * (pc.y - pa.y) - (pb.y - pa.y) * (pc.x - pa.x);
432     Normalise(&n);
433     d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
434
435     //Calculate the position on the line that intersects the plane
436     denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
437     if (fabs(denom) < 0.0000001)        // Line and plane don't intersect
438         return 0;
439     mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
440     p->x = p1.x + mu * (p2.x - p1.x);
441     p->y = p1.y + mu * (p2.y - p1.y);
442     p->z = p1.z + mu * (p2.z - p1.z);
443     if (mu < 0 || mu > 1)   // Intersection not along line segment
444         return 0;
445
446     if (!PointInTriangle( p, n, &pa, &pb, &pc)) {
447         return 0;
448     }
449
450     return 1;
451 }
452
453 float LineFacetd(XYZ p1, XYZ p2, XYZ pa, XYZ pb, XYZ pc, XYZ n, XYZ *p)
454 {
455     static float d;
456     static float denom, mu;
457
458     //Calculate the parameters for the plane
459     d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
460
461     //Calculate the position on the line that intersects the plane
462     denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
463     if (fabs(denom) < 0.0000001)        // Line and plane don't intersect
464         return 0;
465     mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
466     p->x = p1.x + mu * (p2.x - p1.x);
467     p->y = p1.y + mu * (p2.y - p1.y);
468     p->z = p1.z + mu * (p2.z - p1.z);
469     if (mu < 0 || mu > 1)   // Intersection not along line segment
470         return 0;
471
472     if (!PointInTriangle( p, n, &pa, &pb, &pc)) {
473         return 0;
474     }
475     return 1;
476 }
477
478 float LineFacetd(XYZ *p1, XYZ *p2, XYZ *pa, XYZ *pb, XYZ *pc, XYZ *p)
479 {
480     static float d;
481     static float denom, mu;
482     static XYZ n;
483
484     //Calculate the parameters for the plane
485     n.x = (pb->y - pa->y) * (pc->z - pa->z) - (pb->z - pa->z) * (pc->y - pa->y);
486     n.y = (pb->z - pa->z) * (pc->x - pa->x) - (pb->x - pa->x) * (pc->z - pa->z);
487     n.z = (pb->x - pa->x) * (pc->y - pa->y) - (pb->y - pa->y) * (pc->x - pa->x);
488     Normalise(&n);
489     d = - n.x * pa->x - n.y * pa->y - n.z * pa->z;
490
491
492     //Calculate the position on the line that intersects the plane
493     denom = n.x * (p2->x - p1->x) + n.y * (p2->y - p1->y) + n.z * (p2->z - p1->z);
494     if (fabs(denom) < 0.0000001)        // Line and plane don't intersect
495         return 0;
496     mu = - (d + n.x * p1->x + n.y * p1->y + n.z * p1->z) / denom;
497     p->x = p1->x + mu * (p2->x - p1->x);
498     p->y = p1->y + mu * (p2->y - p1->y);
499     p->z = p1->z + mu * (p2->z - p1->z);
500     if (mu < 0 || mu > 1)   // Intersection not along line segment
501         return 0;
502
503     if (!PointInTriangle( p, n, pa, pb, pc)) {
504         return 0;
505     }
506     return 1;
507 }
508
509 float LineFacetd(XYZ *p1, XYZ *p2, XYZ *pa, XYZ *pb, XYZ *pc, XYZ *n, XYZ *p)
510 {
511     static float d;
512     static float denom, mu;
513
514     //Calculate the parameters for the plane
515     d = - n->x * pa->x - n->y * pa->y - n->z * pa->z;
516
517     //Calculate the position on the line that intersects the plane
518     denom = n->x * (p2->x - p1->x) + n->y * (p2->y - p1->y) + n->z * (p2->z - p1->z);
519     if (fabs(denom) < 0.0000001)        // Line and plane don't intersect
520         return 0;
521     mu = - (d + n->x * p1->x + n->y * p1->y + n->z * p1->z) / denom;
522     p->x = p1->x + mu * (p2->x - p1->x);
523     p->y = p1->y + mu * (p2->y - p1->y);
524     p->z = p1->z + mu * (p2->z - p1->z);
525     if (mu < 0 || mu > 1)   // Intersection not along line segment
526         return 0;
527
528     if (!PointInTriangle( p, *n, pa, pb, pc)) {
529         return 0;
530     }
531     return 1;
532 }
533
534