Blender  V2.93
mathutils_Quaternion.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <Python.h>
22 
23 #include "mathutils.h"
24 
25 #include "BLI_math.h"
26 #include "BLI_utildefines.h"
27 
28 #include "../generic/py_capi_utils.h"
29 #include "../generic/python_utildefines.h"
30 
31 #ifndef MATH_STANDALONE
32 # include "BLI_dynstr.h"
33 #endif
34 
35 #define QUAT_SIZE 4
36 
37 static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
38  QuaternionObject *self);
39 static void quat__axis_angle_sanitize(float axis[3], float *angle);
40 static PyObject *Quaternion_copy(QuaternionObject *self);
41 static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args);
42 
43 /* -----------------------------METHODS------------------------------ */
44 
45 /* note: BaseMath_ReadCallback must be called beforehand */
46 static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
47 {
48  PyObject *ret;
49  int i;
50 
51  ret = PyTuple_New(QUAT_SIZE);
52 
53  if (ndigits >= 0) {
54  for (i = 0; i < QUAT_SIZE; i++) {
55  PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->quat[i], ndigits)));
56  }
57  }
58  else {
59  for (i = 0; i < QUAT_SIZE; i++) {
60  PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->quat[i]));
61  }
62  }
63 
64  return ret;
65 }
66 
67 PyDoc_STRVAR(Quaternion_to_euler_doc,
68  ".. method:: to_euler(order, euler_compat)\n"
69  "\n"
70  " Return Euler representation of the quaternion.\n"
71  "\n"
72  " :arg order: Optional rotation order argument in\n"
73  " ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
74  " :type order: string\n"
75  " :arg euler_compat: Optional euler argument the new euler will be made\n"
76  " compatible with (no axis flipping between them).\n"
77  " Useful for converting a series of matrices to animation curves.\n"
78  " :type euler_compat: :class:`Euler`\n"
79  " :return: Euler representation of the quaternion.\n"
80  " :rtype: :class:`Euler`\n");
81 static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
82 {
83  float tquat[4];
84  float eul[3];
85  const char *order_str = NULL;
86  short order = EULER_ORDER_XYZ;
87  EulerObject *eul_compat = NULL;
88 
89  if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat)) {
90  return NULL;
91  }
92 
93  if (BaseMath_ReadCallback(self) == -1) {
94  return NULL;
95  }
96 
97  if (order_str) {
98  order = euler_order_from_string(order_str, "Quaternion.to_euler()");
99 
100  if (order == -1) {
101  return NULL;
102  }
103  }
104 
105  normalize_qt_qt(tquat, self->quat);
106 
107  if (eul_compat) {
108  if (BaseMath_ReadCallback(eul_compat) == -1) {
109  return NULL;
110  }
111 
112  if (order == EULER_ORDER_XYZ) {
113  quat_to_compatible_eul(eul, eul_compat->eul, tquat);
114  }
115  else {
116  quat_to_compatible_eulO(eul, eul_compat->eul, order, tquat);
117  }
118  }
119  else {
120  if (order == EULER_ORDER_XYZ) {
121  quat_to_eul(eul, tquat);
122  }
123  else {
124  quat_to_eulO(eul, order, tquat);
125  }
126  }
127 
128  return Euler_CreatePyObject(eul, order, NULL);
129 }
130 
131 PyDoc_STRVAR(Quaternion_to_matrix_doc,
132  ".. method:: to_matrix()\n"
133  "\n"
134  " Return a matrix representation of the quaternion.\n"
135  "\n"
136  " :return: A 3x3 rotation matrix representation of the quaternion.\n"
137  " :rtype: :class:`Matrix`\n");
138 static PyObject *Quaternion_to_matrix(QuaternionObject *self)
139 {
140  float mat[9]; /* all values are set */
141 
142  if (BaseMath_ReadCallback(self) == -1) {
143  return NULL;
144  }
145 
146  quat_to_mat3((float(*)[3])mat, self->quat);
147  return Matrix_CreatePyObject(mat, 3, 3, NULL);
148 }
149 
150 PyDoc_STRVAR(Quaternion_to_axis_angle_doc,
151  ".. method:: to_axis_angle()\n"
152  "\n"
153  " Return the axis, angle representation of the quaternion.\n"
154  "\n"
155  " :return: axis, angle.\n"
156  " :rtype: (:class:`Vector`, float) pair\n");
158 {
159  PyObject *ret;
160 
161  float tquat[4];
162 
163  float axis[3];
164  float angle;
165 
166  if (BaseMath_ReadCallback(self) == -1) {
167  return NULL;
168  }
169 
170  normalize_qt_qt(tquat, self->quat);
171  quat_to_axis_angle(axis, &angle, tquat);
172 
174 
175  ret = PyTuple_New(2);
176  PyTuple_SET_ITEMS(ret, Vector_CreatePyObject(axis, 3, NULL), PyFloat_FromDouble(angle));
177  return ret;
178 }
179 
180 PyDoc_STRVAR(Quaternion_to_swing_twist_doc,
181  ".. method:: to_swing_twist(axis)\n"
182  "\n"
183  " Split the rotation into a swing quaternion with the specified\n"
184  " axis fixed at zero, and the remaining twist rotation angle.\n"
185  "\n"
186  " :arg axis: twist axis as a string in ['X', 'Y', 'Z']\n"
187  " :return: swing, twist angle.\n"
188  " :rtype: (:class:`Quaternion`, float) pair\n");
189 static PyObject *Quaternion_to_swing_twist(QuaternionObject *self, PyObject *axis_arg)
190 {
191  PyObject *ret;
192 
193  const char *axis_str = NULL;
194  float swing[4], twist;
195  int axis;
196 
197  if (axis_arg && PyUnicode_Check(axis_arg)) {
198  axis_str = PyUnicode_AsUTF8(axis_arg);
199  }
200 
201  if (axis_str && axis_str[0] >= 'X' && axis_str[0] <= 'Z' && axis_str[1] == 0) {
202  axis = axis_str[0] - 'X';
203  }
204  else {
205  PyErr_SetString(PyExc_ValueError,
206  "Quaternion.to_swing_twist(): "
207  "the axis argument must be "
208  "a string in 'X', 'Y', 'Z'");
209  return NULL;
210  }
211 
212  if (BaseMath_ReadCallback(self) == -1) {
213  return NULL;
214  }
215 
216  twist = quat_split_swing_and_twist(self->quat, axis, swing, NULL);
217 
218  ret = PyTuple_New(2);
220  ret, Quaternion_CreatePyObject(swing, Py_TYPE(self)), PyFloat_FromDouble(twist));
221  return ret;
222 }
223 
225  Quaternion_to_exponential_map_doc,
226  ".. method:: to_exponential_map()\n"
227  "\n"
228  " Return the exponential map representation of the quaternion.\n"
229  "\n"
230  " This representation consist of the rotation axis multiplied by the rotation angle.\n"
231  " Such a representation is useful for interpolation between multiple orientations.\n"
232  "\n"
233  " :return: exponential map.\n"
234  " :rtype: :class:`Vector` of size 3\n"
235  "\n"
236  " To convert back to a quaternion, pass it to the :class:`Quaternion` constructor.\n");
238 {
239  float expmap[3];
240 
241  if (BaseMath_ReadCallback(self) == -1) {
242  return NULL;
243  }
244 
245  quat_to_expmap(expmap, self->quat);
246  return Vector_CreatePyObject(expmap, 3, NULL);
247 }
248 
249 PyDoc_STRVAR(Quaternion_cross_doc,
250  ".. method:: cross(other)\n"
251  "\n"
252  " Return the cross product of this quaternion and another.\n"
253  "\n"
254  " :arg other: The other quaternion to perform the cross product with.\n"
255  " :type other: :class:`Quaternion`\n"
256  " :return: The cross product.\n"
257  " :rtype: :class:`Quaternion`\n");
258 static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value)
259 {
260  float quat[QUAT_SIZE], tquat[QUAT_SIZE];
261 
262  if (BaseMath_ReadCallback(self) == -1) {
263  return NULL;
264  }
265 
267  tquat, QUAT_SIZE, QUAT_SIZE, value, "Quaternion.cross(other), invalid 'other' arg") ==
268  -1) {
269  return NULL;
270  }
271 
272  mul_qt_qtqt(quat, self->quat, tquat);
273  return Quaternion_CreatePyObject(quat, Py_TYPE(self));
274 }
275 
276 PyDoc_STRVAR(Quaternion_dot_doc,
277  ".. method:: dot(other)\n"
278  "\n"
279  " Return the dot product of this quaternion and another.\n"
280  "\n"
281  " :arg other: The other quaternion to perform the dot product with.\n"
282  " :type other: :class:`Quaternion`\n"
283  " :return: The dot product.\n"
284  " :rtype: float\n");
285 static PyObject *Quaternion_dot(QuaternionObject *self, PyObject *value)
286 {
287  float tquat[QUAT_SIZE];
288 
289  if (BaseMath_ReadCallback(self) == -1) {
290  return NULL;
291  }
292 
294  tquat, QUAT_SIZE, QUAT_SIZE, value, "Quaternion.dot(other), invalid 'other' arg") ==
295  -1) {
296  return NULL;
297  }
298 
299  return PyFloat_FromDouble(dot_qtqt(self->quat, tquat));
300 }
301 
302 PyDoc_STRVAR(Quaternion_rotation_difference_doc,
303  ".. function:: rotation_difference(other)\n"
304  "\n"
305  " Returns a quaternion representing the rotational difference.\n"
306  "\n"
307  " :arg other: second quaternion.\n"
308  " :type other: :class:`Quaternion`\n"
309  " :return: the rotational difference between the two quat rotations.\n"
310  " :rtype: :class:`Quaternion`\n");
311 static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject *value)
312 {
313  float tquat[QUAT_SIZE], quat[QUAT_SIZE];
314 
315  if (BaseMath_ReadCallback(self) == -1) {
316  return NULL;
317  }
318 
319  if (mathutils_array_parse(tquat,
320  QUAT_SIZE,
321  QUAT_SIZE,
322  value,
323  "Quaternion.difference(other), invalid 'other' arg") == -1) {
324  return NULL;
325  }
326 
327  rotation_between_quats_to_quat(quat, self->quat, tquat);
328 
329  return Quaternion_CreatePyObject(quat, Py_TYPE(self));
330 }
331 
332 PyDoc_STRVAR(Quaternion_slerp_doc,
333  ".. function:: slerp(other, factor)\n"
334  "\n"
335  " Returns the interpolation of two quaternions.\n"
336  "\n"
337  " :arg other: value to interpolate with.\n"
338  " :type other: :class:`Quaternion`\n"
339  " :arg factor: The interpolation value in [0.0, 1.0].\n"
340  " :type factor: float\n"
341  " :return: The interpolated rotation.\n"
342  " :rtype: :class:`Quaternion`\n");
343 static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args)
344 {
345  PyObject *value;
346  float tquat[QUAT_SIZE], quat[QUAT_SIZE], fac;
347 
348  if (!PyArg_ParseTuple(args, "Of:slerp", &value, &fac)) {
349  PyErr_SetString(PyExc_TypeError,
350  "quat.slerp(): "
351  "expected Quaternion types and float");
352  return NULL;
353  }
354 
355  if (BaseMath_ReadCallback(self) == -1) {
356  return NULL;
357  }
358 
360  tquat, QUAT_SIZE, QUAT_SIZE, value, "Quaternion.slerp(other), invalid 'other' arg") ==
361  -1) {
362  return NULL;
363  }
364 
365  if (fac > 1.0f || fac < 0.0f) {
366  PyErr_SetString(PyExc_ValueError,
367  "quat.slerp(): "
368  "interpolation factor must be between 0.0 and 1.0");
369  return NULL;
370  }
371 
372  interp_qt_qtqt(quat, self->quat, tquat, fac);
373 
374  return Quaternion_CreatePyObject(quat, Py_TYPE(self));
375 }
376 
377 PyDoc_STRVAR(Quaternion_rotate_doc,
378  ".. method:: rotate(other)\n"
379  "\n"
380  " Rotates the quaternion by another mathutils value.\n"
381  "\n"
382  " :arg other: rotation component of mathutils value\n"
383  " :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n");
384 static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value)
385 {
386  float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
387  float tquat[4], length;
388 
389  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
390  return NULL;
391  }
392 
393  if (mathutils_any_to_rotmat(other_rmat, value, "Quaternion.rotate(value)") == -1) {
394  return NULL;
395  }
396 
397  length = normalize_qt_qt(tquat, self->quat);
398  quat_to_mat3(self_rmat, tquat);
399  mul_m3_m3m3(rmat, other_rmat, self_rmat);
400 
401  mat3_to_quat(self->quat, rmat);
402  mul_qt_fl(self->quat, length); /* maintain length after rotating */
403 
404  (void)BaseMath_WriteCallback(self);
405  Py_RETURN_NONE;
406 }
407 
408 PyDoc_STRVAR(Quaternion_make_compatible_doc,
409  ".. method:: make_compatible(other)\n"
410  "\n"
411  " Make this quaternion compatible with another,\n"
412  " so interpolating between them works as intended.\n");
413 static PyObject *Quaternion_make_compatible(QuaternionObject *self, PyObject *value)
414 {
415  float quat[QUAT_SIZE];
416  float tquat[QUAT_SIZE];
417 
418  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
419  return NULL;
420  }
421 
422  if (mathutils_array_parse(tquat,
423  QUAT_SIZE,
424  QUAT_SIZE,
425  value,
426  "Quaternion.make_compatible(other), invalid 'other' arg") == -1) {
427  return NULL;
428  }
429 
430  /* Can only operate on unit length quaternions. */
431  const float quat_len = normalize_qt_qt(quat, self->quat);
432  quat_to_compatible_quat(self->quat, quat, tquat);
433  mul_qt_fl(self->quat, quat_len);
434 
435  (void)BaseMath_WriteCallback(self);
436 
437  Py_RETURN_NONE;
438 }
439 
440 /* ----------------------------Quaternion.normalize()---------------- */
441 /* Normalize the quaternion. This may change the angle as well as the
442  * rotation axis, as all of (w, x, y, z) are scaled. */
443 PyDoc_STRVAR(Quaternion_normalize_doc,
444  ".. function:: normalize()\n"
445  "\n"
446  " Normalize the quaternion.\n");
447 static PyObject *Quaternion_normalize(QuaternionObject *self)
448 {
449  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
450  return NULL;
451  }
452 
453  normalize_qt(self->quat);
454 
455  (void)BaseMath_WriteCallback(self);
456  Py_RETURN_NONE;
457 }
458 PyDoc_STRVAR(Quaternion_normalized_doc,
459  ".. function:: normalized()\n"
460  "\n"
461  " Return a new normalized quaternion.\n"
462  "\n"
463  " :return: a normalized copy.\n"
464  " :rtype: :class:`Quaternion`\n");
466 {
468 }
469 
470 PyDoc_STRVAR(Quaternion_invert_doc,
471  ".. function:: invert()\n"
472  "\n"
473  " Set the quaternion to its inverse.\n");
474 static PyObject *Quaternion_invert(QuaternionObject *self)
475 {
476  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
477  return NULL;
478  }
479 
480  invert_qt(self->quat);
481 
482  (void)BaseMath_WriteCallback(self);
483  Py_RETURN_NONE;
484 }
485 PyDoc_STRVAR(Quaternion_inverted_doc,
486  ".. function:: inverted()\n"
487  "\n"
488  " Return a new, inverted quaternion.\n"
489  "\n"
490  " :return: the inverted value.\n"
491  " :rtype: :class:`Quaternion`\n");
492 static PyObject *Quaternion_inverted(QuaternionObject *self)
493 {
495 }
496 
497 PyDoc_STRVAR(Quaternion_identity_doc,
498  ".. function:: identity()\n"
499  "\n"
500  " Set the quaternion to an identity quaternion.\n"
501  "\n"
502  " :rtype: :class:`Quaternion`\n");
503 static PyObject *Quaternion_identity(QuaternionObject *self)
504 {
505  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
506  return NULL;
507  }
508 
509  unit_qt(self->quat);
510 
511  (void)BaseMath_WriteCallback(self);
512  Py_RETURN_NONE;
513 }
514 
515 PyDoc_STRVAR(Quaternion_negate_doc,
516  ".. function:: negate()\n"
517  "\n"
518  " Set the quaternion to its negative.\n"
519  "\n"
520  " :rtype: :class:`Quaternion`\n");
521 static PyObject *Quaternion_negate(QuaternionObject *self)
522 {
523  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
524  return NULL;
525  }
526 
527  mul_qt_fl(self->quat, -1.0f);
528 
529  (void)BaseMath_WriteCallback(self);
530  Py_RETURN_NONE;
531 }
532 
533 PyDoc_STRVAR(Quaternion_conjugate_doc,
534  ".. function:: conjugate()\n"
535  "\n"
536  " Set the quaternion to its conjugate (negate x, y, z).\n");
537 static PyObject *Quaternion_conjugate(QuaternionObject *self)
538 {
539  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
540  return NULL;
541  }
542 
543  conjugate_qt(self->quat);
544 
545  (void)BaseMath_WriteCallback(self);
546  Py_RETURN_NONE;
547 }
548 PyDoc_STRVAR(Quaternion_conjugated_doc,
549  ".. function:: conjugated()\n"
550  "\n"
551  " Return a new conjugated quaternion.\n"
552  "\n"
553  " :return: a new quaternion.\n"
554  " :rtype: :class:`Quaternion`\n");
556 {
558 }
559 
560 PyDoc_STRVAR(Quaternion_copy_doc,
561  ".. function:: copy()\n"
562  "\n"
563  " Returns a copy of this quaternion.\n"
564  "\n"
565  " :return: A copy of the quaternion.\n"
566  " :rtype: :class:`Quaternion`\n"
567  "\n"
568  " .. note:: use this to get a copy of a wrapped quaternion with\n"
569  " no reference to the original data.\n");
570 static PyObject *Quaternion_copy(QuaternionObject *self)
571 {
572  if (BaseMath_ReadCallback(self) == -1) {
573  return NULL;
574  }
575 
576  return Quaternion_CreatePyObject(self->quat, Py_TYPE(self));
577 }
578 static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args)
579 {
580  if (!PyC_CheckArgs_DeepCopy(args)) {
581  return NULL;
582  }
583  return Quaternion_copy(self);
584 }
585 
586 /* print the object to screen */
587 static PyObject *Quaternion_repr(QuaternionObject *self)
588 {
589  PyObject *ret, *tuple;
590 
591  if (BaseMath_ReadCallback(self) == -1) {
592  return NULL;
593  }
594 
595  tuple = Quaternion_to_tuple_ext(self, -1);
596 
597  ret = PyUnicode_FromFormat("Quaternion(%R)", tuple);
598 
599  Py_DECREF(tuple);
600  return ret;
601 }
602 
603 #ifndef MATH_STANDALONE
604 static PyObject *Quaternion_str(QuaternionObject *self)
605 {
606  DynStr *ds;
607 
608  if (BaseMath_ReadCallback(self) == -1) {
609  return NULL;
610  }
611 
612  ds = BLI_dynstr_new();
613 
615  "<Quaternion (w=%.4f, x=%.4f, y=%.4f, z=%.4f)>",
616  self->quat[0],
617  self->quat[1],
618  self->quat[2],
619  self->quat[3]);
620 
621  return mathutils_dynstr_to_py(ds); /* frees ds */
622 }
623 #endif
624 
625 static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
626 {
627  PyObject *res;
628  int ok = -1; /* zero is true */
629 
631  QuaternionObject *quatA = (QuaternionObject *)a;
632  QuaternionObject *quatB = (QuaternionObject *)b;
633 
634  if (BaseMath_ReadCallback(quatA) == -1 || BaseMath_ReadCallback(quatB) == -1) {
635  return NULL;
636  }
637 
638  ok = (EXPP_VectorsAreEqual(quatA->quat, quatB->quat, QUAT_SIZE, 1)) ? 0 : -1;
639  }
640 
641  switch (op) {
642  case Py_NE:
643  ok = !ok;
645  case Py_EQ:
646  res = ok ? Py_False : Py_True;
647  break;
648 
649  case Py_LT:
650  case Py_LE:
651  case Py_GT:
652  case Py_GE:
653  res = Py_NotImplemented;
654  break;
655  default:
656  PyErr_BadArgument();
657  return NULL;
658  }
659 
660  return Py_INCREF_RET(res);
661 }
662 
663 static Py_hash_t Quaternion_hash(QuaternionObject *self)
664 {
665  if (BaseMath_ReadCallback(self) == -1) {
666  return -1;
667  }
668 
669  if (BaseMathObject_Prepare_ForHash(self) == -1) {
670  return -1;
671  }
672 
673  return mathutils_array_hash(self->quat, QUAT_SIZE);
674 }
675 
676 /* ---------------------SEQUENCE PROTOCOLS------------------------ */
677 /* ----------------------------len(object)------------------------ */
678 /* sequence length */
680 {
681  return QUAT_SIZE;
682 }
683 /* ----------------------------object[]--------------------------- */
684 /* sequence accessor (get) */
685 static PyObject *Quaternion_item(QuaternionObject *self, int i)
686 {
687  if (i < 0) {
688  i = QUAT_SIZE - i;
689  }
690 
691  if (i < 0 || i >= QUAT_SIZE) {
692  PyErr_SetString(PyExc_IndexError,
693  "quaternion[attribute]: "
694  "array index out of range");
695  return NULL;
696  }
697 
698  if (BaseMath_ReadIndexCallback(self, i) == -1) {
699  return NULL;
700  }
701 
702  return PyFloat_FromDouble(self->quat[i]);
703 }
704 /* ----------------------------object[]------------------------- */
705 /* sequence accessor (set) */
706 static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
707 {
708  float f;
709 
710  if (BaseMath_Prepare_ForWrite(self) == -1) {
711  return -1;
712  }
713 
714  f = (float)PyFloat_AsDouble(ob);
715 
716  if (f == -1.0f && PyErr_Occurred()) { /* parsed item not a number */
717  PyErr_SetString(PyExc_TypeError,
718  "quaternion[index] = x: "
719  "assigned value not a number");
720  return -1;
721  }
722 
723  if (i < 0) {
724  i = QUAT_SIZE - i;
725  }
726 
727  if (i < 0 || i >= QUAT_SIZE) {
728  PyErr_SetString(PyExc_IndexError,
729  "quaternion[attribute] = x: "
730  "array assignment index out of range");
731  return -1;
732  }
733  self->quat[i] = f;
734 
735  if (BaseMath_WriteIndexCallback(self, i) == -1) {
736  return -1;
737  }
738 
739  return 0;
740 }
741 /* ----------------------------object[z:y]------------------------ */
742 /* sequence slice (get) */
743 static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end)
744 {
745  PyObject *tuple;
746  int count;
747 
748  if (BaseMath_ReadCallback(self) == -1) {
749  return NULL;
750  }
751 
752  CLAMP(begin, 0, QUAT_SIZE);
753  if (end < 0) {
754  end = (QUAT_SIZE + 1) + end;
755  }
756  CLAMP(end, 0, QUAT_SIZE);
757  begin = MIN2(begin, end);
758 
759  tuple = PyTuple_New(end - begin);
760  for (count = begin; count < end; count++) {
761  PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->quat[count]));
762  }
763 
764  return tuple;
765 }
766 /* ----------------------------object[z:y]------------------------ */
767 /* sequence slice (set) */
768 static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq)
769 {
770  int i, size;
771  float quat[QUAT_SIZE];
772 
773  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
774  return -1;
775  }
776 
777  CLAMP(begin, 0, QUAT_SIZE);
778  if (end < 0) {
779  end = (QUAT_SIZE + 1) + end;
780  }
781  CLAMP(end, 0, QUAT_SIZE);
782  begin = MIN2(begin, end);
783 
785  quat, 0, QUAT_SIZE, seq, "mathutils.Quaternion[begin:end] = []")) == -1) {
786  return -1;
787  }
788 
789  if (size != (end - begin)) {
790  PyErr_SetString(PyExc_ValueError,
791  "quaternion[begin:end] = []: "
792  "size mismatch in slice assignment");
793  return -1;
794  }
795 
796  /* parsed well - now set in vector */
797  for (i = 0; i < size; i++) {
798  self->quat[begin + i] = quat[i];
799  }
800 
801  (void)BaseMath_WriteCallback(self);
802  return 0;
803 }
804 
805 static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
806 {
807  if (PyIndex_Check(item)) {
808  Py_ssize_t i;
809  i = PyNumber_AsSsize_t(item, PyExc_IndexError);
810  if (i == -1 && PyErr_Occurred()) {
811  return NULL;
812  }
813  if (i < 0) {
814  i += QUAT_SIZE;
815  }
816  return Quaternion_item(self, i);
817  }
818  if (PySlice_Check(item)) {
819  Py_ssize_t start, stop, step, slicelength;
820 
821  if (PySlice_GetIndicesEx(item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0) {
822  return NULL;
823  }
824 
825  if (slicelength <= 0) {
826  return PyTuple_New(0);
827  }
828  if (step == 1) {
829  return Quaternion_slice(self, start, stop);
830  }
831 
832  PyErr_SetString(PyExc_IndexError, "slice steps not supported with quaternions");
833  return NULL;
834  }
835 
836  PyErr_Format(
837  PyExc_TypeError, "quaternion indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
838  return NULL;
839 }
840 
841 static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyObject *value)
842 {
843  if (PyIndex_Check(item)) {
844  Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
845  if (i == -1 && PyErr_Occurred()) {
846  return -1;
847  }
848  if (i < 0) {
849  i += QUAT_SIZE;
850  }
851  return Quaternion_ass_item(self, i, value);
852  }
853  if (PySlice_Check(item)) {
854  Py_ssize_t start, stop, step, slicelength;
855 
856  if (PySlice_GetIndicesEx(item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0) {
857  return -1;
858  }
859 
860  if (step == 1) {
861  return Quaternion_ass_slice(self, start, stop, value);
862  }
863 
864  PyErr_SetString(PyExc_IndexError, "slice steps not supported with quaternion");
865  return -1;
866  }
867 
868  PyErr_Format(
869  PyExc_TypeError, "quaternion indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
870  return -1;
871 }
872 
873 /* ------------------------NUMERIC PROTOCOLS---------------------- */
874 /* ------------------------obj + obj------------------------------ */
875 /* addition */
876 static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
877 {
878  float quat[QUAT_SIZE];
879  QuaternionObject *quat1 = NULL, *quat2 = NULL;
880 
882  PyErr_Format(PyExc_TypeError,
883  "Quaternion addition: (%s + %s) "
884  "invalid type for this operation",
885  Py_TYPE(q1)->tp_name,
886  Py_TYPE(q2)->tp_name);
887  return NULL;
888  }
889  quat1 = (QuaternionObject *)q1;
890  quat2 = (QuaternionObject *)q2;
891 
892  if (BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1) {
893  return NULL;
894  }
895 
896  add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f);
897  return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
898 }
899 /* ------------------------obj - obj------------------------------ */
900 /* subtraction */
901 static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2)
902 {
903  int x;
904  float quat[QUAT_SIZE];
905  QuaternionObject *quat1 = NULL, *quat2 = NULL;
906 
908  PyErr_Format(PyExc_TypeError,
909  "Quaternion subtraction: (%s - %s) "
910  "invalid type for this operation",
911  Py_TYPE(q1)->tp_name,
912  Py_TYPE(q2)->tp_name);
913  return NULL;
914  }
915 
916  quat1 = (QuaternionObject *)q1;
917  quat2 = (QuaternionObject *)q2;
918 
919  if (BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1) {
920  return NULL;
921  }
922 
923  for (x = 0; x < QUAT_SIZE; x++) {
924  quat[x] = quat1->quat[x] - quat2->quat[x];
925  }
926 
927  return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
928 }
929 
930 static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
931 {
932  float tquat[4];
933  copy_qt_qt(tquat, quat->quat);
934  mul_qt_fl(tquat, scalar);
935  return Quaternion_CreatePyObject(tquat, Py_TYPE(quat));
936 }
937 
938 /*------------------------obj * obj------------------------------
939  * multiplication */
940 static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
941 {
942  float scalar;
943  QuaternionObject *quat1 = NULL, *quat2 = NULL;
944 
945  if (QuaternionObject_Check(q1)) {
946  quat1 = (QuaternionObject *)q1;
947  if (BaseMath_ReadCallback(quat1) == -1) {
948  return NULL;
949  }
950  }
951  if (QuaternionObject_Check(q2)) {
952  quat2 = (QuaternionObject *)q2;
953  if (BaseMath_ReadCallback(quat2) == -1) {
954  return NULL;
955  }
956  }
957 
958  if (quat1 && quat2) { /* QUAT * QUAT (element-wise product) */
959  float quat[QUAT_SIZE];
960  mul_vn_vnvn(quat, quat1->quat, quat2->quat, QUAT_SIZE);
961  return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
962  }
963  /* the only case this can happen (for a supported type is "FLOAT * QUAT") */
964  if (quat2) { /* FLOAT * QUAT */
965  if (((scalar = PyFloat_AsDouble(q1)) == -1.0f && PyErr_Occurred()) == 0) {
966  return quat_mul_float(quat2, scalar);
967  }
968  }
969  else if (quat1) { /* QUAT * FLOAT */
970  if ((((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
971  return quat_mul_float(quat1, scalar);
972  }
973  }
974 
975  PyErr_Format(PyExc_TypeError,
976  "Element-wise multiplication: "
977  "not supported between '%.200s' and '%.200s' types",
978  Py_TYPE(q1)->tp_name,
979  Py_TYPE(q2)->tp_name);
980  return NULL;
981 }
982 /*------------------------obj *= obj------------------------------
983  * in-place multiplication */
984 static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2)
985 {
986  float scalar;
987  QuaternionObject *quat1 = NULL, *quat2 = NULL;
988 
989  if (QuaternionObject_Check(q1)) {
990  quat1 = (QuaternionObject *)q1;
991  if (BaseMath_ReadCallback(quat1) == -1) {
992  return NULL;
993  }
994  }
995  if (QuaternionObject_Check(q2)) {
996  quat2 = (QuaternionObject *)q2;
997  if (BaseMath_ReadCallback(quat2) == -1) {
998  return NULL;
999  }
1000  }
1001 
1002  if (quat1 && quat2) { /* QUAT *= QUAT (in-place element-wise product). */
1003  mul_vn_vn(quat1->quat, quat2->quat, QUAT_SIZE);
1004  }
1005  else if (quat1 && (((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
1006  /* QUAT *= FLOAT */
1007  mul_qt_fl(quat1->quat, scalar);
1008  }
1009  else {
1010  PyErr_Format(PyExc_TypeError,
1011  "Element-wise multiplication: "
1012  "not supported between '%.200s' and '%.200s' types",
1013  Py_TYPE(q1)->tp_name,
1014  Py_TYPE(q2)->tp_name);
1015  return NULL;
1016  }
1017 
1018  (void)BaseMath_WriteCallback(quat1);
1019  Py_INCREF(q1);
1020  return q1;
1021 }
1022 /*------------------------obj @ obj------------------------------
1023  * quaternion multiplication */
1024 static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2)
1025 {
1026  float quat[QUAT_SIZE];
1027  QuaternionObject *quat1 = NULL, *quat2 = NULL;
1028 
1029  if (QuaternionObject_Check(q1)) {
1030  quat1 = (QuaternionObject *)q1;
1031  if (BaseMath_ReadCallback(quat1) == -1) {
1032  return NULL;
1033  }
1034  }
1035  if (QuaternionObject_Check(q2)) {
1036  quat2 = (QuaternionObject *)q2;
1037  if (BaseMath_ReadCallback(quat2) == -1) {
1038  return NULL;
1039  }
1040  }
1041 
1042  if (quat1 && quat2) { /* QUAT @ QUAT (cross product) */
1043  mul_qt_qtqt(quat, quat1->quat, quat2->quat);
1044  return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
1045  }
1046  if (quat1) {
1047  /* QUAT @ VEC */
1048  if (VectorObject_Check(q2)) {
1049  VectorObject *vec2 = (VectorObject *)q2;
1050  float tvec[3];
1051 
1052  if (vec2->size != 3) {
1053  PyErr_SetString(PyExc_ValueError,
1054  "Vector multiplication: "
1055  "only 3D vector rotations (with quats) "
1056  "currently supported");
1057  return NULL;
1058  }
1059  if (BaseMath_ReadCallback(vec2) == -1) {
1060  return NULL;
1061  }
1062 
1063  copy_v3_v3(tvec, vec2->vec);
1064  mul_qt_v3(quat1->quat, tvec);
1065 
1066  return Vector_CreatePyObject(tvec, 3, Py_TYPE(vec2));
1067  }
1068  }
1069 
1070  PyErr_Format(PyExc_TypeError,
1071  "Quaternion multiplication: "
1072  "not supported between '%.200s' and '%.200s' types",
1073  Py_TYPE(q1)->tp_name,
1074  Py_TYPE(q2)->tp_name);
1075  return NULL;
1076 }
1077 /*------------------------obj @= obj------------------------------
1078  * in-place quaternion multiplication */
1079 static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2)
1080 {
1081  float quat[QUAT_SIZE];
1082  QuaternionObject *quat1 = NULL, *quat2 = NULL;
1083 
1084  if (QuaternionObject_Check(q1)) {
1085  quat1 = (QuaternionObject *)q1;
1086  if (BaseMath_ReadCallback(quat1) == -1) {
1087  return NULL;
1088  }
1089  }
1090  if (QuaternionObject_Check(q2)) {
1091  quat2 = (QuaternionObject *)q2;
1092  if (BaseMath_ReadCallback(quat2) == -1) {
1093  return NULL;
1094  }
1095  }
1096 
1097  if (quat1 && quat2) { /* QUAT @ QUAT (cross product) */
1098  mul_qt_qtqt(quat, quat1->quat, quat2->quat);
1099  copy_qt_qt(quat1->quat, quat);
1100  }
1101  else {
1102  PyErr_Format(PyExc_TypeError,
1103  "In place quaternion multiplication: "
1104  "not supported between '%.200s' and '%.200s' types",
1105  Py_TYPE(q1)->tp_name,
1106  Py_TYPE(q2)->tp_name);
1107  return NULL;
1108  }
1109 
1110  (void)BaseMath_WriteCallback(quat1);
1111  Py_INCREF(q1);
1112  return q1;
1113 }
1114 
1115 /* -obj
1116  * returns the negative of this object*/
1117 static PyObject *Quaternion_neg(QuaternionObject *self)
1118 {
1119  float tquat[QUAT_SIZE];
1120 
1121  if (BaseMath_ReadCallback(self) == -1) {
1122  return NULL;
1123  }
1124 
1125  negate_v4_v4(tquat, self->quat);
1126  return Quaternion_CreatePyObject(tquat, Py_TYPE(self));
1127 }
1128 
1129 /* -----------------PROTOCOL DECLARATIONS-------------------------- */
1130 static PySequenceMethods Quaternion_SeqMethods = {
1131  (lenfunc)Quaternion_len, /* sq_length */
1132  (binaryfunc)NULL, /* sq_concat */
1133  (ssizeargfunc)NULL, /* sq_repeat */
1134  (ssizeargfunc)Quaternion_item, /* sq_item */
1135  (ssizessizeargfunc)NULL, /* sq_slice, deprecated */
1136  (ssizeobjargproc)Quaternion_ass_item, /* sq_ass_item */
1137  (ssizessizeobjargproc)NULL, /* sq_ass_slice, deprecated */
1138  (objobjproc)NULL, /* sq_contains */
1139  (binaryfunc)NULL, /* sq_inplace_concat */
1140  (ssizeargfunc)NULL, /* sq_inplace_repeat */
1141 };
1142 
1143 static PyMappingMethods Quaternion_AsMapping = {
1144  (lenfunc)Quaternion_len,
1145  (binaryfunc)Quaternion_subscript,
1146  (objobjargproc)Quaternion_ass_subscript,
1147 };
1148 
1149 static PyNumberMethods Quaternion_NumMethods = {
1150  (binaryfunc)Quaternion_add, /*nb_add*/
1151  (binaryfunc)Quaternion_sub, /*nb_subtract*/
1152  (binaryfunc)Quaternion_mul, /*nb_multiply*/
1153  NULL, /*nb_remainder*/
1154  NULL, /*nb_divmod*/
1155  NULL, /*nb_power*/
1156  (unaryfunc)Quaternion_neg, /*nb_negative*/
1157  (unaryfunc)Quaternion_copy, /*tp_positive*/
1158  (unaryfunc)0, /*tp_absolute*/
1159  (inquiry)0, /*tp_bool*/
1160  (unaryfunc)0, /*nb_invert*/
1161  NULL, /*nb_lshift*/
1162  (binaryfunc)0, /*nb_rshift*/
1163  NULL, /*nb_and*/
1164  NULL, /*nb_xor*/
1165  NULL, /*nb_or*/
1166  NULL, /*nb_int*/
1167  NULL, /*nb_reserved*/
1168  NULL, /*nb_float*/
1169  NULL, /* nb_inplace_add */
1170  NULL, /* nb_inplace_subtract */
1171  (binaryfunc)Quaternion_imul, /* nb_inplace_multiply */
1172  NULL, /* nb_inplace_remainder */
1173  NULL, /* nb_inplace_power */
1174  NULL, /* nb_inplace_lshift */
1175  NULL, /* nb_inplace_rshift */
1176  NULL, /* nb_inplace_and */
1177  NULL, /* nb_inplace_xor */
1178  NULL, /* nb_inplace_or */
1179  NULL, /* nb_floor_divide */
1180  NULL, /* nb_true_divide */
1181  NULL, /* nb_inplace_floor_divide */
1182  NULL, /* nb_inplace_true_divide */
1183  NULL, /* nb_index */
1184  (binaryfunc)Quaternion_matmul, /* nb_matrix_multiply */
1185  (binaryfunc)Quaternion_imatmul, /* nb_inplace_matrix_multiply */
1186 };
1187 
1188 PyDoc_STRVAR(Quaternion_axis_doc, "Quaternion axis value.\n\n:type: float");
1189 static PyObject *Quaternion_axis_get(QuaternionObject *self, void *type)
1190 {
1191  return Quaternion_item(self, POINTER_AS_INT(type));
1192 }
1193 
1194 static int Quaternion_axis_set(QuaternionObject *self, PyObject *value, void *type)
1195 {
1196  return Quaternion_ass_item(self, POINTER_AS_INT(type), value);
1197 }
1198 
1199 PyDoc_STRVAR(Quaternion_magnitude_doc, "Size of the quaternion (read-only).\n\n:type: float");
1200 static PyObject *Quaternion_magnitude_get(QuaternionObject *self, void *UNUSED(closure))
1201 {
1202  if (BaseMath_ReadCallback(self) == -1) {
1203  return NULL;
1204  }
1205 
1206  return PyFloat_FromDouble(sqrtf(dot_qtqt(self->quat, self->quat)));
1207 }
1208 
1209 PyDoc_STRVAR(Quaternion_angle_doc, "Angle of the quaternion.\n\n:type: float");
1210 static PyObject *Quaternion_angle_get(QuaternionObject *self, void *UNUSED(closure))
1211 {
1212  float tquat[4];
1213  float angle;
1214 
1215  if (BaseMath_ReadCallback(self) == -1) {
1216  return NULL;
1217  }
1218 
1219  normalize_qt_qt(tquat, self->quat);
1220 
1221  angle = 2.0f * saacos(tquat[0]);
1222 
1224 
1225  return PyFloat_FromDouble(angle);
1226 }
1227 
1228 static int Quaternion_angle_set(QuaternionObject *self, PyObject *value, void *UNUSED(closure))
1229 {
1230  float tquat[4];
1231  float len;
1232 
1233  float axis[3], angle_dummy;
1234  float angle;
1235 
1236  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
1237  return -1;
1238  }
1239 
1240  len = normalize_qt_qt(tquat, self->quat);
1241  quat_to_axis_angle(axis, &angle_dummy, tquat);
1242 
1243  angle = PyFloat_AsDouble(value);
1244 
1245  if (angle == -1.0f && PyErr_Occurred()) { /* parsed item not a number */
1246  PyErr_SetString(PyExc_TypeError, "Quaternion.angle = value: float expected");
1247  return -1;
1248  }
1249 
1251 
1253 
1254  axis_angle_to_quat(self->quat, axis, angle);
1255  mul_qt_fl(self->quat, len);
1256 
1257  if (BaseMath_WriteCallback(self) == -1) {
1258  return -1;
1259  }
1260 
1261  return 0;
1262 }
1263 
1264 PyDoc_STRVAR(Quaternion_axis_vector_doc, "Quaternion axis as a vector.\n\n:type: :class:`Vector`");
1265 static PyObject *Quaternion_axis_vector_get(QuaternionObject *self, void *UNUSED(closure))
1266 {
1267  float tquat[4];
1268 
1269  float axis[3];
1270  float angle_dummy;
1271 
1272  if (BaseMath_ReadCallback(self) == -1) {
1273  return NULL;
1274  }
1275 
1276  normalize_qt_qt(tquat, self->quat);
1277  quat_to_axis_angle(axis, &angle_dummy, tquat);
1278 
1280 
1281  return Vector_CreatePyObject(axis, 3, NULL);
1282 }
1283 
1285  PyObject *value,
1286  void *UNUSED(closure))
1287 {
1288  float tquat[4];
1289  float len;
1290 
1291  float axis[3];
1292  float angle;
1293 
1294  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
1295  return -1;
1296  }
1297 
1298  len = normalize_qt_qt(tquat, self->quat);
1299  quat_to_axis_angle(axis, &angle, tquat); /* axis value is unused */
1300 
1301  if (mathutils_array_parse(axis, 3, 3, value, "quat.axis = other") == -1) {
1302  return -1;
1303  }
1304 
1306 
1307  axis_angle_to_quat(self->quat, axis, angle);
1308  mul_qt_fl(self->quat, len);
1309 
1310  if (BaseMath_WriteCallback(self) == -1) {
1311  return -1;
1312  }
1313 
1314  return 0;
1315 }
1316 
1317 /* ----------------------------------mathutils.Quaternion() -------------- */
1318 static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1319 {
1320  PyObject *seq = NULL;
1321  double angle = 0.0f;
1322  float quat[QUAT_SIZE];
1323  unit_qt(quat);
1324 
1325  if (kwds && PyDict_Size(kwds)) {
1326  PyErr_SetString(PyExc_TypeError,
1327  "mathutils.Quaternion(): "
1328  "takes no keyword args");
1329  return NULL;
1330  }
1331 
1332  if (!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle)) {
1333  return NULL;
1334  }
1335 
1336  switch (PyTuple_GET_SIZE(args)) {
1337  case 0:
1338  break;
1339  case 1: {
1340  int size;
1341 
1342  if ((size = mathutils_array_parse(quat, 3, QUAT_SIZE, seq, "mathutils.Quaternion()")) ==
1343  -1) {
1344  return NULL;
1345  }
1346 
1347  if (size == 4) {
1348  /* 4d: Quaternion (common case) */
1349  }
1350  else {
1351  /* 3d: Interpret as exponential map */
1352  BLI_assert(size == 3);
1353  expmap_to_quat(quat, quat);
1354  }
1355 
1356  break;
1357  }
1358  case 2: {
1359  float axis[3];
1360  if (mathutils_array_parse(axis, 3, 3, seq, "mathutils.Quaternion()") == -1) {
1361  return NULL;
1362  }
1363  angle = angle_wrap_rad(angle); /* clamp because of precision issues */
1364  axis_angle_to_quat(quat, axis, angle);
1365  break;
1366  /* PyArg_ParseTuple assures no more than 2 */
1367  }
1368  }
1369  return Quaternion_CreatePyObject(quat, type);
1370 }
1371 
1372 static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
1373  QuaternionObject *self)
1374 {
1375  PyObject *ret = Quaternion_copy(self);
1376  PyObject *ret_dummy = quat_func((QuaternionObject *)ret);
1377  if (ret_dummy) {
1378  Py_DECREF(ret_dummy);
1379  return ret;
1380  }
1381  /* error */
1382  Py_DECREF(ret);
1383  return NULL;
1384 }
1385 
1386 /* axis vector suffers from precision errors, use this function to ensure */
1387 static void quat__axis_angle_sanitize(float axis[3], float *angle)
1388 {
1389  if (axis) {
1390  if (is_zero_v3(axis) || !isfinite(axis[0]) || !isfinite(axis[1]) || !isfinite(axis[2])) {
1391  axis[0] = 1.0f;
1392  axis[1] = 0.0f;
1393  axis[2] = 0.0f;
1394  }
1395  else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
1396  EXPP_FloatsAreEqual(axis[2], 0.0f, 10)) {
1397  axis[0] = 1.0f;
1398  }
1399  }
1400 
1401  if (angle) {
1402  if (!isfinite(*angle)) {
1403  *angle = 0.0f;
1404  }
1405  }
1406 }
1407 
1408 /* -----------------------METHOD DEFINITIONS ---------------------- */
1409 static struct PyMethodDef Quaternion_methods[] = {
1410  /* in place only */
1411  {"identity", (PyCFunction)Quaternion_identity, METH_NOARGS, Quaternion_identity_doc},
1412  {"negate", (PyCFunction)Quaternion_negate, METH_NOARGS, Quaternion_negate_doc},
1413 
1414  /* operate on original or copy */
1415  {"conjugate", (PyCFunction)Quaternion_conjugate, METH_NOARGS, Quaternion_conjugate_doc},
1416  {"conjugated", (PyCFunction)Quaternion_conjugated, METH_NOARGS, Quaternion_conjugated_doc},
1417 
1418  {"invert", (PyCFunction)Quaternion_invert, METH_NOARGS, Quaternion_invert_doc},
1419  {"inverted", (PyCFunction)Quaternion_inverted, METH_NOARGS, Quaternion_inverted_doc},
1420 
1421  {"normalize", (PyCFunction)Quaternion_normalize, METH_NOARGS, Quaternion_normalize_doc},
1422  {"normalized", (PyCFunction)Quaternion_normalized, METH_NOARGS, Quaternion_normalized_doc},
1423 
1424  /* return converted representation */
1425  {"to_euler", (PyCFunction)Quaternion_to_euler, METH_VARARGS, Quaternion_to_euler_doc},
1426  {"to_matrix", (PyCFunction)Quaternion_to_matrix, METH_NOARGS, Quaternion_to_matrix_doc},
1427  {"to_axis_angle",
1428  (PyCFunction)Quaternion_to_axis_angle,
1429  METH_NOARGS,
1430  Quaternion_to_axis_angle_doc},
1431  {"to_swing_twist",
1432  (PyCFunction)Quaternion_to_swing_twist,
1433  METH_O,
1434  Quaternion_to_swing_twist_doc},
1435  {"to_exponential_map",
1436  (PyCFunction)Quaternion_to_exponential_map,
1437  METH_NOARGS,
1438  Quaternion_to_exponential_map_doc},
1439 
1440  /* operation between 2 or more types */
1441  {"cross", (PyCFunction)Quaternion_cross, METH_O, Quaternion_cross_doc},
1442  {"dot", (PyCFunction)Quaternion_dot, METH_O, Quaternion_dot_doc},
1443  {"rotation_difference",
1444  (PyCFunction)Quaternion_rotation_difference,
1445  METH_O,
1446  Quaternion_rotation_difference_doc},
1447  {"slerp", (PyCFunction)Quaternion_slerp, METH_VARARGS, Quaternion_slerp_doc},
1448  {"rotate", (PyCFunction)Quaternion_rotate, METH_O, Quaternion_rotate_doc},
1449  {"make_compatible",
1450  (PyCFunction)Quaternion_make_compatible,
1451  METH_O,
1452  Quaternion_make_compatible_doc},
1453 
1454  /* base-math methods */
1455  {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
1456 
1457  {"copy", (PyCFunction)Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
1458  {"__copy__", (PyCFunction)Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
1459  {"__deepcopy__", (PyCFunction)Quaternion_deepcopy, METH_VARARGS, Quaternion_copy_doc},
1460  {NULL, NULL, 0, NULL},
1461 };
1462 
1463 /*****************************************************************************/
1464 /* Python attributes get/set structure: */
1465 /*****************************************************************************/
1466 static PyGetSetDef Quaternion_getseters[] = {
1467  {"w",
1468  (getter)Quaternion_axis_get,
1469  (setter)Quaternion_axis_set,
1470  Quaternion_axis_doc,
1471  (void *)0},
1472  {"x",
1473  (getter)Quaternion_axis_get,
1474  (setter)Quaternion_axis_set,
1475  Quaternion_axis_doc,
1476  (void *)1},
1477  {"y",
1478  (getter)Quaternion_axis_get,
1479  (setter)Quaternion_axis_set,
1480  Quaternion_axis_doc,
1481  (void *)2},
1482  {"z",
1483  (getter)Quaternion_axis_get,
1484  (setter)Quaternion_axis_set,
1485  Quaternion_axis_doc,
1486  (void *)3},
1487  {"magnitude", (getter)Quaternion_magnitude_get, (setter)NULL, Quaternion_magnitude_doc, NULL},
1488  {"angle",
1489  (getter)Quaternion_angle_get,
1490  (setter)Quaternion_angle_set,
1491  Quaternion_angle_doc,
1492  NULL},
1493  {"axis",
1496  Quaternion_axis_vector_doc,
1497  NULL},
1498  {"is_wrapped",
1500  (setter)NULL,
1502  NULL},
1503  {"is_frozen",
1505  (setter)NULL,
1507  NULL},
1508  {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
1509  {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
1510 };
1511 
1512 /* ------------------PY_OBECT DEFINITION-------------------------- */
1513 PyDoc_STRVAR(quaternion_doc,
1514  ".. class:: Quaternion([seq, [angle]])\n"
1515  "\n"
1516  " This object gives access to Quaternions in Blender.\n"
1517  "\n"
1518  " :param seq: size 3 or 4\n"
1519  " :type seq: :class:`Vector`\n"
1520  " :param angle: rotation angle, in radians\n"
1521  " :type angle: float\n"
1522  "\n"
1523  " The constructor takes arguments in various forms:\n"
1524  "\n"
1525  " (), *no args*\n"
1526  " Create an identity quaternion\n"
1527  " (*wxyz*)\n"
1528  " Create a quaternion from a ``(w, x, y, z)`` vector.\n"
1529  " (*exponential_map*)\n"
1530  " Create a quaternion from a 3d exponential map vector.\n"
1531  "\n"
1532  " .. seealso:: :meth:`to_exponential_map`\n"
1533  " (*axis, angle*)\n"
1534  " Create a quaternion representing a rotation of *angle* radians over *axis*.\n"
1535  "\n"
1536  " .. seealso:: :meth:`to_axis_angle`\n");
1537 PyTypeObject quaternion_Type = {
1538  PyVarObject_HEAD_INIT(NULL, 0) "Quaternion", /* tp_name */
1539  sizeof(QuaternionObject), /* tp_basicsize */
1540  0, /* tp_itemsize */
1541  (destructor)BaseMathObject_dealloc, /* tp_dealloc */
1542  (printfunc)NULL, /* tp_print */
1543  NULL, /* tp_getattr */
1544  NULL, /* tp_setattr */
1545  NULL, /* tp_compare */
1546  (reprfunc)Quaternion_repr, /* tp_repr */
1547  &Quaternion_NumMethods, /* tp_as_number */
1548  &Quaternion_SeqMethods, /* tp_as_sequence */
1549  &Quaternion_AsMapping, /* tp_as_mapping */
1550  (hashfunc)Quaternion_hash, /* tp_hash */
1551  NULL, /* tp_call */
1552 #ifndef MATH_STANDALONE
1553  (reprfunc)Quaternion_str, /* tp_str */
1554 #else
1555  NULL, /* tp_str */
1556 #endif
1557  NULL, /* tp_getattro */
1558  NULL, /* tp_setattro */
1559  NULL, /* tp_as_buffer */
1560  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1561  quaternion_doc, /* tp_doc */
1562  (traverseproc)BaseMathObject_traverse, /* tp_traverse */
1563  (inquiry)BaseMathObject_clear, /* tp_clear */
1564  (richcmpfunc)Quaternion_richcmpr, /* tp_richcompare */
1565  0, /* tp_weaklistoffset */
1566  NULL, /* tp_iter */
1567  NULL, /* tp_iternext */
1568  Quaternion_methods, /* tp_methods */
1569  NULL, /* tp_members */
1570  Quaternion_getseters, /* tp_getset */
1571  NULL, /* tp_base */
1572  NULL, /* tp_dict */
1573  NULL, /* tp_descr_get */
1574  NULL, /* tp_descr_set */
1575  0, /* tp_dictoffset */
1576  NULL, /* tp_init */
1577  NULL, /* tp_alloc */
1578  Quaternion_new, /* tp_new */
1579  NULL, /* tp_free */
1580  NULL, /* tp_is_gc */
1581  NULL, /* tp_bases */
1582  NULL, /* tp_mro */
1583  NULL, /* tp_cache */
1584  NULL, /* tp_subclasses */
1585  NULL, /* tp_weaklist */
1586  NULL, /* tp_del */
1587 };
1588 
1589 PyObject *Quaternion_CreatePyObject(const float quat[4], PyTypeObject *base_type)
1590 {
1591  QuaternionObject *self;
1592  float *quat_alloc;
1593 
1594  quat_alloc = PyMem_Malloc(QUAT_SIZE * sizeof(float));
1595  if (UNLIKELY(quat_alloc == NULL)) {
1596  PyErr_SetString(PyExc_MemoryError,
1597  "Quaternion(): "
1598  "problem allocating data");
1599  return NULL;
1600  }
1601 
1602  self = BASE_MATH_NEW(QuaternionObject, quaternion_Type, base_type);
1603  if (self) {
1604  self->quat = quat_alloc;
1605  /* init callbacks as NULL */
1606  self->cb_user = NULL;
1607  self->cb_type = self->cb_subtype = 0;
1608 
1609  /* NEW */
1610  if (!quat) { /* new empty */
1611  unit_qt(self->quat);
1612  }
1613  else {
1614  copy_qt_qt(self->quat, quat);
1615  }
1616  self->flag = BASE_MATH_FLAG_DEFAULT;
1617  }
1618  else {
1619  PyMem_Free(quat_alloc);
1620  }
1621 
1622  return (PyObject *)self;
1623 }
1624 
1625 PyObject *Quaternion_CreatePyObject_wrap(float quat[4], PyTypeObject *base_type)
1626 {
1627  QuaternionObject *self;
1628 
1629  self = BASE_MATH_NEW(QuaternionObject, quaternion_Type, base_type);
1630  if (self) {
1631  /* init callbacks as NULL */
1632  self->cb_user = NULL;
1633  self->cb_type = self->cb_subtype = 0;
1634 
1635  /* WRAP */
1636  self->quat = quat;
1638  }
1639  return (PyObject *)self;
1640 }
1641 
1642 PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar cb_subtype)
1643 {
1645  if (self) {
1646  Py_INCREF(cb_user);
1647  self->cb_user = cb_user;
1648  self->cb_type = cb_type;
1649  self->cb_subtype = cb_subtype;
1650  PyObject_GC_Track(self);
1651  }
1652 
1653  return (PyObject *)self;
1654 }
typedef float(TangentPoint)[2]
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define ATTR_FALLTHROUGH
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_dynstr.c:71
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
MINLINE float saacos(float fac)
double double_round(double x, int ndigits)
Definition: math_base.c:47
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
Definition: math_matrix.c:391
void quat_to_eulO(float eul[3], const short order, const float quat[4])
void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q2[4])
void mul_qt_fl(float q[4], const float f)
@ EULER_ORDER_XYZ
void mat3_to_quat(float q[4], const float mat[3][3])
void axis_angle_to_quat(float r[4], const float axis[3], const float angle)
float normalize_qt(float q[4])
void invert_qt(float q[4])
void mul_qt_v3(const float q[4], float r[3])
Definition: math_rotation.c:97
void unit_qt(float q[4])
Definition: math_rotation.c:46
void quat_to_compatible_eulO(float eul[3], const float old[3], const short order, const float quat[4])
void quat_to_eul(float eul[3], const float quat[4])
float normalize_qt_qt(float r[4], const float q[4])
float dot_qtqt(const float a[4], const float b[4])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
Definition: math_rotation.c:65
void quat_to_axis_angle(float axis[3], float *angle, const float q[4])
void quat_to_expmap(float expmap[3], const float q[4])
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t)
void conjugate_qt(float q[4])
void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4])
void copy_qt_qt(float q[4], const float a[4])
Definition: math_rotation.c:52
float angle_wrap_rad(float angle)
void quat_to_compatible_quat(float q[4], const float a[4], const float old[4])
void quat_to_mat3(float mat[3][3], const float q[4])
void expmap_to_quat(float r[4], const float expmap[3])
float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4])
void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void mul_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, const int size)
Definition: math_vector.c:1230
void mul_vn_vn(float *array_tar, const float *array_src, const int size)
Definition: math_vector.c:1220
MINLINE void negate_v4_v4(float r[4], const float a[3])
unsigned char uchar
Definition: BLI_sys_types.h:86
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define UNLIKELY(x)
#define MIN2(a, b)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint order
Group RGB to Bright Vector Camera CLAMP
PyObject * self
Definition: bpy_driver.c:185
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
int count
#define sqrtf(x)
PyObject * BaseMathObject_freeze(BaseMathObject *self)
Definition: mathutils.c:698
PyObject * BaseMathObject_is_frozen_get(BaseMathObject *self, void *UNUSED(closure))
Definition: mathutils.c:685
int EXPP_FloatsAreEqual(float af, float bf, int maxDiff)
Definition: mathutils.c:533
PyObject * BaseMathObject_is_wrapped_get(BaseMathObject *self, void *UNUSED(closure))
Definition: mathutils.c:678
PyObject * mathutils_dynstr_to_py(struct DynStr *ds)
Definition: mathutils.c:564
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
Definition: mathutils.c:85
void BaseMathObject_dealloc(BaseMathObject *self)
Definition: mathutils.c:722
int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps)
Definition: mathutils.c:551
PyObject * BaseMathObject_owner_get(BaseMathObject *self, void *UNUSED(closure))
Definition: mathutils.c:670
char BaseMathObject_is_wrapped_doc[]
Definition: mathutils.c:676
char BaseMathObject_is_frozen_doc[]
Definition: mathutils.c:683
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
Definition: mathutils.c:118
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
Definition: mathutils.c:471
char BaseMathObject_owner_doc[]
Definition: mathutils.c:669
char BaseMathObject_freeze_doc[]
Definition: mathutils.c:690
int BaseMathObject_clear(BaseMathObject *self)
Definition: mathutils.c:716
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
Definition: mathutils.c:710
#define BaseMath_ReadCallback_ForWrite(_self)
Definition: mathutils.h:138
#define BaseMath_ReadIndexCallback(_self, _index)
Definition: mathutils.h:132
#define BaseMath_WriteCallback(_self)
Definition: mathutils.h:130
#define BASE_MATH_NEW(struct_name, root_type, base_type)
Definition: mathutils.h:33
#define BaseMathObject_Prepare_ForHash(_self)
Definition: mathutils.h:153
@ BASE_MATH_FLAG_IS_WRAP
Definition: mathutils.h:44
#define BASE_MATH_FLAG_DEFAULT
Definition: mathutils.h:51
#define BaseMath_Prepare_ForWrite(_self)
Definition: mathutils.h:148
#define BaseMath_ReadCallback(_self)
Definition: mathutils.h:128
#define BaseMath_WriteIndexCallback(_self, _index)
Definition: mathutils.h:134
short euler_order_from_string(const char *str, const char *error_prefix)
PyTypeObject euler_Type
PyObject * Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
PyObject * Matrix_CreatePyObject(const float *mat, const ushort num_col, const ushort num_row, PyTypeObject *base_type)
static PyObject * Quaternion_normalized(QuaternionObject *self)
static PyObject * Quaternion_neg(QuaternionObject *self)
static PyObject * Quaternion_axis_vector_get(QuaternionObject *self, void *UNUSED(closure))
static int Quaternion_axis_vector_set(QuaternionObject *self, PyObject *value, void *UNUSED(closure))
static PyObject * Quaternion_to_matrix(QuaternionObject *self)
static PyObject * Quaternion_inverted(QuaternionObject *self)
static PyObject * Quaternion_to_euler(QuaternionObject *self, PyObject *args)
static PyObject * Quaternion_repr(QuaternionObject *self)
static PyObject * Quaternion_normalize(QuaternionObject *self)
static PyObject * Quaternion_matmul(PyObject *q1, PyObject *q2)
static PySequenceMethods Quaternion_SeqMethods
static int Quaternion_len(QuaternionObject *UNUSED(self))
static PyMappingMethods Quaternion_AsMapping
static PyObject * Quaternion_imatmul(PyObject *q1, PyObject *q2)
static PyGetSetDef Quaternion_getseters[]
static int Quaternion_angle_set(QuaternionObject *self, PyObject *value, void *UNUSED(closure))
static PyObject * Quaternion_cross(QuaternionObject *self, PyObject *value)
static PyObject * Quaternion_invert(QuaternionObject *self)
static PyObject * Quaternion_make_compatible(QuaternionObject *self, PyObject *value)
PyObject * Quaternion_CreatePyObject(const float quat[4], PyTypeObject *base_type)
static PyObject * Quaternion_identity(QuaternionObject *self)
static PyObject * Quaternion_angle_get(QuaternionObject *self, void *UNUSED(closure))
PyDoc_STRVAR(Quaternion_to_euler_doc, ".. method:: to_euler(order, euler_compat)\n" "\n" " Return Euler representation of the quaternion.\n" "\n" " :arg order: Optional rotation order argument in\n" " ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n" " :type order: string\n" " :arg euler_compat: Optional euler argument the new euler will be made\n" " compatible with (no axis flipping between them).\n" " Useful for converting a series of matrices to animation curves.\n" " :type euler_compat: :class:`Euler`\n" " :return: Euler representation of the quaternion.\n" " :rtype: :class:`Euler`\n")
PyObject * Quaternion_CreatePyObject_wrap(float quat[4], PyTypeObject *base_type)
static PyObject * Quaternion_sub(PyObject *q1, PyObject *q2)
static PyObject * Quaternion_to_exponential_map(QuaternionObject *self)
static PyObject * Quaternion_dot(QuaternionObject *self, PyObject *value)
static PyObject * Quaternion_axis_get(QuaternionObject *self, void *type)
static PyObject * Quaternion_slice(QuaternionObject *self, int begin, int end)
static PyObject * Quaternion_rotation_difference(QuaternionObject *self, PyObject *value)
static void quat__axis_angle_sanitize(float axis[3], float *angle)
static PyObject * Quaternion_conjugate(QuaternionObject *self)
#define QUAT_SIZE
static PyObject * Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
static PyObject * Quaternion_magnitude_get(QuaternionObject *self, void *UNUSED(closure))
static PyObject * Quaternion_to_swing_twist(QuaternionObject *self, PyObject *axis_arg)
static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyObject *value)
PyObject * Quaternion_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar cb_subtype)
static PyObject * Quaternion_str(QuaternionObject *self)
static PyObject * Quaternion_deepcopy(QuaternionObject *self, PyObject *args)
static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq)
static PyObject * Quaternion_mul(PyObject *q1, PyObject *q2)
static PyObject * Quaternion_slerp(QuaternionObject *self, PyObject *args)
static PyObject * Quaternion_negate(QuaternionObject *self)
static PyNumberMethods Quaternion_NumMethods
static PyObject * Quaternion_subscript(QuaternionObject *self, PyObject *item)
static PyObject * Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
static PyObject * Quaternion_item(QuaternionObject *self, int i)
static PyObject * Quaternion_add(PyObject *q1, PyObject *q2)
PyTypeObject quaternion_Type
static PyObject * Quaternion_imul(PyObject *q1, PyObject *q2)
static PyObject * Quaternion_to_axis_angle(QuaternionObject *self)
static PyObject * Quaternion_rotate(QuaternionObject *self, PyObject *value)
static int Quaternion_axis_set(QuaternionObject *self, PyObject *value, void *type)
static PyObject * quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *), QuaternionObject *self)
static Py_hash_t Quaternion_hash(QuaternionObject *self)
static PyObject * quat_mul_float(QuaternionObject *quat, const float scalar)
static PyObject * Quaternion_conjugated(QuaternionObject *self)
static PyObject * Quaternion_copy(QuaternionObject *self)
static PyObject * Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
static struct PyMethodDef Quaternion_methods[]
#define QuaternionObject_Check(v)
PyObject * Vector_CreatePyObject(const float *vec, const int size, PyTypeObject *base_type)
#define VectorObject_Check(v)
bool isfinite(uchar)
Definition: image.cpp:44
static unsigned a[3]
Definition: RandGen.cpp:92
int PyC_CheckArgs_DeepCopy(PyObject *args)
#define PyTuple_SET_ITEMS(op_arg,...)
return ret
uint len