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