2 * Copyright © 2013 Keith Packard <keithp@keithp.com>
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; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 #ifndef _AO_QUATERNION_H_
20 #define _AO_QUATERNION_H_
24 struct ao_quaternion {
25 float r; /* real bit */
26 float x, y, z; /* imaginary bits */
29 static inline void ao_quaternion_multiply(struct ao_quaternion *r,
30 const struct ao_quaternion *a,
31 const struct ao_quaternion *b)
33 struct ao_quaternion t;
34 #define T(_a,_b) (((a)->_a) * ((b)->_b))
39 * ii = jj = kk = ijk = -1;
47 * Multiplication p * q:
49 * (pr + ipx + jpy + kpz) (qr + iqx + jqy + kqz) =
51 * ( pr * qr + pr * iqx + pr * jqy + pr * kqz) +
52 * (ipx * qr + ipx * iqx + ipx * jqy + ipx * kqz) +
53 * (jpy * qr + jpy * iqx + jpy * jqy + jpy * kqz) +
54 * (kpz * qr + kpz * iqx + kpz * jqy + kpz * kqz) =
57 * (pr * qr) + i(pr * qx) + j(pr * qy) + k(pr * qz) +
58 * i(px * qr) - (px * qx) + k(px * qy) - j(px * qz) +
59 * j(py * qr) - k(py * qx) - (py * qy) + i(py * qz) +
60 * k(pz * qr) + j(pz * qx) - i(pz * qy) - (pz * qz) =
62 * 1 * ( (pr * qr) - (px * qx) - (py * qy) - (pz * qz) ) +
63 * i * ( (pr * qx) + (px * qr) + (py * qz) - (pz * qy) ) +
64 * j * ( (pr * qy) - (px * qz) + (py * qr) + (pz * qx) ) +
65 * k * ( (pr * qz) + (px * qy) - (py * qx) + (pz * qr);
68 t.r = T(r,r) - T(x,x) - T(y,y) - T(z,z);
69 t.x = T(r,x) + T(x,r) + T(y,z) - T(z,y);
70 t.y = T(r,y) - T(x,z) + T(y,r) + T(z,x);
71 t.z = T(r,z) + T(x,y) - T(y,x) + T(z,r);
76 static inline void ao_quaternion_conjugate(struct ao_quaternion *r,
77 const struct ao_quaternion *a)
85 static inline float ao_quaternion_normal(const struct ao_quaternion *a)
87 #define S(_a) (((a)->_a) * ((a)->_a))
88 return S(r) + S(x) + S(y) + S(z);
92 static inline void ao_quaternion_scale(struct ao_quaternion *r,
93 const struct ao_quaternion *a,
102 static inline void ao_quaternion_normalize(struct ao_quaternion *r,
103 const struct ao_quaternion *a)
105 float n = ao_quaternion_normal(a);
108 ao_quaternion_scale(r, a, 1/sqrtf(n));
113 static inline float ao_quaternion_dot(const struct ao_quaternion *a,
114 const struct ao_quaternion *b)
116 #define T(_a) (((a)->_a) * ((b)->_a))
117 return T(r) + T(x) + T(y) + T(z);
122 static inline void ao_quaternion_rotate(struct ao_quaternion *r,
123 const struct ao_quaternion *a,
124 const struct ao_quaternion *b)
126 struct ao_quaternion c;
127 struct ao_quaternion t;
129 ao_quaternion_multiply(&t, b, a);
130 ao_quaternion_conjugate(&c, b);
131 ao_quaternion_multiply(r, &t, &c);
135 * Compute a rotation quaternion between two vectors
137 * cos(θ) + u * sin(θ)
139 * where θ is the angle between the two vectors and u
140 * is a unit vector axis of rotation
143 static inline void ao_quaternion_vectors_to_rotation(struct ao_quaternion *r,
144 const struct ao_quaternion *a,
145 const struct ao_quaternion *b)
148 * The cross product will point orthogonally to the two
149 * vectors, forming our rotation axis. The length will be
150 * sin(θ), so these values are already multiplied by that.
153 float x = a->y * b->z - a->z * b->y;
154 float y = a->z * b->x - a->x * b->z;
155 float z = a->x * b->y - a->y * b->x;
157 float s_2 = x*x + y*y + z*z;
158 float s = sqrtf(s_2);
160 /* cos(θ) = a · b / (|a| |b|).
162 * a and b are both unit vectors, so the divisor is one
164 float c = a->x*b->x + a->y*b->y + a->z*b->z;
166 float c_half = sqrtf ((1 + c) / 2);
167 float s_half = sqrtf ((1 - c) / 2);
170 * Divide out the sine factor from the
171 * cross product, then multiply in the
172 * half sine factor needed for the quaternion
174 float s_scale = s_half / s;
182 ao_quaternion_normalize(r, r);
185 static inline void ao_quaternion_init_vector(struct ao_quaternion *r,
186 float x, float y, float z)
194 static inline void ao_quaternion_init_rotation(struct ao_quaternion *r,
195 float x, float y, float z,
204 static inline void ao_quaternion_init_zero_rotation(struct ao_quaternion *r)
207 r->x = r->y = r->z = 0;
211 * The sincosf from newlib just calls sinf and cosf. This is a bit
212 * faster, if slightly less precise
216 ao_sincosf(float a, float *s, float *c) {
219 *c = sqrtf(1 - _s*_s);
223 * Initialize a quaternion from 1/2 euler rotation angles (in radians).
225 * Yes, it would be nicer if there were a faster way, but because we
226 * sample the gyros at only 100Hz, we end up getting angles too large
227 * to take advantage of sin(x) ≃ x.
229 * We might be able to use just a couple of elements of the sin taylor
230 * series though, instead of the whole sin function?
233 static inline void ao_quaternion_init_half_euler(struct ao_quaternion *r,
234 float x, float y, float z)
240 ao_sincosf(x, &s_x, &c_x);
241 ao_sincosf(y, &s_y, &c_y);
242 ao_sincosf(z, &s_z, &c_z);
244 r->r = c_x * c_y * c_z + s_x * s_y * s_z;
245 r->x = s_x * c_y * c_z - c_x * s_y * s_z;
246 r->y = c_x * s_y * c_z + s_x * c_y * s_z;
247 r->z = c_x * c_y * s_z - s_x * s_y * c_z;
250 #endif /* _AO_QUATERNION_H_ */