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