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