Blender  V3.3
mathutils_Quaternion.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <Python.h>
8 
9 #include "mathutils.h"
10 
11 #include "BLI_math.h"
12 #include "BLI_utildefines.h"
13 
14 #include "../generic/py_capi_utils.h"
15 #include "../generic/python_utildefines.h"
16 
17 #ifndef MATH_STANDALONE
18 # include "BLI_dynstr.h"
19 #endif
20 
21 #define QUAT_SIZE 4
22 
23 static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
24  QuaternionObject *self);
25 static void quat__axis_angle_sanitize(float axis[3], float *angle);
26 static PyObject *Quaternion_copy(QuaternionObject *self);
27 static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args);
28 
29 /* -------------------------------------------------------------------- */
33 static PyObject *quat__apply_to_copy(PyObject *(*quat_func)(QuaternionObject *),
34  QuaternionObject *self)
35 {
36  PyObject *ret = Quaternion_copy(self);
37  PyObject *ret_dummy = quat_func((QuaternionObject *)ret);
38  if (ret_dummy) {
39  Py_DECREF(ret_dummy);
40  return ret;
41  }
42  /* error */
43  Py_DECREF(ret);
44  return NULL;
45 }
46 
48 static void quat__axis_angle_sanitize(float axis[3], float *angle)
49 {
50  if (axis) {
51  if (is_zero_v3(axis) || !isfinite(axis[0]) || !isfinite(axis[1]) || !isfinite(axis[2])) {
52  axis[0] = 1.0f;
53  axis[1] = 0.0f;
54  axis[2] = 0.0f;
55  }
56  else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
57  EXPP_FloatsAreEqual(axis[2], 0.0f, 10)) {
58  axis[0] = 1.0f;
59  }
60  }
61 
62  if (angle) {
63  if (!isfinite(*angle)) {
64  *angle = 0.0f;
65  }
66  }
67 }
68 
72 static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
73 {
74  PyObject *ret;
75  int i;
76 
77  ret = PyTuple_New(QUAT_SIZE);
78 
79  if (ndigits >= 0) {
80  for (i = 0; i < QUAT_SIZE; i++) {
81  PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->quat[i], ndigits)));
82  }
83  }
84  else {
85  for (i = 0; i < QUAT_SIZE; i++) {
86  PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->quat[i]));
87  }
88  }
89 
90  return ret;
91 }
92 
95 /* -------------------------------------------------------------------- */
99 static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
100 {
101  PyObject *seq = NULL;
102  double angle = 0.0f;
103  float quat[QUAT_SIZE];
104  unit_qt(quat);
105 
106  if (kwds && PyDict_Size(kwds)) {
107  PyErr_SetString(PyExc_TypeError,
108  "mathutils.Quaternion(): "
109  "takes no keyword args");
110  return NULL;
111  }
112 
113  if (!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle)) {
114  return NULL;
115  }
116 
117  switch (PyTuple_GET_SIZE(args)) {
118  case 0:
119  break;
120  case 1: {
121  int size;
122 
123  if ((size = mathutils_array_parse(quat, 3, QUAT_SIZE, seq, "mathutils.Quaternion()")) ==
124  -1) {
125  return NULL;
126  }
127 
128  if (size == 4) {
129  /* 4d: Quaternion (common case) */
130  }
131  else {
132  /* 3d: Interpret as exponential map */
133  BLI_assert(size == 3);
134  expmap_to_quat(quat, quat);
135  }
136 
137  break;
138  }
139  case 2: {
140  float axis[3];
141  if (mathutils_array_parse(axis, 3, 3, seq, "mathutils.Quaternion()") == -1) {
142  return NULL;
143  }
144  angle = angle_wrap_rad(angle); /* clamp because of precision issues */
145  axis_angle_to_quat(quat, axis, angle);
146  break;
147  /* PyArg_ParseTuple assures no more than 2 */
148  }
149  }
150  return Quaternion_CreatePyObject(quat, type);
151 }
152 
155 /* -------------------------------------------------------------------- */
159 PyDoc_STRVAR(Quaternion_to_euler_doc,
160  ".. method:: to_euler(order, euler_compat)\n"
161  "\n"
162  " Return Euler representation of the quaternion.\n"
163  "\n"
164  " :arg order: Optional rotation order argument in\n"
165  " ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
166  " :type order: string\n"
167  " :arg euler_compat: Optional euler argument the new euler will be made\n"
168  " compatible with (no axis flipping between them).\n"
169  " Useful for converting a series of matrices to animation curves.\n"
170  " :type euler_compat: :class:`Euler`\n"
171  " :return: Euler representation of the quaternion.\n"
172  " :rtype: :class:`Euler`\n");
173 static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
174 {
175  float tquat[4];
176  float eul[3];
177  const char *order_str = NULL;
178  short order = EULER_ORDER_XYZ;
179  EulerObject *eul_compat = NULL;
180 
181  if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat)) {
182  return NULL;
183  }
184 
185  if (BaseMath_ReadCallback(self) == -1) {
186  return NULL;
187  }
188 
189  if (order_str) {
190  order = euler_order_from_string(order_str, "Quaternion.to_euler()");
191 
192  if (order == -1) {
193  return NULL;
194  }
195  }
196 
197  normalize_qt_qt(tquat, self->quat);
198 
199  if (eul_compat) {
200  if (BaseMath_ReadCallback(eul_compat) == -1) {
201  return NULL;
202  }
203 
204  if (order == EULER_ORDER_XYZ) {
205  quat_to_compatible_eul(eul, eul_compat->eul, tquat);
206  }
207  else {
208  quat_to_compatible_eulO(eul, eul_compat->eul, order, tquat);
209  }
210  }
211  else {
212  if (order == EULER_ORDER_XYZ) {
213  quat_to_eul(eul, tquat);
214  }
215  else {
216  quat_to_eulO(eul, order, tquat);
217  }
218  }
219 
220  return Euler_CreatePyObject(eul, order, NULL);
221 }
222 
225 /* -------------------------------------------------------------------- */
229 PyDoc_STRVAR(Quaternion_to_matrix_doc,
230  ".. method:: to_matrix()\n"
231  "\n"
232  " Return a matrix representation of the quaternion.\n"
233  "\n"
234  " :return: A 3x3 rotation matrix representation of the quaternion.\n"
235  " :rtype: :class:`Matrix`\n");
236 static PyObject *Quaternion_to_matrix(QuaternionObject *self)
237 {
238  float mat[9]; /* all values are set */
239 
240  if (BaseMath_ReadCallback(self) == -1) {
241  return NULL;
242  }
243 
244  quat_to_mat3((float(*)[3])mat, self->quat);
245  return Matrix_CreatePyObject(mat, 3, 3, NULL);
246 }
247 
250 /* -------------------------------------------------------------------- */
254 PyDoc_STRVAR(Quaternion_to_axis_angle_doc,
255  ".. method:: to_axis_angle()\n"
256  "\n"
257  " Return the axis, angle representation of the quaternion.\n"
258  "\n"
259  " :return: axis, angle.\n"
260  " :rtype: (:class:`Vector`, float) pair\n");
262 {
263  PyObject *ret;
264 
265  float tquat[4];
266 
267  float axis[3];
268  float angle;
269 
270  if (BaseMath_ReadCallback(self) == -1) {
271  return NULL;
272  }
273 
274  normalize_qt_qt(tquat, self->quat);
275  quat_to_axis_angle(axis, &angle, tquat);
276 
278 
279  ret = PyTuple_New(2);
280  PyTuple_SET_ITEMS(ret, Vector_CreatePyObject(axis, 3, NULL), PyFloat_FromDouble(angle));
281  return ret;
282 }
283 
286 /* -------------------------------------------------------------------- */
290 PyDoc_STRVAR(Quaternion_to_swing_twist_doc,
291  ".. method:: to_swing_twist(axis)\n"
292  "\n"
293  " Split the rotation into a swing quaternion with the specified\n"
294  " axis fixed at zero, and the remaining twist rotation angle.\n"
295  "\n"
296  " :arg axis: twist axis as a string in ['X', 'Y', 'Z']\n"
297  " :return: swing, twist angle.\n"
298  " :rtype: (:class:`Quaternion`, float) pair\n");
299 static PyObject *Quaternion_to_swing_twist(QuaternionObject *self, PyObject *axis_arg)
300 {
301  PyObject *ret;
302 
303  const char *axis_str = NULL;
304  float swing[4], twist;
305  int axis;
306 
307  if (axis_arg && PyUnicode_Check(axis_arg)) {
308  axis_str = PyUnicode_AsUTF8(axis_arg);
309  }
310 
311  if (axis_str && axis_str[0] >= 'X' && axis_str[0] <= 'Z' && axis_str[1] == 0) {
312  axis = axis_str[0] - 'X';
313  }
314  else {
315  PyErr_SetString(PyExc_ValueError,
316  "Quaternion.to_swing_twist(): "
317  "the axis argument must be "
318  "a string in 'X', 'Y', 'Z'");
319  return NULL;
320  }
321 
322  if (BaseMath_ReadCallback(self) == -1) {
323  return NULL;
324  }
325 
326  twist = quat_split_swing_and_twist(self->quat, axis, swing, NULL);
327 
328  ret = PyTuple_New(2);
330  ret, Quaternion_CreatePyObject(swing, Py_TYPE(self)), PyFloat_FromDouble(twist));
331  return ret;
332 }
333 
336 /* -------------------------------------------------------------------- */
341  Quaternion_to_exponential_map_doc,
342  ".. method:: to_exponential_map()\n"
343  "\n"
344  " Return the exponential map representation of the quaternion.\n"
345  "\n"
346  " This representation consist of the rotation axis multiplied by the rotation angle.\n"
347  " Such a representation is useful for interpolation between multiple orientations.\n"
348  "\n"
349  " :return: exponential map.\n"
350  " :rtype: :class:`Vector` of size 3\n"
351  "\n"
352  " To convert back to a quaternion, pass it to the :class:`Quaternion` constructor.\n");
354 {
355  float expmap[3];
356 
357  if (BaseMath_ReadCallback(self) == -1) {
358  return NULL;
359  }
360 
361  quat_to_expmap(expmap, self->quat);
362  return Vector_CreatePyObject(expmap, 3, NULL);
363 }
364 
367 /* -------------------------------------------------------------------- */
371 PyDoc_STRVAR(Quaternion_cross_doc,
372  ".. method:: cross(other)\n"
373  "\n"
374  " Return the cross product of this quaternion and another.\n"
375  "\n"
376  " :arg other: The other quaternion to perform the cross product with.\n"
377  " :type other: :class:`Quaternion`\n"
378  " :return: The cross product.\n"
379  " :rtype: :class:`Quaternion`\n");
380 static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value)
381 {
382  float quat[QUAT_SIZE], tquat[QUAT_SIZE];
383 
384  if (BaseMath_ReadCallback(self) == -1) {
385  return NULL;
386  }
387 
389  tquat, QUAT_SIZE, QUAT_SIZE, value, "Quaternion.cross(other), invalid 'other' arg") ==
390  -1) {
391  return NULL;
392  }
393 
394  mul_qt_qtqt(quat, self->quat, tquat);
395  return Quaternion_CreatePyObject(quat, Py_TYPE(self));
396 }
397 
400 /* -------------------------------------------------------------------- */
404 PyDoc_STRVAR(Quaternion_dot_doc,
405  ".. method:: dot(other)\n"
406  "\n"
407  " Return the dot product of this quaternion and another.\n"
408  "\n"
409  " :arg other: The other quaternion to perform the dot product with.\n"
410  " :type other: :class:`Quaternion`\n"
411  " :return: The dot product.\n"
412  " :rtype: float\n");
413 static PyObject *Quaternion_dot(QuaternionObject *self, PyObject *value)
414 {
415  float tquat[QUAT_SIZE];
416 
417  if (BaseMath_ReadCallback(self) == -1) {
418  return NULL;
419  }
420 
422  tquat, QUAT_SIZE, QUAT_SIZE, value, "Quaternion.dot(other), invalid 'other' arg") ==
423  -1) {
424  return NULL;
425  }
426 
427  return PyFloat_FromDouble(dot_qtqt(self->quat, tquat));
428 }
429 
432 /* -------------------------------------------------------------------- */
436 PyDoc_STRVAR(Quaternion_rotation_difference_doc,
437  ".. function:: rotation_difference(other)\n"
438  "\n"
439  " Returns a quaternion representing the rotational difference.\n"
440  "\n"
441  " :arg other: second quaternion.\n"
442  " :type other: :class:`Quaternion`\n"
443  " :return: the rotational difference between the two quat rotations.\n"
444  " :rtype: :class:`Quaternion`\n");
445 static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject *value)
446 {
447  float tquat[QUAT_SIZE], quat[QUAT_SIZE];
448 
449  if (BaseMath_ReadCallback(self) == -1) {
450  return NULL;
451  }
452 
453  if (mathutils_array_parse(tquat,
454  QUAT_SIZE,
455  QUAT_SIZE,
456  value,
457  "Quaternion.rotation_difference(other), invalid 'other' arg") == -1) {
458  return NULL;
459  }
460 
461  rotation_between_quats_to_quat(quat, self->quat, tquat);
462 
463  return Quaternion_CreatePyObject(quat, Py_TYPE(self));
464 }
465 
468 /* -------------------------------------------------------------------- */
472 PyDoc_STRVAR(Quaternion_slerp_doc,
473  ".. function:: slerp(other, factor)\n"
474  "\n"
475  " Returns the interpolation of two quaternions.\n"
476  "\n"
477  " :arg other: value to interpolate with.\n"
478  " :type other: :class:`Quaternion`\n"
479  " :arg factor: The interpolation value in [0.0, 1.0].\n"
480  " :type factor: float\n"
481  " :return: The interpolated rotation.\n"
482  " :rtype: :class:`Quaternion`\n");
483 static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args)
484 {
485  PyObject *value;
486  float tquat[QUAT_SIZE], quat[QUAT_SIZE], fac;
487 
488  if (!PyArg_ParseTuple(args, "Of:slerp", &value, &fac)) {
489  PyErr_SetString(PyExc_TypeError,
490  "quat.slerp(): "
491  "expected Quaternion types and float");
492  return NULL;
493  }
494 
495  if (BaseMath_ReadCallback(self) == -1) {
496  return NULL;
497  }
498 
500  tquat, QUAT_SIZE, QUAT_SIZE, value, "Quaternion.slerp(other), invalid 'other' arg") ==
501  -1) {
502  return NULL;
503  }
504 
505  if (fac > 1.0f || fac < 0.0f) {
506  PyErr_SetString(PyExc_ValueError,
507  "quat.slerp(): "
508  "interpolation factor must be between 0.0 and 1.0");
509  return NULL;
510  }
511 
512  interp_qt_qtqt(quat, self->quat, tquat, fac);
513 
514  return Quaternion_CreatePyObject(quat, Py_TYPE(self));
515 }
516 
519 /* -------------------------------------------------------------------- */
523 PyDoc_STRVAR(Quaternion_rotate_doc,
524  ".. method:: rotate(other)\n"
525  "\n"
526  " Rotates the quaternion by another mathutils value.\n"
527  "\n"
528  " :arg other: rotation component of mathutils value\n"
529  " :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n");
530 static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value)
531 {
532  float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
533  float tquat[4], length;
534 
535  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
536  return NULL;
537  }
538 
539  if (mathutils_any_to_rotmat(other_rmat, value, "Quaternion.rotate(value)") == -1) {
540  return NULL;
541  }
542 
543  length = normalize_qt_qt(tquat, self->quat);
544  quat_to_mat3(self_rmat, tquat);
545  mul_m3_m3m3(rmat, other_rmat, self_rmat);
546  normalize_m3(rmat);
547  /* This check could also be performed on `other_rmat`, use the final result instead to ensure
548  * float imprecision doesn't allow the multiplication to make `rmat` negative. */
549  if (is_negative_m3(rmat)) {
550  negate_m3(rmat);
551  }
552  mat3_normalized_to_quat(self->quat, rmat);
553  mul_qt_fl(self->quat, length); /* maintain length after rotating */
554 
556  Py_RETURN_NONE;
557 }
558 
559 PyDoc_STRVAR(Quaternion_make_compatible_doc,
560  ".. method:: make_compatible(other)\n"
561  "\n"
562  " Make this quaternion compatible with another,\n"
563  " so interpolating between them works as intended.\n");
564 static PyObject *Quaternion_make_compatible(QuaternionObject *self, PyObject *value)
565 {
566  float quat[QUAT_SIZE];
567  float tquat[QUAT_SIZE];
568 
569  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
570  return NULL;
571  }
572 
573  if (mathutils_array_parse(tquat,
574  QUAT_SIZE,
575  QUAT_SIZE,
576  value,
577  "Quaternion.make_compatible(other), invalid 'other' arg") == -1) {
578  return NULL;
579  }
580 
581  /* Can only operate on unit length quaternions. */
582  const float quat_len = normalize_qt_qt(quat, self->quat);
583  quat_to_compatible_quat(self->quat, quat, tquat);
584  mul_qt_fl(self->quat, quat_len);
585 
587 
588  Py_RETURN_NONE;
589 }
590 
593 /* -------------------------------------------------------------------- */
600 PyDoc_STRVAR(Quaternion_normalize_doc,
601  ".. function:: normalize()\n"
602  "\n"
603  " Normalize the quaternion.\n");
604 static PyObject *Quaternion_normalize(QuaternionObject *self)
605 {
606  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
607  return NULL;
608  }
609 
610  normalize_qt(self->quat);
611 
613  Py_RETURN_NONE;
614 }
615 PyDoc_STRVAR(Quaternion_normalized_doc,
616  ".. function:: normalized()\n"
617  "\n"
618  " Return a new normalized quaternion.\n"
619  "\n"
620  " :return: a normalized copy.\n"
621  " :rtype: :class:`Quaternion`\n");
623 {
625 }
626 
629 /* -------------------------------------------------------------------- */
636 PyDoc_STRVAR(Quaternion_invert_doc,
637  ".. function:: invert()\n"
638  "\n"
639  " Set the quaternion to its inverse.\n");
640 static PyObject *Quaternion_invert(QuaternionObject *self)
641 {
642  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
643  return NULL;
644  }
645 
646  invert_qt(self->quat);
647 
649  Py_RETURN_NONE;
650 }
651 PyDoc_STRVAR(Quaternion_inverted_doc,
652  ".. function:: inverted()\n"
653  "\n"
654  " Return a new, inverted quaternion.\n"
655  "\n"
656  " :return: the inverted value.\n"
657  " :rtype: :class:`Quaternion`\n");
658 static PyObject *Quaternion_inverted(QuaternionObject *self)
659 {
661 }
662 
665 /* -------------------------------------------------------------------- */
669 PyDoc_STRVAR(Quaternion_identity_doc,
670  ".. function:: identity()\n"
671  "\n"
672  " Set the quaternion to an identity quaternion.\n"
673  "\n"
674  " :rtype: :class:`Quaternion`\n");
675 static PyObject *Quaternion_identity(QuaternionObject *self)
676 {
677  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
678  return NULL;
679  }
680 
681  unit_qt(self->quat);
682 
684  Py_RETURN_NONE;
685 }
686 
689 /* -------------------------------------------------------------------- */
693 PyDoc_STRVAR(Quaternion_negate_doc,
694  ".. function:: negate()\n"
695  "\n"
696  " Set the quaternion to its negative.\n"
697  "\n"
698  " :rtype: :class:`Quaternion`\n");
699 static PyObject *Quaternion_negate(QuaternionObject *self)
700 {
701  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
702  return NULL;
703  }
704 
705  mul_qt_fl(self->quat, -1.0f);
706 
708  Py_RETURN_NONE;
709 }
710 
713 /* -------------------------------------------------------------------- */
717 PyDoc_STRVAR(Quaternion_conjugate_doc,
718  ".. function:: conjugate()\n"
719  "\n"
720  " Set the quaternion to its conjugate (negate x, y, z).\n");
721 static PyObject *Quaternion_conjugate(QuaternionObject *self)
722 {
723  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
724  return NULL;
725  }
726 
727  conjugate_qt(self->quat);
728 
730  Py_RETURN_NONE;
731 }
732 PyDoc_STRVAR(Quaternion_conjugated_doc,
733  ".. function:: conjugated()\n"
734  "\n"
735  " Return a new conjugated quaternion.\n"
736  "\n"
737  " :return: a new quaternion.\n"
738  " :rtype: :class:`Quaternion`\n");
740 {
742 }
743 
746 /* -------------------------------------------------------------------- */
750 PyDoc_STRVAR(Quaternion_copy_doc,
751  ".. function:: copy()\n"
752  "\n"
753  " Returns a copy of this quaternion.\n"
754  "\n"
755  " :return: A copy of the quaternion.\n"
756  " :rtype: :class:`Quaternion`\n"
757  "\n"
758  " .. note:: use this to get a copy of a wrapped quaternion with\n"
759  " no reference to the original data.\n");
760 static PyObject *Quaternion_copy(QuaternionObject *self)
761 {
762  if (BaseMath_ReadCallback(self) == -1) {
763  return NULL;
764  }
765 
766  return Quaternion_CreatePyObject(self->quat, Py_TYPE(self));
767 }
768 static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args)
769 {
770  if (!PyC_CheckArgs_DeepCopy(args)) {
771  return NULL;
772  }
773  return Quaternion_copy(self);
774 }
775 
778 /* -------------------------------------------------------------------- */
782 static PyObject *Quaternion_repr(QuaternionObject *self)
783 {
784  PyObject *ret, *tuple;
785 
786  if (BaseMath_ReadCallback(self) == -1) {
787  return NULL;
788  }
789 
790  tuple = Quaternion_to_tuple_ext(self, -1);
791 
792  ret = PyUnicode_FromFormat("Quaternion(%R)", tuple);
793 
794  Py_DECREF(tuple);
795  return ret;
796 }
797 
798 #ifndef MATH_STANDALONE
799 static PyObject *Quaternion_str(QuaternionObject *self)
800 {
801  DynStr *ds;
802 
803  if (BaseMath_ReadCallback(self) == -1) {
804  return NULL;
805  }
806 
807  ds = BLI_dynstr_new();
808 
810  "<Quaternion (w=%.4f, x=%.4f, y=%.4f, z=%.4f)>",
811  self->quat[0],
812  self->quat[1],
813  self->quat[2],
814  self->quat[3]);
815 
816  return mathutils_dynstr_to_py(ds); /* frees ds */
817 }
818 #endif
819 
822 /* -------------------------------------------------------------------- */
826 static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
827 {
828  PyObject *res;
829  int ok = -1; /* zero is true */
830 
832  QuaternionObject *quatA = (QuaternionObject *)a;
833  QuaternionObject *quatB = (QuaternionObject *)b;
834 
835  if (BaseMath_ReadCallback(quatA) == -1 || BaseMath_ReadCallback(quatB) == -1) {
836  return NULL;
837  }
838 
839  ok = (EXPP_VectorsAreEqual(quatA->quat, quatB->quat, QUAT_SIZE, 1)) ? 0 : -1;
840  }
841 
842  switch (op) {
843  case Py_NE:
844  ok = !ok;
846  case Py_EQ:
847  res = ok ? Py_False : Py_True;
848  break;
849 
850  case Py_LT:
851  case Py_LE:
852  case Py_GT:
853  case Py_GE:
854  res = Py_NotImplemented;
855  break;
856  default:
857  PyErr_BadArgument();
858  return NULL;
859  }
860 
861  return Py_INCREF_RET(res);
862 }
863 
866 /* -------------------------------------------------------------------- */
870 static Py_hash_t Quaternion_hash(QuaternionObject *self)
871 {
872  if (BaseMath_ReadCallback(self) == -1) {
873  return -1;
874  }
875 
876  if (BaseMathObject_Prepare_ForHash(self) == -1) {
877  return -1;
878  }
879 
880  return mathutils_array_hash(self->quat, QUAT_SIZE);
881 }
882 
885 /* -------------------------------------------------------------------- */
891 {
892  return QUAT_SIZE;
893 }
894 
896 static PyObject *Quaternion_item(QuaternionObject *self, int i)
897 {
898  if (i < 0) {
899  i = QUAT_SIZE - i;
900  }
901 
902  if (i < 0 || i >= QUAT_SIZE) {
903  PyErr_SetString(PyExc_IndexError,
904  "quaternion[attribute]: "
905  "array index out of range");
906  return NULL;
907  }
908 
909  if (BaseMath_ReadIndexCallback(self, i) == -1) {
910  return NULL;
911  }
912 
913  return PyFloat_FromDouble(self->quat[i]);
914 }
915 
917 static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
918 {
919  float f;
920 
921  if (BaseMath_Prepare_ForWrite(self) == -1) {
922  return -1;
923  }
924 
925  f = (float)PyFloat_AsDouble(ob);
926 
927  if (f == -1.0f && PyErr_Occurred()) { /* parsed item not a number */
928  PyErr_SetString(PyExc_TypeError,
929  "quaternion[index] = x: "
930  "assigned value not a number");
931  return -1;
932  }
933 
934  if (i < 0) {
935  i = QUAT_SIZE - i;
936  }
937 
938  if (i < 0 || i >= QUAT_SIZE) {
939  PyErr_SetString(PyExc_IndexError,
940  "quaternion[attribute] = x: "
941  "array assignment index out of range");
942  return -1;
943  }
944  self->quat[i] = f;
945 
946  if (BaseMath_WriteIndexCallback(self, i) == -1) {
947  return -1;
948  }
949 
950  return 0;
951 }
952 
954 static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end)
955 {
956  PyObject *tuple;
957  int count;
958 
959  if (BaseMath_ReadCallback(self) == -1) {
960  return NULL;
961  }
962 
963  CLAMP(begin, 0, QUAT_SIZE);
964  if (end < 0) {
965  end = (QUAT_SIZE + 1) + end;
966  }
967  CLAMP(end, 0, QUAT_SIZE);
968  begin = MIN2(begin, end);
969 
970  tuple = PyTuple_New(end - begin);
971  for (count = begin; count < end; count++) {
972  PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->quat[count]));
973  }
974 
975  return tuple;
976 }
977 
979 static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq)
980 {
981  int i, size;
982  float quat[QUAT_SIZE];
983 
984  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
985  return -1;
986  }
987 
988  CLAMP(begin, 0, QUAT_SIZE);
989  if (end < 0) {
990  end = (QUAT_SIZE + 1) + end;
991  }
992  CLAMP(end, 0, QUAT_SIZE);
993  begin = MIN2(begin, end);
994 
996  quat, 0, QUAT_SIZE, seq, "mathutils.Quaternion[begin:end] = []")) == -1) {
997  return -1;
998  }
999 
1000  if (size != (end - begin)) {
1001  PyErr_SetString(PyExc_ValueError,
1002  "quaternion[begin:end] = []: "
1003  "size mismatch in slice assignment");
1004  return -1;
1005  }
1006 
1007  /* Parsed well, now set in vector. */
1008  for (i = 0; i < size; i++) {
1009  self->quat[begin + i] = quat[i];
1010  }
1011 
1013  return 0;
1014 }
1015 
1017 static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
1018 {
1019  if (PyIndex_Check(item)) {
1020  Py_ssize_t i;
1021  i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1022  if (i == -1 && PyErr_Occurred()) {
1023  return NULL;
1024  }
1025  if (i < 0) {
1026  i += QUAT_SIZE;
1027  }
1028  return Quaternion_item(self, i);
1029  }
1030  if (PySlice_Check(item)) {
1031  Py_ssize_t start, stop, step, slicelength;
1032 
1033  if (PySlice_GetIndicesEx(item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0) {
1034  return NULL;
1035  }
1036 
1037  if (slicelength <= 0) {
1038  return PyTuple_New(0);
1039  }
1040  if (step == 1) {
1041  return Quaternion_slice(self, start, stop);
1042  }
1043 
1044  PyErr_SetString(PyExc_IndexError, "slice steps not supported with quaternions");
1045  return NULL;
1046  }
1047 
1048  PyErr_Format(
1049  PyExc_TypeError, "quaternion indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
1050  return NULL;
1051 }
1052 
1054 static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyObject *value)
1055 {
1056  if (PyIndex_Check(item)) {
1057  Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
1058  if (i == -1 && PyErr_Occurred()) {
1059  return -1;
1060  }
1061  if (i < 0) {
1062  i += QUAT_SIZE;
1063  }
1064  return Quaternion_ass_item(self, i, value);
1065  }
1066  if (PySlice_Check(item)) {
1067  Py_ssize_t start, stop, step, slicelength;
1068 
1069  if (PySlice_GetIndicesEx(item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0) {
1070  return -1;
1071  }
1072 
1073  if (step == 1) {
1074  return Quaternion_ass_slice(self, start, stop, value);
1075  }
1076 
1077  PyErr_SetString(PyExc_IndexError, "slice steps not supported with quaternion");
1078  return -1;
1079  }
1080 
1081  PyErr_Format(
1082  PyExc_TypeError, "quaternion indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
1083  return -1;
1084 }
1085 
1088 /* -------------------------------------------------------------------- */
1093 static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
1094 {
1095  float quat[QUAT_SIZE];
1096  QuaternionObject *quat1 = NULL, *quat2 = NULL;
1097 
1099  PyErr_Format(PyExc_TypeError,
1100  "Quaternion addition: (%s + %s) "
1101  "invalid type for this operation",
1102  Py_TYPE(q1)->tp_name,
1103  Py_TYPE(q2)->tp_name);
1104  return NULL;
1105  }
1106  quat1 = (QuaternionObject *)q1;
1107  quat2 = (QuaternionObject *)q2;
1108 
1109  if (BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1) {
1110  return NULL;
1111  }
1112 
1113  add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f);
1114  return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
1115 }
1116 
1118 static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2)
1119 {
1120  int x;
1121  float quat[QUAT_SIZE];
1122  QuaternionObject *quat1 = NULL, *quat2 = NULL;
1123 
1125  PyErr_Format(PyExc_TypeError,
1126  "Quaternion subtraction: (%s - %s) "
1127  "invalid type for this operation",
1128  Py_TYPE(q1)->tp_name,
1129  Py_TYPE(q2)->tp_name);
1130  return NULL;
1131  }
1132 
1133  quat1 = (QuaternionObject *)q1;
1134  quat2 = (QuaternionObject *)q2;
1135 
1136  if (BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1) {
1137  return NULL;
1138  }
1139 
1140  for (x = 0; x < QUAT_SIZE; x++) {
1141  quat[x] = quat1->quat[x] - quat2->quat[x];
1142  }
1143 
1144  return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
1145 }
1146 
1147 static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
1148 {
1149  float tquat[4];
1150  copy_qt_qt(tquat, quat->quat);
1151  mul_qt_fl(tquat, scalar);
1152  return Quaternion_CreatePyObject(tquat, Py_TYPE(quat));
1153 }
1154 
1156 static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
1157 {
1158  float scalar;
1159  QuaternionObject *quat1 = NULL, *quat2 = NULL;
1160 
1161  if (QuaternionObject_Check(q1)) {
1162  quat1 = (QuaternionObject *)q1;
1163  if (BaseMath_ReadCallback(quat1) == -1) {
1164  return NULL;
1165  }
1166  }
1167  if (QuaternionObject_Check(q2)) {
1168  quat2 = (QuaternionObject *)q2;
1169  if (BaseMath_ReadCallback(quat2) == -1) {
1170  return NULL;
1171  }
1172  }
1173 
1174  if (quat1 && quat2) { /* QUAT * QUAT (element-wise product) */
1175  float quat[QUAT_SIZE];
1176  mul_vn_vnvn(quat, quat1->quat, quat2->quat, QUAT_SIZE);
1177  return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
1178  }
1179  /* the only case this can happen (for a supported type is "FLOAT * QUAT") */
1180  if (quat2) { /* FLOAT * QUAT */
1181  if (((scalar = PyFloat_AsDouble(q1)) == -1.0f && PyErr_Occurred()) == 0) {
1182  return quat_mul_float(quat2, scalar);
1183  }
1184  }
1185  else if (quat1) { /* QUAT * FLOAT */
1186  if ((((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
1187  return quat_mul_float(quat1, scalar);
1188  }
1189  }
1190 
1191  PyErr_Format(PyExc_TypeError,
1192  "Element-wise multiplication: "
1193  "not supported between '%.200s' and '%.200s' types",
1194  Py_TYPE(q1)->tp_name,
1195  Py_TYPE(q2)->tp_name);
1196  return NULL;
1197 }
1198 
1200 static PyObject *Quaternion_imul(PyObject *q1, PyObject *q2)
1201 {
1202  float scalar;
1203  QuaternionObject *quat1 = NULL, *quat2 = NULL;
1204 
1205  if (QuaternionObject_Check(q1)) {
1206  quat1 = (QuaternionObject *)q1;
1207  if (BaseMath_ReadCallback(quat1) == -1) {
1208  return NULL;
1209  }
1210  }
1211  if (QuaternionObject_Check(q2)) {
1212  quat2 = (QuaternionObject *)q2;
1213  if (BaseMath_ReadCallback(quat2) == -1) {
1214  return NULL;
1215  }
1216  }
1217 
1218  if (quat1 && quat2) { /* QUAT *= QUAT (in-place element-wise product). */
1219  mul_vn_vn(quat1->quat, quat2->quat, QUAT_SIZE);
1220  }
1221  else if (quat1 && (((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
1222  /* QUAT *= FLOAT */
1223  mul_qt_fl(quat1->quat, scalar);
1224  }
1225  else {
1226  PyErr_Format(PyExc_TypeError,
1227  "Element-wise multiplication: "
1228  "not supported between '%.200s' and '%.200s' types",
1229  Py_TYPE(q1)->tp_name,
1230  Py_TYPE(q2)->tp_name);
1231  return NULL;
1232  }
1233 
1234  (void)BaseMath_WriteCallback(quat1);
1235  Py_INCREF(q1);
1236  return q1;
1237 }
1238 
1240 static PyObject *Quaternion_matmul(PyObject *q1, PyObject *q2)
1241 {
1242  float quat[QUAT_SIZE];
1243  QuaternionObject *quat1 = NULL, *quat2 = NULL;
1244 
1245  if (QuaternionObject_Check(q1)) {
1246  quat1 = (QuaternionObject *)q1;
1247  if (BaseMath_ReadCallback(quat1) == -1) {
1248  return NULL;
1249  }
1250  }
1251  if (QuaternionObject_Check(q2)) {
1252  quat2 = (QuaternionObject *)q2;
1253  if (BaseMath_ReadCallback(quat2) == -1) {
1254  return NULL;
1255  }
1256  }
1257 
1258  if (quat1 && quat2) { /* QUAT @ QUAT (cross product) */
1259  mul_qt_qtqt(quat, quat1->quat, quat2->quat);
1260  return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
1261  }
1262  if (quat1) {
1263  /* QUAT @ VEC */
1264  if (VectorObject_Check(q2)) {
1265  VectorObject *vec2 = (VectorObject *)q2;
1266  float tvec[3];
1267 
1268  if (vec2->vec_num != 3) {
1269  PyErr_SetString(PyExc_ValueError,
1270  "Vector multiplication: "
1271  "only 3D vector rotations (with quats) "
1272  "currently supported");
1273  return NULL;
1274  }
1275  if (BaseMath_ReadCallback(vec2) == -1) {
1276  return NULL;
1277  }
1278 
1279  copy_v3_v3(tvec, vec2->vec);
1280  mul_qt_v3(quat1->quat, tvec);
1281 
1282  return Vector_CreatePyObject(tvec, 3, Py_TYPE(vec2));
1283  }
1284  }
1285 
1286  PyErr_Format(PyExc_TypeError,
1287  "Quaternion multiplication: "
1288  "not supported between '%.200s' and '%.200s' types",
1289  Py_TYPE(q1)->tp_name,
1290  Py_TYPE(q2)->tp_name);
1291  return NULL;
1292 }
1293 
1295 static PyObject *Quaternion_imatmul(PyObject *q1, PyObject *q2)
1296 {
1297  float quat[QUAT_SIZE];
1298  QuaternionObject *quat1 = NULL, *quat2 = NULL;
1299 
1300  if (QuaternionObject_Check(q1)) {
1301  quat1 = (QuaternionObject *)q1;
1302  if (BaseMath_ReadCallback(quat1) == -1) {
1303  return NULL;
1304  }
1305  }
1306  if (QuaternionObject_Check(q2)) {
1307  quat2 = (QuaternionObject *)q2;
1308  if (BaseMath_ReadCallback(quat2) == -1) {
1309  return NULL;
1310  }
1311  }
1312 
1313  if (quat1 && quat2) { /* QUAT @ QUAT (cross product) */
1314  mul_qt_qtqt(quat, quat1->quat, quat2->quat);
1315  copy_qt_qt(quat1->quat, quat);
1316  }
1317  else {
1318  PyErr_Format(PyExc_TypeError,
1319  "In place quaternion multiplication: "
1320  "not supported between '%.200s' and '%.200s' types",
1321  Py_TYPE(q1)->tp_name,
1322  Py_TYPE(q2)->tp_name);
1323  return NULL;
1324  }
1325 
1326  (void)BaseMath_WriteCallback(quat1);
1327  Py_INCREF(q1);
1328  return q1;
1329 }
1330 
1332 static PyObject *Quaternion_neg(QuaternionObject *self)
1333 {
1334  float tquat[QUAT_SIZE];
1335 
1336  if (BaseMath_ReadCallback(self) == -1) {
1337  return NULL;
1338  }
1339 
1340  negate_v4_v4(tquat, self->quat);
1341  return Quaternion_CreatePyObject(tquat, Py_TYPE(self));
1342 }
1343 
1346 /* -------------------------------------------------------------------- */
1350 static PySequenceMethods Quaternion_SeqMethods = {
1351  (lenfunc)Quaternion_len, /*sq_length*/
1352  (binaryfunc)NULL, /*sq_concat*/
1353  (ssizeargfunc)NULL, /*sq_repeat*/
1354  (ssizeargfunc)Quaternion_item, /*sq_item*/
1355  (ssizessizeargfunc)NULL, /*sq_slice(deprecated)*/
1356  (ssizeobjargproc)Quaternion_ass_item, /*sq_ass_item*/
1357  (ssizessizeobjargproc)NULL, /*sq_ass_slice(deprecated)*/
1358  (objobjproc)NULL, /*sq_contains*/
1359  (binaryfunc)NULL, /*sq_inplace_concat*/
1360  (ssizeargfunc)NULL, /*sq_inplace_repeat*/
1361 };
1362 
1363 static PyMappingMethods Quaternion_AsMapping = {
1364  (lenfunc)Quaternion_len,
1365  (binaryfunc)Quaternion_subscript,
1366  (objobjargproc)Quaternion_ass_subscript,
1367 };
1368 
1369 static PyNumberMethods Quaternion_NumMethods = {
1370  (binaryfunc)Quaternion_add, /*nb_add*/
1371  (binaryfunc)Quaternion_sub, /*nb_subtract*/
1372  (binaryfunc)Quaternion_mul, /*nb_multiply*/
1373  NULL, /*nb_remainder*/
1374  NULL, /*nb_divmod*/
1375  NULL, /*nb_power*/
1376  (unaryfunc)Quaternion_neg, /*nb_negative*/
1377  (unaryfunc)Quaternion_copy, /*tp_positive*/
1378  (unaryfunc)0, /*tp_absolute*/
1379  (inquiry)0, /*tp_bool*/
1380  (unaryfunc)0, /*nb_invert*/
1381  NULL, /*nb_lshift*/
1382  (binaryfunc)0, /*nb_rshift*/
1383  NULL, /*nb_and*/
1384  NULL, /*nb_xor*/
1385  NULL, /*nb_or*/
1386  NULL, /*nb_int*/
1387  NULL, /*nb_reserved*/
1388  NULL, /*nb_float*/
1389  NULL, /*nb_inplace_add*/
1390  NULL, /*nb_inplace_subtract*/
1391  (binaryfunc)Quaternion_imul, /*nb_inplace_multiply*/
1392  NULL, /*nb_inplace_remainder*/
1393  NULL, /*nb_inplace_power*/
1394  NULL, /*nb_inplace_lshift*/
1395  NULL, /*nb_inplace_rshift*/
1396  NULL, /*nb_inplace_and*/
1397  NULL, /*nb_inplace_xor*/
1398  NULL, /*nb_inplace_or*/
1399  NULL, /*nb_floor_divide*/
1400  NULL, /*nb_true_divide*/
1401  NULL, /*nb_inplace_floor_divide*/
1402  NULL, /*nb_inplace_true_divide*/
1403  NULL, /*nb_index*/
1404  (binaryfunc)Quaternion_matmul, /*nb_matrix_multiply*/
1405  (binaryfunc)Quaternion_imatmul, /*nb_inplace_matrix_multiply*/
1406 };
1407 
1410 /* -------------------------------------------------------------------- */
1414 PyDoc_STRVAR(Quaternion_axis_doc, "Quaternion axis value.\n\n:type: float");
1415 static PyObject *Quaternion_axis_get(QuaternionObject *self, void *type)
1416 {
1417  return Quaternion_item(self, POINTER_AS_INT(type));
1418 }
1419 
1420 static int Quaternion_axis_set(QuaternionObject *self, PyObject *value, void *type)
1421 {
1422  return Quaternion_ass_item(self, POINTER_AS_INT(type), value);
1423 }
1424 
1425 PyDoc_STRVAR(Quaternion_magnitude_doc, "Size of the quaternion (read-only).\n\n:type: float");
1426 static PyObject *Quaternion_magnitude_get(QuaternionObject *self, void *UNUSED(closure))
1427 {
1428  if (BaseMath_ReadCallback(self) == -1) {
1429  return NULL;
1430  }
1431 
1432  return PyFloat_FromDouble(sqrtf(dot_qtqt(self->quat, self->quat)));
1433 }
1434 
1435 PyDoc_STRVAR(Quaternion_angle_doc, "Angle of the quaternion.\n\n:type: float");
1436 static PyObject *Quaternion_angle_get(QuaternionObject *self, void *UNUSED(closure))
1437 {
1438  float tquat[4];
1439  float angle;
1440 
1441  if (BaseMath_ReadCallback(self) == -1) {
1442  return NULL;
1443  }
1444 
1445  normalize_qt_qt(tquat, self->quat);
1446 
1447  angle = 2.0f * saacos(tquat[0]);
1448 
1450 
1451  return PyFloat_FromDouble(angle);
1452 }
1453 
1454 static int Quaternion_angle_set(QuaternionObject *self, PyObject *value, void *UNUSED(closure))
1455 {
1456  float tquat[4];
1457  float len;
1458 
1459  float axis[3], angle_dummy;
1460  float angle;
1461 
1462  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
1463  return -1;
1464  }
1465 
1466  len = normalize_qt_qt(tquat, self->quat);
1467  quat_to_axis_angle(axis, &angle_dummy, tquat);
1468 
1469  angle = PyFloat_AsDouble(value);
1470 
1471  if (angle == -1.0f && PyErr_Occurred()) { /* parsed item not a number */
1472  PyErr_SetString(PyExc_TypeError, "Quaternion.angle = value: float expected");
1473  return -1;
1474  }
1475 
1477 
1479 
1480  axis_angle_to_quat(self->quat, axis, angle);
1481  mul_qt_fl(self->quat, len);
1482 
1483  if (BaseMath_WriteCallback(self) == -1) {
1484  return -1;
1485  }
1486 
1487  return 0;
1488 }
1489 
1490 PyDoc_STRVAR(Quaternion_axis_vector_doc, "Quaternion axis as a vector.\n\n:type: :class:`Vector`");
1491 static PyObject *Quaternion_axis_vector_get(QuaternionObject *self, void *UNUSED(closure))
1492 {
1493  float tquat[4];
1494 
1495  float axis[3];
1496  float angle_dummy;
1497 
1498  if (BaseMath_ReadCallback(self) == -1) {
1499  return NULL;
1500  }
1501 
1502  normalize_qt_qt(tquat, self->quat);
1503  quat_to_axis_angle(axis, &angle_dummy, tquat);
1504 
1506 
1507  return Vector_CreatePyObject(axis, 3, NULL);
1508 }
1509 
1511  PyObject *value,
1512  void *UNUSED(closure))
1513 {
1514  float tquat[4];
1515  float len;
1516 
1517  float axis[3];
1518  float angle;
1519 
1520  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
1521  return -1;
1522  }
1523 
1524  len = normalize_qt_qt(tquat, self->quat);
1525  quat_to_axis_angle(axis, &angle, tquat); /* axis value is unused */
1526 
1527  if (mathutils_array_parse(axis, 3, 3, value, "quat.axis = other") == -1) {
1528  return -1;
1529  }
1530 
1532 
1533  axis_angle_to_quat(self->quat, axis, angle);
1534  mul_qt_fl(self->quat, len);
1535 
1536  if (BaseMath_WriteCallback(self) == -1) {
1537  return -1;
1538  }
1539 
1540  return 0;
1541 }
1542 
1545 /* -------------------------------------------------------------------- */
1549 static PyGetSetDef Quaternion_getseters[] = {
1550  {"w",
1551  (getter)Quaternion_axis_get,
1552  (setter)Quaternion_axis_set,
1553  Quaternion_axis_doc,
1554  (void *)0},
1555  {"x",
1556  (getter)Quaternion_axis_get,
1557  (setter)Quaternion_axis_set,
1558  Quaternion_axis_doc,
1559  (void *)1},
1560  {"y",
1561  (getter)Quaternion_axis_get,
1562  (setter)Quaternion_axis_set,
1563  Quaternion_axis_doc,
1564  (void *)2},
1565  {"z",
1566  (getter)Quaternion_axis_get,
1567  (setter)Quaternion_axis_set,
1568  Quaternion_axis_doc,
1569  (void *)3},
1570  {"magnitude", (getter)Quaternion_magnitude_get, (setter)NULL, Quaternion_magnitude_doc, NULL},
1571  {"angle",
1572  (getter)Quaternion_angle_get,
1573  (setter)Quaternion_angle_set,
1574  Quaternion_angle_doc,
1575  NULL},
1576  {"axis",
1579  Quaternion_axis_vector_doc,
1580  NULL},
1581  {"is_wrapped",
1583  (setter)NULL,
1585  NULL},
1586  {"is_frozen",
1588  (setter)NULL,
1590  NULL},
1591  {"is_valid",
1593  (setter)NULL,
1595  NULL},
1596  {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
1597  {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
1598 };
1599 
1602 /* -------------------------------------------------------------------- */
1606 static struct PyMethodDef Quaternion_methods[] = {
1607  /* In place only. */
1608  {"identity", (PyCFunction)Quaternion_identity, METH_NOARGS, Quaternion_identity_doc},
1609  {"negate", (PyCFunction)Quaternion_negate, METH_NOARGS, Quaternion_negate_doc},
1610 
1611  /* Operate on original or copy. */
1612  {"conjugate", (PyCFunction)Quaternion_conjugate, METH_NOARGS, Quaternion_conjugate_doc},
1613  {"conjugated", (PyCFunction)Quaternion_conjugated, METH_NOARGS, Quaternion_conjugated_doc},
1614 
1615  {"invert", (PyCFunction)Quaternion_invert, METH_NOARGS, Quaternion_invert_doc},
1616  {"inverted", (PyCFunction)Quaternion_inverted, METH_NOARGS, Quaternion_inverted_doc},
1617 
1618  {"normalize", (PyCFunction)Quaternion_normalize, METH_NOARGS, Quaternion_normalize_doc},
1619  {"normalized", (PyCFunction)Quaternion_normalized, METH_NOARGS, Quaternion_normalized_doc},
1620 
1621  /* Return converted representation. */
1622  {"to_euler", (PyCFunction)Quaternion_to_euler, METH_VARARGS, Quaternion_to_euler_doc},
1623  {"to_matrix", (PyCFunction)Quaternion_to_matrix, METH_NOARGS, Quaternion_to_matrix_doc},
1624  {"to_axis_angle",
1625  (PyCFunction)Quaternion_to_axis_angle,
1626  METH_NOARGS,
1627  Quaternion_to_axis_angle_doc},
1628  {"to_swing_twist",
1629  (PyCFunction)Quaternion_to_swing_twist,
1630  METH_O,
1631  Quaternion_to_swing_twist_doc},
1632  {"to_exponential_map",
1633  (PyCFunction)Quaternion_to_exponential_map,
1634  METH_NOARGS,
1635  Quaternion_to_exponential_map_doc},
1636 
1637  /* Operation between 2 or more types. */
1638  {"cross", (PyCFunction)Quaternion_cross, METH_O, Quaternion_cross_doc},
1639  {"dot", (PyCFunction)Quaternion_dot, METH_O, Quaternion_dot_doc},
1640  {"rotation_difference",
1641  (PyCFunction)Quaternion_rotation_difference,
1642  METH_O,
1643  Quaternion_rotation_difference_doc},
1644  {"slerp", (PyCFunction)Quaternion_slerp, METH_VARARGS, Quaternion_slerp_doc},
1645  {"rotate", (PyCFunction)Quaternion_rotate, METH_O, Quaternion_rotate_doc},
1646  {"make_compatible",
1647  (PyCFunction)Quaternion_make_compatible,
1648  METH_O,
1649  Quaternion_make_compatible_doc},
1650 
1651  /* Base-math methods. */
1652  {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
1653 
1654  {"copy", (PyCFunction)Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
1655  {"__copy__", (PyCFunction)Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
1656  {"__deepcopy__", (PyCFunction)Quaternion_deepcopy, METH_VARARGS, Quaternion_copy_doc},
1657  {NULL, NULL, 0, NULL},
1658 };
1659 
1662 /* -------------------------------------------------------------------- */
1666 PyDoc_STRVAR(quaternion_doc,
1667  ".. class:: Quaternion([seq, [angle]])\n"
1668  "\n"
1669  " This object gives access to Quaternions in Blender.\n"
1670  "\n"
1671  " :param seq: size 3 or 4\n"
1672  " :type seq: :class:`Vector`\n"
1673  " :param angle: rotation angle, in radians\n"
1674  " :type angle: float\n"
1675  "\n"
1676  " The constructor takes arguments in various forms:\n"
1677  "\n"
1678  " (), *no args*\n"
1679  " Create an identity quaternion\n"
1680  " (*wxyz*)\n"
1681  " Create a quaternion from a ``(w, x, y, z)`` vector.\n"
1682  " (*exponential_map*)\n"
1683  " Create a quaternion from a 3d exponential map vector.\n"
1684  "\n"
1685  " .. seealso:: :meth:`to_exponential_map`\n"
1686  " (*axis, angle*)\n"
1687  " Create a quaternion representing a rotation of *angle* radians over *axis*.\n"
1688  "\n"
1689  " .. seealso:: :meth:`to_axis_angle`\n");
1690 PyTypeObject quaternion_Type = {
1691  PyVarObject_HEAD_INIT(NULL, 0) "Quaternion", /* tp_name */
1692  sizeof(QuaternionObject), /* tp_basicsize */
1693  0, /* tp_itemsize */
1694  (destructor)BaseMathObject_dealloc, /* tp_dealloc */
1695  (printfunc)NULL, /* tp_print */
1696  NULL, /* tp_getattr */
1697  NULL, /* tp_setattr */
1698  NULL, /* tp_compare */
1699  (reprfunc)Quaternion_repr, /* tp_repr */
1700  &Quaternion_NumMethods, /* tp_as_number */
1701  &Quaternion_SeqMethods, /* tp_as_sequence */
1702  &Quaternion_AsMapping, /* tp_as_mapping */
1703  (hashfunc)Quaternion_hash, /* tp_hash */
1704  NULL, /* tp_call */
1705 #ifndef MATH_STANDALONE
1706  (reprfunc)Quaternion_str, /* tp_str */
1707 #else
1708  NULL, /* tp_str */
1709 #endif
1710  NULL, /* tp_getattro */
1711  NULL, /* tp_setattro */
1712  NULL, /* tp_as_buffer */
1713  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1714  quaternion_doc, /* tp_doc */
1715  (traverseproc)BaseMathObject_traverse, /* tp_traverse */
1716  (inquiry)BaseMathObject_clear, /* tp_clear */
1717  (richcmpfunc)Quaternion_richcmpr, /* tp_richcompare */
1718  0, /* tp_weaklistoffset */
1719  NULL, /* tp_iter */
1720  NULL, /* tp_iternext */
1721  Quaternion_methods, /* tp_methods */
1722  NULL, /* tp_members */
1723  Quaternion_getseters, /* tp_getset */
1724  NULL, /* tp_base */
1725  NULL, /* tp_dict */
1726  NULL, /* tp_descr_get */
1727  NULL, /* tp_descr_set */
1728  0, /* tp_dictoffset */
1729  NULL, /* tp_init */
1730  NULL, /* tp_alloc */
1731  Quaternion_new, /* tp_new */
1732  NULL, /* tp_free */
1733  NULL, /* tp_is_gc */
1734  NULL, /* tp_bases */
1735  NULL, /* tp_mro */
1736  NULL, /* tp_cache */
1737  NULL, /* tp_subclasses */
1738  NULL, /* tp_weaklist */
1739  NULL, /* tp_del */
1740 };
1741 
1744 /* -------------------------------------------------------------------- */
1748 PyObject *Quaternion_CreatePyObject(const float quat[4], PyTypeObject *base_type)
1749 {
1750  QuaternionObject *self;
1751  float *quat_alloc;
1752 
1753  quat_alloc = PyMem_Malloc(QUAT_SIZE * sizeof(float));
1754  if (UNLIKELY(quat_alloc == NULL)) {
1755  PyErr_SetString(PyExc_MemoryError,
1756  "Quaternion(): "
1757  "problem allocating data");
1758  return NULL;
1759  }
1760 
1761  self = BASE_MATH_NEW(QuaternionObject, quaternion_Type, base_type);
1762  if (self) {
1763  self->quat = quat_alloc;
1764  /* init callbacks as NULL */
1765  self->cb_user = NULL;
1766  self->cb_type = self->cb_subtype = 0;
1767 
1768  /* NEW */
1769  if (!quat) { /* new empty */
1770  unit_qt(self->quat);
1771  }
1772  else {
1773  copy_qt_qt(self->quat, quat);
1774  }
1775  self->flag = BASE_MATH_FLAG_DEFAULT;
1776  }
1777  else {
1778  PyMem_Free(quat_alloc);
1779  }
1780 
1781  return (PyObject *)self;
1782 }
1783 
1784 PyObject *Quaternion_CreatePyObject_wrap(float quat[4], PyTypeObject *base_type)
1785 {
1786  QuaternionObject *self;
1787 
1788  self = BASE_MATH_NEW(QuaternionObject, quaternion_Type, base_type);
1789  if (self) {
1790  /* init callbacks as NULL */
1791  self->cb_user = NULL;
1792  self->cb_type = self->cb_subtype = 0;
1793 
1794  /* WRAP */
1795  self->quat = quat;
1797  }
1798  return (PyObject *)self;
1799 }
1800 
1801 PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar cb_subtype)
1802 {
1804  if (self) {
1805  Py_INCREF(cb_user);
1806  self->cb_user = cb_user;
1807  self->cb_type = cb_type;
1808  self->cb_subtype = cb_subtype;
1809  PyObject_GC_Track(self);
1810  }
1811 
1812  return (PyObject *)self;
1813 }
1814 
typedef float(TangentPoint)[2]
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define ATTR_FALLTHROUGH
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_dynstr.c:50
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:27
bool is_negative_m3(const float mat[3][3])
Definition: math_matrix.c:2502
void negate_m3(float R[3][3])
Definition: math_matrix.c:989
void normalize_m3(float R[3][3]) ATTR_NONNULL()
Definition: math_matrix.c:1912
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
Definition: math_matrix.c:388
void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q2[4])
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], float t)
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
@ EULER_ORDER_XYZ
float normalize_qt(float q[4])
void invert_qt(float q[4])
Definition: math_rotation.c:97
void mul_qt_fl(float q[4], float f)
void mul_qt_v3(const float q[4], float r[3])
Definition: math_rotation.c:59
void unit_qt(float q[4])
Definition: math_rotation.c:27
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])
Definition: math_rotation.c:92
void quat_to_compatible_eulO(float eul[3], const float old[3], short order, const float quat[4])
void quat_to_eulO(float eul[3], short order, const float quat[4])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
Definition: math_rotation.c:46
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 add_qt_qtqt(float q[4], const float a[4], const float b[4], float t)
void conjugate_qt(float q[4])
Definition: math_rotation.c:85
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:33
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 mat3_normalized_to_quat(float q[4], const float mat[3][3])
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
MINLINE void negate_v4_v4(float r[4], const float a[4])
void mul_vn_vn(float *array_tar, const float *array_src, int size)
Definition: math_vector.c:1069
void mul_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size)
Definition: math_vector.c:1079
unsigned char uchar
Definition: BLI_sys_types.h:70
#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 Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
PyObject * self
Definition: bpy_driver.c:165
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
int count
PyObject * BaseMathObject_freeze(BaseMathObject *self)
Definition: mathutils.c:681
PyObject * BaseMathObject_is_frozen_get(BaseMathObject *self, void *UNUSED(closure))
Definition: mathutils.c:661
int EXPP_FloatsAreEqual(float af, float bf, int maxDiff)
Definition: mathutils.c:501
PyObject * BaseMathObject_is_wrapped_get(BaseMathObject *self, void *UNUSED(closure))
Definition: mathutils.c:654
PyObject * mathutils_dynstr_to_py(struct DynStr *ds)
Definition: mathutils.c:531
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
Definition: mathutils.c:66
void BaseMathObject_dealloc(BaseMathObject *self)
Definition: mathutils.c:705
int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps)
Definition: mathutils.c:519
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition: mathutils.c:98
char BaseMathObject_is_valid_doc[]
Definition: mathutils.c:666
PyObject * BaseMathObject_owner_get(BaseMathObject *self, void *UNUSED(closure))
Definition: mathutils.c:646
char BaseMathObject_is_wrapped_doc[]
Definition: mathutils.c:652
char BaseMathObject_is_frozen_doc[]
Definition: mathutils.c:659
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
Definition: mathutils.c:439
PyObject * BaseMathObject_is_valid_get(BaseMathObject *self, void *UNUSED(closure))
Definition: mathutils.c:668
char BaseMathObject_owner_doc[]
Definition: mathutils.c:645
char BaseMathObject_freeze_doc[]
Definition: mathutils.c:673
int BaseMathObject_clear(BaseMathObject *self)
Definition: mathutils.c:699
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
Definition: mathutils.c:693
@ BASE_MATH_FLAG_IS_WRAP
Definition: mathutils.h:31
#define BaseMath_ReadCallback_ForWrite(_self)
Definition: mathutils.h:129
#define BaseMath_ReadIndexCallback(_self, _index)
Definition: mathutils.h:123
#define BaseMath_WriteCallback(_self)
Definition: mathutils.h:121
#define BASE_MATH_NEW(struct_name, root_type, base_type)
Definition: mathutils.h:20
#define BaseMathObject_Prepare_ForHash(_self)
Definition: mathutils.h:144
#define BASE_MATH_FLAG_DEFAULT
Definition: mathutils.h:38
#define BaseMath_Prepare_ForWrite(_self)
Definition: mathutils.h:139
#define BaseMath_ReadCallback(_self)
Definition: mathutils.h:119
#define BaseMath_WriteIndexCallback(_self, _index)
Definition: mathutils.h:125
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 col_num, const ushort row_num, 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 vec_num, PyTypeObject *base_type)
#define VectorObject_Check(v)
#define sqrtf(x)
Definition: metal/compat.h:243
bool isfinite(uchar)
Definition: scene/image.cpp:31
static unsigned a[3]
Definition: RandGen.cpp:78
T length(const vec_base< T, Size > &a)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
int PyC_CheckArgs_DeepCopy(PyObject *args)
#define PyTuple_SET_ITEMS(op_arg,...)
return ret