1 /*
2  * Copyright (c) 2021 Kevin Townsend
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <math.h>
8 #include <errno.h>
9 #include <stdio.h>
10 #include <zsl/zsl.h>
11 #include <zsl/vectors.h>
12 #include <zsl/orientation/quaternions.h>
13 
14 /**
15  * @brief Helper function to compare float values.
16  *
17  * @param a 		First float too compare.
18  * @param b 		Second float to compare.
19  * @param epsilon 	Allowed deviatin between first and second values.
20 
21  * @return true		If values are the same within the limits of epsilon.
22  * @return false 	If values are different to an extent greater than epsilon.
23  */
24 static bool
zsl_quat_val_is_equal(zsl_real_t a,zsl_real_t b,zsl_real_t epsilon)25 zsl_quat_val_is_equal(zsl_real_t a, zsl_real_t b, zsl_real_t epsilon)
26 {
27 	zsl_real_t c;
28 
29 	c = a - b;
30 
31 	if (ZSL_ABS(c) < epsilon) {
32 		return 1;
33 	} else {
34 		return 0;
35 	}
36 }
37 
zsl_quat_init(struct zsl_quat * q,enum zsl_quat_type type)38 void zsl_quat_init(struct zsl_quat *q, enum zsl_quat_type type)
39 {
40 	switch (type) {
41 	case ZSL_QUAT_TYPE_IDENTITY:
42 		q->r = 1.0;
43 		q->i = 0.0;
44 		q->j = 0.0;
45 		q->k = 0.0;
46 		break;
47 	case ZSL_QUAT_TYPE_EMPTY:
48 	default:
49 		q->r = 0.0;
50 		q->i = 0.0;
51 		q->j = 0.0;
52 		q->k = 0.0;
53 		break;
54 	}
55 }
56 
zsl_quat_magn(struct zsl_quat * q)57 zsl_real_t zsl_quat_magn(struct zsl_quat *q)
58 {
59 	return ZSL_SQRT(q->r * q->r + q->i * q->i + q->j * q->j + q->k * q->k);
60 }
61 
zsl_quat_to_unit(struct zsl_quat * q,struct zsl_quat * qn)62 int zsl_quat_to_unit(struct zsl_quat *q, struct zsl_quat *qn)
63 {
64 	int rc = 0;
65 	zsl_real_t m = zsl_quat_magn(q);
66 
67 	if (ZSL_ABS(m) < 1E-6) {
68 		qn->r = 0.0;
69 		qn->i = 0.0;
70 		qn->j = 0.0;
71 		qn->k = 0.0;
72 	} else {
73 		qn->r = q->r / m;
74 		qn->i = q->i / m;
75 		qn->j = q->j / m;
76 		qn->k = q->k / m;
77 	}
78 
79 	return rc;
80 }
81 
zsl_quat_to_unit_d(struct zsl_quat * q)82 int zsl_quat_to_unit_d(struct zsl_quat *q)
83 {
84 	return zsl_quat_to_unit(q, q);
85 }
86 
zsl_quat_is_unit(struct zsl_quat * q)87 bool zsl_quat_is_unit(struct zsl_quat *q)
88 {
89 	zsl_real_t unit_len;
90 
91 	/* Verify that sqrt(r^2+i^2+j^2+k^2) = 1.0. */
92 	unit_len = ZSL_SQRT(
93 		q->r * q->r +
94 		q->i * q->i +
95 		q->j * q->j +
96 		q->k * q->k);
97 
98 	return zsl_quat_val_is_equal(unit_len, 1.0, 1E-6);
99 }
100 
zsl_quat_scale(struct zsl_quat * q,zsl_real_t s,struct zsl_quat * qs)101 int zsl_quat_scale(struct zsl_quat *q, zsl_real_t s, struct zsl_quat *qs)
102 {
103 	int rc = 0;
104 
105 	qs->r = q->r * s;
106 	qs->i = q->i * s;
107 	qs->j = q->j * s;
108 	qs->k = q->k * s;
109 
110 	return rc;
111 }
112 
zsl_quat_scale_d(struct zsl_quat * q,zsl_real_t s)113 int zsl_quat_scale_d(struct zsl_quat *q, zsl_real_t s)
114 {
115 	return zsl_quat_scale(q, s, q);
116 }
117 
zsl_quat_mult(struct zsl_quat * qa,struct zsl_quat * qb,struct zsl_quat * qm)118 int zsl_quat_mult(struct zsl_quat *qa, struct zsl_quat *qb,
119 		  struct zsl_quat *qm)
120 {
121 	int rc = 0;
122 
123 	/* Make copies so this function can be used as a destructive one. */
124 	struct zsl_quat qac;
125 	struct zsl_quat qbc;
126 
127 	qac.r = qa->r;
128 	qac.i = qa->i;
129 	qac.j = qa->j;
130 	qac.k = qa->k;
131 
132 	qbc.r = qb->r;
133 	qbc.i = qb->i;
134 	qbc.j = qb->j;
135 	qbc.k = qb->k;
136 
137 	qm->i = qac.r * qbc.i + qac.i * qbc.r + qac.j * qbc.k - qac.k * qbc.j;
138 	qm->j = qac.r * qbc.j - qac.i * qbc.k + qac.j * qbc.r + qac.k * qbc.i;
139 	qm->k = qac.r * qbc.k + qac.i * qbc.j - qac.j * qbc.i + qac.k * qbc.r;
140 	qm->r = qac.r * qbc.r - qac.i * qbc.i - qac.j * qbc.j - qac.k * qbc.k;
141 
142 	return rc;
143 }
144 
zsl_quat_exp(struct zsl_quat * q,struct zsl_quat * qe)145 int zsl_quat_exp(struct zsl_quat *q, struct zsl_quat *qe)
146 {
147 	int rc = 0;
148 
149 	ZSL_VECTOR_DEF(v, 3);
150 	zsl_real_t vmag;        /* Magnitude of v. */
151 	zsl_real_t vsin;        /* Sine of vm. */
152 	zsl_real_t rexp;        /* Exponent of q->r. */
153 
154 	/* Populate the XYZ vector using ijk from q. */
155 	v.data[0] = q->i;
156 	v.data[1] = q->j;
157 	v.data[2] = q->k;
158 
159 	/* Calculate magnitude of v. */
160 	vmag = zsl_vec_norm(&v);
161 
162 	/* Normalise v to unit vector. */
163 	zsl_vec_to_unit(&v);
164 
165 	vsin = ZSL_SIN(vmag);
166 	rexp = ZSL_EXP(q->r);
167 
168 	qe->r = ZSL_COS(vmag) * rexp;
169 	qe->i = v.data[0] * vsin * rexp;
170 	qe->j = v.data[1] * vsin * rexp;
171 	qe->k = v.data[2] * vsin * rexp;
172 
173 	return rc;
174 }
175 
zsl_quat_log(struct zsl_quat * q,struct zsl_quat * ql)176 int zsl_quat_log(struct zsl_quat *q, struct zsl_quat *ql)
177 {
178 	int rc = 0;
179 
180 	ZSL_VECTOR_DEF(v, 3);   /* Vector part of unit quat q. */
181 	zsl_real_t qmag;        /* Magnitude of q. */
182 	zsl_real_t racos;       /* Acos of q->r/qmag. */
183 
184 	/* Populate the XYZ vector using ijk from q. */
185 	v.data[0] = q->i;
186 	v.data[1] = q->j;
187 	v.data[2] = q->k;
188 
189 	/* Normalise v to unit vector. */
190 	zsl_vec_to_unit(&v);
191 
192 	/* Calculate magnitude of input quat. */
193 	qmag = zsl_quat_magn(q);
194 
195 	racos = ZSL_ACOS(q->r / qmag);
196 
197 	ql->r = ZSL_LOG(qmag);
198 	ql->i = v.data[0] * racos;
199 	ql->j = v.data[1] * racos;
200 	ql->k = v.data[2] * racos;
201 
202 	return rc;
203 }
204 
zsl_quat_pow(struct zsl_quat * q,zsl_real_t exp,struct zsl_quat * qout)205 int zsl_quat_pow(struct zsl_quat *q, zsl_real_t exp,
206 		 struct zsl_quat *qout)
207 {
208 	int rc = 0;
209 
210 	struct zsl_quat qlog;
211 	struct zsl_quat qsc;
212 
213 	rc = zsl_quat_log(q, &qlog);
214 	if (rc) {
215 		goto err;
216 	}
217 
218 	rc = zsl_quat_scale(&qlog, exp, &qsc);
219 	if (rc) {
220 		goto err;
221 	}
222 
223 	rc = zsl_quat_exp(&qsc, qout);
224 	if (rc) {
225 		zsl_quat_init(qout, ZSL_QUAT_TYPE_EMPTY);
226 		goto err;
227 	}
228 
229 err:
230 	return rc;
231 }
232 
zsl_quat_conj(struct zsl_quat * q,struct zsl_quat * qc)233 int zsl_quat_conj(struct zsl_quat *q, struct zsl_quat *qc)
234 {
235 	int rc = 0;
236 
237 	/* TODO: Check for div by zero before running this! */
238 	qc->r = q->r;
239 	qc->i = q->i * -1.0;
240 	qc->j = q->j * -1.0;
241 	qc->k = q->k * -1.0;
242 
243 	return rc;
244 }
245 
zsl_quat_inv(struct zsl_quat * q,struct zsl_quat * qi)246 int zsl_quat_inv(struct zsl_quat *q, struct zsl_quat *qi)
247 {
248 	int rc = 0;
249 	zsl_real_t m = zsl_quat_magn(q);
250 
251 	if (ZSL_ABS(m) < 1E-6) {
252 		/* Set to all 0's. */
253 		zsl_quat_init(qi, ZSL_QUAT_TYPE_EMPTY);
254 	} else {
255 		/* TODO: Check for div by zero before running this! */
256 		m *= m;
257 		qi->r = q->r / m;
258 		qi->i = q->i / -m;
259 		qi->j = q->j / -m;
260 		qi->k = q->k / -m;
261 	}
262 
263 	return rc;
264 }
265 
zsl_quat_inv_d(struct zsl_quat * q)266 int zsl_quat_inv_d(struct zsl_quat *q)
267 {
268 	return zsl_quat_inv(q, q);
269 }
270 
zsl_quat_diff(struct zsl_quat * qa,struct zsl_quat * qb,struct zsl_quat * qd)271 int zsl_quat_diff(struct zsl_quat *qa, struct zsl_quat *qb,
272 		  struct zsl_quat *qd)
273 {
274 	int rc;
275 	struct zsl_quat qi;
276 
277 	rc = zsl_quat_inv(qa, &qi);
278 	if (rc) {
279 		goto err;
280 	}
281 
282 	/* Note: order matters here!*/
283 	rc = zsl_quat_mult(&qi, qb, qd);
284 
285 err:
286 	return rc;
287 }
288 
zsl_quat_rot(struct zsl_quat * qa,struct zsl_quat * qb,struct zsl_quat * qr)289 int zsl_quat_rot(struct zsl_quat *qa, struct zsl_quat *qb, struct zsl_quat *qr)
290 {
291 	int rc = 0;
292 
293 #if CONFIG_ZSL_BOUNDS_CHECKS
294 	if (ZSL_ABS(qb->r) > 1E-6) {
295 		rc = -EINVAL;
296 		goto err;
297 	}
298 #endif
299 
300 	struct zsl_quat qm;
301 	struct zsl_quat qn;
302 	struct zsl_quat qi;
303 
304 	zsl_quat_to_unit(qa, &qn);
305 	zsl_quat_mult(&qn, qb, &qm);
306 	zsl_quat_inv(&qn, &qi);
307 	zsl_quat_mult(&qm, &qi, qr);
308 
309 #if CONFIG_ZSL_BOUNDS_CHECKS
310 err:
311 #endif
312 	return rc;
313 }
314 
zsl_quat_lerp(struct zsl_quat * qa,struct zsl_quat * qb,zsl_real_t t,struct zsl_quat * qi)315 int zsl_quat_lerp(struct zsl_quat *qa, struct zsl_quat *qb,
316 		  zsl_real_t t, struct zsl_quat *qi)
317 {
318 	int rc = 0;
319 
320 #if CONFIG_ZSL_BOUNDS_CHECKS
321 	/* Make sure t is between 0 and 1 (included). */
322 	if (t < 0.0 || t > 1.0) {
323 		rc = -EINVAL;
324 		goto err;
325 	}
326 #endif
327 
328 	struct zsl_quat q1, q2;
329 
330 	/* Turn input quaternions into unit quaternions. */
331 	struct zsl_quat qa_u;
332 	struct zsl_quat qb_u;
333 	zsl_quat_to_unit(qa, &qa_u);
334 	zsl_quat_to_unit(qb, &qb_u);
335 
336 	/* Calculate intermediate quats. */
337 	zsl_quat_scale(&qa_u, 1.0 - t, &q1);
338 	zsl_quat_scale(&qb_u, t, &q2);
339 
340 	/* Final result = q1 + q2. */
341 	qi->r = q1.r + q2.r;
342 	qi->i = q1.i + q2.i;
343 	qi->j = q1.j + q2.j;
344 	qi->k = q1.k + q2.k;
345 
346 	/* Normalize output quaternion. */
347 	zsl_quat_to_unit_d(qi);
348 
349 #if CONFIG_ZSL_BOUNDS_CHECKS
350 err:
351 #endif
352 	return rc;
353 }
354 
zsl_quat_slerp(struct zsl_quat * qa,struct zsl_quat * qb,zsl_real_t t,struct zsl_quat * qi)355 int zsl_quat_slerp(struct zsl_quat *qa, struct zsl_quat *qb,
356 		   zsl_real_t t, struct zsl_quat *qi)
357 {
358 	int rc = 0;
359 
360 #if CONFIG_ZSL_BOUNDS_CHECKS
361 	/* Make sure t is between 0 and 1 (included). */
362 	if (t < 0.0 || t > 1.0) {
363 		rc = -EINVAL;
364 		goto err;
365 	}
366 #endif
367 
368 	struct zsl_quat q1, q2; /* Interim quats. */
369 	zsl_real_t dot;         /* Dot product bewteen qa and qb. */
370 	zsl_real_t phi;         /* arccos(dot). */
371 	zsl_real_t phi_s;       /* sin(phi). */
372 	zsl_real_t phi_st;      /* sin(phi * (t)). */
373 	zsl_real_t phi_smt;     /* sin(phi * (1.0 - t)). */
374 
375 	/*
376 	 * Unit quaternion slerp = qa * (qa^-1 * qb)^t
377 	 *
378 	 * We get there in a round-about way in this code, but we avoid pushing
379 	 * and popping values on the stack with trivial calls to helper functions.
380 	 */
381 
382 	/* Turn input quaternions into unit quaternions. */
383 	struct zsl_quat qa_u;
384 	struct zsl_quat qb_u;
385 	zsl_quat_to_unit(qa, &qa_u);
386 	zsl_quat_to_unit(qb, &qb_u);
387 
388 	/* When t = 0.0 or t = 1.0, just memcpy qa or qb. */
389 	if (t == 0.0) {
390 		qi->r = qa_u.r;
391 		qi->i = qa_u.i;
392 		qi->j = qa_u.j;
393 		qi->k = qa_u.k;
394 		goto err;
395 	} else if (t == 1.0) {
396 		qi->r = qb_u.r;
397 		qi->i = qb_u.i;
398 		qi->j = qb_u.j;
399 		qi->k = qb_u.k;
400 		goto err;
401 	}
402 
403 	/* Compute the dot product of the two normalized input quaternions. */
404 	dot = qa_u.r * qb_u.r + qa_u.i * qb_u.i + qa_u.j * qb_u.j + qa_u.k * qb_u.k;
405 
406 	/* The value dot is always between -1 and 1. If dot = 1.0, qa = qb and there
407 	 * is no interpolation. */
408 	if (ZSL_ABS(dot - 1.0) < 1E-6) {
409 		qi->r = qa_u.r;
410 		qi->i = qa_u.i;
411 		qi->j = qa_u.j;
412 		qi->k = qa_u.k;
413 		goto err;
414 	}
415 
416 	/* If dot = -1, then qa = - qb and the interpolation is invald. */
417 	if (ZSL_ABS(dot + 1.0) < 1E-6) {
418 		rc = -EINVAL;
419 		goto err;
420 	}
421 
422 	/*
423 	 * Slerp often has problems with angles close to zero. Consider handling
424 	 * those edge cases slightly differently?
425 	 */
426 
427 	/* Calculate these once before-hand. */
428 	phi = ZSL_ACOS(dot);
429 	phi_s = ZSL_SIN(phi);
430 	phi_st = ZSL_SIN(phi * t);
431 	phi_smt = ZSL_SIN(phi * (1.0 - t));
432 
433 	/* Calculate intermediate quats. */
434 	zsl_quat_scale(&qa_u, phi_smt / phi_s, &q1);
435 	zsl_quat_scale(&qb_u, phi_st / phi_s, &q2);
436 
437 	/* Final result = q1 + q2. */
438 	qi->r = q1.r + q2.r;
439 	qi->i = q1.i + q2.i;
440 	qi->j = q1.j + q2.j;
441 	qi->k = q1.k + q2.k;
442 
443 err:
444 	return rc;
445 }
446 
zsl_quat_from_ang_vel(struct zsl_vec * w,struct zsl_quat * qin,zsl_real_t t,struct zsl_quat * qout)447 int zsl_quat_from_ang_vel(struct zsl_vec *w, struct zsl_quat *qin,
448 			  zsl_real_t t, struct zsl_quat *qout)
449 {
450 	int rc = 0;
451 
452 #if CONFIG_ZSL_BOUNDS_CHECKS
453 	/* Make sure time is positive or zero and the angular velocity is a
454 	 * tridimensional vector. */
455 	if (w->sz != 3 || t < 0.0) {
456 		rc = -EINVAL;
457 		goto err;
458 	}
459 #endif
460 
461 	struct zsl_quat qin2;
462 	struct zsl_quat qout2;
463 	struct zsl_quat wq;
464 	struct zsl_quat wquat = {
465 		.r = 0.0,
466 		.i = w->data[0],
467 		.j = w->data[1],
468 		.k = w->data[2]
469 	};
470 
471 	zsl_quat_to_unit(qin, &qin2);
472 	zsl_quat_mult(&wquat, &qin2, &wq);
473 	zsl_quat_scale_d(&wq, 0.5 * t);
474 	qout2.r = qin2.r + wq.r;
475 	qout2.i = qin2.i + wq.i;
476 	qout2.j = qin2.j + wq.j;
477 	qout2.k = qin2.k + wq.k;
478 
479 	zsl_quat_to_unit(&qout2, qout);
480 
481 #if CONFIG_ZSL_BOUNDS_CHECKS
482 err:
483 #endif
484 	return rc;
485 }
486 
zsl_quat_from_ang_mom(struct zsl_vec * l,struct zsl_quat * qin,zsl_real_t * i,zsl_real_t t,struct zsl_quat * qout)487 int zsl_quat_from_ang_mom(struct zsl_vec *l, struct zsl_quat *qin,
488 			  zsl_real_t *i, zsl_real_t t, struct zsl_quat *qout)
489 {
490 	int rc = 0;
491 
492 #if CONFIG_ZSL_BOUNDS_CHECKS
493 	/* Make sure time is positive or zero and the angular velocity is a
494 	 * tridimensional vector. Inertia can't be negative or zero. */
495 	if (l->sz != 3 || t < 0.0 || *i <= 0.0) {
496 		rc = -EINVAL;
497 		goto err;
498 	}
499 #endif
500 
501 	ZSL_VECTOR_DEF(w, 3);
502 	zsl_vec_copy(&w, l);
503 	zsl_vec_scalar_div(&w, *i);
504 	zsl_quat_from_ang_vel(&w, qin, t, qout);
505 
506 #if CONFIG_ZSL_BOUNDS_CHECKS
507 err:
508 #endif
509 	return rc;
510 }
511 
zsl_quat_to_euler(struct zsl_quat * q,struct zsl_euler * e)512 int zsl_quat_to_euler(struct zsl_quat *q, struct zsl_euler *e)
513 {
514 	int rc = 0;
515 	struct zsl_quat qn;
516 
517 	zsl_quat_to_unit(q, &qn);
518 	zsl_real_t gl = qn.i * qn.k + qn.j * qn.r;
519 	zsl_real_t v = 2. * gl;
520 
521 	if (v > 1.0) {
522 		v = 1.0;
523 	} else if (v < -1.0) {
524 		v = -1.0;
525 	}
526 
527 	e->y = ZSL_ASIN(v);
528 
529 	/* Gimbal lock case. */
530 	if (ZSL_ABS(gl - 0.5) < 1E-6 || ZSL_ABS(gl + 0.5) < 1E-6) {
531 		e->x = ZSL_ATAN2(2.0 * (qn.j * qn.k + qn.i * qn.r),
532 				 1.0 - 2.0 * (qn.i * qn.i + qn.k * qn.k));
533 		e->z = 0.0;
534 		return rc;
535 	}
536 
537 	e->x = ZSL_ATAN2(2.0 * (qn.i * qn.r - qn.j * qn.k),
538 			 1.0 - 2.0 * (qn.i * qn.i + qn.j * qn.j));
539 	e->z = ZSL_ATAN2(2.0 * (qn.k * qn.r - qn.i * qn.j),
540 			 1.0 - 2.0 * (qn.j * qn.j + qn.k * qn.k));
541 
542 	return rc;
543 }
544 
zsl_quat_from_euler(struct zsl_euler * e,struct zsl_quat * q)545 int zsl_quat_from_euler(struct zsl_euler *e, struct zsl_quat *q)
546 {
547 	int rc = 0;
548 
549 	zsl_real_t roll_c = ZSL_COS(e->x * 0.5);
550 	zsl_real_t roll_s = ZSL_SIN(e->x * 0.5);
551 	zsl_real_t pitch_c = ZSL_COS(e->y * 0.5);
552 	zsl_real_t pitch_s = ZSL_SIN(e->y * 0.5);
553 	zsl_real_t yaw_c = ZSL_COS(e->z * 0.5);
554 	zsl_real_t yaw_s = ZSL_SIN(e->z * 0.5);
555 
556 	q->r = roll_c * pitch_c * yaw_c - roll_s * pitch_s * yaw_s;
557 	q->i = roll_s * pitch_c * yaw_c + roll_c * pitch_s * yaw_s;
558 	q->j = roll_c * pitch_s * yaw_c - roll_s * pitch_c * yaw_s;
559 	q->k = roll_c * pitch_c * yaw_s + roll_s * pitch_s * yaw_c;
560 
561 	return rc;
562 }
563 
zsl_quat_to_rot_mtx(struct zsl_quat * q,struct zsl_mtx * m)564 int zsl_quat_to_rot_mtx(struct zsl_quat *q, struct zsl_mtx *m)
565 {
566 	int rc = 0;
567 
568 #if CONFIG_ZSL_BOUNDS_CHECKS
569 	/* Make sure that the rotation matrix has an appropriate shape and size. */
570 	if ((m->sz_cols != 3) || (m->sz_rows != 3)) {
571 		rc = -EINVAL;
572 		goto err;
573 	}
574 #endif
575 
576 	/* Note: This can be optimised by pre-calculating shared values. */
577 
578 	/* Row 0. */
579 	zsl_mtx_set(m, 0, 0, 1.0 - 2.0 * (q->j * q->j + q->k * q->k));
580 	zsl_mtx_set(m, 0, 1, 2.0 * (q->i * q->j - q->k * q->r));
581 	zsl_mtx_set(m, 0, 2, 2.0 * (q->i * q->k + q->j * q->r));
582 
583 	/* Row 1. */
584 	zsl_mtx_set(m, 1, 0, 2.0 * (q->i * q->j + q->k * q->r));
585 	zsl_mtx_set(m, 1, 1, 1.0 - 2.0 * (q->i * q->i + q->k * q->k));
586 	zsl_mtx_set(m, 1, 2, 2.0 * (q->j * q->k - q->i * q->r));
587 
588 	/* Row 2. */
589 	zsl_mtx_set(m, 2, 0, 2.0 * (q->i * q->k - q->j * q->r));
590 	zsl_mtx_set(m, 2, 1, 2.0 * (q->j * q->k + q->i * q->r));
591 	zsl_mtx_set(m, 2, 2, 1.0 - 2.0 * (q->i * q->i + q->j * q->j));
592 
593 #if CONFIG_ZSL_BOUNDS_CHECKS
594 err:
595 #endif
596 	return rc;
597 }
598 
zsl_quat_from_rot_mtx(struct zsl_mtx * m,struct zsl_quat * q)599 int zsl_quat_from_rot_mtx(struct zsl_mtx *m, struct zsl_quat *q)
600 {
601 	int rc = 0;
602 
603 #if CONFIG_ZSL_BOUNDS_CHECKS
604 	/* Make sure that the rotation matrix has an appropriate shape and size. */
605 	if ((m->sz_cols != 3) || (m->sz_rows != 3)) {
606 		rc = -EINVAL;
607 		goto err;
608 	}
609 #endif
610 
611 	/* Convert rotation matrix to unit quaternion. */
612 	q->r = 0.5 * ZSL_SQRT(m->data[0] + m->data[4] + m->data[8] + 1.0);
613 	q->i = 0.5 * ZSL_SQRT(m->data[0] - m->data[4] - m->data[8] + 1.0);
614 	q->j = 0.5 * ZSL_SQRT(-m->data[0] + m->data[4] - m->data[8] + 1.0);
615 	q->k = 0.5 * ZSL_SQRT(-m->data[0] - m->data[4] + m->data[8] + 1.0);
616 
617 	if (ZSL_ABS(m->data[7] - m->data[5]) > 1E-6) {
618 		/* Multiply by the sign of m21 - m12. */
619 		q->i *= (m->data[7] - m->data[5]) / ZSL_ABS(m->data[7] - m->data[5]);
620 	}
621 
622 	if (ZSL_ABS(m->data[2] - m->data[6]) > 1E-6) {
623 		/* Multiply by the sign of m02 - m20. */
624 		q->j *= (m->data[2] - m->data[6]) / ZSL_ABS(m->data[2] - m->data[6]);
625 	}
626 
627 	if (ZSL_ABS(m->data[3] - m->data[1]) > 1E-6) {
628 		/* Multiply by the sign of m10 - m01. */
629 		q->k *= (m->data[3] - m->data[1]) / ZSL_ABS(m->data[3] - m->data[1]);
630 	}
631 
632 #if CONFIG_ZSL_BOUNDS_CHECKS
633 err:
634 #endif
635 	return rc;
636 }
637 
zsl_quat_to_axis_angle(struct zsl_quat * q,struct zsl_vec * a,zsl_real_t * b)638 int zsl_quat_to_axis_angle(struct zsl_quat *q, struct zsl_vec *a,
639 			   zsl_real_t *b)
640 {
641 	int rc = 0;
642 
643 #if CONFIG_ZSL_BOUNDS_CHECKS
644 	/* Make sure that the axis vector is size 3. */
645 	if (a->sz != 3) {
646 		rc = -EINVAL;
647 		goto err;
648 	}
649 #endif
650 
651 	struct zsl_quat qn;
652 	zsl_quat_to_unit(q, &qn);
653 
654 	if (ZSL_ABS(qn.r - 1.0) < 1E-6) {
655 		a->data[0] = 0.0;
656 		a->data[1] = 0.0;
657 		a->data[2] = 0.0;
658 		*b = 0.0;
659 		return 0;
660 	}
661 
662 	zsl_real_t s = ZSL_SQRT(1.0 - (qn.r * qn.r));
663 	*b = 2.0 * ZSL_ACOS(qn.r);
664 	a->data[0] = qn.i / s;
665 	a->data[1] = qn.j / s;
666 	a->data[2] = qn.k / s;
667 
668 #if CONFIG_ZSL_BOUNDS_CHECKS
669 err:
670 #endif
671 	return rc;
672 }
673 
zsl_quat_from_axis_angle(struct zsl_vec * a,zsl_real_t * b,struct zsl_quat * q)674 int zsl_quat_from_axis_angle(struct zsl_vec *a, zsl_real_t *b,
675 			     struct zsl_quat *q)
676 {
677 	int rc = 0;
678 
679 #if CONFIG_ZSL_BOUNDS_CHECKS
680 	/* Make sure that the axis vector is size 3. */
681 	if (a->sz != 3) {
682 		rc = -EINVAL;
683 		goto err;
684 	}
685 #endif
686 
687 	zsl_real_t norm = ZSL_SQRT(a->data[0] * a->data[0] +
688 				   a->data[1] * a->data[1] +
689 				   a->data[2] * a->data[2]);
690 
691 	if (norm < 1E-6) {
692 		q->r = 0.0;
693 		q->i = 0.0;
694 		q->j = 0.0;
695 		q->k = 0.0;
696 		return 0;
697 	}
698 
699 	ZSL_VECTOR_DEF(an, 3);
700 	zsl_vec_copy(&an, a);
701 	zsl_vec_scalar_div(&an, norm);
702 
703 	q->r = ZSL_COS(*b / 2.0);
704 	q->i = an.data[0] * ZSL_SIN(*b / 2.0);
705 	q->j = an.data[1] * ZSL_SIN(*b / 2.0);
706 	q->k = an.data[2] * ZSL_SIN(*b / 2.0);
707 
708 #if CONFIG_ZSL_BOUNDS_CHECKS
709 err:
710 #endif
711 	return rc;
712 }
713 
zsl_quat_print(struct zsl_quat * q)714 int zsl_quat_print(struct zsl_quat *q)
715 {
716 	printf("%.16f + %.16f i + %.16f j + %.16f k\n", q->r, q->i, q->j, q->k);
717 
718 	return 0;
719 }
720