Switch from GPLv2 to GPLv2+
[fw/altos] / src / test / ao_quaternion_test.c
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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
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.
13  *
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.
17  */
18
19 #define _GNU_SOURCE
20
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <getopt.h>
27 #include <math.h>
28
29 #include "ao_quaternion.h"
30
31 #if 0
32 static void
33 print_q(char *name, struct ao_quaternion *q)
34 {
35         printf ("%8.8s: r%8.5f x%8.5f y%8.5f z%8.5f ", name,
36                 q->r, q->x, q->y, q->z);
37 }
38 #endif
39
40 #define STEPS   16
41
42 #define DEG     (1.0f * 3.1415926535f / 180.0f)
43
44 struct ao_rotation {
45         int     steps;
46         float   x, y, z;
47 };
48
49 static struct ao_rotation ao_path[] = {
50         { .steps = 45, .x =  2*DEG, .y = 0, .z = 0 },
51
52         { .steps = 45, .x = 0, .y = 2*DEG, .z = 0 },
53         
54         { .steps = 45, .x = -2*DEG, .y = 0, .z = 0 },
55
56         { .steps = 45, .x = 0, .y = -2*DEG, .z = 0 },
57 };
58
59 #define NUM_PATH        (sizeof ao_path / sizeof ao_path[0])
60
61 static int close(float a, float b) {
62         return fabsf (a - b) < 1e-5;
63 }
64
65 static int check_quaternion(char *where, struct ao_quaternion *got, struct ao_quaternion *expect) {
66         if (!close (got->r, expect->r) ||
67             !close (got->x, expect->x) ||
68             !close (got->y, expect->y) ||
69             !close (got->z, expect->z))
70         {
71                 printf ("%s: got r%8.5f x%8.5f y%8.5f z%8.5f expect r%8.5f x%8.5f y%8.5f z%8.5f\n",
72                         where,
73                         got->r, got->x, got->y, got->z,
74                         expect->r, expect->x, expect->y, expect->z);
75                 return 1;
76         }
77         return 0;
78 }
79
80 int main(int argc, char **argv)
81 {
82         struct ao_quaternion    position;
83         struct ao_quaternion    position_expect;
84         struct ao_quaternion    rotation;
85         struct ao_quaternion    rotated;
86         struct ao_quaternion    little_rotation;
87         int                     i;
88         int                     p;
89         int                     ret = 0;
90
91         /* vector */
92         ao_quaternion_init_vector(&position, 1, 1, 1);
93         ao_quaternion_init_vector(&position_expect, -1, -1, 1);
94
95         /* zero rotation */
96         ao_quaternion_init_zero_rotation(&rotation);
97
98 #define dump() do {                                                     \
99                                                                         \
100                 ao_quaternion_rotate(&rotated, &position, &rotation);   \
101                 print_q("rotated", &rotated);                           \
102                 print_q("rotation", &rotation);                         \
103                 printf ("\n");                                          \
104         } while (0)
105
106 //      dump();
107
108         for (p = 0; p < NUM_PATH; p++) {
109                 ao_quaternion_init_half_euler(&little_rotation,
110                                               ao_path[p].x / 2.0f,
111                                               ao_path[p].y / 2.0f,
112                                               ao_path[p].z / 2.0f);
113 //              printf ("\t\tx: %8.4f, y: %8.4f, z: %8.4f ", ao_path[p].x, ao_path[p].y, ao_path[p].z);
114 //              print_q("step", &little_rotation);
115 //              printf("\n");
116                 for (i = 0; i < ao_path[p].steps; i++) {
117                         ao_quaternion_multiply(&rotation, &little_rotation, &rotation);
118
119                         ao_quaternion_normalize(&rotation, &rotation);
120
121 //                      dump();
122                 }
123         }
124
125         ao_quaternion_rotate(&rotated, &position, &rotation);
126
127         ret += check_quaternion("rotation", &rotated, &position_expect);
128
129         struct ao_quaternion    vertical;
130         struct ao_quaternion    angle;
131         struct ao_quaternion    rot;
132
133         ao_quaternion_init_vector(&vertical, 0, 0, 1);
134         ao_quaternion_init_vector(&angle, 0, 0, 1);
135
136         ao_quaternion_init_half_euler(&rot,
137                                       M_PI * 3.0 / 8.0 , 0, 0);
138
139         ao_quaternion_rotate(&angle, &angle, &rot);
140
141         struct ao_quaternion    rot_compute;
142
143         ao_quaternion_vectors_to_rotation(&rot_compute, &vertical, &angle);
144
145         ret += check_quaternion("vector rotation", &rot_compute, &rot);
146
147         struct ao_quaternion    rotd;
148
149         ao_quaternion_rotate(&rotd, &vertical, &rot_compute);
150
151         ret += check_quaternion("vector rotated", &rotd, &angle);
152
153         return ret;
154 }
155