PyAPI: add utilities PyTuple_SET_ITEMS, Py_INCREF_RET
[blender.git] / source / blender / python / mathutils / mathutils_Quaternion.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_Quaternion.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
35 #include "../generic/python_utildefines.h"
36
37 #ifndef MATH_STANDALONE
38 #  include "BLI_dynstr.h"
39 #endif
40
41 #define QUAT_SIZE 4
42
43 static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self);
44 static void      quat__axis_angle_sanitize(float axis[3], float *angle);
45 static PyObject *Quaternion_copy(QuaternionObject *self);
46 static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args);
47
48 /* -----------------------------METHODS------------------------------ */
49
50 /* note: BaseMath_ReadCallback must be called beforehand */
51 static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
52 {
53         PyObject *ret;
54         int i;
55
56         ret = PyTuple_New(QUAT_SIZE);
57
58         if (ndigits >= 0) {
59                 for (i = 0; i < QUAT_SIZE; i++) {
60                         PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->quat[i], ndigits)));
61                 }
62         }
63         else {
64                 for (i = 0; i < QUAT_SIZE; i++) {
65                         PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->quat[i]));
66                 }
67         }
68
69         return ret;
70 }
71
72 PyDoc_STRVAR(Quaternion_to_euler_doc,
73 ".. method:: to_euler(order, euler_compat)\n"
74 "\n"
75 "   Return Euler representation of the quaternion.\n"
76 "\n"
77 "   :arg order: Optional rotation order argument in\n"
78 "      ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n"
79 "   :type order: string\n"
80 "   :arg euler_compat: Optional euler argument the new euler will be made\n"
81 "      compatible with (no axis flipping between them).\n"
82 "      Useful for converting a series of matrices to animation curves.\n"
83 "   :type euler_compat: :class:`Euler`\n"
84 "   :return: Euler representation of the quaternion.\n"
85 "   :rtype: :class:`Euler`\n"
86 );
87 static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
88 {
89         float tquat[4];
90         float eul[3];
91         const char *order_str = NULL;
92         short order = EULER_ORDER_XYZ;
93         EulerObject *eul_compat = NULL;
94
95         if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
96                 return NULL;
97
98         if (BaseMath_ReadCallback(self) == -1)
99                 return NULL;
100
101         if (order_str) {
102                 order = euler_order_from_string(order_str, "Matrix.to_euler()");
103
104                 if (order == -1)
105                         return NULL;
106         }
107
108         normalize_qt_qt(tquat, self->quat);
109
110         if (eul_compat) {
111                 float mat[3][3];
112
113                 if (BaseMath_ReadCallback(eul_compat) == -1)
114                         return NULL;
115
116                 quat_to_mat3(mat, tquat);
117
118                 if (order == EULER_ORDER_XYZ)  mat3_to_compatible_eul(eul, eul_compat->eul, mat);
119                 else                           mat3_to_compatible_eulO(eul, eul_compat->eul, order, mat);
120         }
121         else {
122                 if (order == EULER_ORDER_XYZ)  quat_to_eul(eul, tquat);
123                 else                           quat_to_eulO(eul, order, tquat);
124         }
125
126         return Euler_CreatePyObject(eul, order, NULL);
127 }
128
129 PyDoc_STRVAR(Quaternion_to_matrix_doc,
130 ".. method:: to_matrix()\n"
131 "\n"
132 "   Return a matrix representation of the quaternion.\n"
133 "\n"
134 "   :return: A 3x3 rotation matrix representation of the quaternion.\n"
135 "   :rtype: :class:`Matrix`\n"
136 );
137 static PyObject *Quaternion_to_matrix(QuaternionObject *self)
138 {
139         float mat[9]; /* all values are set */
140
141         if (BaseMath_ReadCallback(self) == -1)
142                 return NULL;
143
144         quat_to_mat3((float (*)[3])mat, self->quat);
145         return Matrix_CreatePyObject(mat, 3, 3, NULL);
146 }
147
148 PyDoc_STRVAR(Quaternion_to_axis_angle_doc,
149 ".. method:: to_axis_angle()\n"
150 "\n"
151 "   Return the axis, angle representation of the quaternion.\n"
152 "\n"
153 "   :return: axis, angle.\n"
154 "   :rtype: (:class:`Vector`, float) pair\n"
155 );
156 static PyObject *Quaternion_to_axis_angle(QuaternionObject *self)
157 {
158         PyObject *ret;
159
160         float tquat[4];
161
162         float axis[3];
163         float angle;
164
165         if (BaseMath_ReadCallback(self) == -1)
166                 return NULL;
167
168         normalize_qt_qt(tquat, self->quat);
169         quat_to_axis_angle(axis, &angle, tquat);
170
171         quat__axis_angle_sanitize(axis, &angle);
172
173         ret = PyTuple_New(2);
174         PyTuple_SET_ITEMS(ret,
175                 Vector_CreatePyObject(axis, 3, NULL),
176                 PyFloat_FromDouble(angle));
177         return ret;
178 }
179
180 PyDoc_STRVAR(Quaternion_cross_doc,
181 ".. method:: cross(other)\n"
182 "\n"
183 "   Return the cross product of this quaternion and another.\n"
184 "\n"
185 "   :arg other: The other quaternion to perform the cross product with.\n"
186 "   :type other: :class:`Quaternion`\n"
187 "   :return: The cross product.\n"
188 "   :rtype: :class:`Quaternion`\n"
189 );
190 static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value)
191 {
192         float quat[QUAT_SIZE], tquat[QUAT_SIZE];
193
194         if (BaseMath_ReadCallback(self) == -1)
195                 return NULL;
196
197         if (mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value,
198                                   "Quaternion.cross(other), invalid 'other' arg") == -1)
199         {
200                 return NULL;
201         }
202
203         mul_qt_qtqt(quat, self->quat, tquat);
204         return Quaternion_CreatePyObject(quat, Py_TYPE(self));
205 }
206
207 PyDoc_STRVAR(Quaternion_dot_doc,
208 ".. method:: dot(other)\n"
209 "\n"
210 "   Return the dot product of this quaternion and another.\n"
211 "\n"
212 "   :arg other: The other quaternion to perform the dot product with.\n"
213 "   :type other: :class:`Quaternion`\n"
214 "   :return: The dot product.\n"
215 "   :rtype: :class:`Quaternion`\n"
216 );
217 static PyObject *Quaternion_dot(QuaternionObject *self, PyObject *value)
218 {
219         float tquat[QUAT_SIZE];
220
221         if (BaseMath_ReadCallback(self) == -1)
222                 return NULL;
223
224         if (mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value,
225                                   "Quaternion.dot(other), invalid 'other' arg") == -1)
226         {
227                 return NULL;
228         }
229
230         return PyFloat_FromDouble(dot_qtqt(self->quat, tquat));
231 }
232
233 PyDoc_STRVAR(Quaternion_rotation_difference_doc,
234 ".. function:: rotation_difference(other)\n"
235 "\n"
236 "   Returns a quaternion representing the rotational difference.\n"
237 "\n"
238 "   :arg other: second quaternion.\n"
239 "   :type other: :class:`Quaternion`\n"
240 "   :return: the rotational difference between the two quat rotations.\n"
241 "   :rtype: :class:`Quaternion`\n"
242 );
243 static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject *value)
244 {
245         float tquat[QUAT_SIZE], quat[QUAT_SIZE];
246
247         if (BaseMath_ReadCallback(self) == -1)
248                 return NULL;
249
250         if (mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value,
251                                   "Quaternion.difference(other), invalid 'other' arg") == -1)
252         {
253                 return NULL;
254         }
255
256         rotation_between_quats_to_quat(quat, self->quat, tquat);
257
258         return Quaternion_CreatePyObject(quat, Py_TYPE(self));
259 }
260
261 PyDoc_STRVAR(Quaternion_slerp_doc,
262 ".. function:: slerp(other, factor)\n"
263 "\n"
264 "   Returns the interpolation of two quaternions.\n"
265 "\n"
266 "   :arg other: value to interpolate with.\n"
267 "   :type other: :class:`Quaternion`\n"
268 "   :arg factor: The interpolation value in [0.0, 1.0].\n"
269 "   :type factor: float\n"
270 "   :return: The interpolated rotation.\n"
271 "   :rtype: :class:`Quaternion`\n"
272 );
273 static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args)
274 {
275         PyObject *value;
276         float tquat[QUAT_SIZE], quat[QUAT_SIZE], fac;
277
278         if (!PyArg_ParseTuple(args, "Of:slerp", &value, &fac)) {
279                 PyErr_SetString(PyExc_TypeError,
280                                 "quat.slerp(): "
281                                 "expected Quaternion types and float");
282                 return NULL;
283         }
284
285         if (BaseMath_ReadCallback(self) == -1)
286                 return NULL;
287
288         if (mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value,
289                                   "Quaternion.slerp(other), invalid 'other' arg") == -1)
290         {
291                 return NULL;
292         }
293
294         if (fac > 1.0f || fac < 0.0f) {
295                 PyErr_SetString(PyExc_ValueError,
296                                 "quat.slerp(): "
297                                 "interpolation factor must be between 0.0 and 1.0");
298                 return NULL;
299         }
300
301         interp_qt_qtqt(quat, self->quat, tquat, fac);
302
303         return Quaternion_CreatePyObject(quat, Py_TYPE(self));
304 }
305
306 PyDoc_STRVAR(Quaternion_rotate_doc,
307 ".. method:: rotate(other)\n"
308 "\n"
309 "   Rotates the quaternion by another mathutils value.\n"
310 "\n"
311 "   :arg other: rotation component of mathutils value\n"
312 "   :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
313 );
314 static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value)
315 {
316         float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
317         float tquat[4], length;
318
319         if (BaseMath_ReadCallback(self) == -1)
320                 return NULL;
321
322         if (mathutils_any_to_rotmat(other_rmat, value, "Quaternion.rotate(value)") == -1)
323                 return NULL;
324
325         length = normalize_qt_qt(tquat, self->quat);
326         quat_to_mat3(self_rmat, tquat);
327         mul_m3_m3m3(rmat, other_rmat, self_rmat);
328
329         mat3_to_quat(self->quat, rmat);
330         mul_qt_fl(self->quat, length); /* maintain length after rotating */
331
332         (void)BaseMath_WriteCallback(self);
333         Py_RETURN_NONE;
334 }
335
336 /* ----------------------------Quaternion.normalize()---------------- */
337 /* normalize the axis of rotation of [theta, vector] */
338 PyDoc_STRVAR(Quaternion_normalize_doc,
339 ".. function:: normalize()\n"
340 "\n"
341 "   Normalize the quaternion.\n"
342 );
343 static PyObject *Quaternion_normalize(QuaternionObject *self)
344 {
345         if (BaseMath_ReadCallback(self) == -1)
346                 return NULL;
347
348         normalize_qt(self->quat);
349
350         (void)BaseMath_WriteCallback(self);
351         Py_RETURN_NONE;
352 }
353 PyDoc_STRVAR(Quaternion_normalized_doc,
354 ".. function:: normalized()\n"
355 "\n"
356 "   Return a new normalized quaternion.\n"
357 "\n"
358 "   :return: a normalized copy.\n"
359 "   :rtype: :class:`Quaternion`\n"
360 );
361 static PyObject *Quaternion_normalized(QuaternionObject *self)
362 {
363         return quat__apply_to_copy((PyNoArgsFunction)Quaternion_normalize, self);
364 }
365
366 PyDoc_STRVAR(Quaternion_invert_doc,
367 ".. function:: invert()\n"
368 "\n"
369 "   Set the quaternion to its inverse.\n"
370 );
371 static PyObject *Quaternion_invert(QuaternionObject *self)
372 {
373         if (BaseMath_ReadCallback(self) == -1)
374                 return NULL;
375
376         invert_qt(self->quat);
377
378         (void)BaseMath_WriteCallback(self);
379         Py_RETURN_NONE;
380 }
381 PyDoc_STRVAR(Quaternion_inverted_doc,
382 ".. function:: inverted()\n"
383 "\n"
384 "   Return a new, inverted quaternion.\n"
385 "\n"
386 "   :return: the inverted value.\n"
387 "   :rtype: :class:`Quaternion`\n"
388 );
389 static PyObject *Quaternion_inverted(QuaternionObject *self)
390 {
391         return quat__apply_to_copy((PyNoArgsFunction)Quaternion_invert, self);
392 }
393
394 PyDoc_STRVAR(Quaternion_identity_doc,
395 ".. function:: identity()\n"
396 "\n"
397 "   Set the quaternion to an identity quaternion.\n"
398 "\n"
399 "   :rtype: :class:`Quaternion`\n"
400 );
401 static PyObject *Quaternion_identity(QuaternionObject *self)
402 {
403         if (BaseMath_ReadCallback(self) == -1)
404                 return NULL;
405
406         unit_qt(self->quat);
407
408         (void)BaseMath_WriteCallback(self);
409         Py_RETURN_NONE;
410 }
411
412 PyDoc_STRVAR(Quaternion_negate_doc,
413 ".. function:: negate()\n"
414 "\n"
415 "   Set the quaternion to its negative.\n"
416 "\n"
417 "   :rtype: :class:`Quaternion`\n"
418 );
419 static PyObject *Quaternion_negate(QuaternionObject *self)
420 {
421         if (BaseMath_ReadCallback(self) == -1)
422                 return NULL;
423
424         mul_qt_fl(self->quat, -1.0f);
425
426         (void)BaseMath_WriteCallback(self);
427         Py_RETURN_NONE;
428 }
429
430 PyDoc_STRVAR(Quaternion_conjugate_doc,
431 ".. function:: conjugate()\n"
432 "\n"
433 "   Set the quaternion to its conjugate (negate x, y, z).\n"
434 );
435 static PyObject *Quaternion_conjugate(QuaternionObject *self)
436 {
437         if (BaseMath_ReadCallback(self) == -1)
438                 return NULL;
439
440         conjugate_qt(self->quat);
441
442         (void)BaseMath_WriteCallback(self);
443         Py_RETURN_NONE;
444 }
445 PyDoc_STRVAR(Quaternion_conjugated_doc,
446 ".. function:: conjugated()\n"
447 "\n"
448 "   Return a new conjugated quaternion.\n"
449 "\n"
450 "   :return: a new quaternion.\n"
451 "   :rtype: :class:`Quaternion`\n"
452 );
453 static PyObject *Quaternion_conjugated(QuaternionObject *self)
454 {
455         return quat__apply_to_copy((PyNoArgsFunction)Quaternion_conjugate, self);
456 }
457
458 PyDoc_STRVAR(Quaternion_copy_doc,
459 ".. function:: copy()\n"
460 "\n"
461 "   Returns a copy of this quaternion.\n"
462 "\n"
463 "   :return: A copy of the quaternion.\n"
464 "   :rtype: :class:`Quaternion`\n"
465 "\n"
466 "   .. note:: use this to get a copy of a wrapped quaternion with\n"
467 "      no reference to the original data.\n"
468 );
469 static PyObject *Quaternion_copy(QuaternionObject *self)
470 {
471         if (BaseMath_ReadCallback(self) == -1)
472                 return NULL;
473
474         return Quaternion_CreatePyObject(self->quat, Py_TYPE(self));
475 }
476 static PyObject *Quaternion_deepcopy(QuaternionObject *self, PyObject *args)
477 {
478         if (!mathutils_deepcopy_args_check(args))
479                 return NULL;
480         return Quaternion_copy(self);
481 }
482
483 /* print the object to screen */
484 static PyObject *Quaternion_repr(QuaternionObject *self)
485 {
486         PyObject *ret, *tuple;
487
488         if (BaseMath_ReadCallback(self) == -1)
489                 return NULL;
490
491         tuple = Quaternion_to_tuple_ext(self, -1);
492
493         ret = PyUnicode_FromFormat("Quaternion(%R)", tuple);
494
495         Py_DECREF(tuple);
496         return ret;
497 }
498
499 #ifndef MATH_STANDALONE
500 static PyObject *Quaternion_str(QuaternionObject *self)
501 {
502         DynStr *ds;
503
504         if (BaseMath_ReadCallback(self) == -1)
505                 return NULL;
506
507         ds = BLI_dynstr_new();
508
509         BLI_dynstr_appendf(ds, "<Quaternion (w=%.4f, x=%.4f, y=%.4f, z=%.4f)>",
510                            self->quat[0], self->quat[1], self->quat[2], self->quat[3]);
511
512         return mathutils_dynstr_to_py(ds); /* frees ds */
513 }
514 #endif
515
516 static PyObject *Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
517 {
518         PyObject *res;
519         int ok = -1; /* zero is true */
520
521         if (QuaternionObject_Check(a) && QuaternionObject_Check(b)) {
522                 QuaternionObject *quatA = (QuaternionObject *)a;
523                 QuaternionObject *quatB = (QuaternionObject *)b;
524
525                 if (BaseMath_ReadCallback(quatA) == -1 || BaseMath_ReadCallback(quatB) == -1)
526                         return NULL;
527
528                 ok = (EXPP_VectorsAreEqual(quatA->quat, quatB->quat, QUAT_SIZE, 1)) ? 0 : -1;
529         }
530
531         switch (op) {
532                 case Py_NE:
533                         ok = !ok;
534                         /* fall-through */
535                 case Py_EQ:
536                         res = ok ? Py_False : Py_True;
537                         break;
538
539                 case Py_LT:
540                 case Py_LE:
541                 case Py_GT:
542                 case Py_GE:
543                         res = Py_NotImplemented;
544                         break;
545                 default:
546                         PyErr_BadArgument();
547                         return NULL;
548         }
549
550         return Py_INCREF_RET(res);
551 }
552
553 /* ---------------------SEQUENCE PROTOCOLS------------------------ */
554 /* ----------------------------len(object)------------------------ */
555 /* sequence length */
556 static int Quaternion_len(QuaternionObject *UNUSED(self))
557 {
558         return QUAT_SIZE;
559 }
560 /* ----------------------------object[]--------------------------- */
561 /* sequence accessor (get) */
562 static PyObject *Quaternion_item(QuaternionObject *self, int i)
563 {
564         if (i < 0) i = QUAT_SIZE - i;
565
566         if (i < 0 || i >= QUAT_SIZE) {
567                 PyErr_SetString(PyExc_IndexError,
568                                 "quaternion[attribute]: "
569                                 "array index out of range");
570                 return NULL;
571         }
572
573         if (BaseMath_ReadIndexCallback(self, i) == -1)
574                 return NULL;
575
576         return PyFloat_FromDouble(self->quat[i]);
577
578 }
579 /* ----------------------------object[]------------------------- */
580 /* sequence accessor (set) */
581 static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
582 {
583         float scalar = (float)PyFloat_AsDouble(ob);
584         if (scalar == -1.0f && PyErr_Occurred()) { /* parsed item not a number */
585                 PyErr_SetString(PyExc_TypeError,
586                                 "quaternion[index] = x: "
587                                 "assigned value not a number");
588                 return -1;
589         }
590
591         if (i < 0) i = QUAT_SIZE - i;
592
593         if (i < 0 || i >= QUAT_SIZE) {
594                 PyErr_SetString(PyExc_IndexError,
595                                 "quaternion[attribute] = x: "
596                                 "array assignment index out of range");
597                 return -1;
598         }
599         self->quat[i] = scalar;
600
601         if (BaseMath_WriteIndexCallback(self, i) == -1)
602                 return -1;
603
604         return 0;
605 }
606 /* ----------------------------object[z:y]------------------------ */
607 /* sequence slice (get) */
608 static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end)
609 {
610         PyObject *tuple;
611         int count;
612
613         if (BaseMath_ReadCallback(self) == -1)
614                 return NULL;
615
616         CLAMP(begin, 0, QUAT_SIZE);
617         if (end < 0) end = (QUAT_SIZE + 1) + end;
618         CLAMP(end, 0, QUAT_SIZE);
619         begin = MIN2(begin, end);
620
621         tuple = PyTuple_New(end - begin);
622         for (count = begin; count < end; count++) {
623                 PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->quat[count]));
624         }
625
626         return tuple;
627 }
628 /* ----------------------------object[z:y]------------------------ */
629 /* sequence slice (set) */
630 static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq)
631 {
632         int i, size;
633         float quat[QUAT_SIZE];
634
635         if (BaseMath_ReadCallback(self) == -1)
636                 return -1;
637
638         CLAMP(begin, 0, QUAT_SIZE);
639         if (end < 0) end = (QUAT_SIZE + 1) + end;
640         CLAMP(end, 0, QUAT_SIZE);
641         begin = MIN2(begin, end);
642
643         if ((size = mathutils_array_parse(quat, 0, QUAT_SIZE, seq, "mathutils.Quaternion[begin:end] = []")) == -1)
644                 return -1;
645
646         if (size != (end - begin)) {
647                 PyErr_SetString(PyExc_ValueError,
648                                 "quaternion[begin:end] = []: "
649                                 "size mismatch in slice assignment");
650                 return -1;
651         }
652
653         /* parsed well - now set in vector */
654         for (i = 0; i < size; i++)
655                 self->quat[begin + i] = quat[i];
656
657         (void)BaseMath_WriteCallback(self);
658         return 0;
659 }
660
661
662 static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
663 {
664         if (PyIndex_Check(item)) {
665                 Py_ssize_t i;
666                 i = PyNumber_AsSsize_t(item, PyExc_IndexError);
667                 if (i == -1 && PyErr_Occurred())
668                         return NULL;
669                 if (i < 0)
670                         i += QUAT_SIZE;
671                 return Quaternion_item(self, i);
672         }
673         else if (PySlice_Check(item)) {
674                 Py_ssize_t start, stop, step, slicelength;
675
676                 if (PySlice_GetIndicesEx(item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0)
677                         return NULL;
678
679                 if (slicelength <= 0) {
680                         return PyTuple_New(0);
681                 }
682                 else if (step == 1) {
683                         return Quaternion_slice(self, start, stop);
684                 }
685                 else {
686                         PyErr_SetString(PyExc_IndexError,
687                                         "slice steps not supported with quaternions");
688                         return NULL;
689                 }
690         }
691         else {
692                 PyErr_Format(PyExc_TypeError,
693                              "quaternion indices must be integers, not %.200s",
694                              Py_TYPE(item)->tp_name);
695                 return NULL;
696         }
697 }
698
699
700 static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyObject *value)
701 {
702         if (PyIndex_Check(item)) {
703                 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
704                 if (i == -1 && PyErr_Occurred())
705                         return -1;
706                 if (i < 0)
707                         i += QUAT_SIZE;
708                 return Quaternion_ass_item(self, i, value);
709         }
710         else if (PySlice_Check(item)) {
711                 Py_ssize_t start, stop, step, slicelength;
712
713                 if (PySlice_GetIndicesEx(item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0)
714                         return -1;
715
716                 if (step == 1)
717                         return Quaternion_ass_slice(self, start, stop, value);
718                 else {
719                         PyErr_SetString(PyExc_IndexError,
720                                         "slice steps not supported with quaternion");
721                         return -1;
722                 }
723         }
724         else {
725                 PyErr_Format(PyExc_TypeError,
726                              "quaternion indices must be integers, not %.200s",
727                              Py_TYPE(item)->tp_name);
728                 return -1;
729         }
730 }
731
732 /* ------------------------NUMERIC PROTOCOLS---------------------- */
733 /* ------------------------obj + obj------------------------------ */
734 /* addition */
735 static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
736 {
737         float quat[QUAT_SIZE];
738         QuaternionObject *quat1 = NULL, *quat2 = NULL;
739
740         if (!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) {
741                 PyErr_Format(PyExc_TypeError,
742                              "Quaternion addition: (%s + %s) "
743                              "invalid type for this operation",
744                              Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name);
745                 return NULL;
746         }
747         quat1 = (QuaternionObject *)q1;
748         quat2 = (QuaternionObject *)q2;
749
750         if (BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1)
751                 return NULL;
752
753         add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f);
754         return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
755 }
756 /* ------------------------obj - obj------------------------------ */
757 /* subtraction */
758 static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2)
759 {
760         int x;
761         float quat[QUAT_SIZE];
762         QuaternionObject *quat1 = NULL, *quat2 = NULL;
763
764         if (!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) {
765                 PyErr_Format(PyExc_TypeError,
766                              "Quaternion subtraction: (%s - %s) "
767                              "invalid type for this operation",
768                              Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name);
769                 return NULL;
770         }
771
772         quat1 = (QuaternionObject *)q1;
773         quat2 = (QuaternionObject *)q2;
774
775         if (BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1)
776                 return NULL;
777
778         for (x = 0; x < QUAT_SIZE; x++) {
779                 quat[x] = quat1->quat[x] - quat2->quat[x];
780         }
781
782         return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
783 }
784
785 static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
786 {
787         float tquat[4];
788         copy_qt_qt(tquat, quat->quat);
789         mul_qt_fl(tquat, scalar);
790         return Quaternion_CreatePyObject(tquat, Py_TYPE(quat));
791 }
792
793 /*------------------------obj * obj------------------------------
794  * multiplication */
795 static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
796 {
797         float quat[QUAT_SIZE], scalar;
798         QuaternionObject *quat1 = NULL, *quat2 = NULL;
799
800         if (QuaternionObject_Check(q1)) {
801                 quat1 = (QuaternionObject *)q1;
802                 if (BaseMath_ReadCallback(quat1) == -1)
803                         return NULL;
804         }
805         if (QuaternionObject_Check(q2)) {
806                 quat2 = (QuaternionObject *)q2;
807                 if (BaseMath_ReadCallback(quat2) == -1)
808                         return NULL;
809         }
810
811         if (quat1 && quat2) { /* QUAT * QUAT (cross product) */
812                 mul_qt_qtqt(quat, quat1->quat, quat2->quat);
813                 return Quaternion_CreatePyObject(quat, Py_TYPE(q1));
814         }
815         /* the only case this can happen (for a supported type is "FLOAT * QUAT") */
816         else if (quat2) { /* FLOAT * QUAT */
817                 if (((scalar = PyFloat_AsDouble(q1)) == -1.0f && PyErr_Occurred()) == 0) {
818                         return quat_mul_float(quat2, scalar);
819                 }
820         }
821         else if (quat1) {
822                 /* QUAT * VEC */
823                 if (VectorObject_Check(q2)) {
824                         VectorObject *vec2 = (VectorObject *)q2;
825                         float tvec[3];
826
827                         if (vec2->size != 3) {
828                                 PyErr_SetString(PyExc_ValueError,
829                                                 "Vector multiplication: "
830                                                 "only 3D vector rotations (with quats) "
831                                                 "currently supported");
832                                 return NULL;
833                         }
834                         if (BaseMath_ReadCallback(vec2) == -1) {
835                                 return NULL;
836                         }
837
838                         copy_v3_v3(tvec, vec2->vec);
839                         mul_qt_v3(quat1->quat, tvec);
840
841                         return Vector_CreatePyObject(tvec, 3, Py_TYPE(vec2));
842                 }
843                 /* QUAT * FLOAT */
844                 else if ((((scalar = PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred()) == 0)) {
845                         return quat_mul_float(quat1, scalar);
846                 }
847         }
848         else {
849                 BLI_assert(!"internal error");
850         }
851
852         PyErr_Format(PyExc_TypeError,
853                      "Quaternion multiplication: "
854                      "not supported between '%.200s' and '%.200s' types",
855                      Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name);
856         return NULL;
857 }
858
859 /* -obj
860  * returns the negative of this object*/
861 static PyObject *Quaternion_neg(QuaternionObject *self)
862 {
863         float tquat[QUAT_SIZE];
864
865         if (BaseMath_ReadCallback(self) == -1)
866                 return NULL;
867
868         negate_v4_v4(tquat, self->quat);
869         return Quaternion_CreatePyObject(tquat, Py_TYPE(self));
870 }
871
872
873 /* -----------------PROTOCOL DECLARATIONS-------------------------- */
874 static PySequenceMethods Quaternion_SeqMethods = {
875         (lenfunc) Quaternion_len,               /* sq_length */
876         (binaryfunc) NULL,                      /* sq_concat */
877         (ssizeargfunc) NULL,                    /* sq_repeat */
878         (ssizeargfunc) Quaternion_item,         /* sq_item */
879         (ssizessizeargfunc) NULL,               /* sq_slice, deprecated */
880         (ssizeobjargproc) Quaternion_ass_item,  /* sq_ass_item */
881         (ssizessizeobjargproc) NULL,            /* sq_ass_slice, deprecated */
882         (objobjproc) NULL,                      /* sq_contains */
883         (binaryfunc) NULL,                      /* sq_inplace_concat */
884         (ssizeargfunc) NULL,                    /* sq_inplace_repeat */
885 };
886
887 static PyMappingMethods Quaternion_AsMapping = {
888         (lenfunc)Quaternion_len,
889         (binaryfunc)Quaternion_subscript,
890         (objobjargproc)Quaternion_ass_subscript
891 };
892
893 static PyNumberMethods Quaternion_NumMethods = {
894         (binaryfunc)    Quaternion_add, /*nb_add*/
895         (binaryfunc)    Quaternion_sub, /*nb_subtract*/
896         (binaryfunc)    Quaternion_mul, /*nb_multiply*/
897         NULL,                           /*nb_remainder*/
898         NULL,                           /*nb_divmod*/
899         NULL,                           /*nb_power*/
900         (unaryfunc)     Quaternion_neg, /*nb_negative*/
901         (unaryfunc)     Quaternion_copy,/*tp_positive*/
902         (unaryfunc)     0,  /*tp_absolute*/
903         (inquiry)   0,      /*tp_bool*/
904         (unaryfunc) 0,      /*nb_invert*/
905         NULL,               /*nb_lshift*/
906         (binaryfunc)0,      /*nb_rshift*/
907         NULL,               /*nb_and*/
908         NULL,               /*nb_xor*/
909         NULL,               /*nb_or*/
910         NULL,               /*nb_int*/
911         NULL,               /*nb_reserved*/
912         NULL,               /*nb_float*/
913         NULL,               /* nb_inplace_add */
914         NULL,               /* nb_inplace_subtract */
915         NULL,               /* nb_inplace_multiply */
916         NULL,               /* nb_inplace_remainder */
917         NULL,               /* nb_inplace_power */
918         NULL,               /* nb_inplace_lshift */
919         NULL,               /* nb_inplace_rshift */
920         NULL,               /* nb_inplace_and */
921         NULL,               /* nb_inplace_xor */
922         NULL,               /* nb_inplace_or */
923         NULL,               /* nb_floor_divide */
924         NULL,               /* nb_true_divide */
925         NULL,               /* nb_inplace_floor_divide */
926         NULL,               /* nb_inplace_true_divide */
927         NULL,               /* nb_index */
928 };
929
930 PyDoc_STRVAR(Quaternion_axis_doc,
931 "Quaternion axis value.\n\n:type: float"
932 );
933 static PyObject *Quaternion_axis_get(QuaternionObject *self, void *type)
934 {
935         return Quaternion_item(self, GET_INT_FROM_POINTER(type));
936 }
937
938 static int Quaternion_axis_set(QuaternionObject *self, PyObject *value, void *type)
939 {
940         return Quaternion_ass_item(self, GET_INT_FROM_POINTER(type), value);
941 }
942
943 PyDoc_STRVAR(Quaternion_magnitude_doc,
944 "Size of the quaternion (read-only).\n\n:type: float"
945 );
946 static PyObject *Quaternion_magnitude_get(QuaternionObject *self, void *UNUSED(closure))
947 {
948         if (BaseMath_ReadCallback(self) == -1)
949                 return NULL;
950
951         return PyFloat_FromDouble(sqrtf(dot_qtqt(self->quat, self->quat)));
952 }
953
954 PyDoc_STRVAR(Quaternion_angle_doc,
955 "Angle of the quaternion.\n\n:type: float"
956 );
957 static PyObject *Quaternion_angle_get(QuaternionObject *self, void *UNUSED(closure))
958 {
959         float tquat[4];
960         float angle;
961
962         if (BaseMath_ReadCallback(self) == -1)
963                 return NULL;
964
965         normalize_qt_qt(tquat, self->quat);
966
967         angle = 2.0f * saacos(tquat[0]);
968
969         quat__axis_angle_sanitize(NULL, &angle);
970
971         return PyFloat_FromDouble(angle);
972 }
973
974 static int Quaternion_angle_set(QuaternionObject *self, PyObject *value, void *UNUSED(closure))
975 {
976         float tquat[4];
977         float len;
978
979         float axis[3], angle_dummy;
980         float angle;
981
982         if (BaseMath_ReadCallback(self) == -1)
983                 return -1;
984
985         len = normalize_qt_qt(tquat, self->quat);
986         quat_to_axis_angle(axis, &angle_dummy, tquat);
987
988         angle = PyFloat_AsDouble(value);
989
990         if (angle == -1.0f && PyErr_Occurred()) { /* parsed item not a number */
991                 PyErr_SetString(PyExc_TypeError,
992                                 "Quaternion.angle = value: float expected");
993                 return -1;
994         }
995
996         angle = angle_wrap_rad(angle);
997
998         quat__axis_angle_sanitize(axis, &angle);
999
1000         axis_angle_to_quat(self->quat, axis, angle);
1001         mul_qt_fl(self->quat, len);
1002
1003         if (BaseMath_WriteCallback(self) == -1)
1004                 return -1;
1005
1006         return 0;
1007 }
1008
1009 PyDoc_STRVAR(Quaternion_axis_vector_doc,
1010 "Quaternion axis as a vector.\n\n:type: :class:`Vector`"
1011 );
1012 static PyObject *Quaternion_axis_vector_get(QuaternionObject *self, void *UNUSED(closure))
1013 {
1014         float tquat[4];
1015
1016         float axis[3];
1017         float angle_dummy;
1018
1019         if (BaseMath_ReadCallback(self) == -1)
1020                 return NULL;
1021
1022         normalize_qt_qt(tquat, self->quat);
1023         quat_to_axis_angle(axis, &angle_dummy, tquat);
1024
1025         quat__axis_angle_sanitize(axis, NULL);
1026
1027         return Vector_CreatePyObject(axis, 3, NULL);
1028 }
1029
1030 static int Quaternion_axis_vector_set(QuaternionObject *self, PyObject *value, void *UNUSED(closure))
1031 {
1032         float tquat[4];
1033         float len;
1034
1035         float axis[3];
1036         float angle;
1037
1038         if (BaseMath_ReadCallback(self) == -1)
1039                 return -1;
1040
1041         len = normalize_qt_qt(tquat, self->quat);
1042         quat_to_axis_angle(axis, &angle, tquat); /* axis value is unused */
1043
1044         if (mathutils_array_parse(axis, 3, 3, value, "quat.axis = other") == -1)
1045                 return -1;
1046
1047         quat__axis_angle_sanitize(axis, &angle);
1048
1049         axis_angle_to_quat(self->quat, axis, angle);
1050         mul_qt_fl(self->quat, len);
1051
1052         if (BaseMath_WriteCallback(self) == -1)
1053                 return -1;
1054
1055         return 0;
1056 }
1057
1058 /* ----------------------------------mathutils.Quaternion() -------------- */
1059 static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1060 {
1061         PyObject *seq = NULL;
1062         double angle = 0.0f;
1063         float quat[QUAT_SIZE] = {0.0f, 0.0f, 0.0f, 0.0f};
1064
1065         if (kwds && PyDict_Size(kwds)) {
1066                 PyErr_SetString(PyExc_TypeError,
1067                                 "mathutils.Quaternion(): "
1068                                 "takes no keyword args");
1069                 return NULL;
1070         }
1071
1072         if (!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle))
1073                 return NULL;
1074
1075         switch (PyTuple_GET_SIZE(args)) {
1076                 case 0:
1077                         break;
1078                 case 1:
1079                         if (mathutils_array_parse(quat, QUAT_SIZE, QUAT_SIZE, seq, "mathutils.Quaternion()") == -1)
1080                                 return NULL;
1081                         break;
1082                 case 2:
1083                 {
1084                         float axis[3];
1085                         if (mathutils_array_parse(axis, 3, 3, seq, "mathutils.Quaternion()") == -1)
1086                                 return NULL;
1087                         angle = angle_wrap_rad(angle); /* clamp because of precision issues */
1088                         axis_angle_to_quat(quat, axis, angle);
1089                         break;
1090                         /* PyArg_ParseTuple assures no more than 2 */
1091                 }
1092         }
1093         return Quaternion_CreatePyObject(quat, type);
1094 }
1095
1096 static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self)
1097 {
1098         PyObject *ret = Quaternion_copy(self);
1099         PyObject *ret_dummy = quat_func(ret);
1100         if (ret_dummy) {
1101                 Py_DECREF(ret_dummy);
1102                 return ret;
1103         }
1104         else { /* error */
1105                 Py_DECREF(ret);
1106                 return NULL;
1107         }
1108 }
1109
1110 /* axis vector suffers from precision errors, use this function to ensure */
1111 static void quat__axis_angle_sanitize(float axis[3], float *angle)
1112 {
1113         if (axis) {
1114                 if (is_zero_v3(axis) ||
1115                     !finite(axis[0]) ||
1116                     !finite(axis[1]) ||
1117                     !finite(axis[2]))
1118                 {
1119                         axis[0] = 1.0f;
1120                         axis[1] = 0.0f;
1121                         axis[2] = 0.0f;
1122                 }
1123                 else if (EXPP_FloatsAreEqual(axis[0], 0.0f, 10) &&
1124                          EXPP_FloatsAreEqual(axis[1], 0.0f, 10) &&
1125                          EXPP_FloatsAreEqual(axis[2], 0.0f, 10))
1126                 {
1127                         axis[0] = 1.0f;
1128                 }
1129         }
1130
1131         if (angle) {
1132                 if (!finite(*angle)) {
1133                         *angle = 0.0f;
1134                 }
1135         }
1136 }
1137
1138 /* -----------------------METHOD DEFINITIONS ---------------------- */
1139 static struct PyMethodDef Quaternion_methods[] = {
1140         /* in place only */
1141         {"identity", (PyCFunction) Quaternion_identity, METH_NOARGS, Quaternion_identity_doc},
1142         {"negate", (PyCFunction) Quaternion_negate, METH_NOARGS, Quaternion_negate_doc},
1143
1144         /* operate on original or copy */
1145         {"conjugate", (PyCFunction) Quaternion_conjugate, METH_NOARGS, Quaternion_conjugate_doc},
1146         {"conjugated", (PyCFunction) Quaternion_conjugated, METH_NOARGS, Quaternion_conjugated_doc},
1147
1148         {"invert", (PyCFunction) Quaternion_invert, METH_NOARGS, Quaternion_invert_doc},
1149         {"inverted", (PyCFunction) Quaternion_inverted, METH_NOARGS, Quaternion_inverted_doc},
1150
1151         {"normalize", (PyCFunction) Quaternion_normalize, METH_NOARGS, Quaternion_normalize_doc},
1152         {"normalized", (PyCFunction) Quaternion_normalized, METH_NOARGS, Quaternion_normalized_doc},
1153
1154         /* return converted representation */
1155         {"to_euler", (PyCFunction) Quaternion_to_euler, METH_VARARGS, Quaternion_to_euler_doc},
1156         {"to_matrix", (PyCFunction) Quaternion_to_matrix, METH_NOARGS, Quaternion_to_matrix_doc},
1157         {"to_axis_angle", (PyCFunction) Quaternion_to_axis_angle, METH_NOARGS, Quaternion_to_axis_angle_doc},
1158
1159         /* operation between 2 or more types  */
1160         {"cross", (PyCFunction) Quaternion_cross, METH_O, Quaternion_cross_doc},
1161         {"dot", (PyCFunction) Quaternion_dot, METH_O, Quaternion_dot_doc},
1162         {"rotation_difference", (PyCFunction) Quaternion_rotation_difference, METH_O, Quaternion_rotation_difference_doc},
1163         {"slerp", (PyCFunction) Quaternion_slerp, METH_VARARGS, Quaternion_slerp_doc},
1164         {"rotate", (PyCFunction) Quaternion_rotate, METH_O, Quaternion_rotate_doc},
1165
1166         {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
1167         {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
1168         {"__deepcopy__", (PyCFunction) Quaternion_deepcopy, METH_VARARGS, Quaternion_copy_doc},
1169         {NULL, NULL, 0, NULL}
1170 };
1171
1172 /*****************************************************************************/
1173 /* Python attributes get/set structure:                                      */
1174 /*****************************************************************************/
1175 static PyGetSetDef Quaternion_getseters[] = {
1176         {(char *)"w", (getter)Quaternion_axis_get, (setter)Quaternion_axis_set, Quaternion_axis_doc, (void *)0},
1177         {(char *)"x", (getter)Quaternion_axis_get, (setter)Quaternion_axis_set, Quaternion_axis_doc, (void *)1},
1178         {(char *)"y", (getter)Quaternion_axis_get, (setter)Quaternion_axis_set, Quaternion_axis_doc, (void *)2},
1179         {(char *)"z", (getter)Quaternion_axis_get, (setter)Quaternion_axis_set, Quaternion_axis_doc, (void *)3},
1180         {(char *)"magnitude", (getter)Quaternion_magnitude_get, (setter)NULL, Quaternion_magnitude_doc, NULL},
1181         {(char *)"angle", (getter)Quaternion_angle_get, (setter)Quaternion_angle_set, Quaternion_angle_doc, NULL},
1182         {(char *)"axis", (getter)Quaternion_axis_vector_get, (setter)Quaternion_axis_vector_set, Quaternion_axis_vector_doc, NULL},
1183         {(char *)"is_wrapped", (getter)BaseMathObject_is_wrapped_get, (setter)NULL, BaseMathObject_is_wrapped_doc, NULL},
1184         {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL},
1185         {NULL, NULL, NULL, NULL, NULL}  /* Sentinel */
1186 };
1187
1188 /* ------------------PY_OBECT DEFINITION-------------------------- */
1189 PyDoc_STRVAR(quaternion_doc,
1190 "This object gives access to Quaternions in Blender."
1191 );
1192 PyTypeObject quaternion_Type = {
1193         PyVarObject_HEAD_INIT(NULL, 0)
1194         "Quaternion",                       /* tp_name */
1195         sizeof(QuaternionObject),           /* tp_basicsize */
1196         0,                                  /* tp_itemsize */
1197         (destructor)BaseMathObject_dealloc, /* tp_dealloc */
1198         NULL,                               /* tp_print */
1199         NULL,                               /* tp_getattr */
1200         NULL,                               /* tp_setattr */
1201         NULL,                               /* tp_compare */
1202         (reprfunc) Quaternion_repr,         /* tp_repr */
1203         &Quaternion_NumMethods,             /* tp_as_number */
1204         &Quaternion_SeqMethods,             /* tp_as_sequence */
1205         &Quaternion_AsMapping,              /* tp_as_mapping */
1206         NULL,                               /* tp_hash */
1207         NULL,                               /* tp_call */
1208 #ifndef MATH_STANDALONE
1209         (reprfunc) Quaternion_str,          /* tp_str */
1210 #else
1211         NULL,                               /* tp_str */
1212 #endif
1213         NULL,                               /* tp_getattro */
1214         NULL,                               /* tp_setattro */
1215         NULL,                               /* tp_as_buffer */
1216         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
1217         quaternion_doc, /* tp_doc */
1218         (traverseproc)BaseMathObject_traverse,  /* tp_traverse */
1219         (inquiry)BaseMathObject_clear,  /* tp_clear */
1220         (richcmpfunc)Quaternion_richcmpr,   /* tp_richcompare */
1221         0,                                  /* tp_weaklistoffset */
1222         NULL,                               /* tp_iter */
1223         NULL,                               /* tp_iternext */
1224         Quaternion_methods,                 /* tp_methods */
1225         NULL,                               /* tp_members */
1226         Quaternion_getseters,               /* tp_getset */
1227         NULL,                               /* tp_base */
1228         NULL,                               /* tp_dict */
1229         NULL,                               /* tp_descr_get */
1230         NULL,                               /* tp_descr_set */
1231         0,                                  /* tp_dictoffset */
1232         NULL,                               /* tp_init */
1233         NULL,                               /* tp_alloc */
1234         Quaternion_new,                     /* tp_new */
1235         NULL,                               /* tp_free */
1236         NULL,                               /* tp_is_gc */
1237         NULL,                               /* tp_bases */
1238         NULL,                               /* tp_mro */
1239         NULL,                               /* tp_cache */
1240         NULL,                               /* tp_subclasses */
1241         NULL,                               /* tp_weaklist */
1242         NULL,                               /* tp_del */
1243 };
1244
1245 PyObject *Quaternion_CreatePyObject(
1246         const float quat[4],
1247         PyTypeObject *base_type)
1248 {
1249         QuaternionObject *self;
1250         float *quat_alloc;
1251
1252         quat_alloc = PyMem_Malloc(QUAT_SIZE * sizeof(float));
1253         if (UNLIKELY(quat_alloc == NULL)) {
1254                 PyErr_SetString(PyExc_MemoryError,
1255                                 "Quaternion(): "
1256                                 "problem allocating data");
1257                 return NULL;
1258         }
1259
1260         self = BASE_MATH_NEW(QuaternionObject, quaternion_Type, base_type);
1261         if (self) {
1262                 self->quat = quat_alloc;
1263                 /* init callbacks as NULL */
1264                 self->cb_user = NULL;
1265                 self->cb_type = self->cb_subtype = 0;
1266
1267                 /* NEW */
1268                 if (!quat) {  /* new empty */
1269                         unit_qt(self->quat);
1270                 }
1271                 else {
1272                         copy_qt_qt(self->quat, quat);
1273                 }
1274                 self->flag = BASE_MATH_FLAG_DEFAULT;
1275         }
1276         else {
1277                 PyMem_Free(quat_alloc);
1278         }
1279
1280         return (PyObject *)self;
1281 }
1282
1283 PyObject *Quaternion_CreatePyObject_wrap(
1284         float quat[4],
1285         PyTypeObject *base_type)
1286 {
1287         QuaternionObject *self;
1288
1289         self = BASE_MATH_NEW(QuaternionObject, quaternion_Type, base_type);
1290         if (self) {
1291                 /* init callbacks as NULL */
1292                 self->cb_user = NULL;
1293                 self->cb_type = self->cb_subtype = 0;
1294
1295                 /* WRAP */
1296                 self->quat = quat;
1297                 self->flag = BASE_MATH_FLAG_DEFAULT | BASE_MATH_FLAG_IS_WRAP;
1298         }
1299         return (PyObject *) self;
1300 }
1301
1302 PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user,
1303                                        unsigned char cb_type, unsigned char cb_subtype)
1304 {
1305         QuaternionObject *self = (QuaternionObject *)Quaternion_CreatePyObject(NULL, NULL);
1306         if (self) {
1307                 Py_INCREF(cb_user);
1308                 self->cb_user         = cb_user;
1309                 self->cb_type         = cb_type;
1310                 self->cb_subtype      = cb_subtype;
1311                 PyObject_GC_Track(self);
1312         }
1313
1314         return (PyObject *)self;
1315 }
1316