Blender  V3.3
mathutils_Euler.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 "../generic/py_capi_utils.h"
12 #include "../generic/python_utildefines.h"
13 #include "BLI_math.h"
14 #include "BLI_utildefines.h"
15 
16 #ifndef MATH_STANDALONE
17 # include "BLI_dynstr.h"
18 #endif
19 
20 #define EULER_SIZE 3
21 
22 /* -------------------------------------------------------------------- */
27 static const char *euler_order_str(EulerObject *self)
28 {
29  static const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
30  return order[self->order - EULER_ORDER_XYZ];
31 }
32 
33 short euler_order_from_string(const char *str, const char *error_prefix)
34 {
35  if ((str[0] && str[1] && str[2] && str[3] == '\0')) {
36 
37 #ifdef __LITTLE_ENDIAN__
38 # define MAKE_ID3(a, b, c) (((a)) | ((b) << 8) | ((c) << 16))
39 #else
40 # define MAKE_ID3(a, b, c) (((a) << 24) | ((b) << 16) | ((c) << 8))
41 #endif
42 
43  switch (*((const PY_INT32_T *)str)) {
44  case MAKE_ID3('X', 'Y', 'Z'):
45  return EULER_ORDER_XYZ;
46  case MAKE_ID3('X', 'Z', 'Y'):
47  return EULER_ORDER_XZY;
48  case MAKE_ID3('Y', 'X', 'Z'):
49  return EULER_ORDER_YXZ;
50  case MAKE_ID3('Y', 'Z', 'X'):
51  return EULER_ORDER_YZX;
52  case MAKE_ID3('Z', 'X', 'Y'):
53  return EULER_ORDER_ZXY;
54  case MAKE_ID3('Z', 'Y', 'X'):
55  return EULER_ORDER_ZYX;
56  }
57 
58 #undef MAKE_ID3
59  }
60 
61  PyErr_Format(PyExc_ValueError, "%s: invalid euler order '%s'", error_prefix, str);
62  return -1;
63 }
64 
68 static PyObject *Euler_to_tuple_ex(EulerObject *self, int ndigits)
69 {
70  PyObject *ret;
71  int i;
72 
73  ret = PyTuple_New(EULER_SIZE);
74 
75  if (ndigits >= 0) {
76  for (i = 0; i < EULER_SIZE; i++) {
77  PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->eul[i], ndigits)));
78  }
79  }
80  else {
81  for (i = 0; i < EULER_SIZE; i++) {
82  PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->eul[i]));
83  }
84  }
85 
86  return ret;
87 }
88 
91 /* -------------------------------------------------------------------- */
95 static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
96 {
97  PyObject *seq = NULL;
98  const char *order_str = NULL;
99 
100  float eul[EULER_SIZE] = {0.0f, 0.0f, 0.0f};
101  short order = EULER_ORDER_XYZ;
102 
103  if (kwds && PyDict_Size(kwds)) {
104  PyErr_SetString(PyExc_TypeError,
105  "mathutils.Euler(): "
106  "takes no keyword args");
107  return NULL;
108  }
109 
110  if (!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str)) {
111  return NULL;
112  }
113 
114  switch (PyTuple_GET_SIZE(args)) {
115  case 0:
116  break;
117  case 2:
118  if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1) {
119  return NULL;
120  }
122  case 1:
123  if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1) {
124  return NULL;
125  }
126  break;
127  }
128  return Euler_CreatePyObject(eul, order, type);
129 }
130 
133 /* -------------------------------------------------------------------- */
137 PyDoc_STRVAR(Euler_to_quaternion_doc,
138  ".. method:: to_quaternion()\n"
139  "\n"
140  " Return a quaternion representation of the euler.\n"
141  "\n"
142  " :return: Quaternion representation of the euler.\n"
143  " :rtype: :class:`Quaternion`\n");
144 static PyObject *Euler_to_quaternion(EulerObject *self)
145 {
146  float quat[4];
147 
148  if (BaseMath_ReadCallback(self) == -1) {
149  return NULL;
150  }
151 
152  eulO_to_quat(quat, self->eul, self->order);
153 
154  return Quaternion_CreatePyObject(quat, NULL);
155 }
156 
157 PyDoc_STRVAR(Euler_to_matrix_doc,
158  ".. method:: to_matrix()\n"
159  "\n"
160  " Return a matrix representation of the euler.\n"
161  "\n"
162  " :return: A 3x3 rotation matrix representation of the euler.\n"
163  " :rtype: :class:`Matrix`\n");
164 static PyObject *Euler_to_matrix(EulerObject *self)
165 {
166  float mat[9];
167 
168  if (BaseMath_ReadCallback(self) == -1) {
169  return NULL;
170  }
171 
172  eulO_to_mat3((float(*)[3])mat, self->eul, self->order);
173 
174  return Matrix_CreatePyObject(mat, 3, 3, NULL);
175 }
176 
177 PyDoc_STRVAR(Euler_zero_doc,
178  ".. method:: zero()\n"
179  "\n"
180  " Set all values to zero.\n");
181 static PyObject *Euler_zero(EulerObject *self)
182 {
183  if (BaseMath_Prepare_ForWrite(self) == -1) {
184  return NULL;
185  }
186 
187  zero_v3(self->eul);
188 
189  if (BaseMath_WriteCallback(self) == -1) {
190  return NULL;
191  }
192 
193  Py_RETURN_NONE;
194 }
195 
196 PyDoc_STRVAR(Euler_rotate_axis_doc,
197  ".. method:: rotate_axis(axis, angle)\n"
198  "\n"
199  " Rotates the euler a certain amount and returning a unique euler rotation\n"
200  " (no 720 degree pitches).\n"
201  "\n"
202  " :arg axis: single character in ['X, 'Y', 'Z'].\n"
203  " :type axis: string\n"
204  " :arg angle: angle in radians.\n"
205  " :type angle: float\n");
206 static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args)
207 {
208  float angle = 0.0f;
209  int axis; /* actually a character */
210 
211  if (!PyArg_ParseTuple(args, "Cf:rotate_axis", &axis, &angle)) {
212  PyErr_SetString(PyExc_TypeError,
213  "Euler.rotate_axis(): "
214  "expected an axis 'X', 'Y', 'Z' and an angle (float)");
215  return NULL;
216  }
217 
218  if (!(ELEM(axis, 'X', 'Y', 'Z'))) {
219  PyErr_SetString(PyExc_ValueError,
220  "Euler.rotate_axis(): "
221  "expected axis to be 'X', 'Y' or 'Z'");
222  return NULL;
223  }
224 
225  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
226  return NULL;
227  }
228 
229  rotate_eulO(self->eul, self->order, (char)axis, angle);
230 
232 
233  Py_RETURN_NONE;
234 }
235 
236 PyDoc_STRVAR(Euler_rotate_doc,
237  ".. method:: rotate(other)\n"
238  "\n"
239  " Rotates the euler by another mathutils value.\n"
240  "\n"
241  " :arg other: rotation component of mathutils value\n"
242  " :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n");
243 static PyObject *Euler_rotate(EulerObject *self, PyObject *value)
244 {
245  float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
246 
247  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
248  return NULL;
249  }
250 
251  if (mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1) {
252  return NULL;
253  }
254 
255  eulO_to_mat3(self_rmat, self->eul, self->order);
256  mul_m3_m3m3(rmat, other_rmat, self_rmat);
257 
258  mat3_to_compatible_eulO(self->eul, self->eul, self->order, rmat);
259 
261  Py_RETURN_NONE;
262 }
263 
264 PyDoc_STRVAR(Euler_make_compatible_doc,
265  ".. method:: make_compatible(other)\n"
266  "\n"
267  " Make this euler compatible with another,\n"
268  " so interpolating between them works as intended.\n"
269  "\n"
270  " .. note:: the rotation order is not taken into account for this function.\n");
271 static PyObject *Euler_make_compatible(EulerObject *self, PyObject *value)
272 {
273  float teul[EULER_SIZE];
274 
275  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
276  return NULL;
277  }
278 
279  if (mathutils_array_parse(teul,
280  EULER_SIZE,
281  EULER_SIZE,
282  value,
283  "euler.make_compatible(other), invalid 'other' arg") == -1) {
284  return NULL;
285  }
286 
287  compatible_eul(self->eul, teul);
288 
290 
291  Py_RETURN_NONE;
292 }
293 
294 PyDoc_STRVAR(Euler_copy_doc,
295  ".. function:: copy()\n"
296  "\n"
297  " Returns a copy of this euler.\n"
298  "\n"
299  " :return: A copy of the euler.\n"
300  " :rtype: :class:`Euler`\n"
301  "\n"
302  " .. note:: use this to get a copy of a wrapped euler with\n"
303  " no reference to the original data.\n");
304 static PyObject *Euler_copy(EulerObject *self)
305 {
306  if (BaseMath_ReadCallback(self) == -1) {
307  return NULL;
308  }
309 
310  return Euler_CreatePyObject(self->eul, self->order, Py_TYPE(self));
311 }
312 static PyObject *Euler_deepcopy(EulerObject *self, PyObject *args)
313 {
314  if (!PyC_CheckArgs_DeepCopy(args)) {
315  return NULL;
316  }
317  return Euler_copy(self);
318 }
319 
322 /* -------------------------------------------------------------------- */
326 static PyObject *Euler_repr(EulerObject *self)
327 {
328  PyObject *ret, *tuple;
329 
330  if (BaseMath_ReadCallback(self) == -1) {
331  return NULL;
332  }
333 
334  tuple = Euler_to_tuple_ex(self, -1);
335 
336  ret = PyUnicode_FromFormat("Euler(%R, '%s')", tuple, euler_order_str(self));
337 
338  Py_DECREF(tuple);
339  return ret;
340 }
341 
342 #ifndef MATH_STANDALONE
343 static PyObject *Euler_str(EulerObject *self)
344 {
345  DynStr *ds;
346 
347  if (BaseMath_ReadCallback(self) == -1) {
348  return NULL;
349  }
350 
351  ds = BLI_dynstr_new();
352 
354  "<Euler (x=%.4f, y=%.4f, z=%.4f), order='%s'>",
355  self->eul[0],
356  self->eul[1],
357  self->eul[2],
358  euler_order_str(self));
359 
360  return mathutils_dynstr_to_py(ds); /* frees ds */
361 }
362 #endif
363 
366 /* -------------------------------------------------------------------- */
370 static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
371 {
372  PyObject *res;
373  int ok = -1; /* zero is true */
374 
376  EulerObject *eulA = (EulerObject *)a;
377  EulerObject *eulB = (EulerObject *)b;
378 
379  if (BaseMath_ReadCallback(eulA) == -1 || BaseMath_ReadCallback(eulB) == -1) {
380  return NULL;
381  }
382 
383  ok = ((eulA->order == eulB->order) &&
384  EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1)) ?
385  0 :
386  -1;
387  }
388 
389  switch (op) {
390  case Py_NE:
391  ok = !ok;
393  case Py_EQ:
394  res = ok ? Py_False : Py_True;
395  break;
396 
397  case Py_LT:
398  case Py_LE:
399  case Py_GT:
400  case Py_GE:
401  res = Py_NotImplemented;
402  break;
403  default:
404  PyErr_BadArgument();
405  return NULL;
406  }
407 
408  return Py_INCREF_RET(res);
409 }
410 
413 /* -------------------------------------------------------------------- */
417 static Py_hash_t Euler_hash(EulerObject *self)
418 {
419  if (BaseMath_ReadCallback(self) == -1) {
420  return -1;
421  }
422 
423  if (BaseMathObject_Prepare_ForHash(self) == -1) {
424  return -1;
425  }
426 
427  return mathutils_array_hash(self->eul, EULER_SIZE);
428 }
429 
432 /* -------------------------------------------------------------------- */
437 static int Euler_len(EulerObject *UNUSED(self))
438 {
439  return EULER_SIZE;
440 }
441 
443 static PyObject *Euler_item(EulerObject *self, int i)
444 {
445  if (i < 0) {
446  i = EULER_SIZE - i;
447  }
448 
449  if (i < 0 || i >= EULER_SIZE) {
450  PyErr_SetString(PyExc_IndexError,
451  "euler[attribute]: "
452  "array index out of range");
453  return NULL;
454  }
455 
456  if (BaseMath_ReadIndexCallback(self, i) == -1) {
457  return NULL;
458  }
459 
460  return PyFloat_FromDouble(self->eul[i]);
461 }
462 
464 static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
465 {
466  float f;
467 
468  if (BaseMath_Prepare_ForWrite(self) == -1) {
469  return -1;
470  }
471 
472  f = PyFloat_AsDouble(value);
473  if (f == -1 && PyErr_Occurred()) { /* parsed item not a number */
474  PyErr_SetString(PyExc_TypeError,
475  "euler[attribute] = x: "
476  "assigned value not a number");
477  return -1;
478  }
479 
480  if (i < 0) {
481  i = EULER_SIZE - i;
482  }
483 
484  if (i < 0 || i >= EULER_SIZE) {
485  PyErr_SetString(PyExc_IndexError,
486  "euler[attribute] = x: "
487  "array assignment index out of range");
488  return -1;
489  }
490 
491  self->eul[i] = f;
492 
493  if (BaseMath_WriteIndexCallback(self, i) == -1) {
494  return -1;
495  }
496 
497  return 0;
498 }
499 
501 static PyObject *Euler_slice(EulerObject *self, int begin, int end)
502 {
503  PyObject *tuple;
504  int count;
505 
506  if (BaseMath_ReadCallback(self) == -1) {
507  return NULL;
508  }
509 
510  CLAMP(begin, 0, EULER_SIZE);
511  if (end < 0) {
512  end = (EULER_SIZE + 1) + end;
513  }
514  CLAMP(end, 0, EULER_SIZE);
515  begin = MIN2(begin, end);
516 
517  tuple = PyTuple_New(end - begin);
518  for (count = begin; count < end; count++) {
519  PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->eul[count]));
520  }
521 
522  return tuple;
523 }
524 
526 static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
527 {
528  int i, size;
529  float eul[EULER_SIZE];
530 
531  if (BaseMath_ReadCallback_ForWrite(self) == -1) {
532  return -1;
533  }
534 
535  CLAMP(begin, 0, EULER_SIZE);
536  if (end < 0) {
537  end = (EULER_SIZE + 1) + end;
538  }
539  CLAMP(end, 0, EULER_SIZE);
540  begin = MIN2(begin, end);
541 
542  if ((size = mathutils_array_parse(eul, 0, EULER_SIZE, seq, "mathutils.Euler[begin:end] = []")) ==
543  -1) {
544  return -1;
545  }
546 
547  if (size != (end - begin)) {
548  PyErr_SetString(PyExc_ValueError,
549  "euler[begin:end] = []: "
550  "size mismatch in slice assignment");
551  return -1;
552  }
553 
554  for (i = 0; i < EULER_SIZE; i++) {
555  self->eul[begin + i] = eul[i];
556  }
557 
559  return 0;
560 }
561 
563 static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
564 {
565  if (PyIndex_Check(item)) {
566  Py_ssize_t i;
567  i = PyNumber_AsSsize_t(item, PyExc_IndexError);
568  if (i == -1 && PyErr_Occurred()) {
569  return NULL;
570  }
571  if (i < 0) {
572  i += EULER_SIZE;
573  }
574  return Euler_item(self, i);
575  }
576  if (PySlice_Check(item)) {
577  Py_ssize_t start, stop, step, slicelength;
578 
579  if (PySlice_GetIndicesEx(item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0) {
580  return NULL;
581  }
582 
583  if (slicelength <= 0) {
584  return PyTuple_New(0);
585  }
586  if (step == 1) {
587  return Euler_slice(self, start, stop);
588  }
589 
590  PyErr_SetString(PyExc_IndexError, "slice steps not supported with eulers");
591  return NULL;
592  }
593 
594  PyErr_Format(
595  PyExc_TypeError, "euler indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
596  return NULL;
597 }
598 
600 static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *value)
601 {
602  if (PyIndex_Check(item)) {
603  Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
604  if (i == -1 && PyErr_Occurred()) {
605  return -1;
606  }
607  if (i < 0) {
608  i += EULER_SIZE;
609  }
610  return Euler_ass_item(self, i, value);
611  }
612  if (PySlice_Check(item)) {
613  Py_ssize_t start, stop, step, slicelength;
614 
615  if (PySlice_GetIndicesEx(item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0) {
616  return -1;
617  }
618 
619  if (step == 1) {
620  return Euler_ass_slice(self, start, stop, value);
621  }
622 
623  PyErr_SetString(PyExc_IndexError, "slice steps not supported with euler");
624  return -1;
625  }
626 
627  PyErr_Format(
628  PyExc_TypeError, "euler indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
629  return -1;
630 }
631 
634 /* -------------------------------------------------------------------- */
638 static PySequenceMethods Euler_SeqMethods = {
639  (lenfunc)Euler_len, /*sq_length*/
640  (binaryfunc)NULL, /*sq_concat*/
641  (ssizeargfunc)NULL, /*sq_repeat*/
642  (ssizeargfunc)Euler_item, /*sq_item*/
643  (ssizessizeargfunc)NULL, /*sq_slice(DEPRECATED)*/
644  (ssizeobjargproc)Euler_ass_item, /*sq_ass_item*/
645  (ssizessizeobjargproc)NULL, /*sq_ass_slice(DEPRECATED)*/
646  (objobjproc)NULL, /*sq_contains*/
647  (binaryfunc)NULL, /*sq_inplace_concat*/
648  (ssizeargfunc)NULL, /*sq_inplace_repeat*/
649 };
650 
651 static PyMappingMethods Euler_AsMapping = {
652  (lenfunc)Euler_len,
653  (binaryfunc)Euler_subscript,
654  (objobjargproc)Euler_ass_subscript,
655 };
656 
659 /* -------------------------------------------------------------------- */
663 /* Euler axis: `euler.x/y/z`. */
664 
665 PyDoc_STRVAR(Euler_axis_doc, "Euler axis angle in radians.\n\n:type: float");
666 static PyObject *Euler_axis_get(EulerObject *self, void *type)
667 {
668  return Euler_item(self, POINTER_AS_INT(type));
669 }
670 
671 static int Euler_axis_set(EulerObject *self, PyObject *value, void *type)
672 {
673  return Euler_ass_item(self, POINTER_AS_INT(type), value);
674 }
675 
676 /* Euler rotation order: `euler.order`. */
677 
679  Euler_order_doc,
680  "Euler rotation order.\n\n:type: string in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']");
681 static PyObject *Euler_order_get(EulerObject *self, void *UNUSED(closure))
682 {
683  if (BaseMath_ReadCallback(self) == -1) {
684  /* can read order too */
685  return NULL;
686  }
687 
688  return PyUnicode_FromString(euler_order_str(self));
689 }
690 
691 static int Euler_order_set(EulerObject *self, PyObject *value, void *UNUSED(closure))
692 {
693  const char *order_str;
694  short order;
695 
696  if (BaseMath_Prepare_ForWrite(self) == -1) {
697  return -1;
698  }
699 
700  if (((order_str = PyUnicode_AsUTF8(value)) == NULL) ||
701  ((order = euler_order_from_string(order_str, "euler.order")) == -1)) {
702  return -1;
703  }
704 
705  self->order = order;
706  (void)BaseMath_WriteCallback(self); /* order can be written back */
707  return 0;
708 }
709 
712 /* -------------------------------------------------------------------- */
716 static PyGetSetDef Euler_getseters[] = {
717  {"x", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)0},
718  {"y", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)1},
719  {"z", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)2},
720  {"order", (getter)Euler_order_get, (setter)Euler_order_set, Euler_order_doc, (void *)NULL},
721 
722  {"is_wrapped",
724  (setter)NULL,
726  NULL},
727  {"is_frozen",
729  (setter)NULL,
731  NULL},
732  {"is_valid",
734  (setter)NULL,
736  NULL},
737  {"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
738  {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
739 };
740 
743 /* -------------------------------------------------------------------- */
747 static struct PyMethodDef Euler_methods[] = {
748  {"zero", (PyCFunction)Euler_zero, METH_NOARGS, Euler_zero_doc},
749  {"to_matrix", (PyCFunction)Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc},
750  {"to_quaternion", (PyCFunction)Euler_to_quaternion, METH_NOARGS, Euler_to_quaternion_doc},
751  {"rotate_axis", (PyCFunction)Euler_rotate_axis, METH_VARARGS, Euler_rotate_axis_doc},
752  {"rotate", (PyCFunction)Euler_rotate, METH_O, Euler_rotate_doc},
753  {"make_compatible", (PyCFunction)Euler_make_compatible, METH_O, Euler_make_compatible_doc},
754  {"copy", (PyCFunction)Euler_copy, METH_NOARGS, Euler_copy_doc},
755  {"__copy__", (PyCFunction)Euler_copy, METH_NOARGS, Euler_copy_doc},
756  {"__deepcopy__", (PyCFunction)Euler_deepcopy, METH_VARARGS, Euler_copy_doc},
757 
758  /* base-math methods */
759  {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
760  {NULL, NULL, 0, NULL},
761 };
762 
765 /* -------------------------------------------------------------------- */
770  euler_doc,
771  ".. class:: Euler(angles, order='XYZ')\n"
772  "\n"
773  " This object gives access to Eulers in Blender.\n"
774  "\n"
775  " .. seealso:: `Euler angles <https://en.wikipedia.org/wiki/Euler_angles>`__ on Wikipedia.\n"
776  "\n"
777  " :param angles: Three angles, in radians.\n"
778  " :type angles: 3d vector\n"
779  " :param order: Optional order of the angles, a permutation of ``XYZ``.\n"
780  " :type order: str\n");
781 PyTypeObject euler_Type = {
782  PyVarObject_HEAD_INIT(NULL, 0) "Euler", /* tp_name */
783  sizeof(EulerObject), /* tp_basicsize */
784  0, /* tp_itemsize */
785  (destructor)BaseMathObject_dealloc, /* tp_dealloc */
786  (printfunc)NULL, /* tp_print */
787  NULL, /* tp_getattr */
788  NULL, /* tp_setattr */
789  NULL, /* tp_compare */
790  (reprfunc)Euler_repr, /* tp_repr */
791  NULL, /* tp_as_number */
792  &Euler_SeqMethods, /* tp_as_sequence */
793  &Euler_AsMapping, /* tp_as_mapping */
794  (hashfunc)Euler_hash, /* tp_hash */
795  NULL, /* tp_call */
796 #ifndef MATH_STANDALONE
797  (reprfunc)Euler_str, /* tp_str */
798 #else
799  NULL, /* tp_str */
800 #endif
801  NULL, /* tp_getattro */
802  NULL, /* tp_setattro */
803  NULL, /* tp_as_buffer */
804  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
805  euler_doc, /* tp_doc */
806  (traverseproc)BaseMathObject_traverse, /* tp_traverse */
807  (inquiry)BaseMathObject_clear, /* tp_clear */
808  (richcmpfunc)Euler_richcmpr, /* tp_richcompare */
809  0, /* tp_weaklistoffset */
810  NULL, /* tp_iter */
811  NULL, /* tp_iternext */
812  Euler_methods, /* tp_methods */
813  NULL, /* tp_members */
814  Euler_getseters, /* tp_getset */
815  NULL, /* tp_base */
816  NULL, /* tp_dict */
817  NULL, /* tp_descr_get */
818  NULL, /* tp_descr_set */
819  0, /* tp_dictoffset */
820  NULL, /* tp_init */
821  NULL, /* tp_alloc */
822  Euler_new, /* tp_new */
823  NULL, /* tp_free */
824  NULL, /* tp_is_gc */
825  NULL, /* tp_bases */
826  NULL, /* tp_mro */
827  NULL, /* tp_cache */
828  NULL, /* tp_subclasses */
829  NULL, /* tp_weaklist */
830  NULL, /* tp_del */
831 };
832 
835 /* -------------------------------------------------------------------- */
839 PyObject *Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
840 {
841  EulerObject *self;
842  float *eul_alloc;
843 
844  eul_alloc = PyMem_Malloc(EULER_SIZE * sizeof(float));
845  if (UNLIKELY(eul_alloc == NULL)) {
846  PyErr_SetString(PyExc_MemoryError,
847  "Euler(): "
848  "problem allocating data");
849  return NULL;
850  }
851 
852  self = BASE_MATH_NEW(EulerObject, euler_Type, base_type);
853  if (self) {
854  self->eul = eul_alloc;
855 
856  /* init callbacks as NULL */
857  self->cb_user = NULL;
858  self->cb_type = self->cb_subtype = 0;
859 
860  if (eul) {
861  copy_v3_v3(self->eul, eul);
862  }
863  else {
864  zero_v3(self->eul);
865  }
866 
867  self->flag = BASE_MATH_FLAG_DEFAULT;
868  self->order = order;
869  }
870  else {
871  PyMem_Free(eul_alloc);
872  }
873 
874  return (PyObject *)self;
875 }
876 
877 PyObject *Euler_CreatePyObject_wrap(float eul[3], const short order, PyTypeObject *base_type)
878 {
879  EulerObject *self;
880 
881  self = BASE_MATH_NEW(EulerObject, euler_Type, base_type);
882  if (self) {
883  /* init callbacks as NULL */
884  self->cb_user = NULL;
885  self->cb_type = self->cb_subtype = 0;
886 
887  self->eul = eul;
889 
890  self->order = order;
891  }
892 
893  return (PyObject *)self;
894 }
895 
896 PyObject *Euler_CreatePyObject_cb(PyObject *cb_user,
897  const short order,
898  uchar cb_type,
899  uchar cb_subtype)
900 {
902  if (self) {
903  Py_INCREF(cb_user);
904  self->cb_user = cb_user;
905  self->cb_type = cb_type;
906  self->cb_subtype = cb_subtype;
907  PyObject_GC_Track(self);
908  }
909 
910  return (PyObject *)self;
911 }
912 
#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
double double_round(double x, int ndigits)
Definition: math_base.c:27
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
Definition: math_matrix.c:388
void eulO_to_mat3(float mat[3][3], const float eul[3], short order)
void mat3_to_compatible_eulO(float eul[3], const float old[3], short order, const float mat[3][3])
@ EULER_ORDER_ZXY
@ EULER_ORDER_XZY
@ EULER_ORDER_XYZ
@ EULER_ORDER_YZX
@ EULER_ORDER_ZYX
@ EULER_ORDER_YXZ
void rotate_eulO(float eul[3], short order, char axis, float angle)
void eulO_to_quat(float quat[4], const float eul[3], short order)
void compatible_eul(float eul[3], const float old[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v3(float r[3])
unsigned char uchar
Definition: BLI_sys_types.h:70
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define UNLIKELY(x)
#define ELEM(...)
#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
#define str(s)
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
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
static PySequenceMethods Euler_SeqMethods
PyObject * Euler_CreatePyObject_wrap(float eul[3], const short order, PyTypeObject *base_type)
static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
PyObject * Euler_CreatePyObject_cb(PyObject *cb_user, const short order, uchar cb_type, uchar cb_subtype)
short euler_order_from_string(const char *str, const char *error_prefix)
static PyObject * Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static PyObject * Euler_repr(EulerObject *self)
static PyObject * Euler_axis_get(EulerObject *self, void *type)
static PyObject * Euler_zero(EulerObject *self)
static Py_hash_t Euler_hash(EulerObject *self)
static const char * euler_order_str(EulerObject *self)
static int Euler_len(EulerObject *UNUSED(self))
static PyObject * Euler_rotate_axis(EulerObject *self, PyObject *args)
PyTypeObject euler_Type
#define MAKE_ID3(a, b, c)
static PyObject * Euler_slice(EulerObject *self, int begin, int end)
static PyObject * Euler_subscript(EulerObject *self, PyObject *item)
static int Euler_axis_set(EulerObject *self, PyObject *value, void *type)
static PyObject * Euler_to_quaternion(EulerObject *self)
static int Euler_order_set(EulerObject *self, PyObject *value, void *UNUSED(closure))
static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *value)
static PyObject * Euler_to_matrix(EulerObject *self)
static PyObject * Euler_item(EulerObject *self, int i)
PyDoc_STRVAR(Euler_to_quaternion_doc, ".. method:: to_quaternion()\n" "\n" " Return a quaternion representation of the euler.\n" "\n" " :return: Quaternion representation of the euler.\n" " :rtype: :class:`Quaternion`\n")
static PyObject * Euler_copy(EulerObject *self)
PyObject * Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
static PyObject * Euler_rotate(EulerObject *self, PyObject *value)
static PyObject * Euler_str(EulerObject *self)
static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
#define EULER_SIZE
static PyGetSetDef Euler_getseters[]
static PyObject * Euler_richcmpr(PyObject *a, PyObject *b, int op)
static PyObject * Euler_make_compatible(EulerObject *self, PyObject *value)
static PyMappingMethods Euler_AsMapping
static PyObject * Euler_to_tuple_ex(EulerObject *self, int ndigits)
static struct PyMethodDef Euler_methods[]
static PyObject * Euler_order_get(EulerObject *self, void *UNUSED(closure))
static PyObject * Euler_deepcopy(EulerObject *self, PyObject *args)
#define EulerObject_Check(v)
PyObject * Matrix_CreatePyObject(const float *mat, const ushort col_num, const ushort row_num, PyTypeObject *base_type)
PyObject * Quaternion_CreatePyObject(const float quat[4], PyTypeObject *base_type)
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
int PyC_CheckArgs_DeepCopy(PyObject *args)
return ret
unsigned char order