Blender V5.0
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
8
9#include <algorithm>
10
11#include <Python.h>
12
13#include "mathutils.hh"
14
16#include "BLI_math_matrix.h"
17#include "BLI_math_rotation.h"
18#include "BLI_math_vector.h"
19#include "BLI_utildefines.h"
20
21#ifndef MATH_STANDALONE
22# include "BLI_dynstr.h"
23#endif
24
25#define EULER_SIZE 3
26
27/* -------------------------------------------------------------------- */
30
32static const char *euler_order_str(EulerObject *self)
33{
34 static const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
35 return order[self->order - EULER_ORDER_XYZ];
36}
37
38short euler_order_from_string(const char *str, const char *error_prefix)
39{
40 if (str[0] && str[1] && str[2] && str[3] == '\0') {
41
42/* NOTE: this is endianness-sensitive. */
43#define MAKE_ID3(a, b, c) ((a) | ((b) << 8) | ((c) << 16))
44
45 switch (*((const PY_INT32_T *)str)) {
46 case MAKE_ID3('X', 'Y', 'Z'): {
47 return EULER_ORDER_XYZ;
48 }
49 case MAKE_ID3('X', 'Z', 'Y'): {
50 return EULER_ORDER_XZY;
51 }
52 case MAKE_ID3('Y', 'X', 'Z'): {
53 return EULER_ORDER_YXZ;
54 }
55 case MAKE_ID3('Y', 'Z', 'X'): {
56 return EULER_ORDER_YZX;
57 }
58 case MAKE_ID3('Z', 'X', 'Y'): {
59 return EULER_ORDER_ZXY;
60 }
61 case MAKE_ID3('Z', 'Y', 'X'): {
62 return EULER_ORDER_ZYX;
63 }
64 }
65
66#undef MAKE_ID3
67 }
68
69 PyErr_Format(PyExc_ValueError, "%s: invalid euler order '%s'", error_prefix, str);
70 return -1;
71}
72
76static PyObject *Euler_to_tuple_ex(EulerObject *self, int ndigits)
77{
78 PyObject *ret;
79 int i;
80
81 ret = PyTuple_New(EULER_SIZE);
82
83 if (ndigits >= 0) {
84 for (i = 0; i < EULER_SIZE; i++) {
85 PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round(double(self->eul[i]), ndigits)));
86 }
87 }
88 else {
89 for (i = 0; i < EULER_SIZE; i++) {
90 PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->eul[i]));
91 }
92 }
93
94 return ret;
95}
96
98
99/* -------------------------------------------------------------------- */
102
103static PyObject *Euler_vectorcall(PyObject *type,
104 PyObject *const *args,
105 const size_t nargsf,
106 PyObject *kwnames)
107{
108 if (UNLIKELY(kwnames && PyTuple_GET_SIZE(kwnames))) {
109 PyErr_SetString(PyExc_TypeError,
110 "mathutils.Euler(): "
111 "takes no keyword args");
112 return nullptr;
113 }
114
115 float eul[EULER_SIZE] = {0.0f, 0.0f, 0.0f};
116 short order = EULER_ORDER_XYZ;
117
118 const size_t nargs = PyVectorcall_NARGS(nargsf);
119 switch (nargs) {
120 case 0: {
121 break;
122 }
123 case 2: {
124 const char *order_str;
125
126 if (((order_str = PyUnicode_AsUTF8(args[1])) == nullptr) ||
127 ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1))
128 {
129 return nullptr;
130 }
132 }
133 case 1: {
134 if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, args[0], "mathutils.Euler()") == -1) {
135 return nullptr;
136 }
137 break;
138 }
139 default: {
140 PyErr_Format(PyExc_TypeError,
141 "mathutils.Euler(): "
142 "takes at most 2 arguments (%zd given)",
143 nargs);
144 return nullptr;
145 }
146 }
147 return Euler_CreatePyObject(eul, order, (PyTypeObject *)type);
148}
149
150static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
151{
152 /* Only called on sub-classes. */
153 if (UNLIKELY(kwds && PyDict_GET_SIZE(kwds))) {
154 PyErr_SetString(PyExc_TypeError,
155 "mathutils.Euler(): "
156 "takes no keyword args");
157 return nullptr;
158 }
159 PyObject *const *args_array = &PyTuple_GET_ITEM(args, 0);
160 const size_t args_array_num = PyTuple_GET_SIZE(args);
161 return Euler_vectorcall(reinterpret_cast<PyObject *>(type), args_array, args_array_num, nullptr);
162}
163
165
166/* -------------------------------------------------------------------- */
169
171 /* Wrap. */
172 Euler_to_quaternion_doc,
173 ".. method:: to_quaternion()\n"
174 "\n"
175 " Return a quaternion representation of the euler.\n"
176 "\n"
177 " :return: Quaternion representation of the euler.\n"
178 " :rtype: :class:`Quaternion`\n");
180{
181 float quat[4];
182
183 if (BaseMath_ReadCallback(self) == -1) {
184 return nullptr;
185 }
186
187 eulO_to_quat(quat, self->eul, self->order);
188
189 return Quaternion_CreatePyObject(quat, nullptr);
190}
191
193 /* Wrap. */
194 Euler_to_matrix_doc,
195 ".. method:: to_matrix()\n"
196 "\n"
197 " Return a matrix representation of the euler.\n"
198 "\n"
199 " :return: A 3x3 rotation matrix representation of the euler.\n"
200 " :rtype: :class:`Matrix`\n");
202{
203 float mat[9];
204
205 if (BaseMath_ReadCallback(self) == -1) {
206 return nullptr;
207 }
208
209 eulO_to_mat3((float (*)[3])mat, self->eul, self->order);
210
211 return Matrix_CreatePyObject(mat, 3, 3, nullptr);
212}
213
215 /* Wrap. */
216 Euler_zero_doc,
217 ".. method:: zero()\n"
218 "\n"
219 " Set all values to zero.\n");
220static PyObject *Euler_zero(EulerObject *self)
221{
222 if (BaseMath_Prepare_ForWrite(self) == -1) {
223 return nullptr;
224 }
225
226 zero_v3(self->eul);
227
228 if (BaseMath_WriteCallback(self) == -1) {
229 return nullptr;
230 }
231
232 Py_RETURN_NONE;
233}
234
236 /* Wrap. */
237 Euler_rotate_axis_doc,
238 ".. method:: rotate_axis(axis, angle, /)\n"
239 "\n"
240 " Rotates the euler a certain amount and returning a unique euler rotation\n"
241 " (no 720 degree pitches).\n"
242 "\n"
243 " :arg axis: An axis string.\n"
244 " :type axis: Literal['X', 'Y', 'Z']\n"
245 " :arg angle: angle in radians.\n"
246 " :type angle: float\n");
247static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args)
248{
249 float angle = 0.0f;
250 int axis; /* actually a character */
251
252 if (!PyArg_ParseTuple(args, "Cf:rotate_axis", &axis, &angle)) {
253 PyErr_SetString(PyExc_TypeError,
254 "Euler.rotate_axis(): "
255 "expected an axis 'X', 'Y', 'Z' and an angle (float)");
256 return nullptr;
257 }
258
259 if (!ELEM(axis, 'X', 'Y', 'Z')) {
260 PyErr_SetString(PyExc_ValueError,
261 "Euler.rotate_axis(): "
262 "expected axis to be 'X', 'Y' or 'Z'");
263 return nullptr;
264 }
265
267 return nullptr;
268 }
269
270 rotate_eulO(self->eul, self->order, char(axis), angle);
271
273
274 Py_RETURN_NONE;
275}
276
278 /* Wrap. */
279 Euler_rotate_doc,
280 ".. method:: rotate(other, /)\n"
281 "\n"
282 " Rotates the euler by another mathutils value.\n"
283 "\n"
284 " :arg other: rotation component of mathutils value\n"
285 " :type other: :class:`Euler` | :class:`Quaternion` | :class:`Matrix`\n");
286static PyObject *Euler_rotate(EulerObject *self, PyObject *value)
287{
288 float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
289
291 return nullptr;
292 }
293
294 if (mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1) {
295 return nullptr;
296 }
297
298 eulO_to_mat3(self_rmat, self->eul, self->order);
299 mul_m3_m3m3(rmat, other_rmat, self_rmat);
300
301 mat3_to_compatible_eulO(self->eul, self->eul, self->order, rmat);
302
304 Py_RETURN_NONE;
305}
306
308 /* Wrap. */
309 Euler_make_compatible_doc,
310 ".. method:: make_compatible(other, /)\n"
311 "\n"
312 " Make this euler compatible with another,\n"
313 " so interpolating between them works as intended.\n"
314 "\n"
315 " :arg other: Other euler rotation.\n"
316 " :type other: :class:`Euler`\n"
317 "\n"
318 " .. note:: the rotation order is not taken into account for this function.\n");
319static PyObject *Euler_make_compatible(EulerObject *self, PyObject *value)
320{
321 float teul[EULER_SIZE];
322
324 return nullptr;
325 }
326
327 if (mathutils_array_parse(teul,
330 value,
331 "euler.make_compatible(other), invalid 'other' arg") == -1)
332 {
333 return nullptr;
334 }
335
336 compatible_eul(self->eul, teul);
337
339
340 Py_RETURN_NONE;
341}
342
344 /* Wrap. */
345 Euler_copy_doc,
346 ".. function:: copy()\n"
347 "\n"
348 " Returns a copy of this euler.\n"
349 "\n"
350 " :return: A copy of the euler.\n"
351 " :rtype: :class:`Euler`\n"
352 "\n"
353 " .. note:: use this to get a copy of a wrapped euler with\n"
354 " no reference to the original data.\n");
355static PyObject *Euler_copy(EulerObject *self)
356{
357 if (BaseMath_ReadCallback(self) == -1) {
358 return nullptr;
359 }
360
361 return Euler_CreatePyObject(self->eul, self->order, Py_TYPE(self));
362}
363static PyObject *Euler_deepcopy(EulerObject *self, PyObject *args)
364{
365 if (!PyC_CheckArgs_DeepCopy(args)) {
366 return nullptr;
367 }
368 return Euler_copy(self);
369}
370
372
373/* -------------------------------------------------------------------- */
376
377static PyObject *Euler_repr(EulerObject *self)
378{
379 PyObject *ret, *tuple;
380
381 if (BaseMath_ReadCallback(self) == -1) {
382 return nullptr;
383 }
384
385 tuple = Euler_to_tuple_ex(self, -1);
386
387 ret = PyUnicode_FromFormat("Euler(%R, '%s')", tuple, euler_order_str(self));
388
389 Py_DECREF(tuple);
390 return ret;
391}
392
393#ifndef MATH_STANDALONE
394static PyObject *Euler_str(EulerObject *self)
395{
396 DynStr *ds;
397
398 if (BaseMath_ReadCallback(self) == -1) {
399 return nullptr;
400 }
401
402 ds = BLI_dynstr_new();
403
405 "<Euler (x=%.4f, y=%.4f, z=%.4f), order='%s'>",
406 self->eul[0],
407 self->eul[1],
408 self->eul[2],
410
411 return mathutils_dynstr_to_py(ds); /* frees ds */
412}
413#endif
414
416
417/* -------------------------------------------------------------------- */
420
421static int Euler_getbuffer(PyObject *obj, Py_buffer *view, int flags)
422{
423 EulerObject *self = (EulerObject *)obj;
425 return -1;
426 }
427 if (UNLIKELY(BaseMath_ReadCallback(self) == -1)) {
428 return -1;
429 }
430
431 memset(view, 0, sizeof(*view));
432
433 view->obj = (PyObject *)self;
434 view->buf = (void *)self->eul;
435 view->len = Py_ssize_t(EULER_SIZE * sizeof(float));
436 view->itemsize = sizeof(float);
437 view->ndim = 1;
438 if ((flags & PyBUF_WRITABLE) == 0) {
439 view->readonly = 1;
440 }
441 if (flags & PyBUF_FORMAT) {
442 view->format = (char *)"f";
443 }
444
446
447 Py_INCREF(self);
448 return 0;
449}
450
451static void Euler_releasebuffer(PyObject * /*exporter*/, Py_buffer *view)
452{
453 EulerObject *self = (EulerObject *)view->obj;
455
456 if (view->readonly == 0) {
458 PyErr_Print();
459 }
460 }
461}
462
463static PyBufferProcs Euler_as_buffer = {
464 (getbufferproc)Euler_getbuffer,
465 (releasebufferproc)Euler_releasebuffer,
466};
467
469
470/* -------------------------------------------------------------------- */
473
474static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
475{
476 PyObject *res;
477 int ok = -1; /* zero is true */
478
480 EulerObject *eulA = (EulerObject *)a;
481 EulerObject *eulB = (EulerObject *)b;
482
483 if (BaseMath_ReadCallback(eulA) == -1 || BaseMath_ReadCallback(eulB) == -1) {
484 return nullptr;
485 }
486
487 ok = ((eulA->order == eulB->order) &&
488 EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1)) ?
489 0 :
490 -1;
491 }
492
493 switch (op) {
494 case Py_NE: {
495 ok = !ok;
497 }
498 case Py_EQ: {
499 res = ok ? Py_False : Py_True;
500 break;
501 }
502 case Py_LT:
503 case Py_LE:
504 case Py_GT:
505 case Py_GE: {
506 res = Py_NotImplemented;
507 break;
508 }
509 default: {
510 PyErr_BadArgument();
511 return nullptr;
512 }
513 }
514
515 return Py_NewRef(res);
516}
517
519
520/* -------------------------------------------------------------------- */
523
524static Py_hash_t Euler_hash(EulerObject *self)
525{
526 if (BaseMath_ReadCallback(self) == -1) {
527 return -1;
528 }
529
531 return -1;
532 }
533
535}
536
538
539/* -------------------------------------------------------------------- */
542
544static Py_ssize_t Euler_len(EulerObject * /*self*/)
545{
546 return EULER_SIZE;
547}
548
550static PyObject *Euler_item(EulerObject *self, Py_ssize_t i)
551{
552 if (i < 0) {
553 i = EULER_SIZE - i;
554 }
555
557 PyErr_SetString(PyExc_IndexError,
558 "euler[attribute]: "
559 "array index out of range");
560 return nullptr;
561 }
562
563 if (BaseMath_ReadIndexCallback(self, i) == -1) {
564 return nullptr;
565 }
566
567 return PyFloat_FromDouble(self->eul[i]);
568}
569
571static int Euler_ass_item(EulerObject *self, Py_ssize_t i, PyObject *value)
572{
573 float f;
574
575 if (BaseMath_Prepare_ForWrite(self) == -1) {
576 return -1;
577 }
578
579 f = PyFloat_AsDouble(value);
580 if (f == -1 && PyErr_Occurred()) { /* parsed item not a number */
581 PyErr_SetString(PyExc_TypeError,
582 "euler[attribute] = x: "
583 "assigned value not a number");
584 return -1;
585 }
586
587 if (i < 0) {
588 i = EULER_SIZE - i;
589 }
590
592 PyErr_SetString(PyExc_IndexError,
593 "euler[attribute] = x: "
594 "array assignment index out of range");
595 return -1;
596 }
597
598 self->eul[i] = f;
599
600 if (BaseMath_WriteIndexCallback(self, i) == -1) {
601 return -1;
602 }
603
604 return 0;
605}
606
608static PyObject *Euler_slice(EulerObject *self, int begin, int end)
609{
610 PyObject *tuple;
611 int count;
612
613 if (BaseMath_ReadCallback(self) == -1) {
614 return nullptr;
615 }
616
618 if (end < 0) {
619 end = (EULER_SIZE + 1) + end;
620 }
621 CLAMP(end, 0, EULER_SIZE);
622 begin = std::min(begin, end);
623
624 tuple = PyTuple_New(end - begin);
625 for (count = begin; count < end; count++) {
626 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->eul[count]));
627 }
628
629 return tuple;
630}
631
633static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
634{
635 int i, size;
636 float eul[EULER_SIZE];
637
639 return -1;
640 }
641
643 if (end < 0) {
644 end = (EULER_SIZE + 1) + end;
645 }
646 CLAMP(end, 0, EULER_SIZE);
647 begin = std::min(begin, end);
648
649 if ((size = mathutils_array_parse(eul, 0, EULER_SIZE, seq, "mathutils.Euler[begin:end] = []")) ==
650 -1)
651 {
652 return -1;
653 }
654
655 if (size != (end - begin)) {
656 PyErr_SetString(PyExc_ValueError,
657 "euler[begin:end] = []: "
658 "size mismatch in slice assignment");
659 return -1;
660 }
661
662 for (i = 0; i < EULER_SIZE; i++) {
663 self->eul[begin + i] = eul[i];
664 }
665
667 return 0;
668}
669
671static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
672{
673 if (PyIndex_Check(item)) {
674 Py_ssize_t i;
675 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
676 if (i == -1 && PyErr_Occurred()) {
677 return nullptr;
678 }
679 if (i < 0) {
680 i += EULER_SIZE;
681 }
682 return Euler_item(self, i);
683 }
684 if (PySlice_Check(item)) {
685 Py_ssize_t start, stop, step, slicelength;
686
687 if (PySlice_GetIndicesEx(item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0) {
688 return nullptr;
689 }
690
691 if (slicelength <= 0) {
692 return PyTuple_New(0);
693 }
694 if (step == 1) {
695 return Euler_slice(self, start, stop);
696 }
697
698 PyErr_SetString(PyExc_IndexError, "slice steps not supported with eulers");
699 return nullptr;
700 }
701
702 PyErr_Format(
703 PyExc_TypeError, "euler indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
704 return nullptr;
705}
706
708static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *value)
709{
710 if (PyIndex_Check(item)) {
711 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
712 if (i == -1 && PyErr_Occurred()) {
713 return -1;
714 }
715 if (i < 0) {
716 i += EULER_SIZE;
717 }
718 return Euler_ass_item(self, i, value);
719 }
720 if (PySlice_Check(item)) {
721 Py_ssize_t start, stop, step, slicelength;
722
723 if (PySlice_GetIndicesEx(item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0) {
724 return -1;
725 }
726
727 if (step == 1) {
728 return Euler_ass_slice(self, start, stop, value);
729 }
730
731 PyErr_SetString(PyExc_IndexError, "slice steps not supported with euler");
732 return -1;
733 }
734
735 PyErr_Format(
736 PyExc_TypeError, "euler indices must be integers, not %.200s", Py_TYPE(item)->tp_name);
737 return -1;
738}
739
741
742/* -------------------------------------------------------------------- */
745
746static PySequenceMethods Euler_SeqMethods = {
747 /*sq_length*/ (lenfunc)Euler_len,
748 /*sq_concat*/ nullptr,
749 /*sq_repeat*/ nullptr,
750 /*sq_item*/ (ssizeargfunc)Euler_item,
751 /*was_sq_slice*/ nullptr, /* DEPRECATED. */
752 /*sq_ass_item*/ (ssizeobjargproc)Euler_ass_item,
753 /*was_sq_ass_slice*/ nullptr, /* DEPRECATED. */
754 /*sq_contains*/ nullptr,
755 /*sq_inplace_concat*/ nullptr,
756 /*sq_inplace_repeat*/ nullptr,
757};
758
759static PyMappingMethods Euler_AsMapping = {
760 /*mp_length*/ (lenfunc)Euler_len,
761 /*mp_subscript*/ (binaryfunc)Euler_subscript,
762 /*mp_ass_subscript*/ (objobjargproc)Euler_ass_subscript,
763};
764
766
767/* -------------------------------------------------------------------- */
770
771/* Euler axis: `euler.x/y/z`. */
772
774 /* Wrap. */
775 Euler_axis_doc,
776 "Euler axis angle in radians.\n"
777 "\n"
778 ":type: float\n");
779static PyObject *Euler_axis_get(EulerObject *self, void *type)
780{
781 return Euler_item(self, POINTER_AS_INT(type));
782}
783
784static int Euler_axis_set(EulerObject *self, PyObject *value, void *type)
785{
786 return Euler_ass_item(self, POINTER_AS_INT(type), value);
787}
788
789/* Euler rotation order: `euler.order`. */
790
792 /* Wrap. */
793 Euler_order_doc,
794 "Euler rotation order.\n"
795 "\n"
796 ":type: Literal['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']\n");
797static PyObject *Euler_order_get(EulerObject *self, void * /*closure*/)
798{
799 if (BaseMath_ReadCallback(self) == -1) {
800 /* can read order too */
801 return nullptr;
802 }
803
804 return PyUnicode_FromString(euler_order_str(self));
805}
806
807static int Euler_order_set(EulerObject *self, PyObject *value, void * /*closure*/)
808{
809 const char *order_str;
810 short order;
811
812 if (BaseMath_Prepare_ForWrite(self) == -1) {
813 return -1;
814 }
815
816 if (((order_str = PyUnicode_AsUTF8(value)) == nullptr) ||
817 ((order = euler_order_from_string(order_str, "euler.order")) == -1))
818 {
819 return -1;
820 }
821
822 self->order = order;
823 (void)BaseMath_WriteCallback(self); /* order can be written back */
824 return 0;
825}
826
828
829/* -------------------------------------------------------------------- */
832
833static PyGetSetDef Euler_getseters[] = {
834 {"x", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, POINTER_FROM_INT(0)},
835 {"y", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, POINTER_FROM_INT(1)},
836 {"z", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, POINTER_FROM_INT(2)},
837 {"order", (getter)Euler_order_get, (setter)Euler_order_set, Euler_order_doc, nullptr},
838
839 {"is_wrapped",
841 (setter) nullptr,
843 nullptr},
844 {"is_frozen",
846 (setter) nullptr,
848 nullptr},
849 {"is_valid",
851 (setter) nullptr,
853 nullptr},
854 {"owner",
856 (setter) nullptr,
858 nullptr},
859 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */};
860
862
863/* -------------------------------------------------------------------- */
866
867#ifdef __GNUC__
868# ifdef __clang__
869# pragma clang diagnostic push
870# pragma clang diagnostic ignored "-Wcast-function-type"
871# else
872# pragma GCC diagnostic push
873# pragma GCC diagnostic ignored "-Wcast-function-type"
874# endif
875#endif
876
877static PyMethodDef Euler_methods[] = {
878 {"zero", (PyCFunction)Euler_zero, METH_NOARGS, Euler_zero_doc},
879 {"to_matrix", (PyCFunction)Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc},
880 {"to_quaternion", (PyCFunction)Euler_to_quaternion, METH_NOARGS, Euler_to_quaternion_doc},
881 {"rotate_axis", (PyCFunction)Euler_rotate_axis, METH_VARARGS, Euler_rotate_axis_doc},
882 {"rotate", (PyCFunction)Euler_rotate, METH_O, Euler_rotate_doc},
883 {"make_compatible", (PyCFunction)Euler_make_compatible, METH_O, Euler_make_compatible_doc},
884 {"copy", (PyCFunction)Euler_copy, METH_NOARGS, Euler_copy_doc},
885 {"__copy__", (PyCFunction)Euler_copy, METH_NOARGS, Euler_copy_doc},
886 {"__deepcopy__", (PyCFunction)Euler_deepcopy, METH_VARARGS, Euler_copy_doc},
887
888 /* base-math methods */
889 {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
890 {nullptr, nullptr, 0, nullptr},
891};
892
893#ifdef __GNUC__
894# ifdef __clang__
895# pragma clang diagnostic pop
896# else
897# pragma GCC diagnostic pop
898# endif
899#endif
900
902
903/* -------------------------------------------------------------------- */
906
907#ifdef MATH_STANDALONE
908# define Euler_str nullptr
909#endif
910
912 /* Wrap. */
913 euler_doc,
914 ".. class:: Euler(angles=(0.0, 0.0, 0.0), order='XYZ', /)\n"
915 "\n"
916 " This object gives access to Eulers in Blender.\n"
917 "\n"
918 " .. seealso:: `Euler angles <https://en.wikipedia.org/wiki/Euler_angles>`__ on "
919 "Wikipedia.\n"
920 "\n"
921 " :arg angles: (X, Y, Z) angles in radians.\n"
922 " :type angles: Sequence[float]\n"
923 " :arg order: Euler rotation order.\n"
924 " :type order: Literal['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']\n");
925PyTypeObject euler_Type = {
926 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
927 /*tp_name*/ "Euler",
928 /*tp_basicsize*/ sizeof(EulerObject),
929 /*tp_itemsize*/ 0,
930 /*tp_dealloc*/ (destructor)BaseMathObject_dealloc,
931 /*tp_vectorcall_offset*/ 0,
932 /*tp_getattr*/ nullptr,
933 /*tp_setattr*/ nullptr,
934 /*tp_as_async*/ nullptr,
935 /*tp_repr*/ (reprfunc)Euler_repr,
936 /*tp_as_number*/ nullptr,
937 /*tp_as_sequence*/ &Euler_SeqMethods,
938 /*tp_as_mapping*/ &Euler_AsMapping,
939 /*tp_hash*/ (hashfunc)Euler_hash,
940 /*tp_call*/ nullptr,
941 /*tp_str*/ (reprfunc)Euler_str,
942 /*tp_getattro*/ nullptr,
943 /*tp_setattro*/ nullptr,
944 /*tp_as_buffer*/ &Euler_as_buffer,
945 /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
946 /*tp_doc*/ euler_doc,
947 /*tp_traverse*/ (traverseproc)BaseMathObject_traverse,
948 /*tp_clear*/ (inquiry)BaseMathObject_clear,
949 /*tp_richcompare*/ (richcmpfunc)Euler_richcmpr,
950 /*tp_weaklistoffset*/ 0,
951 /*tp_iter*/ nullptr,
952 /*tp_iternext*/ nullptr,
953 /*tp_methods*/ Euler_methods,
954 /*tp_members*/ nullptr,
955 /*tp_getset*/ Euler_getseters,
956 /*tp_base*/ nullptr,
957 /*tp_dict*/ nullptr,
958 /*tp_descr_get*/ nullptr,
959 /*tp_descr_set*/ nullptr,
960 /*tp_dictoffset*/ 0,
961 /*tp_init*/ nullptr,
962 /*tp_alloc*/ nullptr,
963 /*tp_new*/ Euler_new,
964 /*tp_free*/ nullptr,
965 /*tp_is_gc*/ (inquiry)BaseMathObject_is_gc,
966 /*tp_bases*/ nullptr,
967 /*tp_mro*/ nullptr,
968 /*tp_cache*/ nullptr,
969 /*tp_subclasses*/ nullptr,
970 /*tp_weaklist*/ nullptr,
971 /*tp_del*/ nullptr,
972 /*tp_version_tag*/ 0,
973 /*tp_finalize*/ nullptr,
974 /*tp_vectorcall*/ Euler_vectorcall,
975};
976
977#ifdef MATH_STANDALONE
978# undef Euler_str
979#endif
980
982
983/* -------------------------------------------------------------------- */
986
987PyObject *Euler_CreatePyObject(const float eul[3], const short order, PyTypeObject *base_type)
988{
990 float *eul_alloc;
991
992 eul_alloc = static_cast<float *>(PyMem_Malloc(EULER_SIZE * sizeof(float)));
993 if (UNLIKELY(eul_alloc == nullptr)) {
994 PyErr_SetString(PyExc_MemoryError,
995 "Euler(): "
996 "problem allocating data");
997 return nullptr;
998 }
999
1001 if (self) {
1002 self->eul = eul_alloc;
1003
1004 /* init callbacks as nullptr */
1005 self->cb_user = nullptr;
1006 self->cb_type = self->cb_subtype = 0;
1007
1008 if (eul) {
1009 copy_v3_v3(self->eul, eul);
1010 }
1011 else {
1012 zero_v3(self->eul);
1013 }
1014
1016 self->order = order;
1017 }
1018 else {
1019 PyMem_Free(eul_alloc);
1020 }
1021
1022 return (PyObject *)self;
1023}
1024
1025PyObject *Euler_CreatePyObject_wrap(float eul[3], const short order, PyTypeObject *base_type)
1026{
1028
1030 if (self) {
1031 /* init callbacks as nullptr */
1032 self->cb_user = nullptr;
1033 self->cb_type = self->cb_subtype = 0;
1034
1035 self->eul = eul;
1037
1038 self->order = order;
1039 }
1040
1041 return (PyObject *)self;
1042}
1043
1044PyObject *Euler_CreatePyObject_cb(PyObject *cb_user,
1045 const short order,
1046 uchar cb_type,
1047 uchar cb_subtype)
1048{
1049 EulerObject *self = (EulerObject *)Euler_CreatePyObject(nullptr, order, nullptr);
1050 if (self) {
1051 Py_INCREF(cb_user);
1052 self->cb_user = cb_user;
1053 self->cb_type = cb_type;
1054 self->cb_subtype = cb_subtype;
1055 BLI_assert(!PyObject_GC_IsTracked((PyObject *)self));
1056 PyObject_GC_Track(self);
1057 }
1058
1059 return (PyObject *)self;
1060}
1061
#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.cc: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.cc: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(...)
static AppView * view
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
iter begin(iter)
PyObject * self
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
nullptr float
#define str(s)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
int count
int BaseMathObject_is_gc(BaseMathObject *self)
Definition mathutils.cc:762
Py_hash_t mathutils_array_hash(const float *array, size_t array_len)
Definition mathutils.cc:68
void BaseMathObject_dealloc(BaseMathObject *self)
Definition mathutils.cc:740
int EXPP_VectorsAreEqual(const float *vecA, const float *vecB, int size, int floatSteps)
Definition mathutils.cc:489
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition mathutils.cc:96
char BaseMathObject_is_valid_doc[]
Definition mathutils.cc:685
char BaseMathObject_is_wrapped_doc[]
Definition mathutils.cc:671
PyObject * BaseMathObject_owner_get(BaseMathObject *self, void *)
Definition mathutils.cc:665
char BaseMathObject_is_frozen_doc[]
Definition mathutils.cc:678
PyObject * mathutils_dynstr_to_py(DynStr *ds)
Definition mathutils.cc:501
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
Definition mathutils.cc:408
PyObject * BaseMathObject_is_frozen_get(BaseMathObject *self, void *)
Definition mathutils.cc:680
PyObject * BaseMathObject_freeze(BaseMathObject *self)
Definition mathutils.cc:699
PyObject * BaseMathObject_is_wrapped_get(BaseMathObject *self, void *)
Definition mathutils.cc:673
char BaseMathObject_owner_doc[]
Definition mathutils.cc:664
char BaseMathObject_freeze_doc[]
Definition mathutils.cc:691
PyObject * BaseMathObject_is_valid_get(BaseMathObject *self, void *)
Definition mathutils.cc:686
int BaseMathObject_clear(BaseMathObject *self)
Definition mathutils.cc:722
int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg)
Definition mathutils.cc:716
#define BaseMath_ReadCallback_ForWrite(_self)
Definition mathutils.hh:151
#define BaseMath_Prepare_ForBufferAccess(_self, _view, _flags)
Definition mathutils.hh:183
#define BaseMath_ReadIndexCallback(_self, _index)
Definition mathutils.hh:145
#define BaseMath_WriteCallback(_self)
Definition mathutils.hh:143
#define BASE_MATH_NEW(struct_name, root_type, base_type)
Definition mathutils.hh:27
#define BaseMathObject_Prepare_ForHash(_self)
Definition mathutils.hh:166
#define BASE_MATH_FLAG_DEFAULT
Definition mathutils.hh:52
#define BaseMath_Prepare_ForWrite(_self)
Definition mathutils.hh:161
@ BASE_MATH_FLAG_HAS_BUFFER_VIEW
Definition mathutils.hh:50
@ BASE_MATH_FLAG_IS_WRAP
Definition mathutils.hh:37
#define BaseMath_ReadCallback(_self)
Definition mathutils.hh:141
#define BaseMath_WriteIndexCallback(_self, _index)
Definition mathutils.hh:147
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 int Euler_getbuffer(PyObject *obj, Py_buffer *view, int flags)
static PyObject * Euler_vectorcall(PyObject *type, PyObject *const *args, const size_t nargsf, PyObject *kwnames)
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 PyBufferProcs Euler_as_buffer
static void Euler_releasebuffer(PyObject *, Py_buffer *view)
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)
Py_DECREF(oname)
return ret
unsigned char order
i
Definition text_draw.cc:230