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