Welcome to mirror list, hosted at ThFree Co, Russian Federation.

BLI_math_rotation.h « blenlib « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: fef51fa780ee3654734a79358ad4d9e824072dad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
/* SPDX-License-Identifier: GPL-2.0-or-later
 * Copyright 2001-2002 NaN Holding BV. All rights reserved. */

#pragma once

/** \file
 * \ingroup bli
 */

#include "BLI_math_base.h"
#include "BLI_utildefines.h"
#include "DNA_vec_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/* -------------------------------------------------------------------- */
/** \name Conversion Defines
 * \{ */

#define RAD2DEG(_rad) ((_rad) * (180.0 / M_PI))
#define DEG2RAD(_deg) ((_deg) * (M_PI / 180.0))

#define RAD2DEGF(_rad) ((_rad) * (float)(180.0 / M_PI))
#define DEG2RADF(_deg) ((_deg) * (float)(M_PI / 180.0))

/** \} */

/* -------------------------------------------------------------------- */
/** \name Quaternions
 * Stored in (w, x, y, z) order.
 * \{ */

/* Initialize */

/* Convenience, avoids setting Y axis everywhere. */

void unit_axis_angle(float axis[3], float *angle);
void unit_qt(float q[4]);
void copy_qt_qt(float q[4], const float a[4]);

/* Arithmetic. */

void mul_qt_qtqt(float q[4], const float a[4], const float b[4]);
/**
 * \note
 * Assumes a unit quaternion?
 *
 * in fact not, but you may want to use a unit quaternion read on...
 *
 * Shortcut for 'q v q*' when \a v is actually a quaternion.
 * This removes the need for converting a vector to a quaternion,
 * calculating q's conjugate and converting back to a vector.
 * It also happens to be faster (17+,24* vs * 24+,32*).
 * If \a q is not a unit quaternion, then \a v will be both rotated by
 * the same amount as if q was a unit quaternion, and scaled by the square of
 * the length of q.
 *
 * For people used to python mathutils, its like:
 * def mul_qt_v3(q, v): (q * Quaternion((0.0, v[0], v[1], v[2])) * q.conjugated())[1:]
 *
 * \note Multiplying by 3x3 matrix is ~25% faster.
 */
void mul_qt_v3(const float q[4], float r[3]);
/**
 * Simple multiply.
 */
void mul_qt_fl(float q[4], float f);

/**
 * Raise a unit quaternion to the specified power.
 */
void pow_qt_fl_normalized(float q[4], float f);

void sub_qt_qtqt(float q[4], const float a[4], const float b[4]);

void invert_qt(float q[4]);
void invert_qt_qt(float q1[4], const float q2[4]);
/**
 * This is just conjugate_qt for cases we know \a q is unit-length.
 * we could use #conjugate_qt directly, but use this function to show intent,
 * and assert if its ever becomes non-unit-length.
 */
void invert_qt_normalized(float q[4]);
void invert_qt_qt_normalized(float q1[4], const float q2[4]);
void conjugate_qt(float q[4]);
void conjugate_qt_qt(float q1[4], const float q2[4]);
float dot_qtqt(const float a[4], const float b[4]);
float normalize_qt(float q[4]);
float normalize_qt_qt(float r[4], const float q[4]);

/* Comparison. */

bool is_zero_qt(const float q[4]);

/* interpolation */
/**
 * Generic function for implementing slerp
 * (quaternions and spherical vector coords).
 *
 * \param t: factor in [0..1]
 * \param cosom: dot product from normalized vectors/quats.
 * \param r_w: calculated weights.
 */
void interp_dot_slerp(float t, float cosom, float r_w[2]);
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], float t);
void add_qt_qtqt(float q[4], const float a[4], const float b[4], float t);

/* Conversion. */

void quat_to_mat3(float mat[3][3], const float q[4]);
void quat_to_mat4(float mat[4][4], const float q[4]);

/**
 * Apply the rotation of \a a to \a q keeping the values compatible with \a old.
 * Avoid axis flipping for animated f-curves for eg.
 */
void quat_to_compatible_quat(float q[4], const float a[4], const float old[4]);

void mat3_normalized_to_quat(float q[4], const float mat[3][3]);
void mat4_normalized_to_quat(float q[4], const float mat[4][4]);
void mat3_to_quat(float q[4], const float mat[3][3]);
void mat4_to_quat(float q[4], const float mat[4][4]);
/**
 * Same as tri_to_quat() but takes pre-computed normal from the triangle
 * used for ngons when we know their normal.
 */
void tri_to_quat_ex(float quat[4],
                    const float v1[3],
                    const float v2[3],
                    const float v3[3],
                    const float no_orig[3]);
/**
 * \return the length of the normal, use to test for degenerate triangles.
 */
