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