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