altos: Add some comments describing quaternion multiplication
[fw/altos] / src / core / ao_quaternion.h
1 /*
2  * Copyright © 2013 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #ifndef _AO_QUATERNION_H_
19 #define _AO_QUATERNION_H_
20
21 #include <math.h>
22
23 struct ao_quaternion {
24         float   r;              /* real bit */
25         float   x, y, z;        /* imaginary bits */
26 };
27
28 static inline void ao_quaternion_multiply(struct ao_quaternion *r,
29                                           const struct ao_quaternion *a,
30                                           const struct ao_quaternion *b)
31 {
32         struct ao_quaternion    t;
33 #define T(_a,_b)        (((a)->_a) * ((b)->_b))
34
35 /*
36  * Quaternions
37  *
38  *      ii = jj = kk = ijk = -1;
39  *
40  *      kji = 1;
41  *
42  *      ij = k;         ji = -k;
43  *      kj = -i;        jk = i;
44  *      ik = -j;        ki = j;
45  *
46  * Multiplication p * q:
47  *
48  *      (pr + ipx + jpy + kpz) (qr + iqx + jqy + kqz) =
49  *
50  *              ( pr * qr +  pr * iqx +  pr * jqy +  pr * kqz) +
51  *              (ipx * qr + ipx * iqx + ipx * jqy + ipx * kqz) +
52  *              (jpy * qr + jpy * iqx + jpy * jqy + jpy * kqz) +
53  *              (kpz * qr + kpz * iqx + kpz * jqy + kpz * kqz) =
54  *
55  *
56  *               (pr * qr) + i(pr * qx) + j(pr * qy) + k(pr * qz) +
57  *              i(px * qr) -  (px * qx) + k(px * qy) - j(px * qz) +
58  *              j(py * qr) - k(py * qx) -  (py * qy) + i(py * qz) +
59  *              k(pz * qr) + j(pz * qx) - i(pz * qy) -  (pz * qz) =
60  *
61  *              1 * ( (pr * qr) - (px * qx) - (py * qy) - (pz * qz) ) +
62  *              i * ( (pr * qx) + (px * qr) + (py * qz) - (pz * qy) ) +
63  *              j * ( (pr * qy) - (px * qz) + (py * qr) + (pz * qx) ) +
64  *              k * ( (pr * qz) + (px * qy) - (py * qx) + (pz * qr);
65  */
66
67         t.r = T(r,r) - T(x,x) - T(y,y) - T(z,z);
68         t.x = T(r,x) + T(x,r) + T(y,z) - T(z,y);
69         t.y = T(r,y) - T(x,z) + T(y,r) + T(z,x);
70         t.z = T(r,z) + T(x,y) - T(y,x) + T(z,r);
71 #undef T
72         *r = t;
73 }
74
75 static inline void ao_quaternion_conjugate(struct ao_quaternion *r,
76                                            const struct ao_quaternion *a)
77 {
78         r->r = a->r;
79         r->x = -a->x;
80         r->y = -a->y;
81         r->z = -a->z;
82 }
83
84 static inline float ao_quaternion_normal(const struct ao_quaternion *a)
85 {
86 #define S(_a)   (((a)->_a) * ((a)->_a))
87         return S(r) + S(x) + S(y) + S(z);
88 #undef S
89 }
90
91 static inline void ao_quaternion_scale(struct ao_quaternion *r,
92                                        const struct ao_quaternion *a,
93                                        float b)
94 {
95         r->r = a->r * b;
96         r->x = a->x * b;
97         r->y = a->y * b;
98         r->z = a->z * b;
99 }
100
101 static inline void ao_quaternion_normalize(struct ao_quaternion *r,
102                                            const struct ao_quaternion *a)
103 {
104         float   n = ao_quaternion_normal(a);
105
106         if (n > 0)
107                 ao_quaternion_scale(r, a, 1/sqrtf(n));
108         else
109                 *r = *a;
110 }
111
112 static inline void ao_quaternion_rotate(struct ao_quaternion *r,
113                                         struct ao_quaternion *a,
114                                         struct ao_quaternion *b)
115 {
116         struct ao_quaternion    c;
117         struct ao_quaternion    t;
118
119         ao_quaternion_conjugate(&c, b);
120         ao_quaternion_multiply(&t, b, a);
121         ao_quaternion_multiply(r, &t, &c);
122 }
123
124 static inline void ao_quaternion_init_vector(struct ao_quaternion *r,
125                                              float x, float y, float z)
126 {
127         r->r = 0;
128         r->x = x;
129         r->y = y;
130         r->z = z;
131 }
132
133 static inline void ao_quaternion_init_rotation(struct ao_quaternion *r,
134                                                float x, float y, float z,
135                                                float s, float c)
136 {
137         r->r = c;
138         r->x = s * x;
139         r->y = s * y;
140         r->z = s * z;
141 }
142
143 static inline void ao_quaternion_init_zero_rotation(struct ao_quaternion *r)
144 {
145         r->r = 1;
146         r->x = r->y = r->z = 0;
147 }
148
149 #endif /* _AO_QUATERNION_H_ */