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