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