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