| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "na64util/numerical/spatialRotations.h" | ||
| 2 | |||
| 3 | #include <math.h> | ||
| 4 | #include <string.h> | ||
| 5 | #include <assert.h> | ||
| 6 | |||
| 7 | #ifdef STANDALONE_BUILD | ||
| 8 | # include <stdio.h> | ||
| 9 | #endif | ||
| 10 | |||
| 11 | /* Reference: https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix */ | ||
| 12 | |||
| 13 | static const struct { | ||
| 14 | char ext[3], intr[3]; | ||
| 15 | } _gStrOrder[] = { | ||
| 16 | { "XZX", "xzx" }, { "XYX", "xyx" }, { "YXY", "yxy" }, | ||
| 17 | { "YZY", "yzy" }, { "ZYZ", "zyz" }, { "ZXZ", "zxz" }, | ||
| 18 | { "XZY", "yzx" }, { "XYZ", "zyx" }, { "YXZ", "zxy" }, | ||
| 19 | { "YZX", "xzy" }, { "ZYX", "xyz" }, { "ZXY", "yxz" }, | ||
| 20 | }; | ||
| 21 | |||
| 22 | int | ||
| 23 | ✗ | na64sw_rotation_order_from_str( const char * str | |
| 24 | , enum na64sw_RotationOrder * dest ) { | ||
| 25 | ✗ | for(int i = 0; i < sizeof(_gStrOrder)/sizeof(*_gStrOrder); ++i) { | |
| 26 | ✗ | if( strncmp(str, _gStrOrder[i].ext, 3) | |
| 27 | ✗ | && strncmp(str, _gStrOrder[i].intr, 3) ) continue; | |
| 28 | ✗ | *dest = (enum na64sw_RotationOrder) i; | |
| 29 | ✗ | return 0; | |
| 30 | } | ||
| 31 | ✗ | return 1; | |
| 32 | } | ||
| 33 | |||
| 34 | /* | ||
| 35 | * Euler rotation matrices | ||
| 36 | */ | ||
| 37 | #define _M_Eul_X1_Z2_X3 \ | ||
| 38 | c2, -c3*s2, s2*s3, \ | ||
| 39 | c1*s2, c1*c2*c3 - s1*s3, -c3*s1 - c1*c2*s3, \ | ||
| 40 | s1*s2, c1*s3 + c2*c3*s1, c1*c3 - c2*s1*s3 | ||
| 41 | #define _M_Rev_X1_Z2_X3 \ | ||
| 42 | a[0] = atan2(R[2*3+0], R[1*3+0]); \ | ||
| 43 | a[1] = acos(R[0*3+0]); \ | ||
| 44 | a[2] = atan2(R[0*3+2], -R[0*3+1]); | ||
| 45 | |||
| 46 | #define _M_Eul_X1_Y2_X3 \ | ||
| 47 | c2, s2*s3, c3*s2, \ | ||
| 48 | s1*s2, c1*c3-c2*s1*s3, -c1*s3-c2*c3*s1, \ | ||
| 49 | -c1*s2, c3*s1+c1*c2*s3, c1*c2*c3-s1*s3 | ||
| 50 | #define _M_Rev_X1_Y2_X3 \ | ||
| 51 | a[0] = atan2(R[1*3+0], -R[2*3+0]); \ | ||
| 52 | a[1] = acos(R[0*3+0]); \ | ||
| 53 | a[2] = atan2(R[0*3+1], R[0*3+2]); | ||
| 54 | |||
| 55 | #define _M_Eul_Y1_X2_Y3 \ | ||
| 56 | c1*c3 - c2*s1*s3, s1*s2, c1*s3 + c2*c3*s1, \ | ||
| 57 | s2*s3, c2, -c3*s2, \ | ||
| 58 | -c3*s1 - c1*c2*s3, c1*s2, c1*c2*c3 - s1*s3 | ||
| 59 | #define _M_Rev_Y1_X2_Y3 \ | ||
| 60 | a[0] = atan2(R[0*3+1], R[2*3+1]); \ | ||
| 61 | a[1] = acos(R[1*3+1]); \ | ||
| 62 | a[2] = atan2(R[1*3+0], -R[1*3+2]); | ||
| 63 | |||
| 64 | #define _M_Eul_Y1_Z2_Y3 \ | ||
| 65 | c1*c2*c3 - s1*s3, -c1*s2, c3*s1 + c1*c2*s3, \ | ||
| 66 | c3*s2, c2, s2*s3, \ | ||
| 67 | -c1*s3 - c2*c3*s1, s1*s2, c1*c3 - c2*s1*s3 | ||
| 68 | #define _M_Rev_Y1_Z2_Y3 \ | ||
| 69 | a[0] = atan2(R[2*3+1], -R[0*3+1]); \ | ||
| 70 | a[1] = acos(R[1*3+1]); \ | ||
| 71 | a[2] = atan2(R[1*3+2], R[1*3+0]); | ||
| 72 | |||
| 73 | #define _M_Eul_Z1_Y2_Z3 \ | ||
| 74 | c1*c2*c3 - s1*s3, -c3*s1 - c1*c2*s3, c1*s2, \ | ||
| 75 | c1*s3 + c2*c3*s1, c1*c3 - c2*s1*s3, s1*s2, \ | ||
| 76 | -c3*s2, s2*s3, c2 | ||
| 77 | #define _M_Rev_Z1_Y2_Z3 \ | ||
| 78 | a[0] = atan2(R[1*3+2], R[0*3+2]); \ | ||
| 79 | a[1] = atan2(sqrt(1 - R[2*3+2]*R[2*3+2]), R[2*3+2]); \ | ||
| 80 | a[2] = atan2(R[2*3+1], -R[2*3+0]); | ||
| 81 | |||
| 82 | #define _M_Eul_Z1_X2_Z3 \ | ||
| 83 | c1*c3 - c2*s1*s3, -c1*s3 - c2*c3*s1, s1*s2, \ | ||
| 84 | c3*s1 + c1*c2*s3, c1*c2*c3 - s1*s3, -c1*s2, \ | ||
| 85 | s2*s3, c3*s2, c2 | ||
| 86 | #define _M_Rev_Z1_X2_Z3 \ | ||
| 87 | a[0] = atan2(R[0*3+2], -R[1*3+2]); \ | ||
| 88 | a[1] = acos(R[2*3+2]); \ | ||
| 89 | a[2] = atan2(R[2*3+0], R[2*3+1]); | ||
| 90 | |||
| 91 | /* | ||
| 92 | * Tait-Bryan rotation matrices | ||
| 93 | */ | ||
| 94 | #define _M_TBr_X1_Z2_Y3 \ | ||
| 95 | c2*c3, -s2, c2*s3, \ | ||
| 96 | s1*s3 + c1*c3*s2, c1*c2, c1*s2*s3-c3*s1, \ | ||
| 97 | c3*s1*s2 - c1*s3, c2*s1, c1*c3+s1*s2*s3 | ||
| 98 | #define _M_Rev_X1_Z2_Y3 \ | ||
| 99 | a[0] = atan2(R[2*3+1], R[1*3+1]); \ | ||
| 100 | a[1] = asin(-R[0*3+1]); \ | ||
| 101 | a[2] = atan2(R[0*3+2], R[0*3+0]); | ||
| 102 | |||
| 103 | #define _M_TBr_X1_Y2_Z3 \ | ||
| 104 | c2*c3, -c2*s3, s2, \ | ||
| 105 | c1*s3 + c3*s1*s2, c1*c3 - s1*s2*s3, -c2*s1, \ | ||
| 106 | s1*s3 - c1*c3*s2, c3*s1 + c1*s2*s3, c1*c2 | ||
| 107 | #define _M_Rev_X1_Y2_Z3 \ | ||
| 108 | a[0] = atan2(-R[1*3+2], R[2*3+2]); \ | ||
| 109 | a[1] = asin(R[0*3+2]); \ | ||
| 110 | a[2] = atan2(-R[0*3+1], R[0*3+0]); | ||
| 111 | |||
| 112 | #define _M_TBr_Y1_X2_Z3 \ | ||
| 113 | c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3, c2*s1, \ | ||
| 114 | c2*s3, c2*c3, -s2, \ | ||
| 115 | c1*s2*s3 - c3*s1, c1*c3*s2 + s1*s3, c1*c2 | ||
| 116 | #define _M_Rev_Y1_X2_Z3 \ | ||
| 117 | a[0] = atan2(R[0*3+2], R[2*3+2]); \ | ||
| 118 | a[1] = asin(-R[1*3+2]); \ | ||
| 119 | a[2] = atan2(R[1*3+0], R[1*3+1]); | ||
| 120 | |||
| 121 | #define _M_TBr_Y1_Z2_X3 \ | ||
| 122 | c1*c2, s1*s3 - c1*c3*s2, c3*s1 + c1*s2*s3, \ | ||
| 123 | s2, c2*c3, -c2*s3, \ | ||
| 124 | -c2*s1, c1*s3 + c3*s1*s2, c1*c3 - s1*s2*s3 | ||
| 125 | #define _M_Rev_Y1_Z2_X3 \ | ||
| 126 | a[0] = atan2(-R[2*3+0], R[0*3+0]); \ | ||
| 127 | a[1] = asin(R[1*3+0]); \ | ||
| 128 | a[2] = atan2(-R[1*3+2], R[1*3+1]); | ||
| 129 | |||
| 130 | #define _M_TBr_Z1_Y2_X3 \ | ||
| 131 | c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2, \ | ||
| 132 | c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3, \ | ||
| 133 | -s2, c2*s3, c2*c3 | ||
| 134 | #define _M_Rev_Z1_Y2_X3 \ | ||
| 135 | a[0] = atan2(R[1*3+0], R[0*3+0]); \ | ||
| 136 | a[1] = asin(-R[2*3+0]); \ | ||
| 137 | a[2] = atan2(R[2*3+1], R[2*3+2]); | ||
| 138 | |||
| 139 | #define _M_TBr_Z1_X2_Y3 \ | ||
| 140 | c1*c3 - s1*s2*s3, -c2*s1, c1*s3 + c3*s1*s2, \ | ||
| 141 | c3*s1 + c1*s2*s3, c1*c2, s1*s3 - c1*c3*s2, \ | ||
| 142 | -c2*s3, s2, c2*c3 | ||
| 143 | #define _M_Rev_Z1_X2_Y3 \ | ||
| 144 | a[0] = atan2(-R[0*3+1], R[1*3+1]); \ | ||
| 145 | a[1] = asin(R[2*3+1]); \ | ||
| 146 | a[2] = atan2(-R[2*3+0], R[2*3+2]); | ||
| 147 | |||
| 148 | /* | ||
| 149 | * Implementation | ||
| 150 | */ | ||
| 151 | |||
| 152 | #define _M_implem( NAME_SUFFIX, FLOAT, BODY1, BODY2 ) \ | ||
| 153 | static void _mx_ ## NAME_SUFFIX (FLOAT * dest, const FLOAT * a) { \ | ||
| 154 | const FLOAT s1 = sin(a[0]), c1 = cos(a[0]) \ | ||
| 155 | , s2 = sin(a[1]), c2 = cos(a[1]) \ | ||
| 156 | , s3 = sin(a[2]), c3 = cos(a[2]) \ | ||
| 157 | ; \ | ||
| 158 | const FLOAT m[] = { BODY1 }; \ | ||
| 159 | memcpy(dest, m, sizeof(m)); \ | ||
| 160 | } \ | ||
| 161 | static void _angles_ ## NAME_SUFFIX (FLOAT * a, const FLOAT * R) { \ | ||
| 162 | BODY2 ; \ | ||
| 163 | } | ||
| 164 | |||
| 165 | /* Euler */ | ||
| 166 | ✗ | _M_implem(xzx_f, float, _M_Eul_X1_Z2_X3, _M_Rev_X1_Z2_X3); | |
| 167 | ✗ | _M_implem(xyx_f, float, _M_Eul_X1_Y2_X3, _M_Rev_X1_Y2_X3); | |
| 168 | ✗ | _M_implem(yxy_f, float, _M_Eul_Y1_X2_Y3, _M_Rev_Y1_X2_Y3); | |
| 169 | ✗ | _M_implem(yzy_f, float, _M_Eul_Y1_Z2_Y3, _M_Rev_Y1_Z2_Y3); | |
| 170 | ✗ | _M_implem(zyz_f, float, _M_Eul_Z1_Y2_Z3, _M_Rev_Z1_Y2_Z3); | |
| 171 | ✗ | _M_implem(zxz_f, float, _M_Eul_Z1_X2_Z3, _M_Rev_Z1_X2_Z3); | |
| 172 | /* Tait-Bryan */ | ||
| 173 | ✗ | _M_implem(xzy_f, float, _M_TBr_X1_Z2_Y3, _M_Rev_X1_Z2_Y3); | |
| 174 | 2 | _M_implem(xyz_f, float, _M_TBr_X1_Y2_Z3, _M_Rev_X1_Y2_Z3); | |
| 175 | ✗ | _M_implem(yxz_f, float, _M_TBr_Y1_X2_Z3, _M_Rev_Y1_X2_Z3); | |
| 176 | ✗ | _M_implem(yzx_f, float, _M_TBr_Y1_Z2_X3, _M_Rev_Y1_Z2_X3); | |
| 177 | 10 | _M_implem(zyx_f, float, _M_TBr_Z1_Y2_X3, _M_Rev_Z1_Y2_X3); | |
| 178 | ✗ | _M_implem(zxy_f, float, _M_TBr_Z1_X2_Y3, _M_Rev_Z1_X2_Y3); | |
| 179 | |||
| 180 | #define x (0x1) | ||
| 181 | #define y (0x2) | ||
| 182 | #define z (0x3) | ||
| 183 | #define _M_encode_seq( first, second, third ) \ | ||
| 184 | (first) | (second << 2) | (third << 4) | ||
| 185 | |||
| 186 | static struct { | ||
| 187 | void (*implem)(float *, const float *); | ||
| 188 | void (*rev)(float *, const float *); | ||
| 189 | } _float_matrices[] = { | ||
| 190 | #define _M_entry(first, second, third) \ | ||
| 191 | { _mx_ ## first ## second ## third ## _f \ | ||
| 192 | , _angles_ ## first ## second ## third ## _f }, | ||
| 193 | _M_entry( x, z, x ) _M_entry( x, y, x ) | ||
| 194 | _M_entry( y, x, y ) _M_entry( y, z, y ) | ||
| 195 | _M_entry( z, y, z ) _M_entry( z, x, z ) | ||
| 196 | |||
| 197 | _M_entry( x, z, y ) _M_entry( x, y, z ) | ||
| 198 | _M_entry( y, x, z ) _M_entry( y, z, x ) | ||
| 199 | _M_entry( z, y, x ) _M_entry( z, x, y ) | ||
| 200 | #undef _M_entry | ||
| 201 | }; | ||
| 202 | |||
| 203 | /* Euler */ | ||
| 204 | ✗ | _M_implem(xzx_d, double, _M_Eul_X1_Z2_X3, _M_Rev_X1_Z2_X3); | |
| 205 | ✗ | _M_implem(xyx_d, double, _M_Eul_X1_Y2_X3, _M_Rev_X1_Y2_X3); | |
| 206 | ✗ | _M_implem(yxy_d, double, _M_Eul_Y1_X2_Y3, _M_Rev_Y1_X2_Y3); | |
| 207 | ✗ | _M_implem(yzy_d, double, _M_Eul_Y1_Z2_Y3, _M_Rev_Y1_Z2_Y3); | |
| 208 | ✗ | _M_implem(zyz_d, double, _M_Eul_Z1_Y2_Z3, _M_Rev_Z1_Y2_Z3); | |
| 209 | ✗ | _M_implem(zxz_d, double, _M_Eul_Z1_X2_Z3, _M_Rev_Z1_X2_Z3); | |
| 210 | /* Tait-Bryan */ | ||
| 211 | ✗ | _M_implem(xzy_d, double, _M_TBr_X1_Z2_Y3, _M_Rev_X1_Z2_Y3); | |
| 212 | ✗ | _M_implem(xyz_d, double, _M_TBr_X1_Y2_Z3, _M_Rev_X1_Y2_Z3); | |
| 213 | ✗ | _M_implem(yxz_d, double, _M_TBr_Y1_X2_Z3, _M_Rev_Y1_X2_Z3); | |
| 214 | ✗ | _M_implem(yzx_d, double, _M_TBr_Y1_Z2_X3, _M_Rev_Y1_Z2_X3); | |
| 215 | ✗ | _M_implem(zyx_d, double, _M_TBr_Z1_Y2_X3, _M_Rev_Z1_Y2_X3); | |
| 216 | ✗ | _M_implem(zxy_d, double, _M_TBr_Z1_X2_Y3, _M_Rev_Z1_X2_Y3); | |
| 217 | |||
| 218 | static struct { | ||
| 219 | void (*implem)(double *, const double *); | ||
| 220 | void (*rev)(double *, const double *); | ||
| 221 | } _double_matrices[] = { | ||
| 222 | #define _M_entry(first, second, third) \ | ||
| 223 | { _mx_ ## first ## second ## third ## _d \ | ||
| 224 | , _angles_ ## first ## second ## third ## _d }, | ||
| 225 | _M_entry( x, z, x ) _M_entry( x, y, x ) | ||
| 226 | _M_entry( y, x, y ) _M_entry( y, z, y ) | ||
| 227 | _M_entry( z, y, z ) _M_entry( z, x, z ) | ||
| 228 | |||
| 229 | _M_entry( x, z, y ) _M_entry( x, y, z ) | ||
| 230 | _M_entry( y, x, z ) _M_entry( y, z, x ) | ||
| 231 | _M_entry( z, y, x ) _M_entry( z, x, y ) | ||
| 232 | #undef _M_entry | ||
| 233 | }; | ||
| 234 | |||
| 235 | #define _M_implement_unifunc(FLOAT, SUFFIX) \ | ||
| 236 | int \ | ||
| 237 | na64sw_rotation_matrix_ ## SUFFIX ( enum na64sw_RotationOrder n \ | ||
| 238 | , const FLOAT * angles \ | ||
| 239 | , FLOAT * dest \ | ||
| 240 | ) { \ | ||
| 241 | assert(n < sizeof(_ ## FLOAT ## _matrices) / sizeof(* _ ## FLOAT ## _matrices)); \ | ||
| 242 | _ ## FLOAT ## _matrices[n].implem(dest, angles); \ | ||
| 243 | return 0; \ | ||
| 244 | } \ | ||
| 245 | int \ | ||
| 246 | na64sw_find_rotation_for_ ## SUFFIX ( enum na64sw_RotationOrder n \ | ||
| 247 | , const FLOAT * mx \ | ||
| 248 | , FLOAT * dest \ | ||
| 249 | ) { \ | ||
| 250 | assert(n < sizeof(_ ## FLOAT ## _matrices) / sizeof(* _ ## FLOAT ## _matrices)); \ | ||
| 251 | _ ## FLOAT ## _matrices[n].rev(dest, mx); \ | ||
| 252 | return 0; \ | ||
| 253 | } \ | ||
| 254 | |||
| 255 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
12 | _M_implement_unifunc( float, f ); |
| 256 | ✗ | _M_implement_unifunc( double, d ); | |
| 257 | |||
| 258 | #ifdef STANDALONE_BUILD | ||
| 259 | int | ||
| 260 | main(int argc, char * argv[]) { | ||
| 261 | float m[9] | ||
| 262 | , angles[3] = {2*M_PI/6, 3*M_PI/7, 4*M_PI/9} | ||
| 263 | , revAngles[3]; | ||
| 264 | |||
| 265 | for(int i = 0; i <= (int) na64sw_Rotation_zxy; ++i ) { | ||
| 266 | const enum na64sw_RotationOrder order | ||
| 267 | = (enum na64sw_RotationOrder) i; | ||
| 268 | na64sw_rotation_matrix_f( order, angles, m ); | ||
| 269 | /*for(int p = 0; p < 3; ++p) { | ||
| 270 | for(int k = 0; k < 3; ++k) { | ||
| 271 | printf( "\t%e", m[p*3 + k] ); | ||
| 272 | } | ||
| 273 | printf("\n"); | ||
| 274 | }*/ | ||
| 275 | na64sw_find_rotation_for_f( order, m, revAngles ); | ||
| 276 | printf( " #%i: {%e, %e, %e} - {%e %e %e}\n" | ||
| 277 | , i | ||
| 278 | , angles[0], angles[1], angles[2] | ||
| 279 | , revAngles[0], revAngles[1], revAngles[2] | ||
| 280 | ); | ||
| 281 | } | ||
| 282 | |||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | #endif /*STANDALONE_BUILD*/ | ||
| 286 | |||
| 287 |