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