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