NLA SoC: Merge from 2.5 - 21146 to 21178
[blender.git] / source / blender / python / generic / quat.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 #include "Mathutils.h"
30
31 #include "BLI_arithb.h"
32 #include "BKE_utildefines.h"
33 #include "BLI_blenlib.h"
34
35
36 //-------------------------DOC STRINGS ---------------------------
37 static char Quaternion_Identity_doc[] = "() - set the quaternion to it's identity (1, vector)";
38 static char Quaternion_Negate_doc[] = "() - set all values in the quaternion to their negative";
39 static char Quaternion_Conjugate_doc[] = "() - set the quaternion to it's conjugate";
40 static char Quaternion_Inverse_doc[] = "() - set the quaternion to it's inverse";
41 static char Quaternion_Normalize_doc[] = "() - normalize the vector portion of the quaternion";
42 static char Quaternion_ToEuler_doc[] = "(eul_compat) - return a euler rotation representing the quaternion, optional euler argument that the new euler will be made compatible with.";
43 static char Quaternion_ToMatrix_doc[] = "() - return a rotation matrix representing the quaternion";
44 static char Quaternion_Cross_doc[] = "(other) - return the cross product between this quaternion and another";
45 static char Quaternion_Dot_doc[] = "(other) - return the dot product between this quaternion and another";
46 static char Quaternion_copy_doc[] = "() - return a copy of the quat";
47
48 static PyObject *Quaternion_Identity( QuaternionObject * self );
49 static PyObject *Quaternion_Negate( QuaternionObject * self );
50 static PyObject *Quaternion_Conjugate( QuaternionObject * self );
51 static PyObject *Quaternion_Inverse( QuaternionObject * self );
52 static PyObject *Quaternion_Normalize( QuaternionObject * self );
53 static PyObject *Quaternion_ToEuler( QuaternionObject * self, PyObject *args );
54 static PyObject *Quaternion_ToMatrix( QuaternionObject * self );
55 static PyObject *Quaternion_Cross( QuaternionObject * self, QuaternionObject * value );
56 static PyObject *Quaternion_Dot( QuaternionObject * self, QuaternionObject * value );
57 static PyObject *Quaternion_copy( QuaternionObject * self );
58
59 //-----------------------METHOD DEFINITIONS ----------------------
60 static struct PyMethodDef Quaternion_methods[] = {
61         {"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, Quaternion_Identity_doc},
62         {"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, Quaternion_Negate_doc},
63         {"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, Quaternion_Conjugate_doc},
64         {"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, Quaternion_Inverse_doc},
65         {"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, Quaternion_Normalize_doc},
66         {"toEuler", (PyCFunction) Quaternion_ToEuler, METH_VARARGS, Quaternion_ToEuler_doc},
67         {"toMatrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, Quaternion_ToMatrix_doc},
68         {"cross", (PyCFunction) Quaternion_Cross, METH_O, Quaternion_Cross_doc},
69         {"dot", (PyCFunction) Quaternion_Dot, METH_O, Quaternion_Dot_doc},
70         {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
71         {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
72         {NULL, NULL, 0, NULL}
73 };
74
75 //----------------------------------Mathutils.Quaternion() --------------
76 static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
77 {
78         PyObject *listObject = NULL, *n, *q;
79         int size, i;
80         float quat[4];
81         double angle = 0.0f;
82
83         size = PyTuple_GET_SIZE(args);
84         if (size == 1 || size == 2) { //seq?
85                 listObject = PyTuple_GET_ITEM(args, 0);
86                 if (PySequence_Check(listObject)) {
87                         size = PySequence_Length(listObject);
88                         if ((size == 4 && PySequence_Length(args) !=1) || 
89                                 (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) { 
90                                 // invalid args/size
91                                 PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
92                                 return NULL;
93                         }
94                         if(size == 3){ //get angle in axis/angle
95                                 n = PySequence_GetItem(args, 1);
96                                 if(n == NULL) { // parsed item not a number or getItem fail
97                                         PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
98                                         return NULL;
99                                 }
100                                 
101                                 angle = PyFloat_AsDouble(n);
102                                 Py_DECREF(n);
103                                 
104                                 if (angle==-1 && PyErr_Occurred()) {
105                                         PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
106                                         return NULL;
107                                 }
108                         }
109                 }else{
110                         listObject = PyTuple_GET_ITEM(args, 1);
111                         if (size>1 && PySequence_Check(listObject)) {
112                                 size = PySequence_Length(listObject);
113                                 if (size != 3) { 
114                                         // invalid args/size
115                                         PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
116                                         return NULL;
117                                 }
118                                 angle = PyFloat_AsDouble(PyTuple_GET_ITEM(args, 0));
119                                 
120                                 if (angle==-1 && PyErr_Occurred()) {
121                                         PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
122                                         return NULL;
123                                 }
124                         } else { // argument was not a sequence
125                                 PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
126                                 return NULL;
127                         }
128                 }
129         } else if (size == 0) { //returns a new empty quat
130                 return newQuaternionObject(NULL, Py_NEW); 
131         } else {
132                 listObject = args;
133         }
134
135         if (size == 3) { // invalid quat size
136                 if(PySequence_Length(args) != 2){
137                         PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
138                         return NULL;
139                 }
140         }else{
141                 if(size != 4){
142                         PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
143                         return NULL;
144                 }
145         }
146
147         for (i=0; i<size; i++) { //parse
148                 q = PySequence_GetItem(listObject, i);
149                 if (q == NULL) { // Failed to read sequence
150                         PyErr_SetString(PyExc_RuntimeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
151                         return NULL;
152                 }
153
154                 quat[i] = PyFloat_AsDouble(q);
155                 Py_DECREF(q);
156
157                 if (quat[i]==-1 && PyErr_Occurred()) {
158                         PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
159                         return NULL;
160                 }
161         }
162
163         if(size == 3) //calculate the quat based on axis/angle
164 #ifdef USE_MATHUTILS_DEG
165                 AxisAngleToQuat(quat, quat, angle * (Py_PI / 180));
166 #else
167                 AxisAngleToQuat(quat, quat, angle);
168 #endif
169
170         return newQuaternionObject(quat, Py_NEW);
171 }
172
173 //-----------------------------METHODS------------------------------
174 //----------------------------Quaternion.toEuler()------------------
175 //return the quat as a euler
176 static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
177 {
178         float eul[3];
179         EulerObject *eul_compat = NULL;
180         int x;
181         
182         if(!PyArg_ParseTuple(args, "|O!:toEuler", &euler_Type, &eul_compat))
183                 return NULL;
184         
185         if(!BaseMath_ReadCallback(self))
186                 return NULL;
187
188         if(eul_compat) {
189                 float mat[3][3], eul_compatf[3];
190                 
191                 if(!BaseMath_ReadCallback(eul_compat))
192                         return NULL;
193                 
194                 QuatToMat3(self->quat, mat);
195
196 #ifdef USE_MATHUTILS_DEG
197                 for(x = 0; x < 3; x++) {
198                         eul_compatf[x] = eul_compat->eul[x] * ((float)Py_PI / 180);
199                 }
200                 Mat3ToCompatibleEul(mat, eul, eul_compatf);
201 #else
202                 Mat3ToCompatibleEul(mat, eul, eul_compat->eul);
203 #endif
204         }
205         else {
206                 QuatToEul(self->quat, eul);
207         }
208         
209 #ifdef USE_MATHUTILS_DEG
210         for(x = 0; x < 3; x++) {
211                 eul[x] *= (180 / (float)Py_PI);
212         }
213 #endif
214         return newEulerObject(eul, Py_NEW);
215 }
216 //----------------------------Quaternion.toMatrix()------------------
217 //return the quat as a matrix
218 static PyObject *Quaternion_ToMatrix(QuaternionObject * self)
219 {
220         float mat[9]; /* all values are set */
221
222         if(!BaseMath_ReadCallback(self))
223                 return NULL;
224
225         QuatToMat3(self->quat, (float (*)[3]) mat);
226         return newMatrixObject(mat, 3, 3, Py_NEW);
227 }
228
229 //----------------------------Quaternion.cross(other)------------------
230 //return the cross quat
231 static PyObject *Quaternion_Cross(QuaternionObject * self, QuaternionObject * value)
232 {
233         float quat[4];
234         
235         if (!QuaternionObject_Check(value)) {
236                 PyErr_SetString( PyExc_TypeError, "quat.cross(value): expected a quaternion argument" );
237                 return NULL;
238         }
239         
240         if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
241                 return NULL;
242
243         QuatMul(quat, self->quat, value->quat);
244         return newQuaternionObject(quat, Py_NEW);
245 }
246
247 //----------------------------Quaternion.dot(other)------------------
248 //return the dot quat
249 static PyObject *Quaternion_Dot(QuaternionObject * self, QuaternionObject * value)
250 {
251         if (!QuaternionObject_Check(value)) {
252                 PyErr_SetString( PyExc_TypeError, "quat.dot(value): expected a quaternion argument" );
253                 return NULL;
254         }
255
256         if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
257                 return NULL;
258
259         return PyFloat_FromDouble(QuatDot(self->quat, value->quat));
260 }
261
262 //----------------------------Quaternion.normalize()----------------
263 //normalize the axis of rotation of [theta,vector]
264 static PyObject *Quaternion_Normalize(QuaternionObject * self)
265 {
266         if(!BaseMath_ReadCallback(self))
267                 return NULL;
268
269         NormalQuat(self->quat);
270
271         BaseMath_WriteCallback(self);
272         Py_INCREF(self);
273         return (PyObject*)self;
274 }
275 //----------------------------Quaternion.inverse()------------------
276 //invert the quat
277 static PyObject *Quaternion_Inverse(QuaternionObject * self)
278 {
279         if(!BaseMath_ReadCallback(self))
280                 return NULL;
281
282         QuatInv(self->quat);
283
284         BaseMath_WriteCallback(self);
285         Py_INCREF(self);
286         return (PyObject*)self;
287 }
288 //----------------------------Quaternion.identity()-----------------
289 //generate the identity quaternion
290 static PyObject *Quaternion_Identity(QuaternionObject * self)
291 {
292         if(!BaseMath_ReadCallback(self))
293                 return NULL;
294
295         QuatOne(self->quat);
296
297         BaseMath_WriteCallback(self);
298         Py_INCREF(self);
299         return (PyObject*)self;
300 }
301 //----------------------------Quaternion.negate()-------------------
302 //negate the quat
303 static PyObject *Quaternion_Negate(QuaternionObject * self)
304 {
305         if(!BaseMath_ReadCallback(self))
306                 return NULL;
307
308         QuatMulf(self->quat, -1.0f);
309
310         BaseMath_WriteCallback(self);
311         Py_INCREF(self);
312         return (PyObject*)self;
313 }
314 //----------------------------Quaternion.conjugate()----------------
315 //negate the vector part
316 static PyObject *Quaternion_Conjugate(QuaternionObject * self)
317 {
318         if(!BaseMath_ReadCallback(self))
319                 return NULL;
320
321         QuatConj(self->quat);
322
323         BaseMath_WriteCallback(self);
324         Py_INCREF(self);
325         return (PyObject*)self;
326 }
327 //----------------------------Quaternion.copy()----------------
328 //return a copy of the quat
329 static PyObject *Quaternion_copy(QuaternionObject * self)
330 {
331         if(!BaseMath_ReadCallback(self))
332                 return NULL;
333
334         return newQuaternionObject(self->quat, Py_NEW); 
335 }
336
337 //----------------------------print object (internal)--------------
338 //print the object to screen
339 static PyObject *Quaternion_repr(QuaternionObject * self)
340 {
341         char str[64];
342
343         if(!BaseMath_ReadCallback(self))
344                 return NULL;
345
346         sprintf(str, "[%.6f, %.6f, %.6f, %.6f](quaternion)", self->quat[0], self->quat[1], self->quat[2], self->quat[3]);
347         return PyUnicode_FromString(str);
348 }
349 //------------------------tp_richcmpr
350 //returns -1 execption, 0 false, 1 true
351 static PyObject* Quaternion_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
352 {
353         QuaternionObject *quatA = NULL, *quatB = NULL;
354         int result = 0;
355
356         if(QuaternionObject_Check(objectA)) {
357                 quatA = (QuaternionObject*)objectA;
358                 if(!BaseMath_ReadCallback(quatA))
359                         return NULL;
360         }
361         if(QuaternionObject_Check(objectB)) {
362                 quatB = (QuaternionObject*)objectB;
363                 if(!BaseMath_ReadCallback(quatB))
364                         return NULL;
365         }
366
367         if (!quatA || !quatB){
368                 if (comparison_type == Py_NE){
369                         Py_RETURN_TRUE;
370                 }else{
371                         Py_RETURN_FALSE;
372                 }
373         }
374
375         switch (comparison_type){
376                 case Py_EQ:
377                         result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, 4, 1);
378                         break;
379                 case Py_NE:
380                         result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, 4, 1);
381                         if (result == 0){
382                                 result = 1;
383                         }else{
384                                 result = 0;
385                         }
386                         break;
387                 default:
388                         printf("The result of the comparison could not be evaluated");
389                         break;
390         }
391         if (result == 1){
392                 Py_RETURN_TRUE;
393         }else{
394                 Py_RETURN_FALSE;
395         }
396 }
397 //------------------------tp_doc
398 static char QuaternionObject_doc[] = "This is a wrapper for quaternion objects.";
399 //---------------------SEQUENCE PROTOCOLS------------------------
400 //----------------------------len(object)------------------------
401 //sequence length
402 static int Quaternion_len(QuaternionObject * self)
403 {
404         return 4;
405 }
406 //----------------------------object[]---------------------------
407 //sequence accessor (get)
408 static PyObject *Quaternion_item(QuaternionObject * self, int i)
409 {
410         if(i<0) i= 4-i;
411
412         if(i < 0 || i >= 4) {
413                 PyErr_SetString(PyExc_IndexError, "quaternion[attribute]: array index out of range\n");
414                 return NULL;
415         }
416
417         if(!BaseMath_ReadIndexCallback(self, i))
418                 return NULL;
419
420         return PyFloat_FromDouble(self->quat[i]);
421
422 }
423 //----------------------------object[]-------------------------
424 //sequence accessor (set)
425 static int Quaternion_ass_item(QuaternionObject * self, int i, PyObject * ob)
426 {
427         float scalar= (float)PyFloat_AsDouble(ob);
428         if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
429                 PyErr_SetString(PyExc_TypeError, "quaternion[index] = x: index argument not a number\n");
430                 return -1;
431         }
432
433         if(i<0) i= 4-i;
434
435         if(i < 0 || i >= 4){
436                 PyErr_SetString(PyExc_IndexError, "quaternion[attribute] = x: array assignment index out of range\n");
437                 return -1;
438         }
439         self->quat[i] = scalar;
440
441         if(!BaseMath_WriteIndexCallback(self, i))
442                 return -1;
443
444         return 0;
445 }
446 //----------------------------object[z:y]------------------------
447 //sequence slice (get)
448 static PyObject *Quaternion_slice(QuaternionObject * self, int begin, int end)
449 {
450         PyObject *list = NULL;
451         int count;
452
453         if(!BaseMath_ReadCallback(self))
454                 return NULL;
455
456         CLAMP(begin, 0, 4);
457         if (end<0) end= 5+end;
458         CLAMP(end, 0, 4);
459         begin = MIN2(begin,end);
460
461         list = PyList_New(end - begin);
462         for(count = begin; count < end; count++) {
463                 PyList_SetItem(list, count - begin,
464                                 PyFloat_FromDouble(self->quat[count]));
465         }
466
467         return list;
468 }
469 //----------------------------object[z:y]------------------------
470 //sequence slice (set)
471 static int Quaternion_ass_slice(QuaternionObject * self, int begin, int end, PyObject * seq)
472 {
473         int i, y, size = 0;
474         float quat[4];
475         PyObject *q;
476
477         if(!BaseMath_ReadCallback(self))
478                 return -1;
479
480         CLAMP(begin, 0, 4);
481         if (end<0) end= 5+end;
482         CLAMP(end, 0, 4);
483         begin = MIN2(begin,end);
484
485         size = PySequence_Length(seq);
486         if(size != (end - begin)){
487                 PyErr_SetString(PyExc_TypeError, "quaternion[begin:end] = []: size mismatch in slice assignment\n");
488                 return -1;
489         }
490
491         for (i = 0; i < size; i++) {
492                 q = PySequence_GetItem(seq, i);
493                 if (q == NULL) { // Failed to read sequence
494                         PyErr_SetString(PyExc_RuntimeError, "quaternion[begin:end] = []: unable to read sequence\n");
495                         return -1;
496                 }
497
498                 quat[i]= (float)PyFloat_AsDouble(q);
499                 Py_DECREF(q);
500
501                 if(quat[i]==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
502                         PyErr_SetString(PyExc_TypeError, "quaternion[begin:end] = []: sequence argument not a number\n");
503                         return -1;
504                 }
505         }
506         //parsed well - now set in vector
507         for(y = 0; y < size; y++)
508                 self->quat[begin + y] = quat[y];
509
510         BaseMath_WriteCallback(self);
511         return 0;
512 }
513 //------------------------NUMERIC PROTOCOLS----------------------
514 //------------------------obj + obj------------------------------
515 //addition
516 static PyObject *Quaternion_add(PyObject * q1, PyObject * q2)
517 {
518         float quat[4];
519         QuaternionObject *quat1 = NULL, *quat2 = NULL;
520
521         if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) {
522                 PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation....\n");
523                 return NULL;
524         }
525         quat1 = (QuaternionObject*)q1;
526         quat2 = (QuaternionObject*)q2;
527         
528         if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2))
529                 return NULL;
530
531         QuatAdd(quat, quat1->quat, quat2->quat, 1.0f);
532         return newQuaternionObject(quat, Py_NEW);
533 }
534 //------------------------obj - obj------------------------------
535 //subtraction
536 static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2)
537 {
538         int x;
539         float quat[4];
540         QuaternionObject *quat1 = NULL, *quat2 = NULL;
541
542         if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) {
543                 PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation....\n");
544                 return NULL;
545         }
546         
547         quat1 = (QuaternionObject*)q1;
548         quat2 = (QuaternionObject*)q2;
549         
550         if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2))
551                 return NULL;
552
553         for(x = 0; x < 4; x++) {
554                 quat[x] = quat1->quat[x] - quat2->quat[x];
555         }
556
557         return newQuaternionObject(quat, Py_NEW);
558 }
559 //------------------------obj * obj------------------------------
560 //mulplication
561 static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2)
562 {
563         float quat[4], scalar;
564         QuaternionObject *quat1 = NULL, *quat2 = NULL;
565         VectorObject *vec = NULL;
566
567         if(QuaternionObject_Check(q1)) {
568                 quat1 = (QuaternionObject*)q1;
569                 if(!BaseMath_ReadCallback(quat1))
570                         return NULL;
571         }
572         if(QuaternionObject_Check(q2)) {
573                 quat2 = (QuaternionObject*)q2;
574                 if(!BaseMath_ReadCallback(quat2))
575                         return NULL;
576         }
577
578         if(quat1 && quat2) { /* QUAT*QUAT (dot product) */
579                 return PyFloat_FromDouble(QuatDot(quat1->quat, quat2->quat));
580         }
581         
582         /* the only case this can happen (for a supported type is "FLOAT*QUAT" ) */
583         if(!QuaternionObject_Check(q1)) {
584                 scalar= PyFloat_AsDouble(q1);
585                 if ((scalar == -1.0 && PyErr_Occurred())==0) { /* FLOAT*QUAT */
586                         QUATCOPY(quat, quat2->quat);
587                         QuatMulf(quat, scalar);
588                         return newQuaternionObject(quat, Py_NEW);
589                 }
590                 PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: val * quat, val is not an acceptable type");
591                 return NULL;
592         }
593         else { /* QUAT*SOMETHING */
594                 if(VectorObject_Check(q2)){  /* QUAT*VEC */
595                         vec = (VectorObject*)q2;
596                         if(vec->size != 3){
597                                 PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: only 3D vector rotations currently supported\n");
598                                 return NULL;
599                         }
600                         return quat_rotation((PyObject*)quat1, (PyObject*)vec);
601                 }
602                 
603                 scalar= PyFloat_AsDouble(q2);
604                 if ((scalar == -1.0 && PyErr_Occurred())==0) { /* QUAT*FLOAT */
605                         QUATCOPY(quat, quat1->quat);
606                         QuatMulf(quat, scalar);
607                         return newQuaternionObject(quat, Py_NEW);
608                 }
609         }
610         
611         PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: arguments not acceptable for this operation\n");
612         return NULL;
613 }
614
615 //-----------------PROTOCOL DECLARATIONS--------------------------
616 static PySequenceMethods Quaternion_SeqMethods = {
617         (inquiry) Quaternion_len,                                       /* sq_length */
618         (binaryfunc) 0,                                                         /* sq_concat */
619         (ssizeargfunc) 0,                                                               /* sq_repeat */
620         (ssizeargfunc) Quaternion_item,                         /* sq_item */
621         (ssizessizeargfunc) Quaternion_slice,                   /* sq_slice */
622         (ssizeobjargproc) Quaternion_ass_item,          /* sq_ass_item */
623         (ssizessizeobjargproc) Quaternion_ass_slice,    /* sq_ass_slice */
624 };
625 static PyNumberMethods Quaternion_NumMethods = {
626         (binaryfunc) Quaternion_add,                            /* __add__ */
627         (binaryfunc) Quaternion_sub,                            /* __sub__ */
628         (binaryfunc) Quaternion_mul,                            /* __mul__ */
629         (binaryfunc) 0,                                                         /* __div__ */
630         (binaryfunc) 0,                                                         /* __mod__ */
631         (binaryfunc) 0,                                                         /* __divmod__ */
632         (ternaryfunc) 0,                                                        /* __pow__ */
633         (unaryfunc) 0,                                                          /* __neg__ */
634         (unaryfunc) 0,                                                          /* __pos__ */
635         (unaryfunc) 0,                                                          /* __abs__ */
636         (inquiry) 0,                                                            /* __nonzero__ */
637         (unaryfunc) 0,                                                          /* __invert__ */
638         (binaryfunc) 0,                                                         /* __lshift__ */
639         (binaryfunc) 0,                                                         /* __rshift__ */
640         (binaryfunc) 0,                                                         /* __and__ */
641         (binaryfunc) 0,                                                         /* __xor__ */
642         (binaryfunc) 0,                                                         /* __or__ */
643         /*(coercion)*/  0,                                                              /* __coerce__ */
644         (unaryfunc) 0,                                                          /* __int__ */
645         (unaryfunc) 0,                                                          /* __long__ */
646         (unaryfunc) 0,                                                          /* __float__ */
647         (unaryfunc) 0,                                                          /* __oct__ */
648         (unaryfunc) 0,                                                          /* __hex__ */
649
650 };
651
652
653 static PyObject *Quaternion_getAxis( QuaternionObject * self, void *type )
654 {
655         return Quaternion_item(self, GET_INT_FROM_POINTER(type));
656 }
657
658 static int Quaternion_setAxis( QuaternionObject * self, PyObject * value, void * type )
659 {
660         return Quaternion_ass_item(self, GET_INT_FROM_POINTER(type), value);
661 }
662
663 static PyObject *Quaternion_getMagnitude( QuaternionObject * self, void *type )
664 {
665         return PyFloat_FromDouble(sqrt(QuatDot(self->quat, self->quat)));
666 }
667
668 static PyObject *Quaternion_getAngle( QuaternionObject * self, void *type )
669 {
670         double ang = self->quat[0];
671         ang = 2 * (saacos(ang));
672 #ifdef USE_MATHUTILS_DEG
673         ang *= (180 / Py_PI);
674 #endif
675         return PyFloat_FromDouble(ang);
676 }
677
678 static PyObject *Quaternion_getAxisVec( QuaternionObject * self, void *type )
679 {
680         int i;
681         float vec[3];
682         double mag = self->quat[0] * (Py_PI / 180);
683         mag = 2 * (saacos(mag));
684         mag = sin(mag / 2);
685         for(i = 0; i < 3; i++)
686                 vec[i] = (float)(self->quat[i + 1] / mag);
687         
688         Normalize(vec);
689         //If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations
690         if( EXPP_FloatsAreEqual(vec[0], 0.0f, 10) &&
691                 EXPP_FloatsAreEqual(vec[1], 0.0f, 10) &&
692                 EXPP_FloatsAreEqual(vec[2], 0.0f, 10) ){
693                 vec[0] = 1.0f;
694         }
695         return (PyObject *) newVectorObject(vec, 3, Py_NEW);
696 }
697
698
699 /*****************************************************************************/
700 /* Python attributes get/set structure:                                      */
701 /*****************************************************************************/
702 static PyGetSetDef Quaternion_getseters[] = {
703         {"w",
704          (getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
705          "Quaternion W value",
706          (void *)0},
707         {"x",
708          (getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
709          "Quaternion X axis",
710          (void *)1},
711         {"y",
712          (getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
713          "Quaternion Y axis",
714          (void *)2},
715         {"z",
716          (getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
717          "Quaternion Z axis",
718          (void *)3},
719         {"magnitude",
720          (getter)Quaternion_getMagnitude, (setter)NULL,
721          "Size of the quaternion",
722          NULL},
723         {"angle",
724          (getter)Quaternion_getAngle, (setter)NULL,
725          "angle of the quaternion",
726          NULL},
727         {"axis",
728          (getter)Quaternion_getAxisVec, (setter)NULL,
729          "quaternion axis as a vector",
730          NULL},
731         {"wrapped",
732          (getter)BaseMathObject_getWrapped, (setter)NULL,
733          "True when this wraps blenders internal data",
734          NULL},
735         {"__owner__",
736          (getter)BaseMathObject_getOwner, (setter)NULL,
737          "Read only owner for vectors that depend on another object",
738          NULL},
739
740         {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
741 };
742
743
744 //------------------PY_OBECT DEFINITION--------------------------
745 PyTypeObject quaternion_Type = {
746 #if (PY_VERSION_HEX >= 0x02060000)
747         PyVarObject_HEAD_INIT(NULL, 0)
748 #else
749         /* python 2.5 and below */
750         PyObject_HEAD_INIT( NULL )  /* required py macro */
751         0,                          /* ob_size */
752 #endif
753         "quaternion",                                           //tp_name
754         sizeof(QuaternionObject),                       //tp_basicsize
755         0,                                                              //tp_itemsize
756         (destructor)BaseMathObject_dealloc,             //tp_dealloc
757         0,                                                              //tp_print
758         0,                                                              //tp_getattr
759         0,                                                              //tp_setattr
760         0,                                                              //tp_compare
761         (reprfunc) Quaternion_repr,                     //tp_repr
762         &Quaternion_NumMethods,                         //tp_as_number
763         &Quaternion_SeqMethods,                         //tp_as_sequence
764         0,                                                              //tp_as_mapping
765         0,                                                              //tp_hash
766         0,                                                              //tp_call
767         0,                                                              //tp_str
768         0,                                                              //tp_getattro
769         0,                                                              //tp_setattro
770         0,                                                              //tp_as_buffer
771         Py_TPFLAGS_DEFAULT,                             //tp_flags
772         QuaternionObject_doc,                           //tp_doc
773         0,                                                              //tp_traverse
774         0,                                                              //tp_clear
775         (richcmpfunc)Quaternion_richcmpr,       //tp_richcompare
776         0,                                                              //tp_weaklistoffset
777         0,                                                              //tp_iter
778         0,                                                              //tp_iternext
779         Quaternion_methods,                             //tp_methods
780         0,                                                              //tp_members
781         Quaternion_getseters,                   //tp_getset
782         0,                                                              //tp_base
783         0,                                                              //tp_dict
784         0,                                                              //tp_descr_get
785         0,                                                              //tp_descr_set
786         0,                                                              //tp_dictoffset
787         0,                                                              //tp_init
788         0,                                                              //tp_alloc
789         Quaternion_new,                                 //tp_new
790         0,                                                              //tp_free
791         0,                                                              //tp_is_gc
792         0,                                                              //tp_bases
793         0,                                                              //tp_mro
794         0,                                                              //tp_cache
795         0,                                                              //tp_subclasses
796         0,                                                              //tp_weaklist
797         0                                                               //tp_del
798 };
799 //------------------------newQuaternionObject (internal)-------------
800 //creates a new quaternion object
801 /*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
802  (i.e. it was allocated elsewhere by MEM_mallocN())
803   pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
804  (i.e. it must be created here with PyMEM_malloc())*/
805 PyObject *newQuaternionObject(float *quat, int type)
806 {
807         QuaternionObject *self;
808         
809         self = PyObject_NEW(QuaternionObject, &quaternion_Type);
810
811         /* init callbacks as NULL */
812         self->cb_user= NULL;
813         self->cb_type= self->cb_subtype= 0;
814
815         if(type == Py_WRAP){
816                 self->quat = quat;
817                 self->wrapped = Py_WRAP;
818         }else if (type == Py_NEW){
819                 self->quat = PyMem_Malloc(4 * sizeof(float));
820                 if(!quat) { //new empty
821                         QuatOne(self->quat);
822                 }else{
823                         QUATCOPY(self->quat, quat);
824                 }
825                 self->wrapped = Py_NEW;
826         }else{ //bad type
827                 return NULL;
828         }
829         return (PyObject *) self;
830 }
831
832 PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype)
833 {
834         QuaternionObject *self= (QuaternionObject *)newQuaternionObject(NULL, Py_NEW);
835         if(self) {
836                 Py_INCREF(cb_user);
837                 self->cb_user=                  cb_user;
838                 self->cb_type=                  (unsigned char)cb_type;
839                 self->cb_subtype=               (unsigned char)cb_subtype;
840         }
841
842         return (PyObject *)self;
843 }