Blender V4.3
mathutils_Euler.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10
11#include <Python.h>
12
13#include "mathutils.hh"
14
17#include "BLI_math_matrix.h"
18#include "BLI_math_rotation.h"
19#include "BLI_math_vector.h"
20#include "BLI_utildefines.h"
21
22#ifndef MATH_STANDALONE
23# include "BLI_dynstr.h"
24#endif
25
26#define EULER_SIZE 3
27
28/* -------------------------------------------------------------------- */
33static const char *euler_order_str(EulerObject *self)
34{
35 static const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
36 return order[self->order - EULER_ORDER_XYZ];
37}
38
39short euler_order_from_string(const char *str, const char *error_prefix)
40{
41 if (str[0] && str[1] && str[2] && str[3] == '\0') {
42
43#ifdef __LITTLE_ENDIAN__
44# define MAKE_ID3(a, b, c) ((a) | ((b) << 8) | ((c) << 16))
45#else
46# define MAKE_ID3(a, b, c) (((a) << 24) | ((b) << 16) | ((c) << 8))
47#endif
48
49 switch (*((const PY_INT32_T *)str)) {
50 case MAKE_ID3('X', 'Y', 'Z'):
51 return EULER_ORDER_XYZ;
52 case MAKE_ID3('X', 'Z', 'Y'):
53 return EULER_ORDER_XZY;
54 case MAKE_ID3('Y', 'X', 'Z'):
55 return EULER_ORDER_YXZ;
56 case MAKE_ID3('Y', 'Z', 'X'):
57 return EULER_ORDER_YZX;
58 case MAKE_ID3('Z', 'X', 'Y'):
59 return EULER_ORDER_ZXY;
60 case MAKE_ID3('Z', 'Y', 'X'):
61 return EULER_ORDER_ZYX;
62 }
63
64#undef MAKE_ID3
65 }
66
67 PyErr_Format(PyExc_ValueError, "%s: invalid euler order '%s'", error_prefix, str);
68 return -1;
69}
70
74static PyObject *Euler_to_tuple_ex(EulerObject *self, int ndigits)
75{
76 PyObject *ret;
77 int i;
78
79 ret = PyTuple_New(EULER_SIZE);
80
81 if (ndigits >= 0) {
82 for (i = 0; i < EULER_SIZE; i++) {
83 PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round(double(self->eul[i]), ndigits)));
84 }
85 }
86 else {
87 for (i = 0; i < EULER_SIZE; i++) {
88 PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->eul[i]));
89 }
90 }
91
92 return ret;
93}
94
97/* -------------------------------------------------------------------- */
101static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
102{
103 PyObject *seq = nullptr;
104 const char *order_str = nullptr;
105
106 float eul[EULER_SIZE] = {0.0f, 0.0f, 0.0f};
107 short order = EULER_ORDER_XYZ;
108
109 if (kwds && PyDict_Size(kwds)) {
110 PyErr_SetString(PyExc_TypeError,
111 "mathutils.Euler(): "
112 "takes no keyword args");
113 return nullptr;
114 }
115
116 if (!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str)) {
117 return nullptr;
118 }
119
120 switch (PyTuple_GET_SIZE(args)) {
121 case 0:
122 break;
123 case 2:
124 if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1) {
125 return nullptr;
126 }
128 case 1:
129 if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1) {
130 return nullptr;
131 }
132 break;
133 }
134 return Euler_CreatePyObject(eul, order, type);
135}
136
139/* -------------------------------------------------------------------- */
144 /* Wrap. */
145 Euler_to_quaternion_doc,
146 ".. method:: to_quaternion()\n"
147 "\n"
148 " Return a quaternion representation of the euler.\n"
149 "\n"
150 " :return: Quaternion representation of the euler.\n"
151 " :rtype: :class:`Quaternion`\n");
153{
154 float quat[4];
155
156 if (BaseMath_ReadCallback(self) == -1) {
157 return nullptr;
158 }
159
160 eulO_to_quat(quat, self->eul, self->order);
161
162 return Quaternion_CreatePyObject(quat, nullptr);
163}
164
166 /* Wrap. */
167 Euler_to_matrix_doc,
168 ".. method:: to_matrix()\n"
169 "\n"
170 " Return a matrix representation of the euler.\n"
171 "\n"
172 " :return: A 3x3 rotation matrix representation of the euler.\n"
173 " :rtype: :class:`Matrix`\n");
175{
176 float mat[9];
177
178 if (BaseMath_ReadCallback(self) == -1) {
179 return nullptr;
180 }
181
182 eulO_to_mat3((float(*)[3])mat, self->eul, self->order);
183
184 return Matrix_CreatePyObject(mat, 3, 3, nullptr);
185}
186
188 /* Wrap. */
189 Euler_zero_doc,
190 ".. method:: zero()\n"
191 "\n"
192 " Set all values to zero.\n");
193static PyObject *Euler_zero(EulerObject *self)
194{
195 if (BaseMath_Prepare_ForWrite(self) == -1) {
196 return nullptr;
197 }
198
199 zero_v3(self->eul);
200
201 if (BaseMath_WriteCallback(self) == -1) {
202 return nullptr;
203 }
204
205 Py_RETURN_NONE;
206}
207
209 /* Wrap. */
210 Euler_rotate_axis_doc,
211 ".. method:: rotate_axis(axis, angle)\n"
212 "\n"
213 " Rotates the euler a certain amount and returning a unique euler rotation\n"
214 " (no 720 degree pitches).\n"
215 "\n"
216 " :arg axis: single character in ['X, 'Y', 'Z'].\n"
217 " :type axis: str\n"
218 " :arg angle: angle in radians.\n"
219 " :type angle: float\n");
220static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args)
221{
222 float angle = 0.0f;
223 int axis; /* actually a character */
224
225 if (!PyArg_ParseTuple(args, "Cf:rotate_axis", &axis, &angle)) {
226 PyErr_SetString(PyExc_TypeError,
227 "Euler.rotate_axis(): "
228 "expected an axis 'X', 'Y', 'Z' and an angle (float)");
229 return nullptr;
230 }
231
232 if (!ELEM(axis, 'X', 'Y', 'Z')) {
233 PyErr_SetString(PyExc_ValueError,
234 "Euler.rotate_axis(): "
235 "expected axis to be 'X', 'Y' or 'Z'");
236 return nullptr;
237 }
238
240 return nullptr;
241 }
242
243 rotate_eulO(self->eul, self->order, char(axis), angle);
244
246
247 Py_RETURN_NONE;
248}
249
251 /* Wrap. */
252 Euler_rotate_doc,
253 ".. method:: rotate(other)\n"
254 "\n"
255 " Rotates the euler by another mathutils value.\n"
256 "\n"
257 " :arg other: rotation component of mathutils value\n"
258 " :type other: :class:`Euler` | :class:`Quaternion` | :class:`Matrix`\n");
259static PyObject *Euler_rotate(EulerObject *self, PyObject *value)
260{
261 float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
262
264 return nullptr;
265 }
266
267 if (mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1) {
268 return nullptr;
269 }
270
271 eulO_to_mat3(self_rmat, self->eul, self->order);
272 mul_m3_m3m3(rmat, other_rmat, self_rmat);
273
274 mat3_to_compatible_eulO(self->eul, self->eul, self->order, rmat);
275
277 Py_RETURN_NONE;
278}
279
281 /* Wrap. */
282 Euler_make_compatible_doc,
283 ".. method:: make_compatible(other)\n"
284 "\n"
285 " Make this euler compatible with another,\n"
286 " so interpolating between them works as intended.\n"
287 "\n"
288 " .. note:: the rotation order is not taken into account for this function.\n");
289static PyObject *Euler_make_compatible(EulerObject *self, PyObject *value)
290{
291 float teul[EULER_SIZE];
292
294 return nullptr;
295 }
296
297 if (mathutils_array_parse(teul,
300 value,
301 "euler.make_compatible(other), invalid 'other' arg") == -1)
302 {
303 return nullptr;
304 }
305
306 compatible_eul(self->eul, teul);
307
309
310 Py_RETURN_NONE;
311}
312
314 /* Wrap. */
315 Euler_copy_doc,
316 ".. function:: copy()\n"
317 "\n"
318 " Returns a copy of this euler.\n"
319 "\n"
320 " :return: A copy of the euler.\n"
321 " :rtype: :class:`Euler`\n"
322 "\n"
323 " .. note:: use this to get a copy of a wrapped euler with\n"
324 " no reference to the original data.\n");
325static PyObject *Euler_copy(EulerObject *self)
326{
327 if (BaseMath_ReadCallback(self) == -1) {
328 return nullptr;
329 }
330
331 return Euler_CreatePyObject(self->eul, self->order, Py_TYPE(self));
332}
333static PyObject *Euler_deepcopy(EulerObject *self, PyObject *args)
334{
335 if (!PyC_CheckArgs_DeepCopy(args)) {
336 return nullptr;
337 }
338 return Euler_copy(self);
339}
340
343/* -------------------------------------------------------------------- */
347static PyObject *Euler_repr(EulerObject *self)
348{
349 PyObject *ret, *tuple;
350
351 if (BaseMath_ReadCallback(self) == -1) {
352 return nullptr;
353 }
354
355 tuple = Euler_to_tuple_ex(self, -1);
356
357 ret = PyUnicode_FromFormat("Euler(%R, '%s')", tuple, euler_order_str(self));
358
359 Py_DECREF(tuple);
360 return ret;
361}
362
363#ifndef MATH_STANDALONE
364static PyObject *Euler_str(EulerObject *self)
365{
366 DynStr *ds;
367
368 if (BaseMath_ReadCallback(self) == -1) {
369 return nullptr;
370 }
371
372 ds = BLI_dynstr_new();
373
375 "<Euler (x=%.4f, y=%.4f, z=%.4f), order='%s'>",
376 self->eul[0],
377 self->eul[1],
378 self->eul[2],
380
381 return mathutils_dynstr_to_py(ds); /* frees ds */
382}
383#endif
384
387/* -------------------------------------------------------------------- */
391static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
392{
393 PyObject *res;
394 int ok = -1; /* zero is true */
395
397 EulerObject *eulA = (EulerObject *)a;
398 EulerObject *eulB = (EulerObject *)b;
399
400 if (BaseMath_ReadCallback(eulA) == -1 || BaseMath_ReadCallback(eulB) == -1) {
401 return nullptr;
402 }
403
404 ok = ((eulA->order == eulB->order) &&
405 EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1)) ?
406 0 :
407 -1;
408 }
409
410 switch (op) {
411 case Py_NE:
412 ok = !ok;
414 case Py_EQ:
415 res = ok ? Py_False : Py_True;
416 break;
417
418 case Py_LT:
419 case Py_LE:
420 case Py_GT:
421 case Py_GE:
422 res = Py_NotImplemented;
423 break;
424 default:
425 PyErr_BadArgument();
426 return nullptr;
427 }
428
429 return Py_NewRef(res);
430}
431
434/* -------------------------------------------------------------------- */
438static Py_hash_t Euler_hash(EulerObject *self)
439{
440 if (BaseMath_ReadCallback(self) == -1) {
441 return -1;
442 }
443
445 return -1;
446 }
447
449}
450
453/* -------------------------------------------------------------------- */
458static Py_ssize_t Euler_len(EulerObject * /*self*/)
459{
460 return EULER_SIZE;
461}
462
464static PyObject *Euler_item(EulerObject *self, Py_ssize_t i)
465{
466 if (i < 0) {
467 i = EULER_SIZE - i;
468 }
469
470 if (i < 0 || i >= EULER_SIZE) {
471 PyErr_SetString(PyExc_IndexError,
472 "euler[attribute]: "
473 "array index out of range");
474 return nullptr;
475 }
476
477 if (BaseMath_ReadIndexCallback(self, i) == -1) {
478 return nullptr;
479 }
480
481 return PyFloat_FromDouble(self->eul[i]);
482}
483
485static int Euler_ass_item(EulerObject *self, Py_ssize_t i, PyObject *value)
486{
487 float f;
488
489 if (BaseMath_Prepare_ForWrite(self) == -1) {
490 return -1;
491 }
492
493 f = PyFloat_AsDouble(value);
494 if (f == -1 && PyErr_Occurred()) { /* parsed item not a number */
495 PyErr_SetString(PyExc_TypeError,
496 "euler[attribute] = x: "
497 "assigned value not a number");
498 return -1;
499 }
500
501 if (i < 0) {
502 i = EULER_SIZE - i;
503 }
504
505 if (i < 0 || i >= EULER_SIZE) {
506 PyErr_SetString(PyExc_IndexError,
507 "euler[attribute] = x: "
508 "array assignment index out of range");
509 return -1;
510 }
511
512 self->eul[i] = f;
513
514 if (BaseMath_WriteIndexCallback(self, i) == -1) {
515 return -1;
516 }
517
518 return 0;
519}
520
522static PyObject *Euler_slice(EulerObject *self, int begin, int end)
523{
524 PyObject *tuple;
525 int count;
526
527 if (BaseMath_ReadCallback(self) == -1) {
528 return nullptr;
529 }
530
531 CLAMP(begin, 0, EULER_SIZE);
532 if (end < 0) {
533 end = (EULER_SIZE + 1) + end;
534 }
535 CLAMP(end, 0, EULER_SIZE);
536 begin = std::min(begin, end);
537
538 tuple = PyTuple_New(end - begin);
539 for (count = begin; count < end; count++) {
540 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->eul[count]));
541 }
542
543 return tuple;
544}
545
547static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
548{
549 int i, size;
550 float eul[EULER_SIZE];
551
553 return -1;
554 }
555
556 CLAMP(begin, 0, EULER_SIZE);
557 if (end < 0) {
558 end = (EULER_SIZE + 1) + end;
559 }
560 CLAMP(end, 0, EULER_SIZE);
561 begin = std::min(begin, end);
562
563 if ((size = mathutils_array_parse(eul, 0, EULER_SIZE, seq, "mathutils.Euler[begin:end] = []")) ==
564 -1)
565 {
566 return -1;
567 }
568
569 if (size != (end - begin)) {
570 PyErr_SetString(PyExc_ValueError,
571 "euler[begin:end] = []: "
572 "size mismatch in slice assignment");
573 return -1;
574 }
575
576 for (i = 0; i < EULER_SIZE; i++) {
577 self->eul[begin + i] = eul[i];
578 }
579
581 return 0;
582}
583
585static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
586{
587 if (PyIndex_Check(item)) {
588 Py_ssize_t i;
589 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
590 if (i == -1 && PyErr_Occurred()) {
591 return nullptr;
592 }
593 if (i < 0) {
594 i += EULER_SIZE;
595 }
596 return Euler_item(self, i);
597 }
598 if (PySlice_Check(item)) {
599 Py_ssize_t start, stop, step, slicelength;
600
601 if (PySlice_GetIndicesEx(item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0) {
602 return nullptr;
603 }
604
605 if (slicelength <= 0) {
606 return PyTuple_New(0);
607 }
608 if (step == 1) {
609 return Euler_slice(self, start, stop);
610 }
611
612 PyErr_SetString(PyExc_IndexError, "slice steps not supported with eulers");
613 return nullptr;
614 }
615
616 PyErr_Format(
617 PyExc_TypeError, "euler indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
618 return nullptr;
619}
620
622static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *value)
623{
624 if (PyIndex_Check(item)) {
625 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
626 if (i == -1 && PyErr_Occurred()) {
627 return -1;
628 }
629 if (i < 0) {
630 i += EULER_SIZE;
631 }
632 return Euler_ass_item(self, i, value);
633 }
634 if (PySlice_Check(item)) {
635 Py_ssize_t start, stop, step, slicelength;
636
637 if (PySlice_GetIndicesEx(item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0) {
638 return -1;
639 }
640
641 if (step == 1) {
642 return Euler_ass_slice(self, start, stop, value);
643 }
644
645 PyErr_SetString(PyExc_IndexError, "slice steps not supported with euler");
646 return -1;
647 }
648
649 PyErr_Format(
650 PyExc_TypeError, "euler indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
651 return -1;
652}
653
656/* -------------------------------------------------------------------- */
660static PySequenceMethods Euler_SeqMethods = {
661 /*sq_length*/ (lenfunc)Euler_len,
662 /*sq_concat*/ nullptr,
663 /*sq_repeat*/ nullptr,
664 /*sq_item*/ (ssizeargfunc)Euler_item,
665 /*was_sq_slice*/ nullptr, /* DEPRECATED. */
666 /*sq_ass_item*/ (ssizeobjargproc)Euler_ass_item,
667 /*was_sq_ass_slice*/ nullptr, /* DEPRECATED. */
668 /*sq_contains*/ nullptr,
669 /*sq_inplace_concat*/ nullptr,
670 /*sq_inplace_repeat*/ nullptr,
671};
672
673static PyMappingMethods Euler_AsMapping = {
674 /*mp_length*/ (lenfunc)Euler_len,
675 /*mp_subscript*/ (binaryfunc)Euler_subscript,
676 /*mp_ass_subscript*/ (objobjargproc)Euler_ass_subscript,
677};
678
681/* -------------------------------------------------------------------- */
685/* Euler axis: `euler.x/y/z`. */
686
688 /* Wrap. */
689 Euler_axis_doc,
690 "Euler axis angle in radians.\n"
691 "\n"
692 ":type: float");
693static PyObject *Euler_axis_get(EulerObject *self, void *type)
694{
695 return Euler_item(self, POINTER_AS_INT(type));
696}
697
698static int Euler_axis_set(EulerObject *self, PyObject *value, void *type)
699{
700 return Euler_ass_item(self, POINTER_AS_INT(type), value);
701}
702
703/* Euler rotation order: `euler.order`. */
704
706 /* Wrap. */
707 Euler_order_doc,
708 "Euler rotation order.\n"
709 "\n"
710 ":type: str in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']");
711static PyObject *Euler_order_get(EulerObject *self, void * /*closure*/)
712{
713 if (BaseMath_ReadCallback(self) == -1) {
714 /* can read order too */
715 return nullptr;
716 }
717
718 return PyUnicode_FromString(euler_order_str(self));
719}
720
721static int Euler_order_set(EulerObject *self, PyObject *value, void * /*closure*/)
722{
723 const char *order_str;
724 short order;
725
726 if (BaseMath_Prepare_ForWrite(self) == -1) {
727 return -1;
728 }
729
730 if (((order_str = PyUnicode_AsUTF8(value)) == nullptr) ||
731 ((order = euler_order_from_string(order_str, "euler.order")) == -1))
732 {
733 return -1;
734 }
735
736 self->order = order;
737 (void)BaseMath_WriteCallback(self); /* order can be written back */
738 return 0;
739}
740
743/* -------------------------------------------------------------------- */
747static PyGetSetDef Euler_getseters[] = {
748 {"x", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, POINTER_FROM_INT(0)},
749 {"y", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, POINTER_FROM_INT(1)},
750 {"z", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, POINTER_FROM_INT(2)},
751 {"order", (getter)Euler_order_get, (setter)Euler_order_set, Euler_order_doc, nullptr},
752
753 {"is_wrapped",
755 (setter) nullptr,
757 nullptr},
758 {"is_frozen",
760 (setter) nullptr,
762 nullptr},
763 {"is_valid",
765 (setter) nullptr,
767 nullptr},
768 {"owner",
770 (setter) nullptr,
772 nullptr},
773 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
774};
775
778/* -------------------------------------------------------------------- */
782#if (defined(__GNUC__) && !defined(__clang__))
783# pragma GCC diagnostic push
784# pragma GCC diagnostic ignored "-Wcast-function-type"
785#endif
786
787static PyMethodDef Euler_methods[] = {
788 {"zero", (PyCFunction)Euler_zero, METH_NOARGS, Euler_zero_doc},
789 {"to_matrix", (PyCFunction)Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc},
790 {"to_quaternion", (PyCFunction)Euler_to_quaternion, METH_NOARGS, Euler_to_quaternion_doc},
791 {"rotate_axis", (PyCFunction)Euler_rotate_axis, METH_VARARGS, Euler_rotate_axis_doc},
792 {"rotate", (PyCFunction)Euler_rotate, METH_O, Euler_rotate_doc},
793 {"make_compatible", (PyCFunction)Euler_make_compatible, METH_O, Euler_make_compatible_doc},
794 {"copy", (PyCFunction)Euler_copy, METH_NOARGS, Euler_copy_doc},
795 {"__copy__", (PyCFunction)Euler_copy, METH_NOARGS, Euler_copy_doc},
796 {"__deepcopy__", (PyCFunction)Euler_deepcopy, METH_VARARGS, Euler_copy_doc},
797
798 /* base-math methods */
799 {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
800 {nullptr, nullptr, 0, nullptr},
801};
802
803#if (defined(__GNUC__) && !defined(__clang__))
804# pragma GCC diagnostic pop
805#endif
806
809/* -------------------------------------------------------------------- */
813#ifdef MATH_STANDALONE
814# define Euler_str nullptr
815#endif
816
818 /* Wrap. */
819 euler_doc,
820 ".. class:: Euler(angles, order='XYZ')\n"
821 "\n"
822 " This object gives access to Eulers in Blender.\n"
823 "\n"
824 " .. seealso:: `Euler angles <https://en.wikipedia.org/wiki/Euler_angles>`__ on Wikipedia.\n"
825 "\n"
826 " :arg angles: (X, Y, Z) angles in radians.\n"
827 " :type angles: Sequence[float]\n"
828 " :arg order: Optional order of the angles, a permutation of ``XYZ``.\n"
829 " :type order: str\n");
830PyTypeObject euler_Type = {
831 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
832 /*tp_name*/ "Euler",
833 /*tp_basicsize*/ sizeof(EulerObject),
834 /*tp_itemsize*/ 0,
835 /*tp_dealloc*/ (destructor)BaseMathObject_dealloc,
836 /*tp_vectorcall_offset*/ 0,
837 /*tp_getattr*/ nullptr,
838 /*tp_setattr*/ nullptr,
839 /*tp_as_async*/ nullptr,
840 /*tp_repr*/ (reprfunc)Euler_repr,
841 /*tp_as_number*/ nullptr,
842 /*tp_as_sequence*/ &Euler_SeqMethods,
843 /*tp_as_mapping*/ &Euler_AsMapping,
844 /*tp_hash*/ (hashfunc)Euler_hash,
845 /*tp_call*/ nullptr,
846 /*tp_str*/ (reprfunc)Euler_str,
847 /*tp_getattro*/ nullptr,
848 /*tp_setattro*/ nullptr,
849 /*tp_as_buffer*/ nullptr,
850 /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
851 /*tp_doc*/ euler_doc,
852 /*tp_traverse*/ (traverseproc)BaseMathObject_traverse,
853 /*tp_clear*/ (inquiry)BaseMathObject_clear,
854 /*tp_richcompare*/ (richcmpfunc)Euler_richcmpr,
855 /*tp_weaklistoffset*/ 0,
856 /*tp_iter*/ nullptr,
857 /*tp_iternext*/ nullptr,
858 /*tp_methods*/ Euler_methods,
859 /*tp_members*/ nullptr,
860 /*tp_getset*/ Euler_getseters,
861 /*tp_base*/ nullptr,
862 /*tp_dict*/ nullptr,
863 /*tp_descr_get*/ nullptr,
864 /*tp_descr_set*/ nullptr,
865 /*tp_dictoffset*/ 0,
866 /*tp_init*/ nullptr,
867 /*tp_alloc*/ nullptr,
868 /*tp_new*/ Euler_new,
869 /*tp_free*/ nullptr,
870 /*tp_is_gc*/ (inquiry)BaseMathObject_is_gc,
871 /*tp_bases*/ nullptr,
872 /*tp_mro*/ nullptr,
873 /*tp_cache*/ nullptr,
874 /*tp_subclasses*/ nullptr,
875 /*tp_weaklist*/ nullptr,
876 /*tp_del*/ nullptr,
877 /*tp_version_tag*/ 0,
878 /*tp_finalize*/ nullptr,
879 /*tp_vectorcall*/ nullptr,
880};
881
882#ifdef MATH_STANDALONE
883# undef Euler_str
884#endif
885
888/* -------------------------------------------------------------------- */
892PyObject *Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
893{
895 float *eul_alloc;
896
897 eul_alloc = static_cast<float *>(PyMem_Malloc(EULER_SIZE * sizeof(float)));
898 if (UNLIKELY(eul_alloc == nullptr)) {
899 PyErr_SetString(PyExc_MemoryError,
900 "Euler(): "
901 "problem allocating data");
902 return nullptr;
903 }
904
906 if (self) {
907 self->eul = eul_alloc;
908
909 /* init callbacks as nullptr */
910 self->cb_user = nullptr;
911 self->cb_type = self->cb_subtype = 0;
912
913 if (eul) {
914 copy_v3_v3(self->eul, eul);
915 }
916 else {
917 zero_v3(self->eul);
918 }
919
921 self->order = order;
922 }
923 else {
924 PyMem_Free(eul_alloc);
925 }
926
927 return (PyObject *)self;
928}
929
930PyObject *Euler_CreatePyObject_wrap(float eul[3], const short order, PyTypeObject *base_type)
931{
933
935 if (self) {
936 /* init callbacks as nullptr */
937 self->cb_user = nullptr;
938 self->cb_type = self->cb_subtype = 0;
939
940 self->eul = eul;
942
943 self->order = order;
944 }
945
946 return (PyObject *)self;
947}
948
949PyObject *Euler_CreatePyObject_cb(PyObject *cb_user,
950 const short order,
951 uchar cb_type,
952 uchar cb_subtype)
953{
954 EulerObject *self = (EulerObject *)Euler_CreatePyObject(nullptr, order, nullptr);
955 if (self) {
956 Py_INCREF(cb_user);
957 self->cb_user = cb_user;
958 self->cb_type = cb_type;
959 self->cb_subtype = cb_subtype;
960 BLI_assert(!PyObject_GC_IsTracked((PyObject *)self));
961 PyObject_GC_Track(self);
962 }
963
964 return (PyObject *)self;
965}
966
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ATTR_FALLTHROUGH
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_dynstr.c:37
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:28
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
void rotate_eulO(float beul[3], short order, char axis, float angle)
@ EULER_ORDER_ZXY
@ EULER_ORDER_XZY
@ EULER_ORDER_XYZ
@ EULER_ORDER_YZX
@ EULER_ORDER_ZYX
@ EULER_ORDER_YXZ
void eulO_to_quat(float q[4], const float e[3], short order)
void mat3_to_compatible_eulO(float eul[3], const float oldrot[3], short order, const float mat[3][3])
void compatible_eul(float eul[3], const float oldrot[3])
void eulO_to_mat3(float M[3][3], const float e[3], short order)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void zero_v3(float r[3])
unsigned char uchar
#define CLAMP(a, b, c)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define UNLIKELY(x)
#define ELEM(...)
PyObject * self
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
local_group_size(16, 16) .push_constant(Type b
#define str(s)
int count
int BaseMathObject_is_gc(BaseMathObject *self)
Definition mathutils.cc:711
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
Definition mathutils.cc:69
void BaseMathObject_dealloc(BaseMathObject *self)
Definition mathutils.cc:689
int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps)
Definition mathutils.cc:490
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition mathutils.cc:97
char BaseMathObject_is_valid_doc[]
Definition mathutils.cc:639
char BaseMathObject_is_wrapped_doc[]
Definition mathutils.cc:625
PyObject * BaseMathObject_owner_get(BaseMathObject *self, void *)
Definition mathutils.cc:619
char BaseMathObject_is_frozen_doc[]
Definition mathutils.cc:632
PyObject * mathutils_dynstr_to_py(DynStr *ds)
Definition mathutils.cc:502
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
Definition mathutils.cc:409
PyObject * BaseMathObject_is_frozen_get(BaseMathObject *self, void *)
Definition mathutils.cc:634
PyObject * BaseMathObject_freeze(BaseMathObject *self)
Definition mathutils.cc:653
PyObject * BaseMathObject_is_wrapped_get(BaseMathObject *self, void *)
Definition mathutils.cc:627
char BaseMathObject_owner_doc[]
Definition mathutils.cc:618
char BaseMathObject_freeze_doc[]
Definition mathutils.cc:645
PyObject * BaseMathObject_is_valid_get(BaseMathObject *self, void *)
Definition mathutils.cc:640
int BaseMathObject_clear(BaseMathObject *self)
Definition mathutils.cc:671
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
Definition mathutils.cc:665
@ BASE_MATH_FLAG_IS_WRAP
Definition mathutils.hh:36
#define BaseMath_ReadCallback_ForWrite(_self)
Definition mathutils.hh:135
#define BaseMath_ReadIndexCallback(_self, _index)
Definition mathutils.hh:129
#define BaseMath_WriteCallback(_self)
Definition mathutils.hh:127
#define BASE_MATH_NEW(struct_name, root_type, base_type)
Definition mathutils.hh:26
#define BaseMathObject_Prepare_ForHash(_self)
Definition mathutils.hh:150
#define BASE_MATH_FLAG_DEFAULT
Definition mathutils.hh:43
#define BaseMath_Prepare_ForWrite(_self)
Definition mathutils.hh:145
#define BaseMath_ReadCallback(_self)
Definition mathutils.hh:125
#define BaseMath_WriteIndexCallback(_self, _index)
Definition mathutils.hh:131
static PyObject * Euler_copy(EulerObject *self)
static PyObject * Euler_to_tuple_ex(EulerObject *self, int ndigits)
static PySequenceMethods Euler_SeqMethods
static PyObject * Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
PyObject * Euler_CreatePyObject_wrap(float eul[3], const short order, PyTypeObject *base_type)
static PyObject * Euler_item(EulerObject *self, Py_ssize_t i)
static PyObject * Euler_zero(EulerObject *self)
short euler_order_from_string(const char *str, const char *error_prefix)
static PyObject * Euler_subscript(EulerObject *self, PyObject *item)
static PyObject * Euler_rotate(EulerObject *self, PyObject *value)
static const char * euler_order_str(EulerObject *self)
static Py_hash_t Euler_hash(EulerObject *self)
static PyObject * Euler_order_get(EulerObject *self, void *)
PyTypeObject euler_Type
#define MAKE_ID3(a, b, c)
PyObject * Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
static int Euler_axis_set(EulerObject *self, PyObject *value, void *type)
static PyObject * Euler_repr(EulerObject *self)
static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *value)
static int Euler_order_set(EulerObject *self, PyObject *value, void *)
static PyObject * Euler_str(EulerObject *self)
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_richcmpr(PyObject *a, PyObject *b, int op)
static PyObject * Euler_deepcopy(EulerObject *self, PyObject *args)
static PyObject * Euler_make_compatible(EulerObject *self, PyObject *value)
#define EULER_SIZE
static PyGetSetDef Euler_getseters[]
static Py_ssize_t Euler_len(EulerObject *)
static int Euler_ass_item(EulerObject *self, Py_ssize_t i, PyObject *value)
static PyObject * Euler_rotate_axis(EulerObject *self, PyObject *args)
static PyMappingMethods Euler_AsMapping
static PyObject * Euler_axis_get(EulerObject *self, void *type)
PyObject * Euler_CreatePyObject_cb(PyObject *cb_user, const short order, uchar cb_type, uchar cb_subtype)
static PyObject * Euler_slice(EulerObject *self, int begin, int end)
static PyMethodDef Euler_methods[]
static PyObject * Euler_to_matrix(EulerObject *self)
static PyObject * Euler_to_quaternion(EulerObject *self)
#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)
int PyC_CheckArgs_DeepCopy(PyObject *args)
header-only utilities
return ret
unsigned char order