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