float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3]);
void vec_to_quat(float q[4], const float vec[3], short axis, short upflag);
/**
 * Calculate a rotation matrix from 2 normalized vectors.
 * \note `v1` and `v2` must be normalized.
 */
void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3]);
/**
 * \note Expects vectors to be normalized.
 */
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3]);
void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q2[4]);

/**
 * Decompose a quaternion into a swing rotation (quaternion with the selected
 * axis component locked at zero), followed by a twist rotation around the axis.
 *
 * \param q: input quaternion.
 * \param axis: twist axis in [0,1,2]
 * \param r_swing: if not NULL, receives the swing quaternion.
 * \param r_twist: if not NULL, receives the twist quaternion.
 * \returns twist angle.
 */
float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]);

float angle_normalized_qt(const float q[4]);
float angle_normalized_qtqt(const float q1[4], const float q2[4]);
float angle_qt(const float q[4]);
float angle_qtqt(const float q1[4], const float q2[4]);

float angle_signed_normalized_qt(const float q[4]);
float angle_signed_normalized_qtqt(const float q1[4], const float q2[4]);
float angle_signed_qt(const float q[4]);
float angle_signed_qtqt(const float q1[4], const float q2[4]);

/**
 * TODO: don't what this is, but it's not the same as #mat3_to_quat.
 */
void mat3_to_quat_is_ok(float q[4], const float mat[3][3]);

/* Other. */

/**
 * Utility function that performs `sinf` & `cosf` where the quadrants of the circle
 * will have exactly matching values when their sign is flipped.
 * This works as long as the denominator can be divided by 2 or 4,
 * otherwise `sinf` & `cosf` are used without any additional logic.
 *
 * Besides adjustments to precision, this function is the equivalent of:
 * \code {.c}
 * float phi = (2 * M_PI) * (float)i / (float)denominator;
 * *r_sin = sinf(phi);
 * *r_cos = cosf(phi);
 * \endcode
 *
 * \param numerator: An integer factor in [0..denominator] (inclusive).
 * \param denominator: The faction denominator (typically the number of segments of the circle).
 * \param r_sin: The resulting sine.
 * \param r_cos: The resulting cosine.
 */
void sin_cos_from_fraction(const int numerator, const int denominator, float *r_sin, float *r_cos);

void print_qt(const char *str, const float q[4]);

#define print_qt_id(q) print_qt(STRINGIFY(q), q)

/** \} */

/* -------------------------------------------------------------------- */
/** \name Axis Angle
 * \{ */

/* Conversion. */

void axis_angle_normalized_to_quat(float r[4], const float axis[3], float angle);
void axis_angle_to_quat(float r[4], const float axis[3], float angle);
/**
 * Axis angle to 3x3 matrix - safer version (normalization of axis performed).
 */
void axis_angle_to_mat3(float R[3][3], const float axis[3], float angle);
/**
 * axis angle to 3x3 matrix
 *
 * This takes the angle with sin/cos applied so we can avoid calculating it in some cases.
 *
 * \param axis: rotation axis (must be normalized).
 * \param angle_sin: sin(angle)
 * \param angle_cos: cos(angle)
 */
void axis_angle_normalized_to_mat3_ex(float mat[3][3],
                                      const float axis[3],
                                      float angle_sin,
                                      float angle_cos);
void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], float angle);
/**
 * Axis angle to 4x4 matrix - safer version (normalization of axis performed).
 */
void axis_angle_to_mat4(float R[4][4], const float axis[3], float angle);

/**
 * 3x3 matrix to axis angle.
 */
void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float M[3][3]);
/**
 * 4x4 matrix to axis angle.
 */
void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
void mat3_to_axis_angle(float axis[3], float *angle, const float M[3][3]);
/**
 * 4x4 matrix to axis angle.
 */
void mat4_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
/**
 * Quaternions to Axis Angle.
 */
void quat_to_axis_angle(float axis[3], float *angle, const float q[4]);

void angle_to_mat2(float R[2][2], float angle);
/**
 * Create a 3x3 rotation matrix from a single axis.
 */
void axis_angle_to_mat3_single(float R[3][3], char axis, float angle);
/**
 * Create a 4x4 rotation matrix from a single axis.
 */
void axis_angle_to_mat4_single(float R[4][4], char axis, float angle);

void axis_angle_to_quat_single(float q[4], char axis, float angle);

/** \} */

/* -------------------------------------------------------------------- */
/** \name Exponential Map
 * \{ */

void quat_to_expmap(float expmap[3], const float q[4]);
void quat_normalized_to_expmap(float expmap[3], const float q[4]);
void expmap_to_quat(float r[4], const float expmap[3]);

/** \} */

/* -------------------------------------------------------------------- */
/** \name XYZ Eulers
 * \{ */

void eul_to_quat(float quat[4], const float eul[3]);
void eul_to_mat3(float mat[3][3], const float eul[3]);
void eul_to_mat4(float mat[4][4], const float eul[3]);

