Resolve unsigned comparison error w/ MSVC
[blender.git] / source / blender / python / mathutils / mathutils_Euler.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Joseph Gilbert
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/python/mathutils/mathutils_Euler.c
24  *  \ingroup pymathutils
25  */
26
27
28 #include <Python.h>
29
30 #include "mathutils.h"
31
32 #include "BLI_math.h"
33 #include "BLI_utildefines.h"
34 #include "../generic/python_utildefines.h"
35
36 #ifndef MATH_STANDALONE
37 #  include "BLI_dynstr.h"
38 #endif
39
40 #define EULER_SIZE 3
41
42 /* ----------------------------------mathutils.Euler() ------------------- */
43 /* makes a new euler for you to play with */
44 static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
45 {
46         PyObject *seq = NULL;
47         const char *order_str = NULL;
48
49         float eul[EULER_SIZE] = {0.0f, 0.0f, 0.0f};
50         short order = EULER_ORDER_XYZ;
51
52         if (kwds && PyDict_Size(kwds)) {
53                 PyErr_SetString(PyExc_TypeError,
54                                 "mathutils.Euler(): "
55                                 "takes no keyword args");
56                 return NULL;
57         }
58
59         if (!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str))
60                 return NULL;
61
62         switch (PyTuple_GET_SIZE(args)) {
63                 case 0:
64                         break;
65                 case 2:
66                         if ((order = euler_order_from_string(order_str, "mathutils.Euler()")) == -1)
67                                 return NULL;
68                         ATTR_FALLTHROUGH;
69                 case 1:
70                         if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1)
71                                 return NULL;
72                         break;
73         }
74         return Euler_CreatePyObject(eul, order, type);
75 }
76
77 /* internal use, assume read callback is done */
78 static const char *euler_order_str(EulerObject *self)
79 {
80         static const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
81         return order[self->order - EULER_ORDER_XYZ];
82 }
83
84 short euler_order_from_string(const char *str, const char *error_prefix)
85 {
86         if ((str[0] && str[1] && str[2] && str[3] == '\0')) {
87
88 #ifdef __LITTLE_ENDIAN__
89 #  define MAKE_ID3(a, b, c)  (((a)) | ((b) << 8) | ((c) << 16))
90 #else
91 #  define MAKE_ID3(a, b, c)  (((a) << 24) | ((b) << 16) | ((c) << 8))
92 #endif
93
94                 switch (*((PY_INT32_T *)str)) {
95                         case MAKE_ID3('X', 'Y', 'Z'): return EULER_ORDER_XYZ;
96                         case MAKE_ID3('X', 'Z', 'Y'): return EULER_ORDER_XZY;
97                         case MAKE_ID3('Y', 'X', 'Z'): return EULER_ORDER_YXZ;
98                         case MAKE_ID3('Y', 'Z', 'X'): return EULER_ORDER_YZX;
99                         case MAKE_ID3('Z', 'X', 'Y'): return EULER_ORDER_ZXY;
100                         case MAKE_ID3('Z', 'Y', 'X'): return EULER_ORDER_ZYX;
101                 }
102
103 #undef MAKE_ID3
104         }
105
106         PyErr_Format(PyExc_ValueError,
107                      "%s: invalid euler order '%s'",
108                      error_prefix, str);
109         return -1;
110 }
111
112 /* note: BaseMath_ReadCallback must be called beforehand */
113 static PyObject *Euler_ToTupleExt(EulerObject *self, int ndigits)
114 {
115         PyObject *ret;
116         int i;
117
118         ret = PyTuple_New(EULER_SIZE);
119
120         if (ndigits >= 0) {
121                 for (i = 0; i < EULER_SIZE; i++) {
122                         PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->eul[i], ndigits)));
123                 }
124         }
125         else {
126                 for (i = 0; i < EULER_SIZE; i++) {
127                         PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->eul[i]));
128                 }
129         }
130
131         return ret;
132 }
133
134 /* -----------------------------METHODS----------------------------
135  * return a quaternion representation of the euler */
136
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 );
145 static PyObject *Euler_to_quaternion(EulerObject *self)
146 {
147         float quat[4];
148
149         if (BaseMath_ReadCallback(self) == -1)
150                 return NULL;
151
152         eulO_to_quat(quat, self->eul, self->order);
153
154         return Quaternion_CreatePyObject(quat, NULL);
155 }
156
157 /* return a matrix representation of the euler */
158 PyDoc_STRVAR(Euler_to_matrix_doc,
159 ".. method:: to_matrix()\n"
160 "\n"
161 "   Return a matrix representation of the euler.\n"
162 "\n"
163 "   :return: A 3x3 roation matrix representation of the euler.\n"
164 "   :rtype: :class:`Matrix`\n"
165 );
166 static PyObject *Euler_to_matrix(EulerObject *self)
167 {
168         float mat[9];
169
170         if (BaseMath_ReadCallback(self) == -1)
171                 return NULL;
172
173         eulO_to_mat3((float (*)[3])mat, self->eul, self->order);
174
175         return Matrix_CreatePyObject(mat, 3, 3, NULL);
176 }
177
178 PyDoc_STRVAR(Euler_zero_doc,
179 ".. method:: zero()\n"
180 "\n"
181 "   Set all values to zero.\n"
182 );
183 static PyObject *Euler_zero(EulerObject *self)
184 {
185         if (BaseMath_Prepare_ForWrite(self) == -1)
186                 return NULL;
187
188         zero_v3(self->eul);
189
190         if (BaseMath_WriteCallback(self) == -1)
191                 return NULL;
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 );
207 static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args)
208 {
209         float angle = 0.0f;
210         int axis; /* actually a character */
211
212         if (!PyArg_ParseTuple(args, "Cf:rotate_axis", &axis, &angle)) {
213                 PyErr_SetString(PyExc_TypeError,
214                                 "Euler.rotate_axis(): "
215                                 "expected an axis 'X', 'Y', 'Z' and an angle (float)");
216                 return NULL;
217         }
218
219         if (!(ELEM(axis, 'X', 'Y', 'Z'))) {
220                 PyErr_SetString(PyExc_ValueError,
221                                 "Euler.rotate_axis(): "
222                                 "expected axis to be 'X', 'Y' or 'Z'");
223                 return NULL;
224         }
225
226         if (BaseMath_ReadCallback_ForWrite(self) == -1)
227                 return NULL;
228
229
230         rotate_eulO(self->eul, self->order, (char)axis, angle);
231
232         (void)BaseMath_WriteCallback(self);
233
234         Py_RETURN_NONE;
235 }
236
237 PyDoc_STRVAR(Euler_rotate_doc,
238 ".. method:: rotate(other)\n"
239 "\n"
240 "   Rotates the euler by another mathutils value.\n"
241 "\n"
242 "   :arg other: rotation component of mathutils value\n"
243 "   :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
244 );
245 static PyObject *Euler_rotate(EulerObject *self, PyObject *value)
246 {
247         float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
248
249         if (BaseMath_ReadCallback_ForWrite(self) == -1)
250                 return NULL;
251
252         if (mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1)
253                 return NULL;
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
260         (void)BaseMath_WriteCallback(self);
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 );
272 static PyObject *Euler_make_compatible(EulerObject *self, PyObject *value)
273 {
274         float teul[EULER_SIZE];
275
276         if (BaseMath_ReadCallback_ForWrite(self) == -1)
277                 return NULL;
278
279         if (mathutils_array_parse(teul, EULER_SIZE, EULER_SIZE, value,
280                                   "euler.make_compatible(other), invalid 'other' arg") == -1)
281         {
282                 return NULL;
283         }
284
285         compatible_eul(self->eul, teul);
286
287         (void)BaseMath_WriteCallback(self);
288
289         Py_RETURN_NONE;
290 }
291
292 /* ----------------------------Euler.rotate()-----------------------
293  * return a copy of the euler */
294
295 PyDoc_STRVAR(Euler_copy_doc,
296 ".. function:: copy()\n"
297 "\n"
298 "   Returns a copy of this euler.\n"
299 "\n"
300 "   :return: A copy of the euler.\n"
301 "   :rtype: :class:`Euler`\n"
302 "\n"
303 "   .. note:: use this to get a copy of a wrapped euler with\n"
304 "      no reference to the original data.\n"
305 );
306 static PyObject *Euler_copy(EulerObject *self)
307 {
308         if (BaseMath_ReadCallback(self) == -1)
309                 return NULL;
310
311         return Euler_CreatePyObject(self->eul, self->order, Py_TYPE(self));
312 }
313 static PyObject *Euler_deepcopy(EulerObject *self, PyObject *args)
314 {
315         if (!mathutils_deepcopy_args_check(args))
316                 return NULL;
317         return Euler_copy(self);
318 }
319
320 /* ----------------------------print object (internal)--------------
321  * print the object to screen */
322
323 static PyObject *Euler_repr(EulerObject *self)
324 {
325         PyObject *ret, *tuple;
326
327         if (BaseMath_ReadCallback(self) == -1)
328                 return NULL;
329
330         tuple = Euler_ToTupleExt(self, -1);
331
332         ret = PyUnicode_FromFormat("Euler(%R, '%s')", tuple, euler_order_str(self));
333
334         Py_DECREF(tuple);
335         return ret;
336 }
337
338 #ifndef MATH_STANDALONE
339 static PyObject *Euler_str(EulerObject *self)
340 {
341         DynStr *ds;
342
343         if (BaseMath_ReadCallback(self) == -1)
344                 return NULL;
345
346         ds = BLI_dynstr_new();
347
348         BLI_dynstr_appendf(ds, "<Euler (x=%.4f, y=%.4f, z=%.4f), order='%s'>",
349                            self->eul[0], self->eul[1], self->eul[2], euler_order_str(self));
350
351         return mathutils_dynstr_to_py(ds); /* frees ds */
352 }
353 #endif
354
355 static PyObject *Euler_richcmpr(PyObject *a, PyObject *b, int op)
356 {
357         PyObject *res;
358         int ok = -1; /* zero is true */
359
360         if (EulerObject_Check(a) && EulerObject_Check(b)) {
361                 EulerObject *eulA = (EulerObject *)a;
362                 EulerObject *eulB = (EulerObject *)b;
363
364                 if (BaseMath_ReadCallback(eulA) == -1 || BaseMath_ReadCallback(eulB) == -1)
365                         return NULL;
366
367                 ok = ((eulA->order == eulB->order) && EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1)) ? 0 : -1;
368         }
369
370         switch (op) {
371                 case Py_NE:
372                         ok = !ok;
373                         ATTR_FALLTHROUGH;
374                 case Py_EQ:
375                         res = ok ? Py_False : Py_True;
376                         break;
377
378                 case Py_LT:
379                 case Py_LE:
380                 case Py_GT:
381                 case Py_GE:
382                         res = Py_NotImplemented;
383                         break;
384                 default:
385                         PyErr_BadArgument();
386                         return NULL;
387         }
388
389         return Py_INCREF_RET(res);
390 }
391
392 static Py_hash_t Euler_hash(EulerObject *self)
393 {
394         if (BaseMath_ReadCallback(self) == -1)
395                 return -1;
396
397         if (BaseMathObject_Prepare_ForHash(self) == -1)
398                 return -1;
399
400         return mathutils_array_hash(self->eul, EULER_SIZE);
401 }
402
403 /* ---------------------SEQUENCE PROTOCOLS------------------------ */
404 /* ----------------------------len(object)------------------------ */
405 /* sequence length */
406 static int Euler_len(EulerObject *UNUSED(self))
407 {
408         return EULER_SIZE;
409 }
410 /* ----------------------------object[]--------------------------- */
411 /* sequence accessor (get) */
412 static PyObject *Euler_item(EulerObject *self, int i)
413 {
414         if (i < 0) i = EULER_SIZE - i;
415
416         if (i < 0 || i >= EULER_SIZE) {
417                 PyErr_SetString(PyExc_IndexError,
418                                 "euler[attribute]: "
419                                 "array index out of range");
420                 return NULL;
421         }
422
423         if (BaseMath_ReadIndexCallback(self, i) == -1)
424                 return NULL;
425
426         return PyFloat_FromDouble(self->eul[i]);
427
428 }
429 /* ----------------------------object[]------------------------- */
430 /* sequence accessor (set) */
431 static int Euler_ass_item(EulerObject *self, int i, PyObject *value)
432 {
433         float f;
434
435         if (BaseMath_Prepare_ForWrite(self) == -1)
436                 return -1;
437
438         f = PyFloat_AsDouble(value);
439         if (f == -1 && PyErr_Occurred()) {  /* parsed item not a number */
440                 PyErr_SetString(PyExc_TypeError,
441                                 "euler[attribute] = x: "
442                                 "assigned value not a number");
443                 return -1;
444         }
445
446         if (i < 0) i = EULER_SIZE - i;
447
448         if (i < 0 || i >= EULER_SIZE) {
449                 PyErr_SetString(PyExc_IndexError,
450                                 "euler[attribute] = x: "
451                                 "array assignment index out of range");
452                 return -1;
453         }
454
455         self->eul[i] = f;
456
457         if (BaseMath_WriteIndexCallback(self, i) == -1)
458                 return -1;
459
460         return 0;
461 }
462 /* ----------------------------object[z:y]------------------------ */
463 /* sequence slice (get) */
464 static PyObject *Euler_slice(EulerObject *self, int begin, int end)
465 {
466         PyObject *tuple;
467         int count;
468
469         if (BaseMath_ReadCallback(self) == -1)
470                 return NULL;
471
472         CLAMP(begin, 0, EULER_SIZE);
473         if (end < 0) end = (EULER_SIZE + 1) + end;
474         CLAMP(end, 0, EULER_SIZE);
475         begin = MIN2(begin, end);
476
477         tuple = PyTuple_New(end - begin);
478         for (count = begin; count < end; count++) {
479                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->eul[count]));
480         }
481
482         return tuple;
483 }
484 /* ----------------------------object[z:y]------------------------ */
485 /* sequence slice (set) */
486 static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq)
487 {
488         int i, size;
489         float eul[EULER_SIZE];
490
491         if (BaseMath_ReadCallback_ForWrite(self) == -1)
492                 return -1;
493
494         CLAMP(begin, 0, EULER_SIZE);
495         if (end < 0) end = (EULER_SIZE + 1) + end;
496         CLAMP(end, 0, EULER_SIZE);
497         begin = MIN2(begin, end);
498
499         if ((size = mathutils_array_parse(eul, 0, EULER_SIZE, seq, "mathutils.Euler[begin:end] = []")) == -1)
500                 return -1;
501
502         if (size != (end - begin)) {
503                 PyErr_SetString(PyExc_ValueError,
504                                 "euler[begin:end] = []: "
505                                 "size mismatch in slice assignment");
506                 return -1;
507         }
508
509         for (i = 0; i < EULER_SIZE; i++)
510                 self->eul[begin + i] = eul[i];
511
512         (void)BaseMath_WriteCallback(self);
513         return 0;
514 }
515
516 static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
517 {
518         if (PyIndex_Check(item)) {
519                 Py_ssize_t i;
520                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
521                 if (i == -1 && PyErr_Occurred())
522                         return NULL;
523                 if (i < 0)
524                         i += EULER_SIZE;
525                 return Euler_item(self, i);
526         }
527         else if (PySlice_Check(item)) {
528                 Py_ssize_t start, stop, step, slicelength;
529
530                 if (PySlice_GetIndicesEx(item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0)
531                         return NULL;
532
533                 if (slicelength <= 0) {
534                         return PyTuple_New(0);
535                 }
536                 else if (step == 1) {
537                         return Euler_slice(self, start, stop);
538                 }
539                 else {
540                         PyErr_SetString(PyExc_IndexError,
541                                         "slice steps not supported with eulers");
542                         return NULL;
543                 }
544         }
545         else {
546                 PyErr_Format(PyExc_TypeError,
547                              "euler indices must be integers, not %.200s",
548                              Py_TYPE(item)->tp_name);
549                 return NULL;
550         }
551 }
552
553
554 static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *value)
555 {
556         if (PyIndex_Check(item)) {
557                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
558                 if (i == -1 && PyErr_Occurred())
559                         return -1;
560                 if (i < 0)
561                         i += EULER_SIZE;
562                 return Euler_ass_item(self, i, value);
563         }
564         else if (PySlice_Check(item)) {
565                 Py_ssize_t start, stop, step, slicelength;
566
567                 if (PySlice_GetIndicesEx(item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0)
568                         return -1;
569
570                 if (step == 1)
571                         return Euler_ass_slice(self, start, stop, value);
572                 else {
573                         PyErr_SetString(PyExc_IndexError,
574                                         "slice steps not supported with euler");
575                         return -1;
576                 }
577         }
578         else {
579                 PyErr_Format(PyExc_TypeError,
580                              "euler indices must be integers, not %.200s",
581                              Py_TYPE(item)->tp_name);
582                 return -1;
583         }
584 }
585
586 /* -----------------PROTCOL DECLARATIONS-------------------------- */
587 static PySequenceMethods Euler_SeqMethods = {
588         (lenfunc) Euler_len,                    /* sq_length */
589         (binaryfunc) NULL,                      /* sq_concat */
590         (ssizeargfunc) NULL,                    /* sq_repeat */
591         (ssizeargfunc) Euler_item,              /* sq_item */
592         (ssizessizeargfunc) NULL,               /* sq_slice, deprecated  */
593         (ssizeobjargproc) Euler_ass_item,       /* sq_ass_item */
594         (ssizessizeobjargproc) NULL,            /* sq_ass_slice, deprecated */
595         (objobjproc) NULL,                      /* sq_contains */
596         (binaryfunc) NULL,                      /* sq_inplace_concat */
597         (ssizeargfunc) NULL,                    /* sq_inplace_repeat */
598 };
599
600 static PyMappingMethods Euler_AsMapping = {
601         (lenfunc)Euler_len,
602         (binaryfunc)Euler_subscript,
603         (objobjargproc)Euler_ass_subscript
604 };
605
606 /* euler axis, euler.x/y/z */
607
608 PyDoc_STRVAR(Euler_axis_doc,
609 "Euler axis angle in radians.\n\n:type: float"
610 );
611 static PyObject *Euler_axis_get(EulerObject *self, void *type)
612 {
613         return Euler_item(self, GET_INT_FROM_POINTER(type));
614 }
615
616 static int Euler_axis_set(EulerObject *self, PyObject *value, void *type)
617 {
618         return Euler_ass_item(self, GET_INT_FROM_POINTER(type), value);
619 }
620
621 /* rotation order */
622
623 PyDoc_STRVAR(Euler_order_doc,
624 "Euler rotation order.\n\n:type: string in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']"
625 );
626 static PyObject *Euler_order_get(EulerObject *self, void *UNUSED(closure))
627 {
628         if (BaseMath_ReadCallback(self) == -1) /* can read order too */
629                 return NULL;
630
631         return PyUnicode_FromString(euler_order_str(self));
632 }
633
634 static int Euler_order_set(EulerObject *self, PyObject *value, void *UNUSED(closure))
635 {
636         const char *order_str;
637         short order;
638
639         if (BaseMath_Prepare_ForWrite(self) == -1)
640                 return -1;
641
642         if (((order_str = _PyUnicode_AsString(value)) == NULL) ||
643             ((order = euler_order_from_string(order_str, "euler.order")) == -1))
644         {
645                 return -1;
646         }
647
648         self->order = order;
649         (void)BaseMath_WriteCallback(self); /* order can be written back */
650         return 0;
651 }
652
653 /*****************************************************************************/
654 /* Python attributes get/set structure:                                      */
655 /*****************************************************************************/
656 static PyGetSetDef Euler_getseters[] = {
657         {(char *)"x", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)0},
658         {(char *)"y", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)1},
659         {(char *)"z", (getter)Euler_axis_get, (setter)Euler_axis_set, Euler_axis_doc, (void *)2},
660         {(char *)"order", (getter)Euler_order_get, (setter)Euler_order_set, Euler_order_doc, (void *)NULL},
661
662         {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
663         {(char *)"is_frozen",  (getter)BaseMathObject_is_frozen_get,  (setter)NULL, BaseMathObject_is_frozen_doc, NULL},
664         {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
665         {NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
666 };
667
668
669 /* -----------------------METHOD DEFINITIONS ---------------------- */
670 static struct PyMethodDef Euler_methods[] = {
671         {"zero", (PyCFunction) Euler_zero, METH_NOARGS, Euler_zero_doc},
672         {"to_matrix", (PyCFunction) Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc},
673         {"to_quaternion", (PyCFunction) Euler_to_quaternion, METH_NOARGS, Euler_to_quaternion_doc},
674         {"rotate_axis", (PyCFunction) Euler_rotate_axis, METH_VARARGS, Euler_rotate_axis_doc},
675         {"rotate", (PyCFunction) Euler_rotate, METH_O, Euler_rotate_doc},
676         {"make_compatible", (PyCFunction) Euler_make_compatible, METH_O, Euler_make_compatible_doc},
677         {"copy", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc},
678         {"__copy__", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc},
679         {"__deepcopy__", (PyCFunction) Euler_deepcopy, METH_VARARGS, Euler_copy_doc},
680
681         /* base-math methods */
682         {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
683         {NULL, NULL, 0, NULL}
684 };
685
686 /* ------------------PY_OBECT DEFINITION-------------------------- */
687 PyDoc_STRVAR(euler_doc,
688 ".. class:: Euler(angles, order='XYZ')\n"
689 "\n"
690 "   This object gives access to Eulers in Blender.\n"
691 "\n"
692 "   :param angles: Three angles, in radians.\n"
693 "   :type angles: 3d vector\n"
694 "   :param order: Optional order of the angles, a permutation of ``XYZ``.\n"
695 "   :type order: str\n"
696 );
697 PyTypeObject euler_Type = {
698         PyVarObject_HEAD_INIT(NULL, 0)
699         "Euler",                        /* tp_name */
700         sizeof(EulerObject),            /* tp_basicsize */
701         0,                              /* tp_itemsize */
702         (destructor)BaseMathObject_dealloc,     /* tp_dealloc */
703         NULL,                           /* tp_print */
704         NULL,                           /* tp_getattr */
705         NULL,                           /* tp_setattr */
706         NULL,                           /* tp_compare */
707         (reprfunc) Euler_repr,          /* tp_repr */
708         NULL,                           /* tp_as_number */
709         &Euler_SeqMethods,              /* tp_as_sequence */
710         &Euler_AsMapping,               /* tp_as_mapping */
711         (hashfunc)Euler_hash,           /* tp_hash */
712         NULL,                           /* tp_call */
713 #ifndef MATH_STANDALONE
714         (reprfunc) Euler_str,           /* tp_str */
715 #else
716         NULL,                           /* tp_str */
717 #endif
718         NULL,                           /* tp_getattro */
719         NULL,                           /* tp_setattro */
720         NULL,                           /* tp_as_buffer */
721         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
722         euler_doc, /* tp_doc */
723         (traverseproc)BaseMathObject_traverse,  /* tp_traverse */
724         (inquiry)BaseMathObject_clear,  /* tp_clear */
725         (richcmpfunc)Euler_richcmpr,    /* tp_richcompare */
726         0,                              /* tp_weaklistoffset */
727         NULL,                           /* tp_iter */
728         NULL,                           /* tp_iternext */
729         Euler_methods,                  /* tp_methods */
730         NULL,                           /* tp_members */
731         Euler_getseters,                /* tp_getset */
732         NULL,                           /* tp_base */
733         NULL,                           /* tp_dict */
734         NULL,                           /* tp_descr_get */
735         NULL,                           /* tp_descr_set */
736         0,                              /* tp_dictoffset */
737         NULL,                           /* tp_init */
738         NULL,                           /* tp_alloc */
739         Euler_new,                      /* tp_new */
740         NULL,                           /* tp_free */
741         NULL,                           /* tp_is_gc */
742         NULL,                           /* tp_bases */
743         NULL,                           /* tp_mro */
744         NULL,                           /* tp_cache */
745         NULL,                           /* tp_subclasses */
746         NULL,                           /* tp_weaklist */
747         NULL                            /* tp_del */
748 };
749
750
751 PyObject *Euler_CreatePyObject(
752         const float eul[3], const short order,
753         PyTypeObject *base_type)
754 {
755         EulerObject *self;
756         float *eul_alloc;
757
758         eul_alloc = PyMem_Malloc(EULER_SIZE * sizeof(float));
759         if (UNLIKELY(eul_alloc == NULL)) {
760                 PyErr_SetString(PyExc_MemoryError,
761                                 "Euler(): "
762                                 "problem allocating data");
763                 return NULL;
764         }
765
766         self = BASE_MATH_NEW(EulerObject, euler_Type, base_type);
767         if (self) {
768                 self->eul = eul_alloc;
769
770                 /* init callbacks as NULL */
771                 self->cb_user = NULL;
772                 self->cb_type = self->cb_subtype = 0;
773
774                 if (eul) {
775                         copy_v3_v3(self->eul, eul);
776                 }
777                 else {
778                         zero_v3(self->eul);
779                 }
780
781                 self->flag = BASE_MATH_FLAG_DEFAULT;
782                 self->order = order;
783         }
784         else {
785                 PyMem_Free(eul_alloc);
786         }
787
788         return (PyObject *)self;
789 }
790
791 PyObject *Euler_CreatePyObject_wrap(
792         float eul[3], const short order,
793         PyTypeObject *base_type)
794 {
795         EulerObject *self;
796
797         self = BASE_MATH_NEW(EulerObject, euler_Type, base_type);
798         if (self) {
799                 /* init callbacks as NULL */
800                 self->cb_user = NULL;
801                 self->cb_type = self->cb_subtype = 0;
802
803                 self->eul = eul;
804                 self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP;
805
806                 self->order = order;
807         }
808
809         return (PyObject *)self;
810 }
811
812 PyObject *Euler_CreatePyObject_cb(
813         PyObject *cb_user, const short order,
814         unsigned char cb_type, unsigned char cb_subtype)
815 {
816         EulerObject *self = (EulerObject *)Euler_CreatePyObject(NULL, order, NULL);
817         if (self) {
818                 Py_INCREF(cb_user);
819                 self->cb_user         = cb_user;
820                 self->cb_type         = cb_type;
821                 self->cb_subtype      = cb_subtype;
822                 PyObject_GC_Track(self);
823         }
824
825         return (PyObject *)self;
826 }