void mat3_normalized_to_eul(float eul[3], const float mat[3][3]);
void mat4_normalized_to_eul(float eul[3], const float mat[4][4]);
void mat3_to_eul(float eul[3], const float mat[3][3]);
void mat4_to_eul(float eul[3], const float mat[4][4]);
void quat_to_eul(float eul[3], const float quat[4]);

void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]);
void rotate_eul(float eul[3], char axis, float angle);

/* Order independent. */

void compatible_eul(float eul[3], const float old[3]);

void add_eul_euleul(float r_eul[3], float a[3], float b[3], short order);
void sub_eul_euleul(float r_eul[3], float a[3], float b[3], short order);

/** \} */

/* -------------------------------------------------------------------- */
/** \name Arbitrary Order Eulers
 * \{ */

/* WARNING: must match the #eRotationModes in `DNA_action_types.h`
 * order matters - types are saved to file. */

typedef enum eEulerRotationOrders {
  EULER_ORDER_DEFAULT = 1, /* blender classic = XYZ */
  EULER_ORDER_XYZ = 1,
  EULER_ORDER_XZY,
  EULER_ORDER_YXZ,
  EULER_ORDER_YZX,
  EULER_ORDER_ZXY,
  EULER_ORDER_ZYX,
  /* There are 6 more entries with duplicate entries included. */
} eEulerRotationOrders;

/**
 * Construct quaternion from Euler angles (in radians).
 */
void eulO_to_quat(float quat[4], const float eul[3], short order);
/**
 * Construct 3x3 matrix from Euler angles (in radians).
 */
void eulO_to_mat3(float mat[3][3], const float eul[3], short order);
/**
 * Construct 4x4 matrix from Euler angles (in radians).
 */
void eulO_to_mat4(float mat[4][4], const float eul[3], short order);
/**
 * Euler Rotation to Axis Angle.
 */
void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], short order);
/**
 * The matrix is written to as 3 axis vectors.
 */
void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], short order);

/**
 * Convert 3x3 matrix to Euler angles (in radians).
 */
void mat3_normalized_to_eulO(float eul[3], short order, const float mat[3][3]);
/**
 * Convert 4x4 matrix to Euler angles (in radians).
 */
void mat4_normalized_to_eulO(float eul[3], short order, const float mat[4][4]);
void mat3_to_eulO(float eul[3], short order, const float mat[3][3]);
void mat4_to_eulO(float eul[3], short order, const float mat[4][4]);
/**
 * Convert quaternion to Euler angles (in radians).
 */
void quat_to_eulO(float eul[3], short order, const float quat[4]);
/**
 * Axis Angle to Euler Rotation.
 */
void axis_angle_to_eulO(float eul[3], short order, const float axis[3], float angle);

/* Uses 2 methods to retrieve eulers, and picks the closest. */

void mat3_normalized_to_compatible_eulO(float eul[3],
                                        const float old[3],
                                        short order,
                                        const float mat[3][3]);
void mat4_normalized_to_compatible_eulO(float eul[3],
                                        const float old[3],
                                        short order,
                                        const float mat[4][4]);
void mat3_to_compatible_eulO(float eul[3], const float old[3], short order, const float mat[3][3]);
void mat4_to_compatible_eulO(float eul[3], const float old[3], short order, const float mat[4][4]);
void quat_to_compatible_eulO(float eul[3], const float old[3], short order, const float quat[4]);

void rotate_eulO(float eul[3], short order, char axis, float angle);

/** \} */

/* -------------------------------------------------------------------- */
/** \name Dual Quaternions
 * \{ */

void copy_dq_dq(DualQuat *r, const DualQuat *dq);
void normalize_dq(DualQuat *dq, float totw);
void add_weighted_dq_dq(DualQuat *dq_sum, const DualQuat *dq, float weight);
void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq);

void mat4_to_dquat(DualQuat *dq, const float basemat[4][4], const float mat[4][4]);
void dquat_to_mat4(float R[4][4], const DualQuat *dq);

/**
 * Axis matches #eTrackToAxis_Modes.
 */
void quat_apply_track(float quat[4], short axis, short upflag);
void vec_apply_track(float vec[3], short axis);

/**
 * Lens/angle conversion (radians).
 */
float focallength_to_fov(float focal_length, float sensor);
float fov_to_focallength(float fov, float sensor);

float angle_wrap_rad(float angle);
float angle_wrap_deg(float angle);

/**
 * Returns an angle compatible with angle_compat.
 */
float angle_compat_rad(float angle, float angle_compat);

/**
 * Each argument us an axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z']
 * where the first 2 are a source and the second 2 are the target.
 */
bool mat3_from_axis_conversion(
    int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3]);
/**
 * Use when the second axis can be guessed.
 */
bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3]);

/** \} */

#ifdef __cplusplus
}
#endif